@@ -96,12 +96,6 @@ static cl::opt<int> MaxPotentialValuesIterations(
96
96
" Maximum number of iterations we keep dismantling potential values." ),
97
97
cl::init(64 ));
98
98
99
- static cl::opt<unsigned > MaxInterferingAccesses (
100
- " attributor-max-interfering-accesses" , cl::Hidden,
101
- cl::desc (" Maximum number of interfering accesses to "
102
- " check before assuming all might interfere." ),
103
- cl::init(6 ));
104
-
105
99
STATISTIC (NumAAs, " Number of abstract attributes created" );
106
100
107
101
// Some helper macros to deal with statistics tracking.
@@ -1081,7 +1075,6 @@ struct AAPointerInfoImpl
1081
1075
const bool FindInterferingReads = I.mayWriteToMemory ();
1082
1076
const bool UseDominanceReasoning =
1083
1077
FindInterferingWrites && NoRecurseAA.isKnownNoRecurse ();
1084
- const bool CanUseCFGResoning = CanIgnoreThreading (I);
1085
1078
const DominatorTree *DT =
1086
1079
InfoCache.getAnalysisResultForFunction <DominatorTreeAnalysis>(Scope);
1087
1080
@@ -1141,65 +1134,107 @@ struct AAPointerInfoImpl
1141
1134
(!FindInterferingReads || !Acc.isRead ()))
1142
1135
return true ;
1143
1136
1144
- bool Dominates = DT && Exact && Acc.isMustAccess () &&
1145
- (Acc.getLocalInst ()->getFunction () == &Scope) &&
1137
+ bool Dominates = FindInterferingWrites && DT && Exact &&
1138
+ Acc.isMustAccess () &&
1139
+ (Acc.getRemoteInst ()->getFunction () == &Scope) &&
1146
1140
DT->dominates (Acc.getRemoteInst (), &I);
1147
- if (FindInterferingWrites && Dominates)
1148
- HasBeenWrittenTo = true ;
1141
+ if (Dominates)
1142
+ DominatingWrites. insert (&Acc) ;
1149
1143
1150
1144
// Track if all interesting accesses are in the same `nosync` function as
1151
1145
// the given instruction.
1152
1146
AllInSameNoSyncFn &= Acc.getRemoteInst ()->getFunction () == &Scope;
1153
1147
1154
- // For now we only filter accesses based on CFG reasoning which does not
1155
- // work yet if we have threading effects, or the access is complicated.
1156
- if (CanUseCFGResoning && Dominates && UseDominanceReasoning &&
1157
- IsSameThreadAsInst (Acc))
1158
- DominatingWrites.insert (&Acc);
1159
-
1160
1148
InterferingAccesses.push_back ({&Acc, Exact});
1161
1149
return true ;
1162
1150
};
1163
1151
if (!State::forallInterferingAccesses (I, AccessCB, Range))
1164
1152
return false ;
1165
1153
1166
- // Helper to determine if we can skip a specific write access. This is in
1167
- // the worst case quadratic as we are looking for another write that will
1168
- // hide the effect of this one.
1154
+ HasBeenWrittenTo = !DominatingWrites.empty ();
1155
+
1156
+ // Dominating writes form a chain, find the least/lowest member.
1157
+ Instruction *LeastDominatingWriteInst = nullptr ;
1158
+ for (const Access *Acc : DominatingWrites) {
1159
+ if (!LeastDominatingWriteInst) {
1160
+ LeastDominatingWriteInst = Acc->getRemoteInst ();
1161
+ } else if (DT->dominates (LeastDominatingWriteInst,
1162
+ Acc->getRemoteInst ())) {
1163
+ LeastDominatingWriteInst = Acc->getRemoteInst ();
1164
+ }
1165
+ }
1166
+
1167
+ // Helper to determine if we can skip a specific write access.
1169
1168
auto CanSkipAccess = [&](const Access &Acc, bool Exact) {
1170
1169
if (!IsSameThreadAsInst (Acc))
1171
1170
return false ;
1172
- if ((!Acc.isWriteOrAssumption () ||
1173
- !AA::isPotentiallyReachable (A, *Acc.getRemoteInst (), I, QueryingAA,
1174
- &ExclusionSet, IsLiveInCalleeCB)) &&
1175
- (!Acc.isRead () ||
1176
- !AA::isPotentiallyReachable (A, I, *Acc.getRemoteInst (), QueryingAA,
1177
- &ExclusionSet, IsLiveInCalleeCB)))
1171
+
1172
+ // Check read (RAW) dependences and write (WAR) dependences as necessary.
1173
+ // If we successfully excluded all effects we are interested in, the
1174
+ // access can be skipped.
1175
+ bool ReadChecked = !FindInterferingReads;
1176
+ bool WriteChecked = !FindInterferingWrites;
1177
+
1178
+ // If the instruction cannot reach the access, the former does not
1179
+ // interfere with what the access reads.
1180
+ if (!ReadChecked) {
1181
+ if (!AA::isPotentiallyReachable (A, I, *Acc.getRemoteInst (), QueryingAA,
1182
+ &ExclusionSet, IsLiveInCalleeCB))
1183
+ ReadChecked = true ;
1184
+ }
1185
+ // If the instruction cannot be reach from the access, the latter does not
1186
+ // interfere with what the instruction reads.
1187
+ if (!WriteChecked) {
1188
+ if (!AA::isPotentiallyReachable (A, *Acc.getRemoteInst (), I, QueryingAA,
1189
+ &ExclusionSet, IsLiveInCalleeCB))
1190
+ WriteChecked = true ;
1191
+ }
1192
+
1193
+ // If we still might be affected by the write of the access but there are
1194
+ // dominating writes in the function of the instruction
1195
+ // (HasBeenWrittenTo), we can try to reason that the access is overwritten
1196
+ // by them. This would have happend above if they are all in the same
1197
+ // function, so we only check the inter-procedural case. Effectively, we
1198
+ // want to show that there is no call after the dominting write that might
1199
+ // reach the access, and when it returns reach the instruction with the
1200
+ // updated value. To this end, we iterate all call sites, check if they
1201
+ // might reach the instruction without going through another access
1202
+ // (ExclusionSet) and at the same time might reach the access. However,
1203
+ // that is all part of AAInterFnReachability.
1204
+ if (!WriteChecked && HasBeenWrittenTo &&
1205
+ Acc.getRemoteInst ()->getFunction () != &Scope) {
1206
+
1207
+ const auto &FnReachabilityAA = A.getAAFor <AAInterFnReachability>(
1208
+ QueryingAA, IRPosition::function (Scope), DepClassTy::OPTIONAL);
1209
+
1210
+ // Without going backwards in the call tree, can we reach the access
1211
+ // from the least dominating write. Do not allow to pass the instruction
1212
+ // itself either.
1213
+ bool Inserted = ExclusionSet.insert (&I).second ;
1214
+
1215
+ if (!FnReachabilityAA.instructionCanReach (
1216
+ A, *LeastDominatingWriteInst,
1217
+ *Acc.getRemoteInst ()->getFunction (), &ExclusionSet))
1218
+ WriteChecked = true ;
1219
+
1220
+ if (Inserted)
1221
+ ExclusionSet.erase (&I);
1222
+ }
1223
+
1224
+ if (ReadChecked && WriteChecked)
1178
1225
return true ;
1179
1226
1180
1227
if (!DT || !UseDominanceReasoning)
1181
1228
return false ;
1182
1229
if (!DominatingWrites.count (&Acc))
1183
1230
return false ;
1184
- for (const Access *DomAcc : DominatingWrites) {
1185
- assert (Acc.getLocalInst ()->getFunction () ==
1186
- DomAcc->getLocalInst ()->getFunction () &&
1187
- " Expected dominating writes to be in the same function!" );
1188
-
1189
- if (DomAcc != &Acc &&
1190
- DT->dominates (Acc.getLocalInst (), DomAcc->getLocalInst ())) {
1191
- return true ;
1192
- }
1193
- }
1194
- return false ;
1231
+ return LeastDominatingWriteInst != Acc.getLocalInst ();
1195
1232
};
1196
1233
1197
- // Run the user callback on all accesses we cannot skip and return if that
1198
- // succeeded for all or not.
1199
- unsigned NumInterferingAccesses = InterferingAccesses.size ();
1234
+ // Run the user callback on all accesses we cannot skip and return if
1235
+ // that succeeded for all or not.
1200
1236
for (auto &It : InterferingAccesses) {
1201
1237
if ((!AllInSameNoSyncFn && !IsThreadLocalObj) ||
1202
- NumInterferingAccesses > MaxInterferingAccesses ||
1203
1238
!CanSkipAccess (*It.first , It.second )) {
1204
1239
if (!UserCB (*It.first , It.second ))
1205
1240
return false ;
0 commit comments