
This flag indicates that every bit is known to be zero in at least one of the inputs. This allows the Or to be treated as an Add since there is no possibility of a carry from any bit. If the flag is present and this property does not hold, the result is poison. This makes it easier to reverse the InstCombine transform that turns Add into Or. This is inspired by a comment here https://github.com/llvm/llvm-project/pull/71955#discussion_r1391614578 Discourse thread https://discourse.llvm.org/t/rfc-add-or-disjoint-flag/75036
157 lines
3.7 KiB
LLVM
157 lines
3.7 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=simplifycfg -hoist-common-insts=true -S | FileCheck %s
|
|
; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -hoist-common-insts=true -S | FileCheck %s
|
|
|
|
define void @foo(i1 %C, ptr %P) {
|
|
; CHECK-LABEL: @foo(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: store i32 7, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
br i1 %C, label %T, label %F
|
|
T: ; preds = %0
|
|
store i32 7, ptr %P
|
|
ret void
|
|
F: ; preds = %0
|
|
store i32 7, ptr %P
|
|
ret void
|
|
}
|
|
|
|
define void @foo_switch(i64 %C, ptr %P) {
|
|
; CHECK-LABEL: @foo_switch(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: store i32 7, ptr [[P:%.*]], align 4
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
switch i64 %C, label %bb0 [
|
|
i64 1, label %bb1
|
|
i64 2, label %bb2
|
|
]
|
|
bb0: ; preds = %0
|
|
store i32 7, ptr %P
|
|
ret void
|
|
bb1: ; preds = %0
|
|
store i32 7, ptr %P
|
|
ret void
|
|
bb2: ; preds = %0
|
|
store i32 7, ptr %P
|
|
ret void
|
|
}
|
|
|
|
define float @PR39535min(float %x) {
|
|
; CHECK-LABEL: @PR39535min(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TOBOOL:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00
|
|
; CHECK-NEXT: [[DOTX:%.*]] = select fast i1 [[TOBOOL]], float 0.000000e+00, float [[X]]
|
|
; CHECK-NEXT: ret float [[DOTX]]
|
|
;
|
|
entry:
|
|
%tobool = fcmp une float %x, 0.0
|
|
br i1 %tobool, label %cond.true, label %cond.false
|
|
|
|
cond.true:
|
|
br label %cond.end
|
|
|
|
cond.false:
|
|
br label %cond.end
|
|
|
|
cond.end:
|
|
%cond = phi fast float [ 0.0, %cond.true ], [ %x, %cond.false ]
|
|
ret float %cond
|
|
}
|
|
|
|
define float @PR39535min_switch(i64 %i, float %x) {
|
|
; CHECK-LABEL: @PR39535min_switch(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i64 [[I:%.*]], label [[END:%.*]] [
|
|
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
|
|
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: bb1:
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: [[COND:%.*]] = phi fast float [ [[X:%.*]], [[BB1]] ], [ [[X]], [[BB2]] ], [ 0.000000e+00, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: ret float [[COND]]
|
|
;
|
|
entry:
|
|
switch i64 %i, label %bb0 [
|
|
i64 1, label %bb1
|
|
i64 2, label %bb2
|
|
]
|
|
|
|
bb0:
|
|
br label %end
|
|
|
|
bb1:
|
|
br label %end
|
|
|
|
bb2:
|
|
br label %end
|
|
|
|
end:
|
|
%cond = phi fast float [ 0.0, %bb0 ], [ %x, %bb1 ], [ %x, %bb2 ]
|
|
ret float %cond
|
|
}
|
|
|
|
define i32 @hoist_zext_flags_preserve(i1 %C, i8 %x) {
|
|
; CHECK-LABEL: @hoist_zext_flags_preserve(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: [[Z1:%.*]] = zext nneg i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: ret i32 [[Z1]]
|
|
;
|
|
br i1 %C, label %T, label %F
|
|
T:
|
|
%z1 = zext nneg i8 %x to i32
|
|
ret i32 %z1
|
|
F:
|
|
%z2 = zext nneg i8 %x to i32
|
|
ret i32 %z2
|
|
}
|
|
|
|
define i32 @hoist_zext_flags_drop(i1 %C, i8 %x) {
|
|
; CHECK-LABEL: @hoist_zext_flags_drop(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: ret i32 [[Z1]]
|
|
;
|
|
br i1 %C, label %T, label %F
|
|
T:
|
|
%z1 = zext nneg i8 %x to i32
|
|
ret i32 %z1
|
|
F:
|
|
%z2 = zext i8 %x to i32
|
|
ret i32 %z2
|
|
}
|
|
|
|
define i32 @hoist_or_flags_preserve(i1 %C, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @hoist_or_flags_preserve(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: [[Z1:%.*]] = or disjoint i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[Z1]]
|
|
;
|
|
br i1 %C, label %T, label %F
|
|
T:
|
|
%z1 = or disjoint i32 %x, %y
|
|
ret i32 %z1
|
|
F:
|
|
%z2 = or disjoint i32 %x, %y
|
|
ret i32 %z2
|
|
}
|
|
|
|
define i32 @hoist_or_flags_drop(i1 %C, i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @hoist_or_flags_drop(
|
|
; CHECK-NEXT: common.ret:
|
|
; CHECK-NEXT: [[Z1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: ret i32 [[Z1]]
|
|
;
|
|
br i1 %C, label %T, label %F
|
|
T:
|
|
%z1 = or i32 %x, %y
|
|
ret i32 %z1
|
|
F:
|
|
%z2 = or disjoint i32 %x, %y
|
|
ret i32 %z2
|
|
}
|