Skip to content

再帰する呼び出しを診断で断つ - #254

Merged
routersys merged 7 commits into
mainfrom
dev/ComputeWeave.RecursiveCall
Sep 15, 2026
Merged

routersys merged 7 commits into
mainfrom
dev/ComputeWeave.RecursiveCall

Conversation

@routersys

@routersys routersys commented Sep 15, 2026 •

Copy link
Copy Markdown
Owner

Summary / 概要

再帰するメソッドや局所関数がシェーダーの本文にあると、生成器は診断を出さずに書き出し、HLSL には再帰が無いのでシェーダーコンパイラが断っていました。その誤りはシェーダー型の位置へ CMPW0046(Direct2D 側は CMPWD2D0034)として転送されるだけで、文が名指すのは生成 HLSL の関数です。局所関数と補助型のメソッドでは、その関数名は生成器が付けたものです。書き換えが書き出す呼び出しを、シェーダーごとに1つの集合へ記録するようにしました。全ての宣言を書き換えた後にその集合を読み、書かれた宣言へ戻る呼び出しを CMPW0129(Direct2D 側は CMPWD2D0101)として、著者が書いた呼び出しの位置へ報告します。

Linked issue / 関連する課題

Closes #246

Kind / 種別

  • Bug fix / 不具合修正
  • Analyzer or generator / アナライザーまたはジェネレーター

Behavior change / 挙動の変更

再帰する呼び出しを持つシェーダーの挙動が変わります。これまでは転送の診断がシェーダー型の位置に1件出て、文は HLSL 側の関数名を含んでいました。変更後は環の上にある呼び出しごとに CMPW0129 がその呼び出しの位置へ出て、bytecode は建てられません。文は呼び出し先と、その呼び出しが書かれた宣言を C# の名前で名指します。互いを呼ぶ2つのメソッドでは両方の呼び出しに出るので、どちらを消しても直ります。

再帰しないシェーダーは何も変わらず、生成物も同一です(後述の全数比較)。公開 API は増えず、診断の識別子が計算側と Direct2D 側に1つずつ増えます。

Verification / 検証

dotnet build <project> -t:Rebuild -c Release -p:Platform=x64 -p:EmitCompilerGeneratedFiles=true

