Files
clang-p2996/llvm/test/Transforms/InstCombine/branch.ll
Sanjay Patel 1f8ac37e2d [InstCombine] adjust branch on logical-and fold
The transform was just added with:
115d2f69a5
...but as noted in post-commit feedback, it was
confusingly coded. Now, we create the final
expected canonicalized form directly and put
an extra use check on the match, so we should
not ever end up with more instructions.
2022-10-31 17:39:29 -04:00

245 lines
5.8 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
declare void @use(i1)
; Check that we fold the condition of branches of the
; form: br <condition> dest1, dest2, where dest1 == dest2.
define i32 @test(i32 %x) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 false, label [[MERGE:%.*]], label [[MERGE]]
; CHECK: merge:
; CHECK-NEXT: ret i32 [[X:%.*]]
;
entry:
%cmp = icmp ult i32 %x, 7
br i1 %cmp, label %merge, label %merge
merge:
ret i32 %x
}
@global = global i8 0
define i32 @pat(i32 %x) {
; CHECK-LABEL: @pat(
; CHECK-NEXT: br i1 false, label [[PATATINO:%.*]], label [[PATATINO]]
; CHECK: patatino:
; CHECK-NEXT: ret i32 [[X:%.*]]
;
%y = icmp eq i32 27, ptrtoint(ptr @global to i32)
br i1 %y, label %patatino, label %patatino
patatino:
ret i32 %x
}
define i1 @test01(i1 %cond) {
; CHECK-LABEL: @test01(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]]
; CHECK: if.true.1:
; CHECK-NEXT: br label [[MERGE_1:%.*]]
; CHECK: if.false.1:
; CHECK-NEXT: br label [[MERGE_1]]
; CHECK: merge.1:
; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]]
; CHECK: if.true.2:
; CHECK-NEXT: br label [[MERGE_2:%.*]]
; CHECK: if.false.2:
; CHECK-NEXT: br label [[MERGE_2]]
; CHECK: merge.2:
; CHECK-NEXT: ret i1 [[COND]]
;
entry:
br i1 %cond, label %if.true.1, label %if.false.1
if.true.1:
br label %merge.1
if.false.1:
br label %merge.1
merge.1:
%merge.cond.1 = phi i1 [true, %if.true.1], [false, %if.false.1]
br i1 %merge.cond.1, label %if.true.2, label %if.false.2
if.true.2:
br label %merge.2
if.false.2:
br label %merge.2
merge.2:
%merge.cond.2 = phi i1 [true, %if.true.2], [false, %if.false.2]
ret i1 %merge.cond.2
}
define i1 @test02(i1 %cond) {
; CHECK-LABEL: @test02(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]]
; CHECK: if.true.1:
; CHECK-NEXT: br label [[MERGE_1:%.*]]
; CHECK: if.false.1:
; CHECK-NEXT: br label [[MERGE_1]]
; CHECK: merge.1:
; CHECK-NEXT: br i1 [[COND]], label [[IF_FALSE_2:%.*]], label [[IF_TRUE_2:%.*]]
; CHECK: if.true.2:
; CHECK-NEXT: br label [[MERGE_2:%.*]]
; CHECK: if.false.2:
; CHECK-NEXT: br label [[MERGE_2]]
; CHECK: merge.2:
; CHECK-NEXT: ret i1 [[COND]]
;
entry:
br i1 %cond, label %if.true.1, label %if.false.1
if.true.1:
br label %merge.1
if.false.1:
br label %merge.1
merge.1:
%merge.cond.1 = phi i1 [false, %if.true.1], [true, %if.false.1]
br i1 %merge.cond.1, label %if.true.2, label %if.false.2
if.true.2:
br label %merge.2
if.false.2:
br label %merge.2
merge.2:
%merge.cond.2 = phi i1 [false, %if.true.2], [true, %if.false.2]
ret i1 %merge.cond.2
}
; if (x && !y) ret 42; ret 3 --> if (!x || y) ret 3; ret 42
define i32 @logical_and_not(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_and_not(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: [[TMP0:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[Y:%.*]]
; CHECK-NEXT: br i1 [[TMP0]], label [[F:%.*]], label [[T:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f:
; CHECK-NEXT: ret i32 3
;
entry:
%noty = xor i1 %y, true
%and = select i1 %x, i1 %noty, i1 false
br i1 %and, label %t, label %f
t:
ret i32 42
f:
ret i32 3
}
; if (x && y || !x) ret 3; ret 42 --> if (!x || y) ret 3; ret 42
define i32 @logical_and_or(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_and_or(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[Y:%.*]]
; CHECK-NEXT: br i1 [[AND]], label [[F:%.*]], label [[T:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f:
; CHECK-NEXT: ret i32 3
;
entry:
%and = select i1 %x, i1 %y, i1 true
br i1 %and, label %f, label %t
t:
ret i32 42
f:
ret i32 3
}
; if (!x || y) ret 3; ret 42
define i32 @logical_or_not(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_or_not(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOTX:%.*]] = xor i1 [[X:%.*]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOTX]], i1 true, i1 [[Y:%.*]]
; CHECK-NEXT: br i1 [[AND]], label [[F:%.*]], label [[T:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f:
; CHECK-NEXT: ret i32 3
;
entry:
%notx = xor i1 %x, true
%and = select i1 %notx, i1 true, i1 %y
br i1 %and, label %f, label %t
t:
ret i32 42
f:
ret i32 3
}
; negative test
define i32 @logical_and_not_use1(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_and_not_use1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
; CHECK-NEXT: call void @use(i1 [[NOTY]])
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[NOTY]], i1 false
; CHECK-NEXT: br i1 [[AND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f:
; CHECK-NEXT: ret i32 3
;
entry:
%noty = xor i1 %y, true
call void @use(i1 %noty)
%and = select i1 %x, i1 %noty, i1 false
br i1 %and, label %t, label %f
t:
ret i32 42
f:
ret i32 3
}
; negative test
define i32 @logical_and_not_use2(i1 %x, i1 %y) {
; CHECK-LABEL: @logical_and_not_use2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[NOTY:%.*]] = xor i1 [[Y:%.*]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[X:%.*]], i1 [[NOTY]], i1 false
; CHECK-NEXT: call void @use(i1 [[AND]])
; CHECK-NEXT: br i1 [[AND]], label [[T:%.*]], label [[F:%.*]]
; CHECK: t:
; CHECK-NEXT: ret i32 42
; CHECK: f:
; CHECK-NEXT: ret i32 3
;
entry:
%noty = xor i1 %y, true
%and = select i1 %x, i1 %noty, i1 false
call void @use(i1 %and)
br i1 %and, label %t, label %f
t:
ret i32 42
f:
ret i32 3
}