blob: eb2438eb3e2f0f1ea34834255d9157f6ec848ac7 [file] [edit]
; RUN: llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - | FileCheck %s --implicit-check-not=OpSwitch
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan-compute %s -o - -filetype=obj | spirv-val %}
; These CFGs model the conditional branch chains which are roughly equivalent
; to switch statements but without using switch instructions. In particular, the
; break-only chain used to make an outer selection merge branch into a nested
; selection's merge block.
; CHECK-DAG: OpName %[[FALLTHROUGH:[0-9]+]] "fallthrough"
; CHECK-DAG: OpName %[[BREAKS:[0-9]+]] "breaks"
; CHECK-DAG: OpName %[[MIXED:[0-9]+]] "mixed"
; CHECK: %[[FALLTHROUGH]] = OpFunction
; CHECK-COUNT-3: OpSelectionMerge
; CHECK: OpFunctionEnd
define i32 @fallthrough(i32 %value) {
entry:
br label %sw.dispatch
sw.dispatch:
%case0 = icmp eq i32 %value, 0
br i1 %case0, label %sw.bb0, label %sw.next0
sw.bb0:
br label %sw.next0
sw.next0:
%fellthrough0 = phi i1 [ true, %sw.bb0 ], [ false, %sw.dispatch ]
%case1 = icmp eq i32 %value, 1
%take1 = or i1 %fellthrough0, %case1
br i1 %take1, label %sw.bb1, label %sw.next1
sw.bb1:
br label %sw.next1
sw.next1:
%fellthrough1 = phi i1 [ true, %sw.bb1 ], [ false, %sw.next0 ]
%not.case0 = icmp ne i32 %value, 0
%not.case1 = icmp ne i32 %value, 1
%take.default = and i1 %not.case0, %not.case1
%take2 = or i1 %fellthrough1, %take.default
br i1 %take2, label %sw.default, label %sw.epilog
sw.default:
br label %sw.epilog
sw.epilog:
%result = phi i32 [ 7, %sw.default ], [ 0, %sw.next1 ]
ret i32 %result
}
; CHECK: %[[BREAKS]] = OpFunction
; CHECK-NOT: OpSelectionMerge
; CHECK: OpSelectionMerge %[[BREAK_EPILOG:[0-9]+]] None
; CHECK-NEXT: OpBranchConditional %{{[0-9]+}} %[[BREAK_BB0:[0-9]+]] %[[BREAK_NEXT0:[0-9]+]]
; CHECK: %[[BREAK_NEXT0]] = OpLabel
; CHECK-NOT: OpSelectionMerge
; CHECK: OpSelectionMerge %[[BREAK_NEXT0_EXIT:[0-9]+]] None
; CHECK-NEXT: OpBranchConditional %{{[0-9]+}} %[[BREAK_NEXT0_EXIT]] %[[BREAK_NEXT1:[0-9]+]]
; CHECK: %[[BREAK_NEXT1]] = OpLabel
; CHECK-NOT: OpSelectionMerge
; CHECK: OpSelectionMerge %[[BREAK_NEXT1_EXIT:[0-9]+]] None
; CHECK-NEXT: OpBranchConditional %{{[0-9]+}} %[[BREAK_NEXT1_EXIT]] %[[BREAK_CLEANUP:[0-9]+]]
; CHECK: %[[BREAK_CLEANUP]] = OpLabel
; CHECK: OpBranch %[[BREAK_NEXT1_EXIT]]
; CHECK: %[[BREAK_NEXT1_EXIT]] = OpLabel
; CHECK: OpBranchConditional %{{[0-9]+}} %[[BREAK_DEFAULT:[0-9]+]] %[[BREAK_NEXT0_EXIT]]
; CHECK: %[[BREAK_DEFAULT]] = OpLabel
; CHECK: OpBranch %[[BREAK_NEXT0_EXIT]]
; CHECK: %[[BREAK_NEXT0_EXIT]] = OpLabel
; CHECK: OpBranchConditional %{{[0-9]+}} %[[BREAK_BB1:[0-9]+]] %[[BREAK_EPILOG]]
; CHECK: %[[BREAK_BB1]] = OpLabel
; CHECK: OpBranch %[[BREAK_EPILOG]]
; CHECK: %[[BREAK_BB0]] = OpLabel
; CHECK: OpBranch %[[BREAK_EPILOG]]
; CHECK: %[[BREAK_EPILOG]] = OpLabel
; CHECK-NOT: OpSelectionMerge
; CHECK: OpFunctionEnd
define i32 @breaks(i32 %value) {
entry:
br label %sw.dispatch
sw.dispatch:
%case0 = icmp eq i32 %value, 0
br i1 %case0, label %sw.bb0, label %sw.next0
sw.bb0:
br label %sw.epilog
sw.next0:
%case1 = icmp eq i32 %value, 1
br i1 %case1, label %sw.bb1, label %sw.next1
sw.bb1:
br label %sw.epilog
sw.next1:
%not.case0 = icmp ne i32 %value, 0
%not.case1 = icmp ne i32 %value, 1
%take.default = and i1 %not.case0, %not.case1
br i1 %take.default, label %sw.default, label %sw.cleanup
sw.default:
br label %sw.epilog
sw.cleanup:
br label %sw.epilog
sw.epilog:
%result = phi i32 [ 1, %sw.bb0 ], [ 2, %sw.bb1 ],
[ 4, %sw.default ], [ 0, %sw.cleanup ]
ret i32 %result
}
; CHECK: %[[MIXED]] = OpFunction
; CHECK-COUNT-4: OpSelectionMerge
; CHECK: OpFunctionEnd
define i32 @mixed(i32 %value) {
entry:
br label %sw.dispatch
sw.dispatch:
%case0 = icmp eq i32 %value, 0
br i1 %case0, label %sw.bb0, label %sw.next0
sw.bb0:
br label %sw.next0
sw.next0:
%fellthrough0 = phi i1 [ true, %sw.bb0 ], [ false, %sw.dispatch ]
%case1 = icmp eq i32 %value, 1
%take1 = or i1 %fellthrough0, %case1
br i1 %take1, label %sw.bb1, label %sw.next1
sw.bb1:
br label %sw.epilog
sw.next1:
%case2 = icmp eq i32 %value, 2
br i1 %case2, label %sw.bb2, label %sw.next2
sw.bb2:
br label %sw.next2
sw.next2:
%fellthrough2 = phi i1 [ true, %sw.bb2 ], [ false, %sw.next1 ]
%not.case0 = icmp ne i32 %value, 0
%not.case1 = icmp ne i32 %value, 1
%not.case2 = icmp ne i32 %value, 2
%not.case01 = and i1 %not.case0, %not.case1
%take.default = and i1 %not.case01, %not.case2
%take3 = or i1 %fellthrough2, %take.default
br i1 %take3, label %sw.default, label %sw.cleanup
sw.default:
br label %sw.epilog
sw.cleanup:
br label %sw.epilog
sw.epilog:
%result = phi i32 [ 3, %sw.bb1 ], [ 12, %sw.default ],
[ 0, %sw.cleanup ]
ret i32 %result
}