return nullptr;
}
+static bool replaceInInstruction(Value *V, Value *Old, Value *New,
+ InstCombiner &IC, unsigned Depth = 0) {
+ // Conservatively limit replacement to two instructions upwards.
+ if (Depth == 2)
+ return false;
+
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I || !I->hasOneUse() || !isSafeToSpeculativelyExecute(I))
+ return false;
+
+ bool Changed = false;
+ for (Use &U : I->operands()) {
+ if (U == Old) {
+ IC.replaceUse(U, New);
+ Changed = true;
+ } else {
+ Changed |= replaceInInstruction(U, Old, New, IC, Depth + 1);
+ }
+ }
+ return Changed;
+}
+
/// If we have a select with an equality comparison, then we know the value in
/// one of the arms of the select. See if substituting this value into an arm
/// and simplifying the result yields the same value as the other arm.
// with different operands, which should not cause side-effects or trigger
// undefined behavior). Only do this if CmpRHS is a constant, as
// profitability is not clear for other cases.
- // FIXME: The replacement could be performed recursively.
// FIXME: Support vectors.
if (match(CmpRHS, m_ImmConstant()) && !match(CmpLHS, m_ImmConstant()) &&
!Cmp.getType()->isVectorTy())
- if (auto *I = dyn_cast<Instruction>(TrueVal))
- if (I->hasOneUse() && isSafeToSpeculativelyExecute(I))
- for (Use &U : I->operands())
- if (U == CmpLHS) {
- replaceUse(U, CmpRHS);
- return &Sel;
- }
+ if (replaceInInstruction(TrueVal, CmpLHS, CmpRHS, *this))
+ return &Sel;
}
if (TrueVal != CmpRHS &&
isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT))
; Case where the use of %x is in a nested instruction.
-; FIXME: We only perform replacements one level up right now.
define i32 @select_replace_nested(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_nested(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0
-; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y:%.*]], [[X]]
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[SUB]], [[Z:%.*]]
-; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[ADD]], i32 [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = select i1 [[C]], i32 [[Z:%.*]], i32 0
+; CHECK-NEXT: [[S:%.*]] = add i32 [[ADD]], [[Y:%.*]]
; CHECK-NEXT: ret i32 [[S]]
;
%c = icmp eq i32 %x, 0
define i32 @select_replace_nested_no_simplify(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_nested_no_simplify(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 1
-; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y:%.*]], [[X]]
+; CHECK-NEXT: [[SUB:%.*]] = add i32 [[Y:%.*]], -1
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[SUB]], [[Z:%.*]]
; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 [[ADD]], i32 [[Y]]
; CHECK-NEXT: ret i32 [[S]]
ret i32 %s
}
+; FIXME: We only perform replacements two levels up right now.
define i32 @select_replace_deeply_nested(i32 %x, i32 %y, i32 %z) {
; CHECK-LABEL: @select_replace_deeply_nested(
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 0