[Migrated] We should override `thir_body` to inject loop merge points for structurization.
まだ誰も着手していません。
- 主要言語
- Rust
- スター
- 3.4k
- フォーク
- 126
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
Issue automatically imported from old repo: https://github.com/EmbarkStudios/rust-gpu/issues/944
Originally creatd by eddyb on 2022-11-24T08:17:49Z 👍: 1
I was writing up this SPIR-T issue when I realized we can do much better than I ever thought we can:
The "subgroup reconvergence"/"loop merges" problem statement
the fundamental ambiguity here (wrt reconvergence), that explicit merges solve, looks like this:
loop { // ... if cond { // the "then" edge *leaves the loop* A(); // !!! it might be important that this STAYS INSIDE the loop! break; // this is just a linear A -> B edge in the CFG (outside the loop's cycle) } } B(); // !!! it might be important that this STAYS OUTSIDE the loop!because the
A()->B()edge just looks like a redundant fusable edge (isomorphic to a singleA(); B();basic block), structurizers will very likely either produce:
loop { ... if cond { break; } } A(); B();(movingA()out of theloop)
A()no longer called for "early finishers" (losing a desired side-effect)loop { ... if cond { A(); B(); break; } }(movingB()into theloop)
B()now being called for "early finishers" (gaining an undesired side-effect)and they're both bad because a non-uniform
break(i.e. an "early finisher") will block on subgroup neighbors (semantically, at least, in hardware the now-inactive lanes will likely stick around while loop instructions continue being executed for remaining lanes, until they all eventuallybreak)
An actual reasonable solution for once (what prompted me to open this issue)
A better approach might be to "just" make up a SPIR-T instruction that acts as "loop merge barrier", i.e.:
loop { // ... if cond { A(); // !!! definitely INSIDE the loop break; // just an edge to the `LoopMerge`, in the CFG } } asm!("spirt.ControlInst.LoopMerge"); B(); // !!! definitely OUTSIDE the loopEach
LoopMergewould be consumed by one loop structurization - if you have nested loops, you'd need to be careful not to forget to add them to each loop.But wait, even if we make this ergonomic with macros... we'd still want to check that you don't use any instructions that "care" about e.g. subgroups, right? That could be e.g. a MIR check pass, right? Which we can inject... just like...
Yes, that's right,
rustc_codegen_spirvhas enough query overriding power that it could overridethir_body, which MIR construction uses as the source of truth, to introduce additional nodes around loops, allowing Rust to be on par with GLSL wrt structured control-flow guarantees.
Additionally, this could be used to replace #[spirv(unroll_loops)] (once that's removed, see https://github.com/EmbarkStudios/rust-gpu/pull/940#issuecomment-1320004784 for more context), as it would allow us to check for a (new) #[spirv(unroll)] attribute on the loop expression, and then store that in the injected merge point.
That would be much nicer than fn-level catch-alls, and generally a good fit for SPIR-V expressivity.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
リンクされた rustc の MIR 構築リファレンスと、rustc_codegen_spirv における thir_body クエリのオーバーライドから始めます。ループノードが LoopMerge とループレベルの unroll 情報をどのように保持できるかを調査します。ネストしたループと subgroup に依存する命令も対象に含めます。ループのマージポイントと提案された unroll 属性が、意図された制御フローのセマンティクスを失うことなく注入され、検証されれば完了です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- rust
- 領域
- compilers
- issue の種類
- 機能追加
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 25/100