@@ -235,8 +235,10 @@ class ConstantOffsetExtractor {
235
235
// / \p GEP The given GEP
236
236
// / \p UserChainTail Outputs the tail of UserChain so that we can
237
237
// / 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.
238
240
static Value *Extract (Value *Idx, GetElementPtrInst *GEP,
239
- User *&UserChainTail);
241
+ User *&UserChainTail, bool &PreservesNUW );
240
242
241
243
// / Looks for a constant offset from the given GEP index without extracting
242
244
// / it. It returns the numeric value of the extracted constant offset (0 if
@@ -267,6 +269,13 @@ class ConstantOffsetExtractor {
267
269
APInt findInEitherOperand (BinaryOperator *BO, bool SignExtended,
268
270
bool ZeroExtended);
269
271
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
+
270
279
// / After finding the constant offset C from the GEP index I, we build a new
271
280
// / index I' s.t. I' + C = I. This function builds and returns the new
272
281
// / index I' according to UserChain produced by function "find".
@@ -676,6 +685,30 @@ Value *ConstantOffsetExtractor::applyExts(Value *V) {
676
685
return Current;
677
686
}
678
687
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
+
679
712
Value *ConstantOffsetExtractor::rebuildWithoutConstOffset () {
680
713
distributeExtsAndCloneChain (UserChain.size () - 1 );
681
714
// Remove all nullptrs (used to be s/zext) from UserChain.
@@ -779,16 +812,21 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) {
779
812
}
780
813
781
814
Value *ConstantOffsetExtractor::Extract (Value *Idx, GetElementPtrInst *GEP,
782
- User *&UserChainTail) {
815
+ User *&UserChainTail,
816
+ bool &PreservesNUW) {
783
817
ConstantOffsetExtractor Extractor (GEP->getIterator ());
784
818
// Find a non-zero constant offset first.
785
819
APInt ConstantOffset =
786
820
Extractor.find (Idx, /* SignExtended */ false , /* ZeroExtended */ false ,
787
821
GEP->isInBounds ());
788
822
if (ConstantOffset == 0 ) {
789
823
UserChainTail = nullptr ;
824
+ PreservesNUW = true ;
790
825
return nullptr ;
791
826
}
827
+
828
+ PreservesNUW = Extractor.checkRebuildingPreservesNUW ();
829
+
792
830
// Separates the constant offset from the GEP index.
793
831
Value *IdxWithoutConstOffset = Extractor.rebuildWithoutConstOffset ();
794
832
UserChainTail = Extractor.UserChain .back ();
@@ -1052,7 +1090,9 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
1052
1090
}
1053
1091
}
1054
1092
1055
- bool MayRecoverInbounds = AccumulativeByteOffset >= 0 && GEP->isInBounds ();
1093
+ // Track information for preserving GEP flags.
1094
+ bool AllOffsetsNonNegative = AccumulativeByteOffset >= 0 ;
1095
+ bool AllNUWPreserved = true ;
1056
1096
1057
1097
// Remove the constant offset in each sequential index. The resultant GEP
1058
1098
// computes the variadic base.
@@ -1072,20 +1112,19 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
1072
1112
// uses the variadic part as the new index.
1073
1113
Value *OldIdx = GEP->getOperand (I);
1074
1114
User *UserChainTail;
1075
- Value *NewIdx =
1076
- ConstantOffsetExtractor::Extract (OldIdx, GEP, UserChainTail);
1115
+ bool PreservesNUW;
1116
+ Value *NewIdx = ConstantOffsetExtractor::Extract (
1117
+ OldIdx, GEP, UserChainTail, PreservesNUW);
1077
1118
if (NewIdx != nullptr ) {
1078
1119
// Switches to the index with the constant offset removed.
1079
1120
GEP->setOperand (I, NewIdx);
1080
1121
// After switching to the new index, we can garbage-collect UserChain
1081
1122
// and the old index if they are not used.
1082
1123
RecursivelyDeleteTriviallyDeadInstructions (UserChainTail);
1083
1124
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;
1089
1128
}
1090
1129
}
1091
1130
}
@@ -1106,15 +1145,34 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
1106
1145
// inbounds keyword is not present, the offsets are added to the base
1107
1146
// address with silently-wrapping two's complement arithmetic".
1108
1147
// 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
1111
1151
// 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
+
1118
1176
GEP->setNoWrapFlags (NewGEPFlags);
1119
1177
1120
1178
// Lowers a GEP to either GEPs with a single index or arithmetic operations.
0 commit comments