Skip to content

Commit 40889cc

Browse files
committed
Preserve more GEP flags based on NUW
1 parent d467f0d commit 40889cc

File tree

2 files changed

+480
-19
lines changed

2 files changed

+480
-19
lines changed

Diff for: llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp

+76-18
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,10 @@ class ConstantOffsetExtractor {
235235
/// \p GEP The given GEP
236236
/// \p UserChainTail Outputs the tail of UserChain so that we can
237237
/// garbage-collect unused instructions in UserChain.
238+
/// \p PreservesNUW Outputs whether the extraction allows preserving the
239+
/// GEP's nuw flag, if it has one.
238240
static Value *Extract(Value *Idx, GetElementPtrInst *GEP,
239-
User *&UserChainTail);
241+
User *&UserChainTail, bool &PreservesNUW);
240242

241243
/// Looks for a constant offset from the given GEP index without extracting
242244
/// it. It returns the numeric value of the extracted constant offset (0 if
@@ -267,6 +269,13 @@ class ConstantOffsetExtractor {
267269
APInt findInEitherOperand(BinaryOperator *BO, bool SignExtended,
268270
bool ZeroExtended);
269271

272+
/// A helper function to check if a subsequent call to rebuildWithoutConst
273+
/// will allow preserving the GEP's nuw flag. That is the case if all
274+
/// reassociated binary operations are add nuw and no non-nuw trunc is
275+
/// distributed through an add.
276+
/// Can only be called after find has populated the UserChain.
277+
bool checkRebuildingPreservesNUW() const;
278+
270279
/// After finding the constant offset C from the GEP index I, we build a new
271280
/// index I' s.t. I' + C = I. This function builds and returns the new
272281
/// index I' according to UserChain produced by function "find".
@@ -676,6 +685,30 @@ Value *ConstantOffsetExtractor::applyExts(Value *V) {
676685
return Current;
677686
}
678687

688+
bool ConstantOffsetExtractor::checkRebuildingPreservesNUW() const {
689+
auto AllowsPreservingNUW = [](User *U) {
690+
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(U)) {
691+
auto Opcode = BO->getOpcode();
692+
if (Opcode == BinaryOperator::Or) {
693+
// Ors are only considered here if they are disjoint. The addition that
694+
// they represent in this case is NUW.
695+
assert(cast<PossiblyDisjointInst>(BO)->isDisjoint());
696+
return true;
697+
}
698+
return Opcode == BinaryOperator::Add && BO->hasNoUnsignedWrap();
699+
}
700+
// UserChain can only contain ConstantInt, CastInst, or BinaryOperator.
701+
// Among the possible CastInsts, only trunc without nuw is a problem: If it
702+
// is distributed through an add nuw, wrapping may occur:
703+
// "add nuw trunc(a), trunc(b)" is more poisonous than "trunc(add nuw a, b)"
704+
if (TruncInst *TI = dyn_cast<TruncInst>(U))
705+
return TI->hasNoUnsignedWrap();
706+
return true;
707+
};
708+
709+
return all_of(UserChain, AllowsPreservingNUW);
710+
}
711+
679712
Value *ConstantOffsetExtractor::rebuildWithoutConstOffset() {
680713
distributeExtsAndCloneChain(UserChain.size() - 1);
681714
// Remove all nullptrs (used to be s/zext) from UserChain.
@@ -779,16 +812,21 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
779812
}
780813

781814
Value *ConstantOffsetExtractor::Extract(Value *Idx, GetElementPtrInst *GEP,
782-
User *&UserChainTail) {
815+
User *&UserChainTail,
816+
bool &PreservesNUW) {
783817
ConstantOffsetExtractor Extractor(GEP->getIterator());
784818
// Find a non-zero constant offset first.
785819
APInt ConstantOffset =
786820
Extractor.find(Idx, /* SignExtended */ false, /* ZeroExtended */ false,
787821
GEP->isInBounds());
788822
if (ConstantOffset == 0) {
789823
UserChainTail = nullptr;
824+
PreservesNUW = true;
790825
return nullptr;
791826
}
827+
828+
PreservesNUW = Extractor.checkRebuildingPreservesNUW();
829+
792830
// Separates the constant offset from the GEP index.
793831
Value *IdxWithoutConstOffset = Extractor.rebuildWithoutConstOffset();
794832
UserChainTail = Extractor.UserChain.back();
@@ -1052,7 +1090,9 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
10521090
}
10531091
}
10541092

