[InstCombine] Ensure constant folding in binop of select fold

When folding a binop into a select, we need to ensure that one
of the select arms actually does constant fold, otherwise we'll
create two binop instructions and perform the reverse transform.

Ensure this by performing an explicit constant folding attempt,
and failing the transform if neither side simplifies.

A simple alternative here would have been to limit the fold to
ImmConstants, but given the current representation of scalable
vector splats, this wouldn't be ideal.
This commit is contained in:
Nikita Popov 2022-07-15 10:59:33 +02:00
parent bd404fbcc8
commit 8a519b3c21
2 changed files with 51 additions and 2 deletions

View file

@ -994,6 +994,24 @@ Instruction *InstCombinerImpl::foldBinopOfSextBoolToSelect(BinaryOperator &BO) {
return SelectInst::Create(X, TVal, FVal); return SelectInst::Create(X, TVal, FVal);
} }
static Constant *constantFoldOperationIntoSelectOperand(
Instruction &I, SelectInst *SI, Value *SO) {
auto *ConstSO = dyn_cast<Constant>(SO);
if (!ConstSO)
return nullptr;
SmallVector<Constant *> ConstOps;
for (Value *Op : I.operands()) {
if (Op == SI)
ConstOps.push_back(ConstSO);
else if (auto *C = dyn_cast<Constant>(Op))
ConstOps.push_back(C);
else
llvm_unreachable("Operands should be select or constant");
}
return ConstantFoldInstOperands(&I, ConstOps, I.getModule()->getDataLayout());
}
static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO, static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO,
InstCombiner::BuilderTy &Builder) { InstCombiner::BuilderTy &Builder) {
if (auto *Cast = dyn_cast<CastInst>(&I)) if (auto *Cast = dyn_cast<CastInst>(&I))
@ -1101,8 +1119,17 @@ Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, SelectInst *SI,
} }
} }
Value *NewTV = foldOperationIntoSelectOperand(Op, TV, Builder); // Make sure that one of the select arms constant folds successfully.
Value *NewFV = foldOperationIntoSelectOperand(Op, FV, Builder); Value *NewTV = constantFoldOperationIntoSelectOperand(Op, SI, TV);
Value *NewFV = constantFoldOperationIntoSelectOperand(Op, SI, FV);
if (!NewTV && !NewFV)
return nullptr;
// Create an instruction for the arm that did not fold.
if (!NewTV)
NewTV = foldOperationIntoSelectOperand(Op, TV, Builder);
if (!NewFV)
NewFV = foldOperationIntoSelectOperand(Op, FV, Builder);
return SelectInst::Create(SI->getCondition(), NewTV, NewFV, "", nullptr, SI); return SelectInst::Create(SI->getCondition(), NewTV, NewFV, "", nullptr, SI);
} }

View file

@ -3184,6 +3184,28 @@ define <2 x i8> @ne0_is_all_ones_swap_vec_poison(<2 x i8> %x) {
ret <2 x i8> %r ret <2 x i8> %r
} }
define i64 @udiv_of_select_constexpr(i1 %c, i64 %x) {
; CHECK-LABEL: @udiv_of_select_constexpr(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 [[X:%.*]], i64 ptrtoint (i32* @glbl to i64)
; CHECK-NEXT: [[OP:%.*]] = udiv i64 [[SEL]], 3
; CHECK-NEXT: ret i64 [[OP]]
;
%sel = select i1 %c, i64 %x, i64 ptrtoint (i32* @glbl to i64)
%op = udiv i64 %sel, 3
ret i64 %op
}
define i64 @udiv_of_select_constexpr_commuted(i1 %c, i64 %x) {
; CHECK-LABEL: @udiv_of_select_constexpr_commuted(
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 ptrtoint (i32* @glbl to i64), i64 [[X:%.*]]
; CHECK-NEXT: [[OP:%.*]] = udiv i64 [[SEL]], 3
; CHECK-NEXT: ret i64 [[OP]]
;
%sel = select i1 %c, i64 ptrtoint (i32* @glbl to i64), i64 %x
%op = udiv i64 %sel, 3
ret i64 %op
}
declare void @use(i1) declare void @use(i1)
declare void @use_i8(i8) declare void @use_i8(i8)
declare void @use_i32(i32) declare void @use_i32(i32)