microsoft / microsoft/DirectXShaderCompiler

[ScopeNestedCFG] Basic Blocks are cloned when containing convergent ops

Open
#8,141 1 comment 0 reactions 1 assignee View on GitHub

@bob80905 is already working on this.

Since Feb 9, 2026.

bug
Dominant language
C++
Stars
3.7k
Forks
900
Avg merge
2d 11h
Merged PRs (30d)
44

Description

Description

Basic blocks containing convergent ops are being cloned, causing there to be multiple convergent ops, more than the original source. This is bad.

Steps to Reproduce

Run opt.exe on this IR:

; RUN: %opt-exe %s -scopenested -S | FileCheck %s

declare float @dx.wave.op(float) convergent


define void @CSMain(i32 %tid, float %v) convergent {
entry:
  switch i32 %tid, label %exit [
    i32 0, label %case0
    i32 1, label %case1
  ]

case0:                                          ; switch case 0

  %w0 = call float @dx.wave.op(float %v)
  br label %case1                               ; FALLTHROUGH


case1:                                          ; switch case 1
  %a = phi float [ %w0, %case0 ],
                   [ 0.0, %entry ]

  %w1 = call float @dx.wave.op(float %v)
  %sum = fadd float %a, %w1
  br label %exit


exit:
  %r = phi float [ %sum, %case1 ],
                   [ 0.0, %entry ]
  ret void
}

Actual Behavior

The observed issue is that there are 3 calls to the abstract wave op instruction, rather than the expected 2.

This can be seen here:

; ModuleID = 'C:\temp\min.ll'

; Function Attrs: convergent
declare float @dx.wave.op(float) #0

; Function Attrs: convergent
define void @CSMain(i32 %tid, float %v) #0 {
entry:
  switch i32 %tid, label %dx.EndSwitchScope [
    i32 0, label %case0
    i32 1, label %case1.4
  ], !dx.BranchKind !0

case0:                                            ; preds = %entry
  %w0 = call float @dx.wave.op(float %v)
  br label %case1

case1:                                            ; preds = %case0
  %a = phi float [ %w0, %case0 ], [ 0.000000e+00, %entry ]
  %w1 = call float @dx.wave.op(float %v)
  %sum = fadd float %a, %w1
  br label %dx.SwitchBreak

case1.4:                                          ; preds = %entry
  %a.1 = phi float [ %w0, %case0 ], [ 0.000000e+00, %entry ]
  %w1.2 = call float @dx.wave.op(float %v)
  %sum.3 = fadd float %a.1, %w1.2
  br label %dx.SwitchBreak.5

dx.EndSwitchScope:                                ; preds = %dx.SwitchBreak.5, %dx.SwitchBreak, %entry
  br label %exit, !dx.BranchKind !1

dx.SwitchBreak:                                   ; preds = %case1
  br label %dx.EndSwitchScope, !dx.BranchKind !2

dx.SwitchBreak.5:                                 ; preds = %case1.4
  br label %dx.EndSwitchScope, !dx.BranchKind !2

exit:                                             ; preds = %dx.EndSwitchScope
  %r = phi float [ %sum, %case1 ], [ 0.000000e+00, %entry ]
  ret void
}

attributes #0 = { convergent }

!0 = !{i32 4}
!1 = !{i32 5}
!2 = !{i32 7}

Environment

  • DXC version: dxcompiler.dll: 1.10(5196-98bc4c27)(1.8.0.5070) - 1.8.0.5070 (move_coop_vec_feature_to_610, 55805c7f6815-dirty)
  • Host Operating System Windows 11 Version 10.0.26200 Build 26200

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.