Skip to content

Commit e5822de

Browse files
committed
[FunctionAttrs] Infer argmemonly .
This patch adds initial argmemonly inference, by checking the underlying objects of locations returned by MemoryLocation. I think this should cover most cases, except function calls to other argmemonly functions. I'm not sure if there's a reason why we don't infer those yet. Additional argmemonly can improve codegen in some cases. It also makes it easier to come up with a C reproducer for 7662d16 (already fixed, but I'm trying to see if C/C++ fuzzing could help to uncover similar issues.) Compile-time impact: NewPM-O3: +0.01% NewPM-ReleaseThinLTO: +0.03% NewPM-ReleaseLTO+g: +0.05% https://llvm-compile-time-tracker.com/compare.php?from=067c035012fc061ad6378458774ac2df117283c6&to=fe209d4aab5b593bd62d18c0876732ddcca1614d&stat=instructions Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D121415
1 parent 0aab344 commit e5822de

File tree

8 files changed

+95
-59
lines changed

8 files changed

+95
-59
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ using namespace llvm;
6969

7070
#define DEBUG_TYPE "function-attrs"
7171

72+
STATISTIC(NumArgMemOnly, "Number of functions marked argmemonly");
7273
STATISTIC(NumReadNone, "Number of functions marked readnone");
7374
STATISTIC(NumReadOnly, "Number of functions marked readonly");
7475
STATISTIC(NumWriteOnly, "Number of functions marked writeonly");
@@ -135,6 +136,14 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
135136
// Scan the function body for instructions that may read or write memory.
136137
bool ReadsMemory = false;
137138
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+
};
138147
for (Instruction &I : instructions(F)) {
139148
// Some instructions can be ignored even if they read or write memory.
140149
// Detect these now, skipping to the next instruction if one is found.
@@ -167,6 +176,7 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
167176
// If it reads, note it.
168177
if (isRefSet(MRI))
169178
ReadsMemory = true;
179+
AccessesNonArgsOrAlloca = true;
170180
continue;
171181
}
172182

@@ -179,12 +189,13 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
179189

180190
MemoryLocation Loc =
181191
MemoryLocation::getBeforeOrAfter(Arg, I.getAAMetadata());
182-
183192
// Skip accesses to local or constant memory as they don't impact the
184193
// externally visible mod/ref behavior.
185194
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
186195
continue;
187196

197+
AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca(Loc.Ptr);
198+
188199
if (isModSet(MRI))
189200
// Writes non-local memory.
190201
WritesMemory = true;
@@ -194,24 +205,29 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
194205
}
195206
continue;
196207
} else if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
208+
MemoryLocation Loc = MemoryLocation::get(LI);
197209
// 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);
203214
} else if (StoreInst *SI = dyn_cast<StoreInst>(&I)) {
215+
MemoryLocation Loc = MemoryLocation::get(SI);
204216
// 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);
210221
} else if (VAArgInst *VI = dyn_cast<VAArgInst>(&I)) {
211222
// Ignore vaargs on local memory.
212223
MemoryLocation Loc = MemoryLocation::get(VI);
213224
if (AAR.pointsToConstantMemory(Loc, /*OrLocal=*/true))
214225
continue;
226+
AccessesNonArgsOrAlloca |= !IsArgumentOrAlloca(Loc.Ptr);
227+
} else {
228+
// If AccessesNonArgsOrAlloca has not been updated above, set it
229+
// conservatively.
230+
AccessesNonArgsOrAlloca |= I.mayReadOrWriteMemory();
215231
}
216232

217233
// Any remaining instructions need to be taken seriously! Check if they
@@ -224,14 +240,17 @@ checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
224240
ReadsMemory |= I.mayReadFromMemory();
225241
}
226242

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;
235254
}
236255

