
Slang 目标管线索引导读读懂linkAndOptimizeIR的按目标过滤视图【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang这篇技术指南面向需要快速定位 Slang 编译器各后端SPIR-V / HLSL / Metal / WGSL / CUDAIR-pass 执行顺序的编译器开发者。文章以docs/generated/design/target-pipelines/index.md这份导航枢纽文档为核心骨架结合source/slang/slang-emit.cpp中的共享编排器linkAndOptimizeIR源码与各子页面讲透四阶段管线模型、目标过滤与 IR 内容过滤两种机制以及五个目标之间的对比要点。读完你将掌握如何借助索引页快速选定正确的目标子页面并理解RequiredLoweringPassSet这类内容门控对阅读单页管线图的关键影响。这份文档是什么导航枢纽而非管线本身docs/generated/design/target-pipelines/目录下共有六份 Markdown 文档index.md —— 本篇讲解的导航枢纽页spirv.md、hlsl.md、metal.md、wgsl.md、cuda.md —— 五份对等子页面每份记录一个目标家族的有序 IR-pass 与下游工具序列。索引页的核心定位在开头导读中写得很明确它是面向需要挑选正确子页面的编译器开发者的导航枢纽这一受众表述正是该文档生成修复流程中 F-004 项强制要求的产物详见下文的“文档修复背景”。它自身不逐 pass 讲解而是把每个目标的管线呈现为共享编排器linkAndOptimizeIR的“四阶段控制流图视图”。需要与索引页配套阅读的两份邻居文档是pipeline/05-ir-passes.md —— 按主题分类而非按执行顺序排列的 IR-pass 总目录回答“pass X 做什么”cross-cutting/targets.md —— 能力 / profile模型回答“目标被允许发射什么”管线页面只记录行为不重复该模型。索引页与子页面均为自动生成文档front matter 带generated: true与warning: Auto-generated. May drift from source. Do not edit by hand.内容基于固定 source commit 的源码快照生成阅读时应与源码交叉印证。## Pages五个目标子页面的主题索引索引页用五个条目概括每份子页面的覆盖范围这是读者决定“该打开哪份页面”的第一步子页面目标与下游子页面独有亮点spirv.mdSPIR-V 直接发射路径emitSPIRVForEntryPointsDirectly下游 spirv-link / spirv-val / spirv-opt唯一带迭代 pass 的页面另覆盖-debug-info-include-source、-Xspirv-opt透传、描述符堆ConstantBuffer访问、按选择器位宽发射OpSwitchcase 字面量hlsl.mdHLSL 源码 DXCDXIL/ fxcDXBytecode下游work-graph 特性集node阶段、work-graph 记录类型、[NodeLaunch(broadcasting)]等具名常量发射precise限定符仅在 HLSL 与 GLSL 发射器中生效metal.mdMetal 源码 Applemetal编译器MetalLib/MetalLibAssemblyprintf映射到 MSL 3.2 shader-logging 设施1.0h/1.0f半精度 / 单精度字面量后缀覆盖率计数器封顶 32 位wgsl.mdWGSL 源码 TintWGSL → SPIR-V下游WGSLSPIRV/WGSLSPIRVAssemblyprecise的诊断WGSL 无此关键字bool → int 转型发射为select(T(0), T(1), cond)shouldEmitSwitchCaseTerminatingBreak()策略覆写刻意独立于supportsSwitchFallThrough()cuda.mdCUDA C 源码 / 头 nvrtcPTX下游额外## Adjacent targets一节交叉链接 PyTorch / OptiX / host-CPP 路径嵌套被调函数中终止入口点的 OptiX payload 写回路径autodiff 门控目标无关precise限定符的发射差异一个跨发射器的实例索引页在 HLSL 条目中给出了一个具体而微的跨目标差异示例precise限定符只会出现在 HLSL 与 GLSL 发射器产出的源码中。原因是这两个发射器继承了基类CLikeSourceEmitter::emitTempModifiers而 Metal、WGSL、CPP / CUDA 发射器各自覆写了该方法以丢弃该限定符对应源码见 slang-emit-c-like.cpp 与各*SourceEmitter子类。WGSL 侧的行为更进一步由于 WGSL 语言根本没有precise关键字wgsl.md 记录的是一条专门诊断而非静默丢弃。这类“同一起源、五个出口”的差异正是索引页存在的意义——它让读者在打开子页面之前就知道每个目标的关注点在哪。共享形状linkAndOptimizeIR的四阶段模型五份子页面遵循同一份Target-pipeline page contract定义于 docs/generated/design/_meta/prompts/_common.md把各自目标对linkAndOptimizeIR的调用分解为四个阶段阶段职责关键内容Phase A —— 链接与入口点预备链接各模块 IR为合法化准备入口点含按目标的入口点 uniform 处理每个目标的精确 pass 集合见各自子页面Phase B —— 特化与类型合法化特化泛型解决目标无关的类型合法化问题跨目标分歧的大头existential 与资源类型合法化、cooperative-vector 降低、目标特定包装器都在此阶段Phase C —— 目标合法化、降低、phi 消除运行目标特定的合法化驱动存在的话与共享降低最后通过 phi 消除离开 SSA是各目标真正分道扬镳的地方Phase D —— 发射与下游工具把合法化后的 IR 交给目标的CLikeSourceEmitter子类或 SPIR-V 直接发射路径包装为下游编译器输入运行外部工具产出最终 artifactlinkAndOptimizeIR本体定义于 slang-emit.cpp 第 1005 行Result linkAndOptimizeIR(CodeGenContext*, LinkingAndOptimizationOptions const, LinkedIR)是贯穿所有后端的共享编排器五份子页面里的 Phase A–D 图本质上都是它的过滤视图。五份页面因此携带完全相同的##骨架顺序固定为Source→High-level phase diagram→Phase A–Phase D四个小节 →Conditional gates→Loops in the pipeline→Notable passes→See also。只有两处刻意偏离cuda.md 在 Phase D 与 Conditional gates 之间插入## Adjacent targets——因为PyTorchCppBinding、OptiX 与 host-CPP 目标共享多条 CUDA switch 分支却并非 CUDA页面需要明确声明它们超出范围spirv.md 把第四阶段命名为## Phase D: IR-to-SPIR-V emit, simplification loop, downstream tools——因为 SPIR-V 是唯一一个合法化驱动在发射步骤内部运行而非在linkAndOptimizeIR内的目标这一点正是下面比较表要强调的核心差异。另一个贯穿所有页面的骨架约定每页的## Conditional gates小节都以### requiredLoweringPassSet.* flags子小节开头反映“按 IR 内容过滤”见下文对应小节的机制。每个目标的门控差异一次遍历只能看到自己的分支阅读任意单个子页面得到的是linkAndOptimizeIR的过滤视图——只为兄弟目标触发的 pass 会被从图和表中剔除。共享编排器对每个目标都无条件运行区别只在于每个目标落在哪条 switch 分支上。因此只看一页不能看到linkAndOptimizeIR的全局顺序只能看到该目标可达的 pass。要获得不经过任何过滤的全局视图应直接阅读linkAndOptimizeIR源码与 pipeline/05-ir-passes.md。跨目标比较表五个目标并排对照索引页给出了一张浓缩的五目标对比表这是全文信息密度最高的一张表逐项说明如下目标CodeGenTarget 枚举值Phase C 入口Phase D 发射器下游工具循环SPIR-VSPIRV、SPIRVAssembly无单一入口逐 pass 的 SPIR-V 分支——legalizeIRForSPIRV驱动slang-ir-spirv-legalize.cpp 第 3352 行在Phase D运行由emitSPIRVFromIR调用emitSPIRVForEntryPointsDirectlyslang-emit.cpp 第 3670 行→emitSPIRVFromIRslang-emit-spirv.cpp 第 12161 行spirv-link、spirv-val、spirv-opt有——唯一带迭代 pass 的目标simplifyIRForSpirvLegalization与emitSPIRVFromIR中的前向声明指针修复均迭代至收敛HLSLHLSL外加下游DXIL、DXBytecode及各自*Assembly变体无单一入口逐 pass 的 HLSL 分支如 slang-ir-hlsl-legalize.cpp 中的legalizeRayPayloadAccessQualifiersForHLSL、validateBarrierFlagsForHLSLHLSLSourceEmitterslang-emit-hlsl.cppDXCDXIL*、fxcDXBytecode*linkAndOptimizeIR内无循环MetalMetal、MetalLib、MetalLibAssemblylegalizeIRForMetalslang-ir-metal-legalize.cppMetalSourceEmitterslang-emit-metal.cppApplemetal编译器MetalLib*linkAndOptimizeIR内无循环legalizeIRForMetal单趟WGSLWGSL、WGSLSPIRV、WGSLSPIRVAssemblylegalizeIRForWGSLslang-ir-wgsl-legalize.cppWGSLSourceEmitterslang-emit-wgsl.cppTintWGSLSPIRV*linkAndOptimizeIR内无循环legalizeIRForWGSL单趟CUDACUDASource、CUDAHeader、PTX无单一入口逐 pass 的 CUDA 分支——slang-ir-cuda-immutable-load.cpp 中的lowerImmutableBufferLoadForCUDA是唯一只为本目标家族存在的 passCUDASourceEmitterslang-emit-cuda.cpp继承自CPPSourceEmitternvrtc / 运行时 CUDA 编译器PTXlinkAndOptimizeIR内无循环两个必须注意的表格脚注索引页明确要求这张表带两条 caveat它们直接决定你如何理解上表其一“无单一入口”对“具名驱动”。Metal 与 WGSL 各自在linkAndOptimizeIR内只有一条SLANG_PASS(legalizeIRFor*)调用基本拥有其全部目标特定合法化对应源码SLANG_PASS(legalizeIRForMetal, ...)在 slang-emit.cpp 第 2403 行、SLANG_PASS(legalizeIRForWGSL, ...)在第 2433 行。HLSL、CUDA 与 SPIR-V 则不同但原因各异HLSL 与 CUDA 确实把目标特定工作分散在多条独立 switch 分支上表中所列 pass 只是示例并非完整清单——各子页面才列出全部而 SPIR-V确实有单一驱动legalizeIRForSPIRV只是它运行得更晚、在发射步骤内部因此在 spirv.md 上属于 Phase D 而非 Phase C。其二SPIR-V 循环边界并未被强制执行。在 slang-ir-spirv-legalize.cpp 第 3129–3145 行simplifyIRForSpirvLegalization声明了kMaxIterations 8iterationCounter 0与kMaxFuncIterations 16funcIterationCount 0但两个计数器从未被递增。循环条件while (changed iterationCounter kMaxIterations)及其内层等价形式因此实际等同于while (changed)两个循环都迭代到收敛8 / 16 只是源码声明但从未生效的名义上界——即两个循环都没有强制的最大迭代次数。spirv.md 的 Loops 小节记录了该后果以及外层循环额外的 error-count 提前退出逻辑。我已核对该处源码while (changed iterationCounter kMaxIterations)循环体内只做了changed false重置与各 pass 的changed |聚合确无任何iterationCounter语句内层同理。过滤规则为什么单页视图与全局视图不同索引页明确区分了 pass 从子页面缺失的两个相互独立的原因该分支门控在别的目标上——这是五份页面彼此不同的原因该 pass 门控在模块“不包含”它将变换的 IR 上——这是任一份页面在不同编译之间不同的原因。按目标过滤每个子页面都会过滤掉门控在兄弟目标上的 switch 分支。索引页列出的典型谓词包括isSPIRV、isMetalTarget、isWGPUTarget、isCUDATarget、isD3DTarget、isKhronosTarget、target HLSL、target GLSL、target CodeGenTarget::PyTorchCppBinding以及 CPU / Host / LLVM 变体等。需要注意两个目标共享一条分支时列出该 pass 的每份页面都会在正文中说明这种共享——例如 Metal、CUDA 与 CPP 目标都会命中 slang-emit.cpp 第 2511 行的SLANG_PASS(undoParameterCopy)分支索引页标注其在第 2345 行。按 IR 内容过滤RequiredLoweringPassSet这是索引页着墨最多、也最容易被单页读者误解的机制。多数后端 pass 在链接后的模块不含需要它们的 IR时会被跳过。这个谓词是struct RequiredLoweringPassSet声明于 slang-code-gen.h 第 52 行——一个包含 34 个独立bool标志的记录每个标志对应一个降低关注点enumType、taggedUnion、autodiff、appendConsumeStructuredBuffer、reinterpret等。它由calcRequiredLoweringPassSetslang-emit.cpp 第 405 行填充该函数递归遍历模块每发现一个构造就置位对应标志。我在源码中核对了该函数的起始逻辑IRTranslateBase/IRDifferentialPairTypeBase等基类判型会置位autodiffIRAttributedType携带IRNoDiffAttr时同样置位autodiff第 419–431 行而kIROp_DebugValue/kIROp_DebugLine等调试指令置位debugInfo第 440–452 行。linkAndOptimizeIR会运行两次扫描——第 1075 行紧跟linkIR之后与第 1649 行Phase B 中途特化之后——这样特化新引入的构造仍能把门控打开。标志累积而不重置因此第二次扫描只会追加。索引页给出了这种设计的安全性论证标志可以“过期为真”构造已被 DCE 删除pass 空跑无害但永远不会“假阴性”需要的降低不会被跳过因为每个被门控的构造要么由前端产生、要么由最后一次扫描之前运行的 pass 产生。许多门控处还把这套论证原样写成了源码注释。机制的两个跨目标属性索引页特别挑出该机制的两个易错属性autodiff 门控是分支而非跳过。在 slang-emit.cpp 第 1577–1581 行requiredLoweringPassSet.autodiff为假时并不是简单地省略finalizeAutoDiffPass——else分支改跑stripAutoDiffDecorations。这个分支是必需的而非锦上添花即使模块没有任何 autodiff 构造链接进 core-module 的 autodiff 内建函数也携带ExportDecoration/HLSLExportDecoration/KeepAliveDecoration从而被钉住免于死代码消除。剥掉这些装饰后面的eliminateDeadCode才能丢弃未被使用的内建函数。我核对过第 1570–1585 行的源码注释其表述与索引页完全一致stripAutoDiffDecorations移除这些“钉住装饰”连同其他 autodiff 临时装饰且不需要AutoDiffSharedContext。唯一一个在管线中途被修改的标志。在第 1737–1738 行lowerTaggedUnionTypes会在自己的taggedUnion门控内部把requiredLoweringPassSet.reinterpret置为true——因为降低 tagged union 会产生新的reinterpret指令供随后几行的lowerReinterpret消费。其余所有标志都只由那两次扫描写入因此这是唯一一处“门控集是 pass 结果的函数”而非“模块遍历的函数”的地方。文档修复背景从评审到整改的一手流程记录docs/generated/design/_meta/下保留着这套生成文档的质量保障流程痕迹可作为研究该文档可靠性的直接证据。与索引页直接相关的有两份reviews/target-pipelines/index.md.review.md —— 由gpt-5.6-sol模型产出的评审报告基于提交53b76e6d3009b8e6434d41573524c7ce5c499d23复核了 18 项事实断言发现 5 项问题2 critical、1 major、2 minorremediations/target-pipelines/index.md.remediation.md —— 由claude-opus-5模型产出的整改报告修复了其中 4 项并延期 1 项。五个发现及其处置本身就是理解索引页措辞的钥匙编号严重度内容处置F-001criticalMetalprintf并非“门控在metallib_3_2capability atom 上”发射器遇printf时无条件调用requireMetalLanguageVersion(3, 2)与requireLogging()无 capability 测试metallib_3_2atom 虽存在slang-capabilities.capdef 第 204 行并在第 2473 行被alias printf引用却并非此发射路径的驱动fixed改为“使发射器要求 MSL 3.2 并为下游编译启用 Metal logging”F-002critical表中具名的 HLSL/CUDA pass 并非其目标特定工作的全部HLSL 还跑legalizeNonVectorCompositeSelectslang-emit.cpp 第 1627 行 HLSL 分支与wrapStructuredBuffersOfMatrices第 2170 行CUDA 还跑synthesizeActiveMask第 2335 行CUDASource/CUDAHeader/PTX 分支与legalizeEntryPointVaryingParamsForCUDA第 2423 行CUDASource/CUDAHeader 分支fixed改为“所列为示例而非完整清单——各子页面列全”F-003major索引页携带了索引契约_common.md第 421–423 行禁止的逐 pass 细节且整页重组超出了“最小合理改动”规则但_common.md第 404–409 行又强制要求保留两条 pass 级 caveat推荐方案与契约自相矛盾deferred需在紧凑索引契约下按target-pipelines-index.md提示重新生成整页而非逐句修补F-004minor首段只写了覆盖范围未按通用规则写明预期读者fixed首句补上 “written for compiler developers who need to pick the right per-target page”F-005minor“PyTorch /slangpy路径是 autodiff 的主要消费者”属于未经证实的比较性用法断言slang-emit.cpp 第 1577–1581 行的 autodiff 分支没有任何目标谓词fixed改为描述 autodiff 门控目标无关并仅命名 PyTorch /slangpy为会到达它的路径之一这套流程的价值在于它说明索引页中每一句措辞尤其是 Metalprintf与 CUDA autodiff 两处都经过源码级复核与修正你可以放心把它们当作当前提交下的实现事实引用。同时 F-003 被延期也提醒你索引页中仍然残留部分逐 pass 细节最权威的 pass 清单应以各子页面与linkAndOptimizeIR源码为准。如何实际使用这份索引页给编译器的实操路径结合索引页、子页面与源码推荐的使用流程如下确定目标家族。按## Pages五条概述选择子页面。需要唯一带迭代 pass 的 SPIR-V 细节、-debug-info-include-source、-Xspirv-opt透传 → spirv.mdwork-graph 与precise→ hlsl.mdMSLprintf映射与字面量后缀 → metal.mdWGSL 无precise诊断与select型 bool 转换 → wgsl.mdCUDA 的## Adjacent targets与 autodiff 门控 → cuda.md。先用索引页定位阶段。任何“某 pass 何时跑”的问题先在四阶段模型里确定它应属哪个阶段——Phase B 是特化与类型合法化跨目标分歧集中地Phase C 是目标特定合法化驱动Phase D 是发射与下游工具。再到子页面看过滤后的精确顺序。注意每个## Conditional gates小节的### requiredLoweringPassSet.* flags表——reqSet.*门控表示“模块不含该构造时整个 pass 被跳过”不是优化提示。关键结论回到源码验证。所有行号均对应索引页记录的快照提交48c746dc1eda1c6e2aa98c17bbdb7a645c24a048及修复流程中的53b76e6d...。例如怀疑某个 pass 的顺序时直接在 slang-emit.cpp 中搜索SLANG_PASS(passName即可定位实际调用点。需要全局视图时离开本目录。若想知道每个 pass 是什么读 pipeline/05-ir-passes.md无序主题目录若想理解目标能力模型与-capability原子读 cross-cutting/targets.md若想追 AST → IR 或发射阶段概览见See also中的 pipeline/04-ast-to-ir.md 与 pipeline/06-emit.md。延伸阅读pipeline/04-ast-to-ir.md —— AST → IR 降低是管线消费的 IR 的上游。pipeline/05-ir-passes.md —— 无序 IR-pass 主题目录回答“pass X 做什么”。pipeline/06-emit.md —— 跨目标的发射阶段总览。cross-cutting/targets.md —— 按目标选项、capability 集与目标谓词含“Profiles 对比显式-capability”一节界定 profile 与显式 capability atom 的关系该页拥有模型管线页面不重复陈述。ir-reference/index.md —— 逐 opcode 目录Phase C / D 的合法化 pass 变换了其中许多 opcode。用户侧 SPIR-V 目标说明见 user-guide/a2-01-spirv-target-specific.md命令行标志、capability 要求、扩展。【免费下载链接】slangMaking it easier to work with shaders项目地址: https://gitcode.com/GitHub_Trending/sl/slang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考