スイートは、生成器が走る11プロジェクトを1本ずつ -t:Rebuild で建ててから、建てた dll を直接起こして走らせました。土台は枝の先端 44dea9fd(#248 と #241 を含む main の c050699d を取り込んだもの)です。判定は失敗した試験の名前で行います。

スイート 合計 失敗 成功 省略
ComputeWeave.Tests 4189 1 4136 52
ComputeWeave.Tests.SourceGenerators 592 0 592 0
ComputeWeave.Tests.Internals 1085 0 1085 0
ComputeWeave.Tests.DeviceLost 43 0 43 0
ComputeWeave.D2D1.Tests 206 0 205 1
ComputeWeave.D2D1.Tests.SourceGenerators 237 0 237 0
ComputeWeave.D2D1.Tests.AssemblyLevelAttributes 4 0 4 0
ComputeWeave.Tests.DebugLayer 14 0 14 0

失敗の1件は BokehBlur (Discrete) で、実機の画像比較が正規化差分 0.0002% で落ちたものです。WARP 側の同じ試験は通り、このシェーダーの生成物は後述の全数比較で v2.6.0 と1バイトも違いません。この実行は同じ機械で他の並列の構築が走った直後のもので、実機の画像比較はそうした直後に揺れます。同じ枝の先端で同じスイートだけを回し直すと、合計4189、失敗0、成功4137、省略52で、変更前と同じ値です。その後に入口が自分を呼ぶ行を足した先端 98a18b44 では、生成器の2スイートを回し直して 593/593 と 237/237 でした。#243 と #253 を含む main(d6b5bab9)を取り込んだ先端 d0006310 でも11プロジェクトを建て直して8本を回し、失敗の名前はなく(計算側の生成器 616、Direct2D 側の生成器 240、ComputeWeave.Tests 4189/0/52)、生成物の全数も v2.6.0 と同じ 1078/1080 でした。

ComputeWeave.Tests.GlobalStatements は実行可能形式で、Test passed successfully! と終了状態0でした。走らせていないのは ComputeWeave.Tests.NativeLibrariesResolver の1本で、出荷経路のワークフローが回します。変更前の値は v2.6.0(a8245449)を同じ手順で建てて測ったもので、8本とも失敗は0件でした。試験の名前で突き合わせると、増えたのは計算側の生成器が35件(この枝の25件と #248 の10件)、Direct2D 側の生成器が5件(この枝の3件と #248 の2件)、ComputeWeave.D2D1.Tests が #247 の2件で、減ったものはありません。

生成物の全数比較は、v2.6.0(a8245449)と枝の先端を別の木で -t:Rebuild し、generated 配下の全ファイルの SHA-256 を突き合わせました。両方とも1080ファイルで、1078ファイルが同一、片方にしか無いものは0、違うのは同じコミットを2回建てても動く Direct2D の記述子2件だけです。src は v2.6.0 から 39bf66af まで動いておらず、main に入った #248 は生成物を1ファイルも変えていません。

書き換え器は通しシェーダーコンパイラだけが断る入力を要る既存の試験は、その入力を再帰から変えました。計算側は群が持てる大きさを超える [GroupShared] の配列、Direct2D 側は画素シェーダーのプロファイルが持たない同期の組み込み(FXC の X3664)です。

足した試験は、計算側の生成器に、再帰の19形と、環の無い同じ形の6つの対照、文が著者の名前を名指すことを見る1件です。19形は、自分を呼ぶ静的メソッドとインスタンスメソッド、自分を呼ぶ入口、互いを呼ぶ2つと3つのメソッド、外部の静的メソッド、拡張メソッド、外部の静的メソッドを経てシェーダーのメソッドへ戻る形、補助型のインスタンスメソッド、自分の型を作る構築子、構築子とメソッドが互いを経る形、局所関数の3形(自分を呼ぶ、互いを呼ぶ2つ、メソッドと局所関数が互いを経る)、取り込んだメソッドの中の局所関数、静的フィールドの初期化子から取り込むメソッド、部分メソッド、呼ばれない再帰するメソッドと局所関数です。各行は、報告の識別子が CMPW0129 だけであること(転送が並ばないこと)と、報告の位置の文字列が著者の書いた呼び出しそのものであることを見ます。対照は診断が0件で生成物が空でないことを見るので、シェーダーコンパイラが生成 HLSL を受け付けたことも含みます。Direct2D 側の生成器には静的メソッド、局所関数、互いを呼ぶ2つのメソッドの3形を足しました。

変異試験は、実装をコミットしてから7つの形で壊し、生成器の2スイートを全数で起こしました。

変異 計算側の生成器 Direct2D 側の生成器
呼び出しを記録しない 18件(再帰の17行と文の1件) 3件
構築子の呼び出しを記録しない 2件(構築子の2行) 0件
局所関数の本文の呼び出しを、それを持つ宣言のものとして記録する 6件(局所関数の5行と文の1件) 1件
部分メソッドを定義側へ揃えない 1件(部分メソッドの行) 0件
直接の再帰だけを報告する 6件(互いを経る形の6行) 1件
Direct2D 側で報告しない 0件 3件
計算側で報告しない 19件(18行と文の1件) 0件

7つとも名指しで落ち、対照の6行はどの変異でも通ったままです。土台は乗り物の差し替えと試験を載せた e3f2dcfe で、その後に取り込んだ main は書き換え器の別の箇所(定数の参照)を動かしています。入口が自分を呼ぶ行はその後に足したので、上の数には入っていません。

Adapter and driver tested / 試したアダプターとドライバー

Intel(R) Iris(R) Xe Graphics, 32.0.101.7085

Design notes / 設計の記録

直す層は共有の書き換え器にしました。どの呼び出しが生成 HLSL の関数の呼び出しとして書き出されるかを決めているのはそこで、取り込みと改名もそこにあります。呼び出しは、書かれた宣言から解決先の宣言への辺として記録し、判定は全ての宣言を書き換えた後に行います。書き換えの途中で判定しないのは、書き換えが環の全ての辺を通らないからです。シェーダー自身のメソッドは取り込まれずに生成器の経路で書き出され、局所関数は宣言された場所で持ち上げられ、取り込み済みの宣言は2度目には辿られません。互いを呼ぶ2つのシェーダーメソッドや2つの局所関数の環は、取り込みの経路だけでは見えないということです。記録の集合は、書き換えが集める要求と同じ形でシェーダーごとに1つを全ての書き換え器が共有し、2つの生成器はそれぞれの流れの同じ位置で読みます。要求の型へ入れなかったのは、その型が標本器の使用のようなシェーダーの要求を運ぶものであり、呼び出しの記録はその意味に入らないからです。

報告は環の上の呼び出し全てに出します。1つの環に1件だけ出す形は、深さ優先の順で辺を選ぶことになり、示される呼び出しが辿った順に依ります。全ての辺に出せば、どれを消しても直り、順序にも依りません。

部分メソッドは定義側の部分で記録します。呼び出しの解決先は定義側で、実装側の宣言を書き換えるときに得る記号は実装側なので、揃えないと自分を呼ぶ部分メソッドが環になりません。ソースの無いメソッドの呼び出しは記録しません。既に CMPW0049 が断っており、書き出される関数がありません。

触っていない箇所を挙げます。静的フィールドの初期化子は関数ではなく誰からも呼ばれないので、記録の起点にしません。初期化子が取り込むメソッドは、取り込む書き換え器が同じ集合へ記録します。取り込みの印による無限再帰の防止はそのまま残しており、記録はそれより手前で行います。

退けた設計が2つあります。書き換え器に書き換え中の宣言を積む道を持たせ、道の上にある宣言への呼び出しを報告する形は、上の理由で環の一部しか捉えません。全ての宣言を後から意味論的に歩き直して呼び出しの図を作る形は、どの呼び出しが書き出されるかの規則を書き換え器の外にもう一度書くことになり、意味解決も二重になるので採りませんでした。

前提が崩れる筋を書きます。シェーダー自身のメソッドも取り込みの経路で書き出す形へ変えるなら、記録の起点はそのままで判定を書き換えの途中へ移せます。

Not measured / 測っていないこと

Direct2D 側は3形だけを試験にしました。残る形は共有の書き換え器を通るので計算側で測りました。構築子の初期化子(: this(...))を経る環は C# 自身が断るので建てていません。入れ子の局所関数の再帰は建てていません。

Checklist / 確認

  • The pull request is one logical change, with no unrelated refactoring or formatting. / 一つの論理的な変更にまとまっており、無関係な整理や整形を含まない。
  • Every commit builds on its own. / 各コミットが単独でビルドできる。
  • Implementation changes and their verification tests are separate commits. / 実装の変更と検証テストを別のコミットに分けた。
  • No commit already merged into the default branch or referenced by a release tag was rewritten. / 既定ブランチへ入った、またはリリースタグが指すコミットを書き換えていない。
  • The change follows the implementation pattern already established in the subsystem. / 変更は、その部分で既に確立された実装パターンに従っている。
  • Existing documentation comments were preserved. / 既存のドキュメントコメントを維持した。
  • No silent fallback behavior or compatibility shim was introduced. / 暗黙の代替動作や互換性のための繕いを持ち込んでいない。
  • No unrelated dependency was updated. / 無関係な依存関係を更新していない。
  • If a file inherited from upstream changed, the divergence ledger in CONTRIBUTING.md was updated, or the change was judged not to be a divergence. / 上流から受け継いだファイルを変更した場合、CONTRIBUTING.md の乖離台帳を更新したか、乖離ではないと判断した。

If this touches a guarded area / 慎重を要する箇所に触れる場合

  • Tests exercise the guarded behavior itself, and I confirmed they fail when that behavior is deliberately broken. / 試験が守るべき挙動そのものを動かしており、その挙動を意図的に壊すと落ちることを確認した。
  • No test depends on arbitrary delays, fixed retry counts, or assumptions about how fast asynchronous work completes. / 任意の待ち時間、固定の再試行回数、非同期処理の速さへの仮定に依存する試験が無い。
  • For analyzer diagnostics that produce build errors, the complete solution was verified in addition to the analyzer tests. / ビルドエラーを出すアナライザー診断は、アナライザーの試験に加えて解全体を検証した。
  • For public API or generated descriptor changes, the compatibility, deterministic-generation or golden-data checks of the affected subsystem were run. / 公開APIまたは生成される記述子を変えた場合、該当部分の互換性、生成の決定性、または基準データの検査を走らせた。

@routersys routersys added bug Something isn't working / 不具合が起きている analyzer or generator Analyzer or generator / アナライザーまたはジェネレーター labels Sep 15, 2026
@github-actions

github-actions Bot commented Sep 15, 2026 •

Copy link
Copy Markdown

PRレビュー / PR review

変更 20 ファイル、コミット 7 件。 / 20 files, 7 commits.

検証の要否 / Verification required

以下を走らせ、失敗した試験の名前と失敗の様子を変更前と突き合わせてください。総数だけで判断しないでください。
Run the following and compare the names and failure modes against the same suites before your change. Do not judge by totals alone.

dotnet build ComputeWeave.sln -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.SourceGenerators/ComputeWeave.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.Internals/ComputeWeave.Tests.Internals.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests/ComputeWeave.Tests.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.Tests.DeviceLost/ComputeWeave.Tests.DeviceLost.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests.SourceGenerators/ComputeWeave.D2D1.Tests.SourceGenerators.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests/ComputeWeave.D2D1.Tests.csproj -c Release -p:Platform=x64
dotnet test tests/ComputeWeave.D2D1.Tests.AssemblyLevelAttributes/ComputeWeave.D2D1.Tests.AssemblyLevelAttributes.csproj -c Release -p:Platform=x64

ビルドエラーを出す診断を変えた場合は、アナライザーの試験に加えて解全体の検証が要ります。
If a diagnostic that produces build errors changed, verify the complete solution as well.

慎重を要する箇所 / Guarded areas touched

  • 寿命と破棄 / lifetime and disposal
    • src/ComputeWeave.D2D1.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.SourceGeneration.Hlsl/Models/TypeAliases.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxProcessors/HlslDefinitionsSyntaxProcessor.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/ShaderSourceRewriter.cs
    • src/ComputeWeave.SourceGeneration.Hlsl/SyntaxRewriters/StaticFieldRewriter.cs
    • ほか 1 件 / 1 more
  • 記述子と診断 / descriptors and diagnostics
    • src/ComputeWeave.D2D1.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.D2D1.SourceGenerators/D2DPixelShaderDescriptorGenerator.HlslSource.cs
    • src/ComputeWeave.D2D1.SourceGenerators/Diagnostics/DiagnosticDescriptors.cs
    • src/ComputeWeave.SourceGenerators/AnalyzerReleases.Unshipped.md
    • src/ComputeWeave.SourceGenerators/ComputeShaderDescriptorGenerator.HlslSource.cs
    • ほか 1 件 / 1 more

寿命の追跡と危険の追跡は別々の保証です。一方を保っても他方が保たれるとは限りません。
Lifetime tracking and hazard tracking are separate guarantees; preserving one does not preserve the other.

公開APIまたは生成される記述子を変えた場合は、該当部分の互換性、生成の決定性、基準データの検査を走らせてください。
For public API or generated descriptor changes, run the compatibility, deterministic-generation or golden-data checks of the affected subsystem.

確認できた点 / Confirmed

  • 概要が書かれています。 / A summary is present.
  • 検証の結果が書かれています。 / Verification results are present.
  • 関連する課題が示されています。 / A linked issue is referenced.
  • 実装と検証テストが別のコミットに分かれています。 / Implementation and tests are in separate commits.

これは自動の確認で、査読の代わりにはなりません。指摘は判断の材料であって、従う義務はありません。
This is an automated check, not a substitute for review. Findings are input to a decision, not obligations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analyzer or generator Analyzer or generator / アナライザーまたはジェネレーター bug Something isn't working / 不具合が起きている

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Proposal] 再帰するメソッドが診断なく書き出され、シェーダーコンパイラの誤りが転送だけになる

1 participant