From: Nikita Popov Date: Wed, 21 Dec 2022 14:41:54 +0000 (+0100) Subject: [InstCombine] Recursively replace select value equivalence X-Git-Tag: upstream/17.0.6~22960 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=79068275e7c99dfcc1bf17421b591312f775fa16;p=platform%2Fupstream%2Fllvm.git [InstCombine] Recursively replace select value equivalence In the X == C ? f(X) : Y -> X == C ? f(C) : Y fold, perform the replacement in f(X) recursively. For now, this just goes two instructions up rather than one instruction up. --- diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 8808645..e95b867 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1169,6 +1169,28 @@ static Instruction *canonicalizeSPF(SelectInst &Sel, ICmpInst &Cmp, 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(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. @@ -1216,17 +1238,11 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel, // 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(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)) diff --git a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll index 9d57e8b..8a20b09 100644 --- a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll +++ b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll @@ -1206,13 +1206,11 @@ define i32 @select_replace_fold(i32 %x, i32 %y, i32 %z) { ; 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 @@ -1242,7 +1240,7 @@ define i32 @select_replace_nested_extra_use(i32 %x, i32 %y, i32 %z) { 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]] @@ -1254,6 +1252,7 @@ define i32 @select_replace_nested_no_simplify(i32 %x, i32 %y, i32 %z) { 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