Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
}