Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *A, Value *B, Instruction &Outer,
SelectPatternFlavor SPF2, Value *C);
Instruction *foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI);
Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
Value *FalseVal);
Instruction *foldSelectValueEquivalence(SelectInst &SI, CmpInst &CI);
bool replaceInInstruction(Value *V, Value *Old, Value *New,
unsigned Depth = 0);
Expand Down
36 changes: 27 additions & 9 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1823,9 +1823,9 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,

/// Fold `X Pred C1 ? X BOp C2 : C1 BOp C2` to `min/max(X, C1) BOp C2`.
/// This allows for better canonicalization.
static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
Value *FalseVal,
IRBuilderBase &Builder) {
Value *InstCombinerImpl::foldSelectWithConstOpToBinOp(ICmpInst *Cmp,
Value *TrueVal,
Value *FalseVal) {
Constant *C1, *C2, *C3;
Value *X;
CmpPredicate Predicate;
Expand Down Expand Up @@ -1889,11 +1889,29 @@ static Value *foldSelectWithConstOpToBinOp(ICmpInst *Cmp, Value *TrueVal,
return nullptr;
}

Intrinsic::ID IntrinsicID = getMinMaxIntrinsic(SPF);
Value *Intrinsic = Builder.CreateBinaryIntrinsic(IntrinsicID, X, RHS);
return IsIntrinsic ? Builder.CreateBinaryIntrinsic(Opcode, Intrinsic, C2)
: Builder.CreateBinOp(Instruction::BinaryOps(Opcode),
Intrinsic, C2);
Intrinsic::ID MinMaxID = getMinMaxIntrinsic(SPF);
Value *MinMax = Builder.CreateBinaryIntrinsic(MinMaxID, X, RHS);
if (IsIntrinsic)
return Builder.CreateBinaryIntrinsic(Opcode, MinMax, C2);

const auto BinOpc = Instruction::BinaryOps(Opcode);
Value *BinOp = Builder.CreateBinOp(BinOpc, MinMax, C2);

// If we can attach no-wrap flags to the new instruction, do so if the
// old instruction had them and C1 BinOp C2 does not overflow.
if (Instruction *BinOpInst = dyn_cast<Instruction>(BinOp)) {
if (BinOpc == Instruction::Add || BinOpc == Instruction::Sub ||
BinOpc == Instruction::Mul) {
Instruction *OldBinOp = cast<BinaryOperator>(TrueVal);
if (OldBinOp->hasNoSignedWrap() &&
willNotOverflow(BinOpc, RHS, C2, *BinOpInst, /*IsSigned*/ true))
BinOpInst->setHasNoSignedWrap();
if (OldBinOp->hasNoUnsignedWrap() &&
willNotOverflow(BinOpc, RHS, C2, *BinOpInst, /*IsSigned*/ false))
BinOpInst->setHasNoUnsignedWrap();
}
}
return BinOp;
}

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

if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal, Builder))
if (Value *V = foldSelectWithConstOpToBinOp(ICI, TrueVal, FalseVal))
return replaceInstUsesWith(SI, V);

return Changed ? &SI : nullptr;
Expand Down
83 changes: 81 additions & 2 deletions llvm/test/Transforms/InstCombine/canonicalize-const-to-bop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ define i8 @add_and_sgt(i8 %x) {
; CHECK-LABEL: define i8 @add_and_sgt(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
; CHECK-NEXT: ret i8 [[S]]
;
%add = add nsw i8 %x, 16
Expand Down Expand Up @@ -155,7 +155,7 @@ define i8 @multi_use_cond_and_sel(i8 %x) {
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X]], 8
; CHECK-NEXT: call void @use(i1 [[CMP]])
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 8)
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 16
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 16
; CHECK-NEXT: call void @use_byte(i8 [[S]])
; CHECK-NEXT: ret i8 [[S]]
;
Expand Down Expand Up @@ -450,3 +450,82 @@ define i8 @umax_sgt(i8 %x) {
%s = select i1 %cmp, i8 100, i8 %umax
ret i8 %s
}

define i8 @add_sgt_nuw_nsw_safe(i8 %x) {
; CHECK-LABEL: define i8 @add_sgt_nuw_nsw_safe(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
; CHECK-NEXT: [[S:%.*]] = add nuw nsw i8 [[TMP1]], 1
; CHECK-NEXT: ret i8 [[S]]
;
%add = add nuw nsw i8 %x, 1
%cmp = icmp sgt i8 %x, 100
%s = select i1 %cmp, i8 101, i8 %add
ret i8 %s
}

define i8 @add_sgt_nuw_only(i8 %x) {
; CHECK-LABEL: define i8 @add_sgt_nuw_only(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
; CHECK-NEXT: [[S:%.*]] = add nuw i8 [[TMP1]], 50
; CHECK-NEXT: ret i8 [[S]]
;
%add = add nuw nsw i8 %x, 50
%cmp = icmp sgt i8 %x, 100
%s = select i1 %cmp, i8 150, i8 %add
ret i8 %s
}

define i8 @add_sgt_nsw_only(i8 %x) {
; CHECK-LABEL: define i8 @add_sgt_nsw_only(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 100)
; CHECK-NEXT: [[S:%.*]] = add nsw i8 [[TMP1]], -99
; CHECK-NEXT: ret i8 [[S]]
;
%add = add nuw nsw i8 %x, -99
%cmp = icmp sgt i8 %x, 100
%s = select i1 %cmp, i8 1, i8 %add
ret i8 %s
}


define i8 @mul_ult_nuw_nsw_safe(i8 %x) {
; CHECK-LABEL: define i8 @mul_ult_nuw_nsw_safe(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 10)
; CHECK-NEXT: [[S:%.*]] = mul nuw nsw i8 [[TMP1]], 3
; CHECK-NEXT: ret i8 [[S]]
;
%mul = mul nuw nsw i8 %x, 3
%cmp = icmp ult i8 %x, 10
%s = select i1 %cmp, i8 30, i8 %mul
ret i8 %s
}

define i8 @mul_ult_nuw_only(i8 %x) {
; CHECK-LABEL: define i8 @mul_ult_nuw_only(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 10)
; CHECK-NEXT: [[S:%.*]] = mul nuw i8 [[TMP1]], 25
; CHECK-NEXT: ret i8 [[S]]
;
%mul = mul nuw nsw i8 %x, 25
%cmp = icmp ult i8 %x, 10
%s = select i1 %cmp, i8 250, i8 %mul
ret i8 %s
}

define i8 @mul_ult_nsw_only(i8 %x) {
; CHECK-LABEL: define i8 @mul_ult_nsw_only(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 40)
; CHECK-NEXT: [[S:%.*]] = mul nsw i8 [[TMP1]], -2
; CHECK-NEXT: ret i8 [[S]]
;
%mul = mul nuw nsw i8 %x, -2
%cmp = icmp ult i8 %x, 40
%s = select i1 %cmp, i8 -80, i8 %mul
ret i8 %s
}
Loading