Add an nneg flag to the zext instruction, which specifies that the argument is non-negative. Otherwise, the result is a poison value. The primary use-case for the flag is to preserve information when sext gets replaced with zext due to range-based canonicalization. The nneg flag allows us to convert the zext back into an sext later. This is useful for some optimizations (e.g. a signed icmp can fold with sext but not zext), as well as some targets (e.g. RISCV prefers sext over zext). Discourse thread: https://discourse.llvm.org/t/rfc-add-zext-nneg-flag/73914 This patch is based on https://reviews.llvm.org/D156444 by @Panagiotis156, with some implementation simplifications and additional tests. --------- Co-authored-by: Panagiotis K <karouzakispan@gmail.com>
127 lines
3.0 KiB
LLVM
127 lines
3.0 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
|
|
}
|