@@ -478,15 +478,113 @@ exit:
478478 ret void
479479}
480480
481+ ; ============================================================================
482+ ; Test 15: falseBranch is also a direct predecessor of the PHI's parent block
483+ ; (useBB) — no replacement allowed.
484+ ;
485+ ; CFG produced by SROA when a dead ternary alloca is promoted:
486+ ;
487+ ; cmpBB: fcmp oeq %val, 0.0
488+ ; - ternary.true (trueBranch, empty: br endBB)
489+ ; - ternary.false (falseBranch, empty: br endBB)
490+ ; |
491+ ; V
492+ ; endBB: phi [%val, ternary.true], [%val, ternary.false]
493+ ;
494+ ; Must NOT replace %val in the [%val, %ternary.true] incoming because
495+ ; falseBranch is also a direct predecessor of endBB (useBB). If it did,
496+ ; CFGSimplification would later remove both empty blocks, collapsing the
497+ ; two incoming edges back to cmpBB and discarding the ternary.false value,
498+ ; turning the PHI into the constant 0.0. This caused incorrect rendering in
499+ ; a GS shader where the diagonal faceNormal components were zeroed out.
500+ ; ============================================================================
501+ ; CHECK-LABEL: @test_falsebranch_also_pred_of_usebb(
502+ define spir_kernel void @test_falsebranch_also_pred_of_usebb (ptr addrspace (1 ) %out ) {
503+ entry:
504+ %tid = call i32 @llvm.genx.GenISA.DCL.SystemValue.i32 (i32 17 )
505+ %val = uitofp i32 %tid to float
506+ %cmp = fcmp oeq float %val , 0 .000000e+00
507+ br i1 %cmp , label %ternary.true , label %ternary.false
508+
509+ ternary.true:
510+ br label %endBB
511+
512+ ternary.false:
513+ br label %endBB
514+
515+ endBB:
516+ ; falseBranch (%ternary.false) is a direct predecessor of endBB, so
517+ ; the [%val, %ternary.true] arm must not be replaced with 0.0.
518+ ; CHECK-LABEL: endBB:
519+ ; CHECK: %phi_val = phi float [ %val, %ternary.true ], [ %val, %ternary.false ]
520+ %phi_val = phi float [ %val , %ternary.true ], [ %val , %ternary.false ]
521+ store float %phi_val , ptr addrspace (1 ) %out , align 4
522+ ret void
523+ }
524+
525+ ; ============================================================================
526+ ; Test 16: falseBranch reaches trueBranchBB (useBB) via an intermediate block
527+ ; that is dominated by cmpBB — no replacement allowed.
528+ ;
529+ ; This models the CFG produced by JumpThreading when it threads the true path of
530+ ; a ternary-style conditional directly to the downstream join block (endBB),
531+ ; while the false path still goes through intermediate blocks:
532+ ;
533+ ; cmpBB: fcmp oeq %val, 0.0
534+ ; true ------------------------------> endBB
535+ ; false --> ternary.false --> ternary.end --> endBB
536+ ;
537+ ; PCU's Check 1 fires: incomingBB==cmpBB and useBB==trueBranchBB==endBB.
538+ ; The direct-predecessor guard (sub-case A, Test 15) does not help because
539+ ; ternary.false is NOT a direct predecessor of endBB. The new guard catches
540+ ; it: ternary.end is a predecessor of endBB, is not cmpBB, and IS dominated
541+ ; by cmpBB — indicating it lies on the false-branch path.
542+ ;
543+ ; Must NOT replace %val in [%val, %entry] because ternary.end reaches endBB
544+ ; without the equality guarantee, so after CFGSimplification collapses
545+ ; ternary.false->ternary.end the PHI would incorrectly receive the constant 0.0.
546+ ; This was the root cause of a GS shader rendering bug (IGC-13513) where the
547+ ; diagonal faceNormal component was zeroed out.
548+ ; ============================================================================
549+ ; CHECK-LABEL: @test_indirect_falsebranch(
550+ define spir_kernel void @test_indirect_falsebranch (ptr addrspace (1 ) %out ) {
551+ entry:
552+ %tid = call i32 @llvm.genx.GenISA.DCL.SystemValue.i32 (i32 17 )
553+ %val = uitofp i32 %tid to float
554+ %cmp = fcmp oeq float %val , 0 .000000e+00
555+ ; True edge goes directly to endBB (as if JumpThreading threaded ternary.true away).
556+ ; False edge goes to ternary.false, which eventually also reaches endBB.
557+ br i1 %cmp , label %endBB , label %ternary.false
558+
559+ ternary.false:
560+ ; Intermediate block dominated by entry (=cmpBB); no equality guarantee here.
561+ br label %ternary.end
562+
563+ ternary.end:
564+ ; Also dominated by entry (=cmpBB); direct predecessor of endBB.
565+ br label %endBB
566+
567+ endBB:
568+ ; [%val, %entry] — incoming from cmpBB on the true (equality) edge.
569+ ; [%val, %ternary.end] — incoming from the false-path intermediate block.
570+ ; The [%val, %entry] arm must NOT be replaced with 0.0: ternary.end reaches
571+ ; here without equality being guaranteed.
572+ ; CHECK-LABEL: endBB:
573+ ; CHECK: %phi_val = phi float [ %val, %entry ], [ %val, %ternary.end ]
574+ %phi_val = phi float [ %val , %entry ], [ %val , %ternary.end ]
575+ store float %phi_val , ptr addrspace (1 ) %out , align 4
576+ ret void
577+ }
578+
481579declare i32 @llvm.genx.GenISA.DCL.SystemValue.i32 (i32 ) #0
482580
483581attributes #0 = { nounwind readnone }
484582
485583!IGCMetadata = !{!2 }
486- !igc.functions = !{!13 , !22 , !32 , !42 , !52 , !62 , !72 , !82 , !92 , !102 , !112 , !122 , !132 , !142 }
584+ !igc.functions = !{!13 , !22 , !32 , !42 , !52 , !62 , !72 , !82 , !92 , !102 , !112 , !122 , !132 , !142 , !152 , !162 }
487585
488586!2 = !{!"ModuleMD" , !3 }
489- !3 = !{!"FuncMD" , !4 , !5 , !20 , !21 , !30 , !31 , !40 , !41 , !50 , !51 , !60 , !61 , !70 , !71 , !80 , !81 , !90 , !91 , !100 , !101 , !110 , !111 , !120 , !121 , !130 , !131 , !140 , !141 }
587+ !3 = !{!"FuncMD" , !4 , !5 , !20 , !21 , !30 , !31 , !40 , !41 , !50 , !51 , !60 , !61 , !70 , !71 , !80 , !81 , !90 , !91 , !100 , !101 , !110 , !111 , !120 , !121 , !130 , !131 , !140 , !141 , !150 , !151 , !160 , !161 }
490588
491589; Shared metadata nodes reused by all kernels
492590!6 = !{!"localOffsets" }
@@ -569,3 +667,13 @@ attributes #0 = { nounwind readnone }
569667!141 = !{!"FuncMDValue[13]" , !6 , !7 , !11 , !12 }
570668!142 = !{ptr @test_multi_cmpbb_truebb , !14 }
571669
670+ ; test_falsebranch_also_pred_of_usebb
671+ !150 = !{!"FuncMDMap[14]" , ptr @test_falsebranch_also_pred_of_usebb }
672+ !151 = !{!"FuncMDValue[14]" , !6 , !7 , !11 , !12 }
673+ !152 = !{ptr @test_falsebranch_also_pred_of_usebb , !14 }
674+
675+ ; test_indirect_falsebranch
676+ !160 = !{!"FuncMDMap[15]" , ptr @test_indirect_falsebranch }
677+ !161 = !{!"FuncMDValue[15]" , !6 , !7 , !11 , !12 }
678+ !162 = !{ptr @test_indirect_falsebranch , !14 }
679+
0 commit comments