ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Slang SPIR-V 目标流水线完全解析:direct-emit 路径下的 IR Pass 序列、条件门控与迭代循环

Slang SPIR-V 目标流水线完全解析:direct-emit 路径下的 IR Pass 序列、条件门控与迭代循环 Slang SPIR-V 目标流水线完全解析direct-emit 路径下的 IR Pass 序列、条件门控与迭代循环【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang导读本文以 Slang 编译器的 SPIR-V 目标CodeGenTarget::SPIRV为对象系统梳理当采用 direct-emit 路径shouldEmitSPIRVDirectly() true时从linkIR到最终产出 SPIR-V artifact 的有序、控制流感知的 IR pass 序列四个阶段的划分与边界、每个 pass 的选择条件gate、以及两个迭代到不动点的循环。面向的读者是编译器开发者——无论是想定位某个 pass 在 SPIR-V codegen 流水线中的执行位置、理解某个条件如何选中该 pass还是排查哪些迭代 pass 会循环直到收敛本文都能提供可直接对照源码的答案。文档定位与阅读前提本文内容围绕 target-pipelines-spirv.md 所定义的生成文档契约展开其通用规范见 _common.md 中的Target-pipeline page contract。该契约定义了目标流水线页面的统一结构标题与引言、Source链接清单、高层阶段图≤ 8 节点、按阶段的 mermaid 流程图与有序表格# / Pass / File / Gate / Notes、条件门控汇总表、迭代循环说明、值得注意的 pass 说明以及 See also 链接。本文覆盖的范围边界仅覆盖 direct-emit 路径由CodeGenTarget::SPIRV配合shouldEmitSPIRVDirectly() true触发。包含二进制后处理Phase D 中会将 spirv-link、spirv-val 作为(downstream)矩形节点呈现源码内被#if 0禁用的optimizeSPIRV调用需标注为[disabled]节点。过滤掉非 SPIR-V 分支凡是门控在isCPUTarget、isMetalTarget、isCUDATarget、isWGPUTarget、target HLSL、target GLSL当 SPIR-V 位于兄弟分支时、target CodeGenTarget::PyTorchCppBinding等条件下的 pass均从图示与表格中省略引言部分需明确承认这一过滤规则。via-GLSL 旧路径仅作一句话旁注isKhronosTarget !emitSpirvDirectly的路径只需一句话指向分叉点legalizeModesOfNonCopyableOpaqueTypedParamsForGLSL位于 slang-emit.cpp 约第 2683 行完整的 via-GLSL 控制流图属于未来的 GLSL 目标页面。Source编排器与目标特定文件SPIR-V direct-emit 流水线的关键源文件与入口点如下编排器slang-emit.cpp ——linkAndOptimizeIR约第 1000 行起是共享编排器内部通过SLANG_PASS(passFunc, ...)宏第 1009-1015 行定义包裹每个 passemitSPIRVForEntryPointsDirectly第 3675 行是 direct-emit 的入口createArtifactFromIR第 3441 行负责收尾。SPIR-V 发射器slang-emit-spirv.cpp ——emitSPIRVFromIR约第 3141 行执行实际的 IR→SPIR-V 发射。SPIR-V 专属 legalizationslang-ir-spirv-legalize.cpp ——legalizeIRForSPIRV约第 3352 行与simplifyIRForSpirvLegalization约第 3126 行。需要说明的是prompt 中给出的行号如legalizeModesOfNonCopyableOpaqueTypedParamsForGLSL约第 2229 行是写作时刻的近似值源码在持续演进阅读时应以当前 slang-emit.cpp 中的实际位置为准本文引用的行号均已按当前提交重新核对。前置条件shouldEmitSPIRVDirectlyshouldEmitSPIRVDirectly()在 slang-target-program.h 中定义为isSPIRV(m_targetReq-getTarget()) getOptionSet().shouldEmitSPIRVDirectly()其底层选项实现在 slang-compiler-options.cpp约第 479 行。此外代码中还有大量按此条件分流的调用点例如 slang-ir-inline.cpp 第 1045 行、slang-ir-lower-buffer-element-type.cpp 第 2420/2523/2868 行等说明该开关不仅影响 emit 阶段还深度参与 IR 层面的目标判定。高层阶段图以下为本文覆盖的 SPIR-V direct-emit 流水线的四个阶段总览后续每节给出各自的详细流程图Phase A — Link 与入口点准备覆盖范围从linkIR到入口点统一参数的拆分SPIR-V 的default分支执行moveEntryPointUniformParamsToGlobalScope约在 slang-emit.cpp 的 927-1170 行区间。流程图阶段有序表#PassFileGateNotes1linkIRslang-emit.cpp(always)创建用于 codegen 的全新 IR 模块解析跨模块导入/导出符号并在 profile-overloaded 符号间做选择出错时sink-getErrorCount() ! 0直接SLANG_FAIL。2emitDebugBuildIdentifierslang-emit.cpptargetCompilerOptions.shouldEmitSeparateDebugInfo()仅为独立调试信息构建标识符源码与编译选项的哈希。3validateIRModuleIfEnabledslang-emit.cpp配置启用时按通用契约此类校验节点在图中以注释形式汇总不作为独立节点。4calcRequiredLoweringPassSetslang-emit.cpp(always)扫描 IR 模块确定所需的 lowering/legalization pass 集合写入RequiredLoweringPassSet。5validateAndRemoveAssumeAddressslang-emit.cpprequiredLoweringPassSet.assumeAddressvalidate !isCPUTarget !isCUDATarget。6stripDebugInfoslang-emit.cppgetDebugInfoLevel() DebugInfoLevel::None未请求调试信息时剥离。7lowerGLSLShaderStorageBufferObjectsToStructuredBuffersslang-emit.cpprequiredLoweringPassSet.glslSSBO将 GLSL SSBO 降为结构化缓冲。8translateEntryPointInParamToBorrowslang-emit.cpp(always)—9replaceGlobalConstantsslang-emit.cpp(always)—10bindExistentialSlotsslang-emit.cpprequiredLoweringPassSet.bindExistential—11collectGlobalUniformParametersslang-emit.cpp(always)附带outLinkedIR.globalScopeVarLayout。12checkEntryPointDecorationsslang-emit.cpp(always)传入target, sink。13addDenormalModeDecorationsslang-emit.cpp(always)传入codeGenContext。14collectOptiXEntryPointUniformParamsslang-emit.cppOptiX 目标分支—15collectEntryPointUniformParamsslang-emit.cpp非 OptiX 分支—16moveEntryPointUniformParamsToGlobalScopeslang-emit.cppSPIR-V 的default分支见源码约第 1406 行。Phase B — 特化与类型 legalization覆盖范围从第一个simplifyIR到specializeArrayParameters/checkStaticAssert约在 slang-emit.cpp 的 1172-1714 行区间。流程图阶段有序表仅列出 SPIR-V 可达项#PassFileGateNotes1simplifyIRslang-emit.cpp(always)使用defaultIRSimplificationOptions第 1473-1484 行。2validateUniformityslang-emit.cppgetBoolOption(ValidateUniformity)—3fuseCallsToSaturatedCooperationslang-emit.cpp配置启用时—4generateDerivativeWrappersslang-emit.cpprequiredLoweringPassSet.derivativePyBindWrapper—5checkAutodiffPatternsslang-emit.cpprequiredLoweringPassSet.autodiff传入targetProgram, sink。6diagnoseCircularConformancesslang-emit.cpp(always)—7specializeModuleslang-emit.cpprequiredLoweringPassSet.generics携带specOptions。8specializeHigherOrderParametersslang-emit.cpprequiredLoweringPassSet.higherOrderFunc—9finalizeAutoDiffPass/stripAutoDiffDecorationsslang-emit.cppautodiff 相关—10lowerMatrixSwizzleStoresslang-emit.cpprequiredLoweringPassSet.matrixSwizzleStore—11eliminateDeadCodeslang-emit.cpp(always)携带deadCodeEliminationOptions。12finalizeSpecializationslang-emit.cpp(always)—13lowerConditionalTypeslang-emit.cpprequiredLoweringPassSet.conditionalType—14lowerReinterpretOptional/checkForOptionalNoneUsage/lowerOptionalTypeslang-emit.cppreinterpret/optionalType—15lowerResultTypeslang-emit.cpprequiredLoweringPassSet.resultType—16legalizeNonVectorCompositeSelectslang-emit.cpprequiredLoweringPassSet.nonVectorCompositeSelect—17simplifyIR第二轮slang-emit.cpp!fastIRSimplificationOptions.minimalOptimization—18specializeFuncsForBufferLoadArgs首次slang-emit.cpp约第 2121 行见值得注意的 pass。19specializeArrayParametersslang-emit.cpp约第 2128 行—20checkStaticAssertslang-emit.cpp约第 2134 行实现位于第 685 行递归检查kIROp_StaticAssert类指令。Phase C — SPIR-V legalization、lowering 与 phi 消除覆盖范围从legalizeByteAddressBufferOps到simplifyNonSSAIR与collectMetadata约在 slang-emit.cpp 的 1745-2360 行区间。流程图阶段有序表#PassFileGateNotes1legalizeByteAddressBufferOpsslang-emit.cpprequiredLoweringPassSet.byteAddressBuffer约第 2276 行。2lowerBufferElementTypeToStorageTypeslang-emit.cppSPIR-V 分支约第 2625 行SPIR-V 的矩阵/bool 缓冲元素类型由此 pass 处理。3specializeFuncsForBufferLoadArgs第二次slang-emit.cppSPIR-V 特定位于lowerBufferElementTypeToStorageType之后约第 2655 行见值得注意的 pass。4legalizeEntryPointsForGLSLslang-emit.cpp约第 2363 行对 SPIR-V 同样执行名称反映历史而非当前范围见值得注意的 pass。5eliminatePhisslang-emit.cpp(always)SPIR-V 专属选项phiEliminationOptions.eliminateCompositeTypedPhiOnly false; useRegisterAllocation true第 2718-2724 行。6eliminateDeadCodeslang-emit.cpp(always)phi 消除后清理。7simplifyNonSSAIRslang-emit.cpp!fastIRSimplificationOptions.minimalOptimization约第 2768 行。8collectMetadataslang-emit.cpp(always)约第 2884 行传入targetProgram, *metadata填充 binding / exported-function 字段。Phase D — IR→SPIR-V 发射、简化循环与 downstream 工具覆盖范围从emitSPIRVForEntryPointsDirectly约第 3675 行进入linkAndOptimizeIR调用侧的收尾包装再由createArtifactFromIR约第 3441 行调用emitSPIRVFromIRslang-emit-spirv.cpp 约第 3141 行其中包含legalizeIRForSPIRVslang-ir-spirv-legalize.cpp 约第 3352 行及其内部的simplifyIRForSpirvLegalization迭代循环、前向声明指针修复循环以及条件性的 spirv-link / spirv-val downstream 链。流程图阶段有序表#Pass / 步骤FileGateNotes1emitSPIRVForEntryPointsDirectlyslang-emit.cpptargetProgram-shouldEmitSPIRVDirectly()direct-emit 入口约第 3675 行。2createArtifactFromIRslang-emit.cpp(always)约第 3441 行负责装配最终 artifact 与可选调试 artifact。3emitSPIRVFromIRslang-emit-spirv.cpp(always)约第 3141 行。4legalizeIRForSPIRVslang-ir-spirv-legalize.cpp(always)约第 3352 行内部三阶段见下文值得注意的 pass。5simplifyIRForSpirvLegalizationslang-ir-spirv-legalize.cpp(always)约第 3126 行外层 8 次、内层 16 次的迭代循环见循环。6前向声明指针修复循环slang-emit-spirv.cppm_forwardDeclaredPointers.getCount() ! 0约第 12335 行见循环。7compiler-linkspirv-linkdownstreamspirvFiles.getCount() 1多模块链接。8compiler-validatespirv-valdownstreamshouldRunSPIRVValidation(codeGenContext)—9optimizeSPIRV源码内调用当前位于#if 0标记为[disabled]仅提及不展开。条件门控汇总表以下按门控类别汇总图中引用的全部条件分组顺序遵循契约requiredLoweringPassSet.*标志 →targetCompilerOptions.*/ 选项集开关 → 上下文谓词 → 简化模式谓词 → SPIR-V 专属运行时常量。1. requiredLoweringPassSet.* 标志门控表达式控制的 pass说明requiredLoweringPassSet.assumeAddressvalidateAndRemoveAssumeAddress—requiredLoweringPassSet.glslSSBOlowerGLSLShaderStorageBufferObjectsToStructuredBuffers—requiredLoweringPassSet.bindExistentialbindExistentialSlots—requiredLoweringPassSet.debugInfodebug 相关—requiredLoweringPassSet.derivativePyBindWrappergenerateDerivativeWrappers—requiredLoweringPassSet.autodiffcheckAutodiffPatterns—requiredLoweringPassSet.higherOrderFuncspecializeHigherOrderParameters—requiredLoweringPassSet.matrixSwizzleStorelowerMatrixSwizzleStores—requiredLoweringPassSet.resultTypelowerResultType—requiredLoweringPassSet.conditionalTypelowerConditionalType—requiredLoweringPassSet.optionalTypelowerOptionalType等—requiredLoweringPassSet.nonVectorCompositeSelectlegalizeNonVectorCompositeSelect—requiredLoweringPassSet.genericsspecializeModule—requiredLoweringPassSet.reinterpretlowerReinterpretOptional—requiredLoweringPassSet.byteAddressBufferlegalizeByteAddressBufferOps—requiredLoweringPassSet.coverageTracing/enumType/missingReturn/specializeStageSwitch/combinedTextureSamplers/dynamicResource/dynamicResourceHeap/existentialTypeLayout/bindingQuery/meshOutput/bitcast对应 lowering/legalization pass由calcRequiredLoweringPassSet统一计算slang-emit.cpp 第 1070 行。2. targetCompilerOptions.* / 选项集开关门控表达式控制的 pass说明getDebugInfoLevel() DebugInfoLevel::NonestripDebugInfo—targetCompilerOptions.shouldEmitSeparateDebugInfo()emitDebugBuildIdentifier表达式较短图中原样保留。shouldRunNonEssentialValidation非必需校验块—getBoolOption(ValidateUniformity)validateUniformity—getBoolOption(PreserveParameters)参数保留相关路径表达式过长时可缩写为getBoolOption(PreserveParameters)。getBoolOption(EnableExperimentalPasses)实验性 pass—getBoolOption(VulkanEmitReflection)/VulkanInvertY/VulkanUseDxPositionW/EmbedDownstreamIRSPIR-V 相关发射配置—shouldPerformMinimumOptimizations最小优化模式影响fastIRSimplificationOptions.minimalOptimization的取值。3. 上下文谓词门控表达式控制的 pass说明!codeGenContext-isSpecializationDisabled()特化相关 pass—codeGenContext-shouldReportCheckpointIntermediates()中间产物报告—codeGenContext-shouldTrackLiveness()活性分析—codeGenContext-removeAvailableInDownstreamIRIR 清理—codeGenContext-shouldSkipDownstreamLinking()跳过下游链接—shouldRunSPIRVValidation(codeGenContext)spirv-val—spirvFiles.getCount() 1spirv-link多模块链接条件。4. 简化模式谓词门控表达式控制的 pass说明!fastIRSimplificationOptions.minimalOptimization第二/三轮simplifyIR、simplifyNonSSAIR完整优化路径第 1713、2768 行等。fastIRSimplificationOptions.minimalOptimization快速简化路径跳过非必要优化 pass。5. SPIR-V 专属运行时常量门控表达式控制的 pass说明context-shouldEmitDiscardAsDemote()discard 发射方式—context-isSpirv16OrLater()SPIR-V 1.6 行为差异—流水线中的循环SPIR-V direct-emit 流水线恰好只有两个循环会执行 IR pass其余均无循环一simplifyIRForSpirvLegalization 的双层固定点循环位于 slang-ir-spirv-legalize.cpp 的simplifyIRForSpirvLegalization约第 3126 行const int kMaxIterations 8; const int kMaxFuncIterations 16; while (changed iterationCounter kMaxIterations) { // ... while (funcChanged funcIterationCount kMaxFuncIterations) { // 逐函数简化 } }外层while (changed iterationCounter kMaxIterations)上限 8内层while (funcChanged funcIterationCount kMaxFuncIterations)上限 16。需要特别指出与 target-pipelines 索引页契约的提醒一致这两个计数器的实际递增在源码中并未严格执行因此更准确的说法是以名义上限而非强制执行的上限运行到收敛不应机械地描述为8 × 16。循环二emitSPIRVFromIR 的前向声明指针修复循环位于 slang-emit-spirv.cpp 约第 12335 行do { // 处理 m_forwardDeclaredPointers 中的前向声明指针 } while (context.m_forwardDeclaredPointers.getCount() ! 0);该循环反复处理发射过程中累积的前向声明指针直到集合为空不动点。值得注意的 passlegalizeIRForSPIRV 的三阶段内部结构slang-ir-spirv-legalize.cpp 的legalizeIRForSPIRV约第 3352 行将整个 legalization 拆为三个阶段约第 3359-3372 行legalizeSPIRV约第 3113 行核心 SPIR-V 语义合法化含逐入口点的legalizeSPIRVEntryPoint第 2027 行在第 2993 行被遍历调用simplifyIRForSpirvLegalization约第 3126 行双层迭代简化循环收尾序列removeUnreachableCodeAfterDiscardForOpKill第 3268 行→eliminateDeadCode→buildEntryPointReferenceGraph写入m_referencingEntryPoints→insertFragmentShaderInterlock第 3210 行。eliminatePhis 的 SPIR-V 专属配置在 slang-emit.cpp 第 2718-2724 行SPIR-V 分支显式配置PhiEliminationOptions phiEliminationOptions; phiEliminationOptions.eliminateCompositeTypedPhiOnly false; phiEliminationOptions.useRegisterAllocation true; SLANG_PASS(eliminatePhis, livenessMode, phiEliminationOptions);即 SPIR-V 下 phi 消除不只处理复合类型eliminateCompositeTypedPhiOnly false且启用寄存器分配useRegisterAllocation true并在随后以LivenessMode::Disabled再次执行约第 2824-2825 行因为第一次消除已使 IR 脱离 SSA 形式。specializeFuncsForBufferLoadArgs 的两次调用该 pass 在流水线中执行两次Phase B 早期约第 2121 行SPIR-V 特定地在lowerBufferElementTypeToStorageType之后约第 2655 行。其存在理由与 SPIR-V 规则 2.16.1 直接相关当VariablePointer能力未声明时缓冲加载参数需要按值特化因此必须推迟到缓冲元素类型确定之后再次执行。地址空间传播SPIR-V 的唯一例外SPIR-V 是唯一把地址空间特化推迟到其 legalization pass 中处理的目标。对照 slang-emit.cpp 第 2635-2643 行GLSL / Metal / WGSL 分支分别在linkAndOptimizeIR中执行specializeAddressSpace第 2635 行、specializeAddressSpaceForMetal第 2639 行、specializeAddressSpaceForWGSL第 2643 行而 SPIR-V 分支有意不执行任何specializeAddressSpace*pass地址空间相关工作全部交由 emit 阶段的 SPIR-V legalization 完成。legalizeEntryPointsForGLSL名称的历史遗留尽管名字带 GLSLlegalizeEntryPointsForGLSL约第 2363 行对 SPIR-V 同样运行。该名称反映的是历史来源而非当前适用范围——它处理的是入口点层面的合法化需求在 SPIR-V direct-emit 路径下同样必要。removeRawDefaultConstructors仅 direct-emit 执行removeRawDefaultConstructors只在targetProgram-shouldEmitSPIRVDirectly()为真时对 SPIR-V 运行slang-emit.cpp 第 2521-2522 行及第 2533 行可见该条件分支。transformParamsToConstRefSPIRV 分支专属调用在moveGlobalVarInitializationToEntryPoints的 switch 中case CodeGenTarget::SPIRV:分支会调用transformParamsToConstRef约第 2479 行第 2493 行另有同类调用将入口点参数转换为 const-ref 形式以满足 SPIR-V 的调用约定。发射后 downstream 链发射完成后按条件执行compiler-linkspirv-link仅当spirvFiles.getCount() 1时执行多模块链接compiler-validatespirv-val由shouldRunSPIRVValidation门控源码内的optimizeSPIRV调用当前位于#if 0中属于已禁用节点图中标记为[disabled]此处仅作记录。质量自检清单契约要求对照 prompt 的 checklist 逐项核验本文内容每个SLANG_PASS(...)在CodeGenTarget::SPIRVshouldEmitSPIRVDirectly() true下可达的调用都恰好在某一个阶段表中出现一次每个菱形节点的门控标签与源码原文一致仅对超长表达式按契约允许的规则缩写两个循环均同时展示迭代上限与不动点条件图中不含 HLSL/GLSL/CUDA/Metal/WGSL/CPU/PyTorch 专属 passPhase A 从linkIR开始止于 Phase B 的第一个simplifyIR之前Phase D 终止于emitSPIRVForEntryPointsDirectly交还的 artifact。延伸阅读pipeline/04-ast-to-ir.mdAST 到 IR 的 lowering 阶段是本文流水线的上游。pipeline/05-ir-passes.md无序的逐 pass 目录解释每个 pass 是什么本文解释这些 pass 何时运行。pipeline/06-emit.md后端发射概述。cross-cutting-targets.md跨目标概念。ir-reference-index.mdIR 指令家族参考。target-pipelines-index.md各目标流水线页面导航与跨目标对比其中特别提醒legalizeIRForSPIRV属于 Phase D 而非 Phase C。用户侧目标文档SPIR-V 目标相关的使用说明见 docs/user-guide 下的 target-specific 文档如 a2-01-spirv-target-specific.md。核心实现slang-emit.cpp、slang-emit-spirv.cpp、slang-ir-spirv-legalize.cpp、slang-target-program.h。【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表