Skip to content

Commit 16bc374

Browse files
committed
[InstCombine] Preserve NSW/NUW flags when folding const BOp with min/max
1 parent 6bee710 commit 16bc374

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
767767
Value *A, Value *B, Instruction &Outer,
768768
SelectPatternFlavor SPF2, Value *C);
769769
Instruction *foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI);
770+
Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
771+
Value *FalseVal);
770772
Instruction *foldSelectValueEquivalence(SelectInst &SI, CmpInst &CI);
771773
bool replaceInInstruction(Value *V, Value *Old, Value *New,
772774
unsigned Depth = 0);

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,9 +1823,9 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
18231823

18241824
/// Fold `X Pred C1 ? X BOp C2 : C1 BOp C2` to `min/max(X, C1) BOp C2`.
18251825
/// This allows for better canonicalization.
1826-
static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
1827-
Value *FalseVal,
1828-
IRBuilderBase &Builder) {
1826+
Value *InstCombinerImpl::foldSelectWithConstOpToBinOp(ICmpInst *Cmp,
1827+
Value *TrueVal,
1828+
Value *FalseVal) {
18291829
Constant *C1, *C2, *C3;
18301830
Value *X;
18311831
CmpPredicate Predicate;
@@ -1889,11 +1889,29 @@ static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
18891889
return nullptr;
18901890
}
18911891

1892-
Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
1893-
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, X, RHS);
1894-
return IsIntrinsic ? Builder.CreateBinaryIntrinsic(Opcode, Intrinsic, C2)
1895-
: Builder.CreateBinOp(Instruction::BinaryOps(Opcode),
1896-
Intrinsic, C2);
1892+
Intrinsic::ID MinMaxID = getMinMaxIntrinsic(SPF);
1893+
Value *MinMax = Builder.CreateBinaryIntrinsic(MinMaxID, X, RHS);
1894+
if (IsIntrinsic)
1895+
return Builder.CreateBinaryIntrinsic(Opcode, MinMax, C2);
1896+
1897+
const auto BinOpc = Instruction::BinaryOps(Opcode);
1898+
Value *BinOp = Builder.CreateBinOp(BinOpc, MinMax, C2);
1899+
1900+
// If we can attach no-wrap flags to the new instruction, do so if the
1901+
// old instruction had them and C1 BinOp C2 does not overflow.
1902+
if (Instruction *BinOpInst = dyn_cast<Instruction>(BinOp)) {
1903+
if (BinOpc == Instruction::Add || BinOpc == Instruction::Sub ||
1904+
BinOpc == Instruction::Mul) {
1905+
Instruction *OldBinOp = cast<BinaryOperator>(TrueVal);
1906+
if (OldBinOp->hasNoSignedWrap() &&
1907+
willNotOverflow(BinOpc, RHS, C2, *BinOpInst, /*IsSigned*/ true))
1908+
BinOpInst->setHasNoSignedWrap();
1909+
if (OldBinOp->hasNoUnsignedWrap() &&
1910+
willNotOverflow(BinOpc, RHS, C2, *BinOpInst, /*IsSigned*/ false))
1911+
BinOpInst->setHasNoUnsignedWrap();
1912+
}
1913+
}
1914+
return BinOp;
18971915
}
18981916

18991917
/// Visit a SelectInst that has an ICmpInst as its first operand.
@@ -1968,7 +1986,7 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19681986
if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
19691987
return replaceInstUsesWith(SI, V);
19701988

1971-
if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal, Builder))
1989+
if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal))
19721990
return replaceInstUsesWith(SI, V);
19731991

19741992
return Changed ? &SI : nullptr;

llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ define i8 @add_and_sgt(i8 %x) {
55
; CHECK-LABEL: define i8 @add_and_sgt(
66
; CHECK-SAME: i8 [[X:%.*]]) {
77
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
8-
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16
8+
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
99
; CHECK-NEXT: ret i8 [[S]]
1010
;
1111
%add = add nsw i8 %x, 16
@@ -155,7 +155,7 @@ define i8 @multi_use_cond_and_sel(i8 %x) {
155155
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8
156156
; CHECK-NEXT: call void @use(i1 [[CMP]])
157157
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
158-
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16
158+
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
159159
; CHECK-NEXT: call void @use_byte(i8 [[S]])
160160
; CHECK-NEXT: ret i8 [[S]]
161161
;
@@ -455,7 +455,7 @@ define i8 @add_sgt_nuw_nsw_safe(i8 %x) {
455455
; CHECK-LABEL: define i8 @add_sgt_nuw_nsw_safe(
456456
; CHECK-SAME: i8 [[X:%.*]]) {
457457
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
458-
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], 1
458+
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 1
459459
; CHECK-NEXT: ret i8 [[S]]
460460
;
461461
%add = add nuw nsw i8 %x, 1
@@ -468,7 +468,7 @@ define i8 @add_sgt_nuw_only(i8 %x) {
468468
; CHECK-LABEL: define i8 @add_sgt_nuw_only(
469469
; CHECK-SAME: i8 [[X:%.*]]) {
470470
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
471-
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], 50
471+
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 50
472472
; CHECK-NEXT: ret i8 [[S]]
473473
;
474474
%add = add nuw nsw i8 %x, 50
@@ -481,7 +481,7 @@ define i8 @add_sgt_nsw_only(i8 %x) {
481481
; CHECK-LABEL: define i8 @add_sgt_nsw_only(
482482
; CHECK-SAME: i8 [[X:%.*]]) {
483483
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
484-
; CHECK-NEXT: [[S:%.*]] = add i8 [[TMP1]], -99
484+
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -99
485485
; CHECK-NEXT: ret i8 [[S]]
486486
;
487487
%add = add nuw nsw i8 %x, -99
@@ -495,7 +495,7 @@ define i8 @mul_ult_nuw_nsw_safe(i8 %x) {
495495
; CHECK-LABEL: define i8 @mul_ult_nuw_nsw_safe(
496496
; CHECK-SAME: i8 [[X:%.*]]) {
497497
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 10)
498-
; CHECK-NEXT: [[S:%.*]] = mul i8 [[TMP1]], 3
498+
; CHECK-NEXT: [[S:%.*]] = mul nuw nsw i8 [[TMP1]], 3
499499
; CHECK-NEXT: ret i8 [[S]]
500500
;
501501
%mul = mul nuw nsw i8 %x, 3
@@ -508,7 +508,7 @@ define i8 @mul_ult_nuw_only(i8 %x) {
508508
; CHECK-LABEL: define i8 @mul_ult_nuw_only(
509509
; CHECK-SAME: i8 [[X:%.*]]) {
510510
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 10)
511-
; CHECK-NEXT: [[S:%.*]] = mul i8 [[TMP1]], 25
511+
; CHECK-NEXT: [[S:%.*]] = mul nuw i8 [[TMP1]], 25
512512
; CHECK-NEXT: ret i8 [[S]]
513513
;
514514
%mul = mul nuw nsw i8 %x, 25
@@ -521,7 +521,7 @@ define i8 @mul_ult_nsw_only(i8 %x) {
521521
; CHECK-LABEL: define i8 @mul_ult_nsw_only(
522522
; CHECK-SAME: i8 [[X:%.*]]) {
523523
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 40)
524-
; CHECK-NEXT: [[S:%.*]] = mul i8 [[TMP1]], -2
524+
; CHECK-NEXT: [[S:%.*]] = mul nsw i8 [[TMP1]], -2
525525
; CHECK-NEXT: ret i8 [[S]]
526526
;
527527
%mul = mul nuw nsw i8 %x, -2

0 commit comments

Comments
 (0)