@@ -69,6 +69,7 @@ using namespace llvm;
69
69
70
70
#define DEBUG_TYPE " function-attrs"
71
71
72
+ STATISTIC (NumArgMemOnly, " Number of functions marked argmemonly" );
72
73
STATISTIC (NumReadNone, " Number of functions marked readnone" );
73
74
STATISTIC (NumReadOnly, " Number of functions marked readonly" );
74
75
STATISTIC (NumWriteOnly, " Number of functions marked writeonly" );
@@ -135,6 +136,14 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
135
136
// Scan the function body for instructions that may read or write memory.
136
137
bool ReadsMemory = false ;
137
138
bool WritesMemory = false ;
139
+ // Track if the function accesses memory not based on pointer arguments or
140
+ // allocas.
141
+ bool AccessesNonArgsOrAlloca = false ;
142
+ // Returns true if Ptr is not based on a function argument.
143
+ auto IsArgumentOrAlloca = [](const Value *Ptr) {
144
+ const Value *UO = getUnderlyingObject (Ptr);
145
+ return isa<Argument>(UO) || isa<AllocaInst>(UO);
146
+ };
138
147
for (Instruction &I : instructions (F)) {
139
148
// Some instructions can be ignored even if they read or write memory.
140
149
// Detect these now, skipping to the next instruction if one is found.
@@ -167,6 +176,7 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
167
176
// If it reads, note it.
168
177
if (isRefSet (MRI))
169
178
ReadsMemory = true ;
179
+ AccessesNonArgsOrAlloca = true ;
170
180
continue ;
171
181
}
172
182
@@ -179,12 +189,13 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
179
189
180
190
MemoryLocation Loc =
181
191
MemoryLocation::getBeforeOrAfter (Arg, I.getAAMetadata ());
182
-
183
192
// Skip accesses to local or constant memory as they don't impact the
184
193
// externally visible mod/ref behavior.
185
194
if (AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
186
195
continue ;
187
196
197
+ AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca (Loc.Ptr );
198
+
188
199
if (isModSet (MRI))
189
200
// Writes non-local memory.
190
201
WritesMemory = true ;
@@ -194,24 +205,29 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
194
205
}
195
206
continue ;
196
207
} else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
208
+ MemoryLocation Loc = MemoryLocation::get (LI);
197
209
// Ignore non-volatile loads from local memory. (Atomic is okay here.)
198
- if (!LI->isVolatile ()) {
199
- MemoryLocation Loc = MemoryLocation::get (LI);
200
- if (AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
201
- continue ;
202
- }
210
+ if (!LI->isVolatile () &&
211
+ AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
212
+ continue ;
213
+ AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca (Loc.Ptr );
203
214
} else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
215
+ MemoryLocation Loc = MemoryLocation::get (SI);
204
216
// Ignore non-volatile stores to local memory. (Atomic is okay here.)
205
- if (!SI->isVolatile ()) {
206
- MemoryLocation Loc = MemoryLocation::get (SI);
207
- if (AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
208
- continue ;
209
- }
217
+ if (!SI->isVolatile () &&
218
+ AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
219
+ continue ;
220
+ AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca (Loc.Ptr );
210
221
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(&I)) {
211
222
// Ignore vaargs on local memory.
212
223
MemoryLocation Loc = MemoryLocation::get (VI);
213
224
if (AAR.pointsToConstantMemory (Loc, /* OrLocal=*/ true ))
214
225
continue ;
226
+ AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca (Loc.Ptr );
227
+ } else {
228
+ // If AccessesNonArgsOrAlloca has not been updated above, set it
229
+ // conservatively.
230
+ AccessesNonArgsOrAlloca |= I.mayReadOrWriteMemory ();
215
231
}
216
232
217
233
// Any remaining instructions need to be taken seriously! Check if they
@@ -224,14 +240,17 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
224
240
ReadsMemory |= I.mayReadFromMemory ();
225
241
}
226
242
227
- if (WritesMemory) {
228
- if (!ReadsMemory)
229
- return FMRB_OnlyWritesMemory;
230
- else
231
- return FMRB_UnknownModRefBehavior;
232
- }
233
-
234
- return ReadsMemory ? FMRB_OnlyReadsMemory : FMRB_DoesNotAccessMemory;
243
+ if (!WritesMemory && !ReadsMemory)
244
+ return FMRB_DoesNotAccessMemory;
245
+
246
+ FunctionModRefBehavior Result = FunctionModRefBehavior (FMRL_Anywhere);
247
+ if (!AccessesNonArgsOrAlloca)
248
+ Result = FunctionModRefBehavior (FMRL_ArgumentPointees);
249
+ if (WritesMemory)
250
+ Result = FunctionModRefBehavior (Result | static_cast <int >(ModRefInfo::Mod));
251
+ if (ReadsMemory)
252
+ Result = FunctionModRefBehavior (Result | static_cast <int >(ModRefInfo::Ref));
253
+ return Result;
235
254
}
236
255
237
256
FunctionModRefBehavior llvm::computeFunctionBodyMemoryAccess (Function &F,
@@ -247,32 +266,48 @@ static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
247
266
// write memory then they can't be marked readnone or readonly.
248
267
bool ReadsMemory = false ;
249
268
bool WritesMemory = false ;
269
+ // Check if all functions only access memory through their arguments.
270
+ bool ArgMemOnly = true ;
250
271
for (Function *F : SCCNodes) {
251
272
// Call the callable parameter to look up AA results for this function.
252
273
AAResults &AAR = AARGetter (*F);
253
-
254
274
// Non-exact function definitions may not be selected at link time, and an
255
275
// alternative version that writes to memory may be selected. See the
256
276
// comment on GlobalValue::isDefinitionExact for more details.
257
277
FunctionModRefBehavior FMRB =
258
278
checkFunctionMemoryAccess (*F, F->hasExactDefinition (), AAR, SCCNodes);
259
- if (isModAndRefSet (createModRefInfo (FMRB)))
260
- return ;
261
279
if (FMRB == FMRB_DoesNotAccessMemory)
262
280
continue ;
263
- ReadsMemory |= AliasAnalysis::onlyReadsMemory (FMRB);
264
- WritesMemory |= AliasAnalysis::onlyWritesMemory (FMRB);
281
+ ModRefInfo MR = createModRefInfo (FMRB);
282
+ ReadsMemory |= isRefSet (MR);
283
+ WritesMemory |= isModSet (MR);
284
+ ArgMemOnly &= AliasAnalysis::onlyAccessesArgPointees (FMRB);
285
+ // Reached neither readnone, readonly, writeonly nor argmemonly can be
286
+ // inferred. Exit.
287
+ if (ReadsMemory && WritesMemory && !ArgMemOnly)
288
+ return ;
265
289
}
266
290
267
- // If the SCC contains both functions that read and functions that write, then
268
- // we cannot add readonly attributes.
269
- if (ReadsMemory && WritesMemory)
270
- return ;
271
-
272
- // Success! Functions in this SCC do not access memory, or only read memory.
273
- // Give them the appropriate attribute.
291
+ assert ((!ReadsMemory || !WritesMemory || ArgMemOnly) &&
292
+ " no memory attributes can be added for this SCC, should have exited "
293
+ " earlier" );
294
+ // Success! Functions in this SCC do not access memory, only read memory,
295
+ // only write memory, or only access memory through its arguments. Give them
296
+ // the appropriate attribute.
274
297
275
298
for (Function *F : SCCNodes) {
299
+ // If possible add argmemonly attribute to F, if it accesses memory.
300
+ if (ArgMemOnly && !F->onlyAccessesArgMemory () &&
301
+ (ReadsMemory || WritesMemory)) {
302
+ NumArgMemOnly++;
303
+ F->addFnAttr (Attribute::ArgMemOnly);
304
+ Changed.insert (F);
305
+ }
306
+
307
+ // The SCC contains functions both writing and reading from memory. We
308
+ // cannot add readonly or writeonline attributes.
309
+ if (ReadsMemory && WritesMemory)
310
+ continue ;
276
311
if (F->doesNotAccessMemory ())
277
312
// Already perfect!
278
313
continue ;
0 commit comments