237256
FunctionModRefBehavior llvm::computeFunctionBodyMemoryAccess(Function &F,
@@ -247,32 +266,48 @@ static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
247266
// write memory then they can't be marked readnone or readonly.
248267
bool ReadsMemory = false;
249268
bool WritesMemory = false;
269+
// Check if all functions only access memory through their arguments.
270+
bool ArgMemOnly = true;
250271
for (Function *F : SCCNodes) {
251272
// Call the callable parameter to look up AA results for this function.
252273
AAResults &AAR = AARGetter(*F);
253-
254274
// Non-exact function definitions may not be selected at link time, and an
255275
// alternative version that writes to memory may be selected. See the
256276
// comment on GlobalValue::isDefinitionExact for more details.
257277
FunctionModRefBehavior FMRB =
258278
checkFunctionMemoryAccess(*F, F->hasExactDefinition(), AAR, SCCNodes);
259-
if (isModAndRefSet(createModRefInfo(FMRB)))
260-
return;
261279
if (FMRB == FMRB_DoesNotAccessMemory)
262280
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;
265289
}
266290

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.
274297

275298
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;
276311
if (F->doesNotAccessMemory())
277312
// Already perfect!
278313
continue;

llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,12 @@ declare void @callee(i32* %p) nounwind
7373
declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) nounwind
7474

7575
; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn }
76-
; CHECK: attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn writeonly }
76+
; CHECK: attributes #1 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly }
7777
; CHECK: attributes #2 = { nofree nounwind readonly }
7878
; CHECK: attributes #3 = { nounwind }
7979
; CHECK: attributes #4 = { mustprogress nofree nosync nounwind readnone willreturn }
80-
; CHECK: attributes #5 = { mustprogress nofree nosync nounwind willreturn }
81-
; CHECK: attributes #6 = { mustprogress nofree norecurse nosync nounwind willreturn }
80+
; CHECK: attributes #5 = { argmemonly mustprogress nofree nosync nounwind willreturn }
81+
; CHECK: attributes #6 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn }
8282
; CHECK: attributes #7 = { argmemonly nofree nounwind willreturn }
8383

8484
; Root note.

llvm/test/CodeGen/AMDGPU/inline-attr.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
; GCN: %mul.i = fmul float %load, 1.500000e+01
88

99
; UNSAFE: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "unsafe-fp-math"="true" }
10-
; UNSAFE: attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="true" }
10+
; UNSAFE: attributes #1 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "unsafe-fp-math"="true" }
1111

1212
; NOINFS: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "no-infs-fp-math"="true" }
13-
; NOINFS: attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="true" "no-nans-fp-math"="false" "unsafe-fp-math"="false" }
13+
; NOINFS: attributes #1 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="true" "no-nans-fp-math"="false" "unsafe-fp-math"="false" }
1414

1515
; NONANS: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn "no-nans-fp-math"="true" }
16-
; NONANS: attributes #1 = { mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="true" "unsafe-fp-math"="false" }
16+
; NONANS: attributes #1 = { argmemonly mustprogress nofree norecurse nosync nounwind willreturn "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="true" "unsafe-fp-math"="false" }
1717

1818
define float @foo(float %x) #0 {
1919
entry:

llvm/test/Transforms/FunctionAttrs/argmemonly.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ entry:
1414
}
1515

1616
define i32 @test_only_read_arg(i32* %ptr) {
17-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn
17+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
1818
; CHECK-LABEL: @test_only_read_arg(
1919
; CHECK-NEXT: entry:
2020
; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[PTR:%.*]], align 4
@@ -52,7 +52,7 @@ entry:
5252
}
5353