1055-
bool MayRecoverInbounds = AccumulativeByteOffset >= 0 && GEP->isInBounds();
1093+
// Track information for preserving GEP flags.
1094+
bool AllOffsetsNonNegative = AccumulativeByteOffset >= 0;
1095+
bool AllNUWPreserved = true;
10561096

10571097
// Remove the constant offset in each sequential index. The resultant GEP
10581098
// computes the variadic base.
@@ -1072,20 +1112,19 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
10721112
// uses the variadic part as the new index.
10731113
Value *OldIdx = GEP->getOperand(I);
10741114
User *UserChainTail;
1075-
Value *NewIdx =
1076-
ConstantOffsetExtractor::Extract(OldIdx, GEP, UserChainTail);
1115+
bool PreservesNUW;
1116+
Value *NewIdx = ConstantOffsetExtractor::Extract(
1117+
OldIdx, GEP, UserChainTail, PreservesNUW);
10771118
if (NewIdx != nullptr) {
10781119
// Switches to the index with the constant offset removed.
10791120
GEP->setOperand(I, NewIdx);
10801121
// After switching to the new index, we can garbage-collect UserChain
10811122
// and the old index if they are not used.
10821123
RecursivelyDeleteTriviallyDeadInstructions(UserChainTail);
10831124
RecursivelyDeleteTriviallyDeadInstructions(OldIdx);
1084-
MayRecoverInbounds =
1085-
MayRecoverInbounds &&
1086-
isKnownNonNegative(
1087-
NewIdx,
1088-
SimplifyQuery(*DL, TLI, DT, /*AC=*/nullptr, /*CXTI=*/GEP));
1125+
AllOffsetsNonNegative =
1126+
AllOffsetsNonNegative && isKnownNonNegative(NewIdx, *DL);
1127+
AllNUWPreserved &= PreservesNUW;
10891128
}
10901129
}
10911130
}
@@ -1106,15 +1145,34 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
11061145
// inbounds keyword is not present, the offsets are added to the base
11071146
// address with silently-wrapping two's complement arithmetic".
11081147
// Therefore, the final code will be a semantically equivalent.
1109-
//
1110-
// If the initial GEP was inbounds and all variable indices and the
1148+
GEPNoWrapFlags NewGEPFlags = GEPNoWrapFlags::none();
1149+
1150+
// If the initial GEP was inbounds/nusw and all variable indices and the
11111151
// accumulated offsets are non-negative, they can be added in any order and
1112-
// the intermediate results are in bounds. So, we can preserve the inbounds
1113-
// flag for both GEPs. GEPs with inbounds are more friendly to alias analysis.
1114-
//
1115-
// TODO(gep_nowrap): Preserve nuw?
1116-
GEPNoWrapFlags NewGEPFlags =
1117-
MayRecoverInbounds ? GEPNoWrapFlags::inBounds() : GEPNoWrapFlags::none();
1152+
// the intermediate results are in bounds and don't overflow in a nusw sense.
1153+
// So, we can preserve the inbounds/nusw flag for both GEPs.
1154+
bool CanPreserveInBoundsNUSW = AllOffsetsNonNegative;
1155+
1156+
// If the initial GEP was NUW and all operations that we reassociate were NUW
1157+
// additions, the resulting GEPs are also NUW.
1158+
if (GEP->hasNoUnsignedWrap() && AllNUWPreserved) {
1159+
NewGEPFlags |= GEPNoWrapFlags::noUnsignedWrap();
1160+
// If the initial GEP additionally had NUSW (or inbounds, which implies
1161+
// NUSW), we know that the indices in the initial GEP must all have their
1162+
// signbit not set. For indices that are the result of NUW adds, the
1163+
// add-operands therefore also don't have their signbit set. Therefore, all
1164+
// indices of the resulting GEPs are non-negative -> we can preserve
1165+
// the inbounds/nusw flag.
1166+
CanPreserveInBoundsNUSW |= GEP->hasNoUnsignedSignedWrap();
1167+
}
1168+
1169+
if (CanPreserveInBoundsNUSW) {
1170+
if (GEP->isInBounds())
1171+
NewGEPFlags |= GEPNoWrapFlags::inBounds();
1172+
else if (GEP->hasNoUnsignedSignedWrap())
1173+
NewGEPFlags |= GEPNoWrapFlags::noUnsignedSignedWrap();
1174+
}
1175+
11181176
GEP->setNoWrapFlags(NewGEPFlags);
11191177

11201178
// Lowers a GEP to either GEPs with a single index or arithmetic operations.

0 commit comments

Comments
 (0)