澄清 Vulkan SPIR-V 中持续目标的确切构成

whn*_*whn 0 control-flow control-flow-graph vulkan spir-v

我正在尝试了解 SPIR-V 规范,例如了解 for 循环。在 1.6 修订版 2 规范的开头,有以下示例(为了一致性,仅取部分内容)

for (int i = 0; i < 4; ++i)
    color *= multiplier;
Run Code Online (Sandbox Code Playgroud)

变成:

%49 = OpLabel
      OpLoopMerge %51 %52 None ; structured loop
      OpBranch %53
%53 = OpLabel
%54 = OpLoad %16 %48
%56 = OpSLessThan %25 %54 %55 ; i < 4 ?
      OpBranchConditional %56 %50 %51 ; body or break
%50 = OpLabel ; body
%58 = OpLoad %7 %57
%59 = OpLoad %7 %31
%60 = OpFMul %7 %59 %58
      OpStore %31 %60
      OpBranch %52
%52 = OpLabel ; continue target
%61 = OpLoad %16 %48
%62 = OpIAdd %16 %61 %21 ; ++i
      OpStore %48 %62
      OpBranch %49 ; loop back
%51 = OpLabel ; loop merge point
      OpReturn
      OpFunctionEnd
Run Code Online (Sandbox Code Playgroud)

在规范中,它指定一个块以标签开头,并以任何分支终止指令结束。这将上面的内容变成以下内容:

;Block 1
%49 = OpLabel
      OpLoopMerge %51 %52 None ; structured loop
      OpBranch %53

;Block 2
%53 = OpLabel
%54 = OpLoad %16 %48
%56 = OpSLessThan %25 %54 %55 ; i < 4 ?
      OpBranchConditional %56 %50 %51 ; body or break

;Block 3
%50 = OpLabel ; body
%58 = OpLoad %7 %57
%59 = OpLoad %7 %31
%60 = OpFMul %7 %59 %58
      OpStore %31 %60
      OpBranch %52

;Block 4
%52 = OpLabel ; continue target
%61 = OpLoad %16 %48
%62 = OpIAdd %16 %61 %21 ; ++i
      OpStore %48 %62
      OpBranch %49 ; loop back

;Block 5
%51 = OpLabel ; loop merge point
      OpReturn

      OpFunctionEnd
Run Code Online (Sandbox Code Playgroud)

然后规范指出:

标头块:包含合并指令的块。

Loop Header:合并指令为 OpLoopMerge 的头块

所以这里的循环头是块1,OpLoopMerge所在的位置。

OpLoopMerge 声明了三个参数,其中两个在这里很重要:

合并块是此结构化循环的合并块的标签。

Continue Target 是用于处理循环“Continue”的块的标签。

合并块是

合并块:由合并指令的合并块操作数声明的块。

我的理解是“结构化循环/选择”何时结束,在本例中,它位于函数的末尾,块 5。这对我来说是有意义的。

我不清楚“继续”目标。根据操作循环合并指令,这里的继续目标是块 4。为什么继续目标不是块 3?还是块2?是什么让区块 4 成为这里的继续目标?是因为它是最终决定退出或继续循环的块吗?这就是“处理循环”继续“的意思吗?

Nic*_*las 5

“继续目标”的存在是为了满足大多数语言中控制流指令的需要continue。在高级语言中,您可以在循环中发出一条continue语句。这将跳转到循环中的下一次迭代。

“继续目标”是循环代码中开始下一次迭代的部分。您可以直接从continue语句分支到这里,也可以从循环体的末尾分支到这里。

如果源包含一条continue语句,则该语句将成为循环体的一部分,在您的示例中为块 3。因此没有理由将其作为 continue 目标;这将导致无限循环,因为从未检查实际的终止条件,也不会计算迭代表达式。

而且 Block 2 也没有任何意义。当你continue循环时,你必须执行迭代表达式。重复终止条件没有帮助,因为它显然已经过去了。这就是它开始进入循环体的方式。直到对迭代表达式求值为止,终止条件将继续通过。再次,将导致无限循环。