Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit f03a571

Browse files
committed
[InstCombine] fix shuffle-of-binops transform to avoid poison/undef
As noted in D48987, there are many different ways for this transform to go wrong. In particular, the poison potential for shifts means we have to more careful with those ops. I added tests to make that behavior visible for all of the different cases that I could find. This is a partial fix. To make this review easier, I did not make changes for the single binop pattern (handled in foldSelectShuffleWith1Binop()). I also left out some potential optimizations noted with TODO comments. I'll follow-up once we're confident that things are correct here. The goal is to correct all marked FIXME tests to either avoid the shuffle transform or do it safely. Note that distinguishing when the shuffle mask contains undefs and using getBinOpIdentity() allows for some improvements to div/rem patterns, so there are wins along with the missed opportunities and fixes. Differential Revision: https://reviews.llvm.org/D49047 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336546 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent b9d744a commit f03a571

File tree

2 files changed

+110
-68
lines changed

2 files changed

+110
-68
lines changed

lib/Transforms/InstCombine/InstCombineVectorOps.cpp

+52-21
Original file line numberDiff line numberDiff line change
@@ -1280,52 +1280,83 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf,
12801280
// The opcodes must be the same. Use a new name to make that clear.
12811281
BinaryOperator::BinaryOps BOpc = Opc0;
12821282

1283+
// We are moving a binop after a shuffle. When a shuffle has an undefined
1284+
// mask element, the result is undefined, but it is not poison or undefined
1285+
// behavior. That is not necessarily true for div/rem/shift.
1286+
Constant *Mask = Shuf.getMask();
1287+
bool MightCreatePoisonOrUB =
1288+
Mask->containsUndefElement() &&
1289+
(Instruction::isIntDivRem(BOpc) || Instruction::isShift(BOpc));
1290+
1291+
Constant *NewC;
12831292
Value *V;
12841293
if (X == Y) {
1294+
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
1295+
1296+
// The new binop constant must not have any potential for extra poison/UB.
1297+
if (MightCreatePoisonOrUB) {
1298+
// TODO: Use getBinOpAbsorber for LHS replacement constants?
1299+
if (!ConstantsAreOp1)
1300+
return nullptr;
1301+
1302+
Type *EltTy = Shuf.getType()->getVectorElementType();
1303+
auto *IdC = ConstantExpr::getBinOpIdentity(BOpc, EltTy, true);
1304+
if (!IdC)
1305+
return nullptr;
1306+
1307+
// Replace undef elements caused by the mask with identity constants.
1308+
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
1309+
unsigned NumElts = Shuf.getType()->getVectorNumElements();
1310+
SmallVector<Constant *, 16> VectorOfNewC(NumElts);
1311+
for (unsigned i = 0; i != NumElts; i++) {
1312+
if (isa<UndefValue>(Mask->getAggregateElement(i)))
1313+
VectorOfNewC[i] = IdC;
1314+
else
1315+
VectorOfNewC[i] = NewC->getAggregateElement(i);
1316+
}
1317+
NewC = ConstantVector::get(VectorOfNewC);
1318+
}
1319+
12851320
// Remove a binop and the shuffle by rearranging the constant:
12861321
// shuffle (op V, C0), (op V, C1), M --> op V, C'
12871322
// shuffle (op C0, V), (op C1, V), M --> op C', V
12881323
V = X;
1289-
} else if (!Instruction::isIntDivRem(BOpc) &&
1290-
(B0->hasOneUse() || B1->hasOneUse())) {
1324+
} else {
12911325
// If there are 2 different variable operands, we must create a new shuffle
12921326
// (select) first, so check uses to ensure that we don't end up with more
12931327
// instructions than we started with.
1294-
//
1328+
if (!B0->hasOneUse() && !B1->hasOneUse())
1329+
return nullptr;
1330+
1331+
// Bail out if we can not guarantee safety of the transform.
1332+
// TODO: We could try harder by replacing the undef mask elements.
1333+
if (MightCreatePoisonOrUB)
1334+
return nullptr;
1335+
12951336
// Note: In general, we do not create new shuffles in InstCombine because we
12961337
// do not know if a target can lower an arbitrary shuffle optimally. In this
12971338
// case, the shuffle uses the existing mask, so there is no additional risk.
1298-
//
1299-
// TODO: We are disallowing div/rem because a shuffle with an undef mask
1300-
// element would propagate an undef value to the div/rem. That's not
1301-
// safe in general because div/rem allow for undefined behavior. We can
1302-
// loosen this restriction (eg, check if the mask has no undefs or replace
1303-
// undef elements).
13041339

13051340
// Select the variable vectors first, then perform the binop:
13061341
// shuffle (op X, C0), (op Y, C1), M --> op (shuffle X, Y, M), C'
13071342
// shuffle (op C0, X), (op C1, Y), M --> op C', (shuffle X, Y, M)
1308-
V = Builder.CreateShuffleVector(X, Y, Shuf.getMask());
1309-
} else {
1310-
return nullptr;
1343+
NewC = ConstantExpr::getShuffleVector(C0, C1, Mask);
1344+
V = Builder.CreateShuffleVector(X, Y, Mask);
13111345
}
13121346

1313-
Constant *NewC = ConstantExpr::getShuffleVector(C0, C1, Shuf.getMask());
1314-
1315-
// If the shuffle mask contains undef elements, then the new constant
1316-
// vector will have undefs in those lanes. This could cause the entire
1317-
// binop to be undef.
1318-
if (Instruction::isIntDivRem(BOpc))
1319-
NewC = getSafeVectorConstantForIntDivRem(NewC);
1320-
13211347
Instruction *NewBO = ConstantsAreOp1 ? BinaryOperator::Create(BOpc, V, NewC) :
13221348
BinaryOperator::Create(BOpc, NewC, V);
13231349

1324-
// Flags are intersected from the 2 source binops.
1350+
// Flags are intersected from the 2 source binops. But there are 2 exceptions:
1351+
// 1. If we changed an opcode, poison conditions might have changed.
1352+
// 2. If the shuffle had undef mask elements, the new binop might have undefs
1353+
// where the original code did not. Drop all poison potential to be safe.
13251354
NewBO->copyIRFlags(B0);
13261355
NewBO->andIRFlags(B1);
13271356
if (DropNSW)
13281357
NewBO->setHasNoSignedWrap(false);
1358+
if (Mask->containsUndefElement())
1359+
NewBO->dropPoisonGeneratingFlags();
13291360
return NewBO;
13301361
}
13311362

0 commit comments

Comments
 (0)