CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
511 lines
14 KiB
LLVM
511 lines
14 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
|
|
; RUN: opt -passes=simplifycfg,instcombine -simplifycfg-require-and-preserve-domtree=1 < %s -simplifycfg-merge-cond-stores=true -simplifycfg-merge-cond-stores-aggressively=false -phi-node-folding-threshold=2 -S | FileCheck %s
|
|
|
|
; This test should succeed and end up if-converted.
|
|
define void @test_simple(ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_simple(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[B:%.*]] = or i32 [[A:%.*]], [[B1:%.*]]
|
|
; CHECK-NEXT: [[X3:%.*]] = icmp eq i32 [[B]], 0
|
|
; CHECK-NEXT: br i1 [[X3]], label [[TMP2:%.*]], label [[TMP1:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp ne i32 [[B1]], 0
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = zext i1 [[X2]] to i32
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %end, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; This is the same as test_simple, but the branch target order has been swapped
|
|
define void @test_simple_commuted(ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_simple_commuted(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[B:%.*]], 0
|
|
; CHECK-NEXT: [[X3:%.*]] = icmp eq i32 [[B1:%.*]], 0
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[X2]], [[X3]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP1:%.*]], label [[TMP2:%.*]], !prof [[PROF0:![0-9]+]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = zext i1 [[X3]] to i32
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %yes1, label %fallthrough, !prof !0
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %yes2, label %end, !prof !1
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; This test should entirely fold away, leaving one large basic block.
|
|
define void @test_recursive(ptr %p, i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: @test_recursive(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[TMP0]], [[C1:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = or i32 [[TMP1]], [[D:%.*]]
|
|
; CHECK-NEXT: [[X3_NOT:%.*]] = icmp eq i32 [[C]], 0
|
|
; CHECK-NEXT: br i1 [[X3_NOT]], label [[TMP4:%.*]], label [[TMP3:%.*]]
|
|
; CHECK: 3:
|
|
; CHECK-NEXT: [[X4_NOT:%.*]] = icmp eq i32 [[D]], 0
|
|
; CHECK-NEXT: [[X3_NOT1:%.*]] = icmp eq i32 [[C1]], 0
|
|
; CHECK-NEXT: [[X3:%.*]] = icmp ne i32 [[B]], 0
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = zext i1 [[X3]] to i32
|
|
; CHECK-NEXT: [[SPEC_SELECT1:%.*]] = select i1 [[X3_NOT1]], i32 [[SPEC_SELECT]], i32 2
|
|
; CHECK-NEXT: [[SPEC_SELECT2:%.*]] = select i1 [[X4_NOT]], i32 [[SPEC_SELECT1]], i32 3
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT2]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[TMP4]]
|
|
; CHECK: 4:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %next, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %next
|
|
|
|
next:
|
|
%x3 = icmp eq i32 %c, 0
|
|
br i1 %x3, label %fallthrough2, label %yes3
|
|
|
|
yes3:
|
|
store i32 2, ptr %p
|
|
br label %fallthrough2
|
|
|
|
fallthrough2:
|
|
%x4 = icmp eq i32 %d, 0
|
|
br i1 %x4, label %end, label %yes4
|
|
|
|
yes4:
|
|
store i32 3, ptr %p
|
|
br label %end
|
|
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; The code in each diamond is too large - it won't be if-converted so our
|
|
; heuristics should say no.
|
|
define void @test_not_ifconverted(ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_not_ifconverted(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X1:%.*]] = icmp eq i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: br i1 [[X1]], label [[FALLTHROUGH:%.*]], label [[YES1:%.*]]
|
|
; CHECK: yes1:
|
|
; CHECK-NEXT: [[Y1:%.*]] = or i32 [[B:%.*]], 55
|
|
; CHECK-NEXT: [[Y2:%.*]] = add i32 [[Y1]], 24
|
|
; CHECK-NEXT: [[Y3:%.*]] = and i32 [[Y2]], 67
|
|
; CHECK-NEXT: store i32 [[Y3]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FALLTHROUGH]]
|
|
; CHECK: fallthrough:
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[B]], 0
|
|
; CHECK-NEXT: br i1 [[X2]], label [[END:%.*]], label [[YES2:%.*]]
|
|
; CHECK: yes2:
|
|
; CHECK-NEXT: [[Z1:%.*]] = or i32 [[A]], 55
|
|
; CHECK-NEXT: [[Z2:%.*]] = add i32 [[Z1]], 24
|
|
; CHECK-NEXT: [[Z3:%.*]] = and i32 [[Z2]], 67
|
|
; CHECK-NEXT: store i32 [[Z3]], ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
|
|
yes1:
|
|
%y1 = or i32 %b, 55
|
|
%y2 = add i32 %y1, 24
|
|
%y3 = and i32 %y2, 67
|
|
store i32 %y3, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %end, label %yes2
|
|
|
|
yes2:
|
|
%z1 = or i32 %a, 55
|
|
%z2 = add i32 %z1, 24
|
|
%z3 = and i32 %z2, 67
|
|
store i32 %z3, ptr %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; The store to %p clobbers the previous store, so if-converting this would
|
|
; be illegal.
|
|
define void @test_aliasing1(ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_aliasing1(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X1:%.*]] = icmp eq i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: br i1 [[X1]], label [[FALLTHROUGH:%.*]], label [[YES1:%.*]]
|
|
; CHECK: yes1:
|
|
; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FALLTHROUGH]]
|
|
; CHECK: fallthrough:
|
|
; CHECK-NEXT: [[Y1:%.*]] = load i32, ptr [[P]], align 4
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[Y1]], 0
|
|
; CHECK-NEXT: br i1 [[X2]], label [[END:%.*]], label [[YES2:%.*]]
|
|
; CHECK: yes2:
|
|
; CHECK-NEXT: store i32 1, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%y1 = load i32, ptr %p
|
|
%x2 = icmp eq i32 %y1, 0
|
|
br i1 %x2, label %end, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; The load from %q aliases with %p, so if-converting this would be illegal.
|
|
define void @test_aliasing2(ptr %p, ptr %q, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_aliasing2(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X1:%.*]] = icmp eq i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: br i1 [[X1]], label [[FALLTHROUGH:%.*]], label [[YES1:%.*]]
|
|
; CHECK: yes1:
|
|
; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FALLTHROUGH]]
|
|
; CHECK: fallthrough:
|
|
; CHECK-NEXT: [[Y1:%.*]] = load i32, ptr [[Q:%.*]], align 4
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[Y1]], 0
|
|
; CHECK-NEXT: br i1 [[X2]], label [[END:%.*]], label [[YES2:%.*]]
|
|
; CHECK: yes2:
|
|
; CHECK-NEXT: store i32 1, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%y1 = load i32, ptr %q
|
|
%x2 = icmp eq i32 %y1, 0
|
|
br i1 %x2, label %end, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
declare void @f()
|
|
|
|
; This should get if-converted.
|
|
define i32 @test_diamond_simple(ptr %p, ptr %q, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_diamond_simple(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp ne i32 [[B1:%.*]], 0
|
|
; CHECK-NEXT: [[B:%.*]] = or i32 [[A:%.*]], [[B1]]
|
|
; CHECK-NEXT: [[X3:%.*]] = icmp eq i32 [[B]], 0
|
|
; CHECK-NEXT: br i1 [[X3]], label [[TMP2:%.*]], label [[TMP1:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[SIMPLIFYCFG_MERGE:%.*]] = zext i1 [[X2]] to i32
|
|
; CHECK-NEXT: store i32 [[SIMPLIFYCFG_MERGE]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: [[Z4:%.*]] = select i1 [[X2]], i32 3, i32 0
|
|
; CHECK-NEXT: ret i32 [[Z4]]
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %no1, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
no1:
|
|
%z1 = add i32 %a, %b
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%z2 = phi i32 [ %z1, %no1 ], [ 0, %yes1 ]
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %no2, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
no2:
|
|
%z3 = sub i32 %z2, %b
|
|
br label %end
|
|
|
|
end:
|
|
%z4 = phi i32 [ %z3, %no2 ], [ 3, %yes2 ]
|
|
ret i32 %z4
|
|
}
|
|
|
|
; Now there is a call to f() in the bottom branch. The store in the first
|
|
; branch would now be reordered with respect to the call if we if-converted,
|
|
; so we must not.
|
|
define i32 @test_diamond_alias3(ptr %p, ptr %q, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @test_diamond_alias3(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X1:%.*]] = icmp eq i32 [[A:%.*]], 0
|
|
; CHECK-NEXT: br i1 [[X1]], label [[NO1:%.*]], label [[YES1:%.*]]
|
|
; CHECK: yes1:
|
|
; CHECK-NEXT: store i32 0, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[FALLTHROUGH:%.*]]
|
|
; CHECK: no1:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: br label [[FALLTHROUGH]]
|
|
; CHECK: fallthrough:
|
|
; CHECK-NEXT: [[Z2:%.*]] = phi i32 [ [[B:%.*]], [[NO1]] ], [ 0, [[YES1]] ]
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp eq i32 [[B]], 0
|
|
; CHECK-NEXT: br i1 [[X2]], label [[NO2:%.*]], label [[YES2:%.*]]
|
|
; CHECK: yes2:
|
|
; CHECK-NEXT: store i32 1, ptr [[P]], align 4
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
; CHECK: no2:
|
|
; CHECK-NEXT: call void @f()
|
|
; CHECK-NEXT: [[Z3:%.*]] = sub nuw nsw i32 [[Z2]], [[B]]
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: [[Z4:%.*]] = phi i32 [ [[Z3]], [[NO2]] ], [ 3, [[YES2]] ]
|
|
; CHECK-NEXT: ret i32 [[Z4]]
|
|
;
|
|
entry:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %no1, label %yes1
|
|
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
|
|
no1:
|
|
call void @f()
|
|
%z1 = add i32 %a, %b
|
|
br label %fallthrough
|
|
|
|
fallthrough:
|
|
%z2 = phi i32 [ %z1, %no1 ], [ 0, %yes1 ]
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %no2, label %yes2
|
|
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
|
|
no2:
|
|
call void @f()
|
|
%z3 = sub i32 %z2, %b
|
|
br label %end
|
|
|
|
end:
|
|
%z4 = phi i32 [ %z3, %no2 ], [ 3, %yes2 ]
|
|
ret i32 %z4
|
|
}
|
|
|
|
; This test has an outer if over the two triangles. This requires creating a new BB to hold the store.
|
|
define void @test_outer_if(ptr %p, i32 %a, i32 %b, i32 %c) {
|
|
; CHECK-LABEL: @test_outer_if(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[X3:%.*]] = icmp eq i32 [[C:%.*]], 0
|
|
; CHECK-NEXT: br i1 [[X3]], label [[END:%.*]], label [[CONTINUE:%.*]]
|
|
; CHECK: continue:
|
|
; CHECK-NEXT: [[B:%.*]] = or i32 [[A:%.*]], [[B1:%.*]]
|
|
; CHECK-NEXT: [[X4:%.*]] = icmp eq i32 [[B]], 0
|
|
; CHECK-NEXT: br i1 [[X4]], label [[END]], label [[TMP1:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[X2:%.*]] = icmp ne i32 [[B1]], 0
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = zext i1 [[X2]] to i32
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x3 = icmp eq i32 %c, 0
|
|
br i1 %x3, label %end, label %continue
|
|
continue:
|
|
%x1 = icmp eq i32 %a, 0
|
|
br i1 %x1, label %fallthrough, label %yes1
|
|
yes1:
|
|
store i32 0, ptr %p
|
|
br label %fallthrough
|
|
fallthrough:
|
|
%x2 = icmp eq i32 %b, 0
|
|
br i1 %x2, label %end, label %yes2
|
|
yes2:
|
|
store i32 1, ptr %p
|
|
br label %end
|
|
end:
|
|
ret void
|
|
}
|
|
|
|
; Unordered atomic stores can be merged, but the merged store must remain
|
|
; atomic with the same ordering/syncscope (it must not be downgraded to a
|
|
; plain store).
|
|
define void @test_atomic_store_merged(i1 %c1, i1 %c2, ptr %p) {
|
|
; CHECK-LABEL: @test_atomic_store_merged(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[C1:%.*]], [[C2:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP1:%.*]], label [[TMP2:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C2]], i32 2, i32 1
|
|
; CHECK-NEXT: store atomic i32 [[SPEC_SELECT]], ptr [[P:%.*]] unordered, align 4
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %c1, label %if.then, label %if.else
|
|
|
|
if.then:
|
|
store atomic i32 1, ptr %p unordered, align 4
|
|
br label %merge
|
|
|
|
if.else:
|
|
br label %merge
|
|
|
|
merge:
|
|
br i1 %c2, label %if.then2, label %if.end
|
|
|
|
if.then2:
|
|
store atomic i32 2, ptr %p unordered, align 4
|
|
br label %if.end
|
|
|
|
if.end:
|
|
ret void
|
|
}
|
|
|
|
!0 = !{!"branch_weights", i32 7, i32 13}
|
|
!1 = !{!"branch_weights", i32 3, i32 11}
|
|
|
|
; When both merged stores carry the same !invariant.group, every path already
|
|
; asserted that its stored value was the group's invariant value, so the merged
|
|
; store may keep !invariant.group.
|
|
define void @merge_keeps_invariant_group_when_both(i1 %c1, i1 %c2, ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @merge_keeps_invariant_group_when_both(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[C1:%.*]], [[C2:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP1:%.*]], label [[TMP2:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C2]], i32 [[B:%.*]], i32 [[A:%.*]]
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT]], ptr [[P:%.*]], align 4, !invariant.group [[META1:![0-9]+]]
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %c1, label %t1, label %m
|
|
t1:
|
|
store i32 %a, ptr %p, !invariant.group !2
|
|
br label %m
|
|
m:
|
|
br i1 %c2, label %t2, label %e
|
|
t2:
|
|
store i32 %b, ptr %p, !invariant.group !2
|
|
br label %e
|
|
e:
|
|
ret void
|
|
}
|
|
|
|
; When only one of the merged stores carries !invariant.group, keeping it would
|
|
; assert the invariant on the other store's path, which never promised it. The
|
|
; merged store must drop !invariant.group.
|
|
define void @merge_drops_invariant_group_when_asymmetric(i1 %c1, i1 %c2, ptr %p, i32 %a, i32 %b) {
|
|
; CHECK-LABEL: @merge_drops_invariant_group_when_asymmetric(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[C1:%.*]], [[C2:%.*]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[TMP1:%.*]], label [[TMP2:%.*]]
|
|
; CHECK: 1:
|
|
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C2]], i32 [[B:%.*]], i32 [[A:%.*]]
|
|
; CHECK-NEXT: store i32 [[SPEC_SELECT]], ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: br label [[TMP2]]
|
|
; CHECK: 2:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br i1 %c1, label %t1, label %m
|
|
t1:
|
|
store i32 %a, ptr %p, !invariant.group !2
|
|
br label %m
|
|
m:
|
|
br i1 %c2, label %t2, label %e
|
|
t2:
|
|
store i32 %b, ptr %p
|
|
br label %e
|
|
e:
|
|
ret void
|
|
}
|
|
!2 = !{}
|
|
;.
|
|
; CHECK: [[PROF0]] = !{!"branch_weights", i32 137, i32 143}
|
|
; CHECK: [[META1]] = !{}
|
|
;.
|