1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-21 12:02:58 +02:00

[InstCombine] generalize safe vector constant utility

This is almost NFC, but there could be some case where the original
code had undefs in the constants (rather than just the shuffle mask),
and we'll use safe constants rather than undefs now.

The FIXME noted in foldShuffledBinop() is already visible in existing
tests, so correcting that is the next step.

llvm-svn: 336558
This commit is contained in:
Sanjay Patel 2018-07-09 16:16:51 +00:00
parent 416b605a89
commit c4e9312911
3 changed files with 22 additions and 29 deletions

View File

@ -212,19 +212,26 @@ IntrinsicIDToOverflowCheckFlavor(unsigned ID) {
} }
} }
/// Integer division/remainder require special handling to avoid undefined /// Some binary operators require special handling to avoid poison and undefined
/// behavior. If a constant vector has undef elements, replace those undefs with /// behavior. If a constant vector has undef elements, replace those undefs with
/// '1' because that's always safe to execute. /// identity constants because those are always safe to execute. If no identity
static inline Constant *getSafeVectorConstantForIntDivRem(Constant *In) { /// constant exists, replace undef with '1' or '1.0'.
assert(In->getType()->isVectorTy() && "Not expecting scalars here"); static inline Constant *getSafeVectorConstantForBinop(
assert(In->getType()->getVectorElementType()->isIntegerTy() && BinaryOperator::BinaryOps Opcode, Constant *In) {
"Not expecting FP opcodes/operands/constants here"); Type *Ty = In->getType();
assert(Ty->isVectorTy() && "Not expecting scalars here");
unsigned NumElts = In->getType()->getVectorNumElements(); Type *EltTy = Ty->getVectorElementType();
Constant *IdentityC = ConstantExpr::getBinOpIdentity(Opcode, EltTy, true);
if (!IdentityC)
IdentityC = EltTy->isIntegerTy() ? ConstantInt::get(EltTy, 1):
ConstantFP::get(EltTy, 1.0);
unsigned NumElts = Ty->getVectorNumElements();
SmallVector<Constant *, 16> Out(NumElts); SmallVector<Constant *, 16> Out(NumElts);
for (unsigned i = 0; i != NumElts; ++i) { for (unsigned i = 0; i != NumElts; ++i) {
Constant *C = In->getAggregateElement(i); Constant *C = In->getAggregateElement(i);
Out[i] = isa<UndefValue>(C) ? ConstantInt::get(C->getType(), 1) : C; Out[i] = isa<UndefValue>(C) ? IdentityC : C;
} }
return ConstantVector::get(Out); return ConstantVector::get(Out);
} }

View File

@ -1288,33 +1288,18 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf,
Mask->containsUndefElement() && Mask->containsUndefElement() &&
(Instruction::isIntDivRem(BOpc) || Instruction::isShift(BOpc)); (Instruction::isIntDivRem(BOpc) || Instruction::isShift(BOpc));
Constant *NewC; // Select the constant elements needed for the single binop.
Constant *NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
Value *V; Value *V;
if (X == Y) { if (X == Y) {
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
// The new binop constant must not have any potential for extra poison/UB. // The new binop constant must not have any potential for extra poison/UB.
if (MightCreatePoisonOrUB) { if (MightCreatePoisonOrUB) {
// TODO: Use getBinOpAbsorber for LHS replacement constants? // TODO: Use getBinOpAbsorber for LHS replacement constants?
if (!ConstantsAreOp1) if (!ConstantsAreOp1)
return nullptr; return nullptr;
Type *EltTy = Shuf.getType()->getVectorElementType(); // Replace undef elements with identity constants.
auto *IdC = ConstantExpr::getBinOpIdentity(BOpc, EltTy, true); NewC = getSafeVectorConstantForBinop(BOpc, NewC);
if (!IdC)
return nullptr;
// Replace undef elements caused by the mask with identity constants.
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
unsigned NumElts = Shuf.getType()->getVectorNumElements();
SmallVector<Constant *, 16> VectorOfNewC(NumElts);
for (unsigned i = 0; i != NumElts; i++) {
if (isa<UndefValue>(Mask->getAggregateElement(i)))
VectorOfNewC[i] = IdC;
else
VectorOfNewC[i] = NewC->getAggregateElement(i);
}
NewC = ConstantVector::get(VectorOfNewC);
} }
// Remove a binop and the shuffle by rearranging the constant: // Remove a binop and the shuffle by rearranging the constant:
@ -1340,7 +1325,6 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf,
// Select the variable vectors first, then perform the binop: // Select the variable vectors first, then perform the binop:
// shuffle (op X, C0), (op Y, C1), M --> op (shuffle X, Y, M), C' // shuffle (op X, C0), (op Y, C1), M --> op (shuffle X, Y, M), C'
// shuffle (op C0, X), (op C1, Y), M --> op C', (shuffle X, Y, M) // shuffle (op C0, X), (op C1, Y), M --> op C', (shuffle X, Y, M)
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
V = Builder.CreateShuffleVector(X, Y, Mask); V = Builder.CreateShuffleVector(X, Y, Mask);
} }

View File

@ -1423,8 +1423,10 @@ Instruction *InstCombiner::foldShuffledBinop(BinaryOperator &Inst) {
// All other binop opcodes are always safe to speculate, and therefore, it // All other binop opcodes are always safe to speculate, and therefore, it
// is fine to include undef elements for unused lanes (and using undefs // is fine to include undef elements for unused lanes (and using undefs
// may help optimization). // may help optimization).
// FIXME: This transform is also not poison-safe. Eg, shift-by-undef would
// create poison that may not exist in the original code.
if (Inst.isIntDivRem()) if (Inst.isIntDivRem())
NewC = getSafeVectorConstantForIntDivRem(NewC); NewC = getSafeVectorConstantForBinop(Inst.getOpcode(), NewC);
// Op(shuffle(V1, Mask), C) -> shuffle(Op(V1, NewC), Mask) // Op(shuffle(V1, Mask), C) -> shuffle(Op(V1, NewC), Mask)
// Op(C, shuffle(V1, Mask)) -> shuffle(Op(NewC, V1), Mask) // Op(C, shuffle(V1, Mask)) -> shuffle(Op(NewC, V1), Mask)