5454
define void @test_only_write_arg(i32* %ptr) {
55-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly
55+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly
5656
; CHECK-LABEL: @test_only_write_arg(
5757
; CHECK-NEXT: entry:
5858
; CHECK-NEXT: store i32 0, i32* [[PTR:%.*]], align 4
@@ -91,7 +91,7 @@ entry:
9191
declare i32 @fn_readnone() readnone
9292

9393
define void @test_call_readnone(i32* %ptr) {
94-
; CHECK: Function Attrs: writeonly
94+
; CHECK: Function Attrs: argmemonly writeonly
9595
; CHECK-LABEL: @test_call_readnone(
9696
; CHECK-NEXT: entry:
9797
; CHECK-NEXT: [[C:%.*]] = call i32 @fn_readnone()
@@ -118,7 +118,7 @@ entry:
118118
}
119119

120120
define i32 @test_call_fn_where_argmemonly_can_be_inferred(i32* %ptr) {
121-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn
121+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
122122
; CHECK-LABEL: @test_call_fn_where_argmemonly_can_be_inferred(
123123
; CHECK-NEXT: entry:
124124
; CHECK-NEXT: [[C:%.*]] = call i32 @test_only_read_arg(i32* [[PTR:%.*]])
@@ -130,7 +130,7 @@ entry:
130130
}
131131

132132
define void @test_memcpy_argonly(i8* %dst, i8* %src) {
133-
; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn
133+
; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
134134
; CHECK-LABEL: @test_memcpy_argonly(
135135
; CHECK-NEXT: entry:
136136
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DST:%.*]], i8* [[SRC:%.*]], i64 32, i1 false)
@@ -174,7 +174,7 @@ entry:
174174
}
175175

176176
define i32 @test_read_arg_access_alloca(i32* %ptr) {
177-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn
177+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn
178178
; CHECK-LABEL: @test_read_arg_access_alloca(
179179
; CHECK-NEXT: entry:
180180
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4

llvm/test/Transforms/FunctionAttrs/atomic.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ entry:
2121
}
2222

2323
; CHECK: attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone ssp willreturn uwtable }
24-
; CHECK: attributes #1 = { mustprogress nofree norecurse nounwind ssp willreturn uwtable }
24+
; CHECK: attributes #1 = { argmemonly mustprogress nofree norecurse nounwind ssp willreturn uwtable }

llvm/test/Transforms/FunctionAttrs/nofree.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ entry:
3636
declare void @free(i8* nocapture) local_unnamed_addr #2
3737

3838
define i32 @_Z4foo3Pi(i32* nocapture readonly %a) local_unnamed_addr #3 {
39-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable
39+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable
4040
; CHECK-LABEL: @_Z4foo3Pi(
4141
; CHECK-NEXT: entry:
4242
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4

llvm/test/Transforms/FunctionAttrs/nosync.ll

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ define i32 @test4(i32 %a, i32 %b) {
4949

5050
; negative case - explicit sync
5151
define void @test5(i8* %p) {
52-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn
52+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn
5353
; CHECK-LABEL: @test5(
5454
; CHECK-NEXT: store atomic i8 0, i8* [[P:%.*]] seq_cst, align 1
5555
; CHECK-NEXT: ret void
@@ -60,7 +60,7 @@ define void @test5(i8* %p) {
6060

6161
; negative case - explicit sync
6262
define i8 @test6(i8* %p) {
63-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn
63+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn
6464
; CHECK-LABEL: @test6(
6565
; CHECK-NEXT: [[V:%.*]] = load atomic i8, i8* [[P:%.*]] seq_cst, align 1
6666
; CHECK-NEXT: ret i8 [[V]]
@@ -104,7 +104,7 @@ define void @test9(i8* %p) {
104104

105105
; atomic load with monotonic ordering
106106
define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtable {
107-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn uwtable
107+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable
108108
; CHECK-LABEL: @load_monotonic(
109109
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0:%.*]] monotonic, align 4
110110
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -115,7 +115,7 @@ define i32 @load_monotonic(i32* nocapture readonly %0) norecurse nounwind uwtabl
115115

116116
; atomic store with monotonic ordering.
117117
define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
118-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn uwtable
118+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable
119119
; CHECK-LABEL: @store_monotonic(
120120
; CHECK-NEXT: store atomic i32 10, i32* [[TMP0:%.*]] monotonic, align 4
121121
; CHECK-NEXT: ret void
@@ -127,7 +127,7 @@ define void @store_monotonic(i32* nocapture %0) norecurse nounwind uwtable {
127127
; negative, should not deduce nosync
128128
; atomic load with acquire ordering.
129129
define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable {
130-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn uwtable
130+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable
131131
; CHECK-LABEL: @load_acquire(
132132
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0:%.*]] acquire, align 4
133133
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -137,7 +137,7 @@ define i32 @load_acquire(i32* nocapture readonly %0) norecurse nounwind uwtable
137137
}
138138

139139
define i32 @load_unordered(i32* nocapture readonly %0) norecurse nounwind uwtable {
140-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable
140+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn uwtable
141141
; CHECK-LABEL: @load_unordered(
142142
; CHECK-NEXT: [[TMP2:%.*]] = load atomic i32, i32* [[TMP0:%.*]] unordered, align 4
143143
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -148,7 +148,7 @@ define i32 @load_unordered(i32* nocapture readonly %0) norecurse nounwind uwtabl
148148

149149
; atomic store with unordered ordering.
150150
define void @store_unordered(i32* nocapture %0) norecurse nounwind uwtable {
151-
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn writeonly uwtable
151+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind willreturn writeonly uwtable
152152
; CHECK-LABEL: @store_unordered(
153153
; CHECK-NEXT: store atomic i32 10, i32* [[TMP0:%.*]] unordered, align 4
154154
; CHECK-NEXT: ret void
@@ -161,7 +161,7 @@ define void @store_unordered(i32* nocapture %0) norecurse nounwind uwtable {
161161
; negative, should not deduce nosync
162162
; atomic load with release ordering
163163
define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
164-
; CHECK: Function Attrs: nofree norecurse nounwind uwtable
164+
; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable
165165
; CHECK-LABEL: @load_release(
166166
; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0:%.*]] release, align 4
167167
; CHECK-NEXT: ret void
@@ -172,7 +172,7 @@ define void @load_release(i32* nocapture %0) norecurse nounwind uwtable {
172172

173173
; negative volatile, relaxed atomic
174174
define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable {
175-
; CHECK: Function Attrs: nofree norecurse nounwind uwtable
175+
; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable
176176
; CHECK-LABEL: @load_volatile_release(
177177
; CHECK-NEXT: store atomic volatile i32 10, i32* [[TMP0:%.*]] release, align 4
178178
; CHECK-NEXT: ret void
@@ -183,7 +183,7 @@ define void @load_volatile_release(i32* nocapture %0) norecurse nounwind uwtable
183183

184184
; volatile store.
185185
define void @volatile_store(i32* %0) norecurse nounwind uwtable {
186-
; CHECK: Function Attrs: nofree norecurse nounwind uwtable
186+
; CHECK: Function Attrs: argmemonly nofree norecurse nounwind uwtable
187187
; CHECK-LABEL: @volatile_store(
188188
; CHECK-NEXT: store volatile i32 14, i32* [[TMP0:%.*]], align 4
189189
; CHECK-NEXT: ret void
@@ -195,7 +195,7 @@ define void @volatile_store(i32* %0) norecurse nounwind uwtable {
195195
; negative, should not deduce nosync
196196
; volatile load.
197197
define i32 @volatile_load(i32* %0) norecurse nounwind uwtable {
198-
; CHECK: Function Attrs: mustprogress nofree norecurse nounwind willreturn uwtable
198+
; CHECK: Function Attrs: argmemonly mustprogress nofree norecurse nounwind willreturn uwtable
199199
; CHECK-LABEL: @volatile_load(
200200
; CHECK-NEXT: [[TMP2:%.*]] = load volatile i32, i32* [[TMP0:%.*]], align 4
201201
; CHECK-NEXT: ret i32 [[TMP2]]
@@ -237,7 +237,7 @@ declare void @llvm.memset(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
237237

238238
; negative, checking volatile intrinsics.
239239
define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
240-
; CHECK: Function Attrs: mustprogress nofree nounwind willreturn
240+
; CHECK: Function Attrs: argmemonly mustprogress nofree nounwind willreturn
241241
; CHECK-LABEL: @memcpy_volatile(
242242
; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1:%.*]], i8* [[PTR2:%.*]], i32 8, i1 true)
243243
; CHECK-NEXT: ret i32 4
@@ -248,7 +248,7 @@ define i32 @memcpy_volatile(i8* %ptr1, i8* %ptr2) {
248248

249249
; positive, non-volatile intrinsic.
250250
define i32 @memset_non_volatile(i8* %ptr1, i8 %val) {
251-
; CHECK: Function Attrs: mustprogress nofree nosync nounwind willreturn writeonly
251+
; CHECK: Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn writeonly
252252
; CHECK-LABEL: @memset_non_volatile(
253253
; CHECK-NEXT: call void @llvm.memset.p0i8.i32(i8* [[PTR1:%.*]], i8 [[VAL:%.*]], i32 8, i1 false)
254254
; CHECK-NEXT: ret i32 4

0 commit comments

Comments
 (0)