llvm/llvm/test/Transforms/SimplifyCFG/merge-cond-stores.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; 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:    [[TMP0:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[DOTNOT]], label [[TMP2:%.*]], label [[TMP1:%.*]]
; CHECK:       1:
; CHECK-NEXT:    [[X2:%.*]] = icmp ne i32 [[B]], 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:    [[X1_NOT:%.*]] = icmp eq i32 [[A:%.*]], 0
; CHECK-NEXT:    [[X2:%.*]] = icmp eq i32 [[B:%.*]], 0
; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[X1_NOT]], [[X2]]
; CHECK-NEXT:    br i1 [[TMP0]], label [[TMP1:%.*]], label [[TMP2:%.*]]
; CHECK:       1:
; 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 %yes1, label %fallthrough

yes1:
  store i32 0, ptr %p
  br label %fallthrough

fallthrough:
  %x2 = icmp eq i32 %b, 0
  br i1 %x2, label %yes2, label %end

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]], [[C:%.*]]
; CHECK-NEXT:    [[TMP2:%.*]] = or i32 [[TMP1]], [[D:%.*]]
; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[TMP2]], 0
; CHECK-NEXT:    br i1 [[DOTNOT]], label [[TMP4:%.*]], label [[TMP3:%.*]]
; CHECK:       3:
; CHECK-NEXT:    [[X4_NOT:%.*]] = icmp eq i32 [[D]], 0
; CHECK-NEXT:    [[X3_NOT:%.*]] = icmp eq i32 [[C]], 0
; CHECK-NEXT:    [[X2:%.*]] = icmp ne i32 [[B]], 0
; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = zext i1 [[X2]] to i32
; CHECK-NEXT:    [[SPEC_SELECT1:%.*]] = select i1 [[X3_NOT]], 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 [[B:%.*]], 0
; CHECK-NEXT:    [[TMP0:%.*]] = or i32 [[A:%.*]], [[B]]
; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[DOTNOT]], 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:    [[TMP0:%.*]] = or i32 [[A:%.*]], [[B:%.*]]
; CHECK-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[TMP0]], 0
; CHECK-NEXT:    br i1 [[DOTNOT]], label [[END]], label [[TMP1:%.*]]
; CHECK:       1:
; CHECK-NEXT:    [[X2:%.*]] = icmp ne i32 [[B]], 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
}