Skip to content

Commit a34393d

Browse files
JanekvODanielCChen
authored andcommitted
[AMDGPU] Avoid resource propagation for recursion through multiple functions (llvm#111004)
Avoid constructing recursive MCExpr definitions when multiple functions cause a recursion. Fixes llvm#110863
1 parent 13e9810 commit a34393d

File tree

3 files changed

+294
-7
lines changed

3 files changed

+294
-7
lines changed

llvm/lib/Target/AMDGPU/AMDGPUMCResourceInfo.cpp

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,77 @@ MCSymbol *MCResourceInfo::getMaxSGPRSymbol(MCContext &OutContext) {
9191
return OutContext.getOrCreateSymbol("amdgpu.max_num_sgpr");
9292
}
9393

94+
// The (partially complete) expression should have no recursion in it. After
95+
// all, we're trying to avoid recursion using this codepath. Returns true if
96+
// Sym is found within Expr without recursing on Expr, false otherwise.
97+
static bool findSymbolInExpr(MCSymbol *Sym, const MCExpr *Expr,
98+
SmallVectorImpl<const MCExpr *> &Exprs,
99+
SmallPtrSetImpl<const MCExpr *> &Visited) {
100+
// Assert if any of the expressions is already visited (i.e., there is
101+
// existing recursion).
102+
if (!Visited.insert(Expr).second)
103+
llvm_unreachable("already visited expression");
104+
105+
switch (Expr->getKind()) {
106+
default:
107+
return false;
108+
case MCExpr::ExprKind::SymbolRef: {
109+
const MCSymbolRefExpr *SymRefExpr = cast<MCSymbolRefExpr>(Expr);
110+
const MCSymbol &SymRef = SymRefExpr->getSymbol();
111+
if (Sym == &SymRef)
112+
return true;
113+
if (SymRef.isVariable())
114+
Exprs.push_back(SymRef.getVariableValue(/*isUsed=*/false));
115+
return false;
116+
}
117+
case MCExpr::ExprKind::Binary: {
118+
const MCBinaryExpr *BExpr = cast<MCBinaryExpr>(Expr);
119+
Exprs.push_back(BExpr->getLHS());
120+
Exprs.push_back(BExpr->getRHS());
121+
return false;
122+
}
123+
case MCExpr::ExprKind::Unary: {
124+
const MCUnaryExpr *UExpr = cast<MCUnaryExpr>(Expr);
125+
Exprs.push_back(UExpr->getSubExpr());
126+
return false;
127+
}
128+
case MCExpr::ExprKind::Target: {
129+
const AMDGPUMCExpr *AGVK = cast<AMDGPUMCExpr>(Expr);
130+
for (const MCExpr *E : AGVK->getArgs())
131+
Exprs.push_back(E);
132+
return false;
133+
}
134+
}
135+
}
136+
137+
// Symbols whose values eventually are used through their defines (i.e.,
138+
// recursive) must be avoided. Do a walk over Expr to see if Sym will occur in
139+
// it. The Expr is an MCExpr given through a callee's equivalent MCSymbol so if
140+
// no recursion is found Sym can be safely assigned to a (sub-)expr which
141+
// contains the symbol Expr is associated with. Returns true if Sym exists
142+
// in Expr or its sub-expressions, false otherwise.
143+
static bool foundRecursiveSymbolDef(MCSymbol *Sym, const MCExpr *Expr) {
144+
SmallVector<const MCExpr *, 8> WorkList;
145+
SmallPtrSet<const MCExpr *, 8> Visited;
146+
WorkList.push_back(Expr);
147+
148+
while (!WorkList.empty()) {
149+
const MCExpr *CurExpr = WorkList.pop_back_val();
150+
if (findSymbolInExpr(Sym, CurExpr, WorkList, Visited))
151+
return true;
152+
}
153+
154+
return false;
155+
}
156+
94157
void MCResourceInfo::assignResourceInfoExpr(
95158
int64_t LocalValue, ResourceInfoKind RIK, AMDGPUMCExpr::VariantKind Kind,
96159
const MachineFunction &MF, const SmallVectorImpl<const Function *> &Callees,
97160
MCContext &OutContext) {
98161
const MCConstantExpr *LocalConstExpr =
99162
MCConstantExpr::create(LocalValue, OutContext);
100163
const MCExpr *SymVal = LocalConstExpr;
164+
MCSymbol *Sym = getSymbol(MF.getName(), RIK, OutContext);
101165
if (!Callees.empty()) {
102166
SmallVector<const MCExpr *, 8> ArgExprs;
103167
// Avoid recursive symbol assignment.
@@ -110,11 +174,17 @@ void MCResourceInfo::assignResourceInfoExpr(
110174
if (!Seen.insert(Callee).second)
111175
continue;
112176
MCSymbol *CalleeValSym = getSymbol(Callee->getName(), RIK, OutContext);
113-
ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
177+
bool CalleeIsVar = CalleeValSym->isVariable();
178+
if (!CalleeIsVar ||
179+
(CalleeIsVar &&
180+
!foundRecursiveSymbolDef(
181+
Sym, CalleeValSym->getVariableValue(/*IsUsed=*/false)))) {
182+
ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
183+
}
114184
}
115-
SymVal = AMDGPUMCExpr::create(Kind, ArgExprs, OutContext);
185+
if (ArgExprs.size() > 1)
186+
SymVal = AMDGPUMCExpr::create(Kind, ArgExprs, OutContext);
116187
}
117-
MCSymbol *Sym = getSymbol(MF.getName(), RIK, OutContext);
118188
Sym->setVariableValue(SymVal);
119189
}
120190

@@ -155,6 +225,7 @@ void MCResourceInfo::gatherResourceInfo(
155225
// The expression for private segment size should be: FRI.PrivateSegmentSize
156226
// + max(FRI.Callees, FRI.CalleeSegmentSize)
157227
SmallVector<const MCExpr *, 8> ArgExprs;
228+
MCSymbol *Sym = getSymbol(MF.getName(), RIK_PrivateSegSize, OutContext);
158229
if (FRI.CalleeSegmentSize)
159230
ArgExprs.push_back(
160231
MCConstantExpr::create(FRI.CalleeSegmentSize, OutContext));
@@ -165,9 +236,15 @@ void MCResourceInfo::gatherResourceInfo(
165236
if (!Seen.insert(Callee).second)
166237
continue;
167238
if (!Callee->isDeclaration()) {
168-
MCSymbol *calleeValSym =
239+
MCSymbol *CalleeValSym =
169240
getSymbol(Callee->getName(), RIK_PrivateSegSize, OutContext);
170-
ArgExprs.push_back(MCSymbolRefExpr::create(calleeValSym, OutContext));
241+
bool CalleeIsVar = CalleeValSym->isVariable();
242+
if (!CalleeIsVar ||
243+
(CalleeIsVar &&
244+
!foundRecursiveSymbolDef(
245+
Sym, CalleeValSym->getVariableValue(/*IsUsed=*/false)))) {
246+
ArgExprs.push_back(MCSymbolRefExpr::create(CalleeValSym, OutContext));
247+
}
171248
}
172249
}
173250
const MCExpr *localConstExpr =
@@ -178,8 +255,7 @@ void MCResourceInfo::gatherResourceInfo(
178255
localConstExpr =
179256
MCBinaryExpr::createAdd(localConstExpr, transitiveExpr, OutContext);
180257
}
181-
getSymbol(MF.getName(), RIK_PrivateSegSize, OutContext)
182-
->setVariableValue(localConstExpr);
258+
Sym->setVariableValue(localConstExpr);
183259
}
184260

185261
auto SetToLocal = [&](int64_t LocalValue, ResourceInfoKind RIK) {

llvm/test/CodeGen/AMDGPU/function-resource-usage.ll

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,132 @@ define amdgpu_kernel void @usage_direct_recursion(i32 %n) #0 {
481481
ret void
482482
}
483483

484+
; GCN-LABEL: {{^}}multi_stage_recurse2:
485+
; GCN: .set multi_stage_recurse2.num_vgpr, max(41, multi_stage_recurse1.num_vgpr)
486+
; GCN: .set multi_stage_recurse2.num_agpr, max(0, multi_stage_recurse1.num_agpr)
487+
; GCN: .set multi_stage_recurse2.numbered_sgpr, max(34, multi_stage_recurse1.numbered_sgpr)
488+
; GCN: .set multi_stage_recurse2.private_seg_size, 16+(max(multi_stage_recurse1.private_seg_size))
489+
; GCN: .set multi_stage_recurse2.uses_vcc, or(1, multi_stage_recurse1.uses_vcc)
490+
; GCN: .set multi_stage_recurse2.uses_flat_scratch, or(0, multi_stage_recurse1.uses_flat_scratch)
491+
; GCN: .set multi_stage_recurse2.has_dyn_sized_stack, or(0, multi_stage_recurse1.has_dyn_sized_stack)
492+
; GCN: .set multi_stage_recurse2.has_recursion, or(1, multi_stage_recurse1.has_recursion)
493+
; GCN: .set multi_stage_recurse2.has_indirect_call, or(0, multi_stage_recurse1.has_indirect_call)
494+
; GCN: TotalNumSgprs: multi_stage_recurse2.numbered_sgpr+(extrasgprs(multi_stage_recurse2.uses_vcc, multi_stage_recurse2.uses_flat_scratch, 1))
495+
; GCN: NumVgprs: max(41, multi_stage_recurse1.num_vgpr)
496+
; GCN: ScratchSize: 16+(max(multi_stage_recurse1.private_seg_size))
497+
; GCN-LABEL: {{^}}multi_stage_recurse1:
498+
; GCN: .set multi_stage_recurse1.num_vgpr, 41
499+
; GCN: .set multi_stage_recurse1.num_agpr, 0
500+
; GCN: .set multi_stage_recurse1.numbered_sgpr, 34
501+
; GCN: .set multi_stage_recurse1.private_seg_size, 16
502+
; GCN: .set multi_stage_recurse1.uses_vcc, 1
503+
; GCN: .set multi_stage_recurse1.uses_flat_scratch, 0
504+
; GCN: .set multi_stage_recurse1.has_dyn_sized_stack, 0
505+
; GCN: .set multi_stage_recurse1.has_recursion, 1
506+
; GCN: .set multi_stage_recurse1.has_indirect_call, 0
507+
; GCN: TotalNumSgprs: 38
508+
; GCN: NumVgprs: 41
509+
; GCN: ScratchSize: 16
510+
define void @multi_stage_recurse1(i32 %val) #2 {
511+
call void @multi_stage_recurse2(i32 %val)
512+
ret void
513+
}
514+
define void @multi_stage_recurse2(i32 %val) #2 {
515+
call void @multi_stage_recurse1(i32 %val)
516+
ret void
517+
}
518+
519+
; GCN-LABEL: {{^}}usage_multi_stage_recurse:
520+
; GCN: .set usage_multi_stage_recurse.num_vgpr, max(32, multi_stage_recurse1.num_vgpr)
521+
; GCN: .set usage_multi_stage_recurse.num_agpr, max(0, multi_stage_recurse1.num_agpr)
522+
; GCN: .set usage_multi_stage_recurse.numbered_sgpr, max(33, multi_stage_recurse1.numbered_sgpr)
523+
; GCN: .set usage_multi_stage_recurse.private_seg_size, 0+(max(multi_stage_recurse1.private_seg_size))
524+
; GCN: .set usage_multi_stage_recurse.uses_vcc, or(1, multi_stage_recurse1.uses_vcc)
525+
; GCN: .set usage_multi_stage_recurse.uses_flat_scratch, or(1, multi_stage_recurse1.uses_flat_scratch)
526+
; GCN: .set usage_multi_stage_recurse.has_dyn_sized_stack, or(0, multi_stage_recurse1.has_dyn_sized_stack)
527+
; GCN: .set usage_multi_stage_recurse.has_recursion, or(1, multi_stage_recurse1.has_recursion)
528+
; GCN: .set usage_multi_stage_recurse.has_indirect_call, or(0, multi_stage_recurse1.has_indirect_call)
529+
; GCN: TotalNumSgprs: 40
530+
; GCN: NumVgprs: 41
531+
; GCN: ScratchSize: 16
532+
define amdgpu_kernel void @usage_multi_stage_recurse(i32 %n) #0 {
533+
call void @multi_stage_recurse1(i32 %n)
534+
ret void
535+
}
536+
537+
; GCN-LABEL: {{^}}multi_stage_recurse_noattr2:
538+
; GCN: .set multi_stage_recurse_noattr2.num_vgpr, max(41, multi_stage_recurse_noattr1.num_vgpr)
539+
; GCN: .set multi_stage_recurse_noattr2.num_agpr, max(0, multi_stage_recurse_noattr1.num_agpr)
540+
; GCN: .set multi_stage_recurse_noattr2.numbered_sgpr, max(34, multi_stage_recurse_noattr1.numbered_sgpr)
541+
; GCN: .set multi_stage_recurse_noattr2.private_seg_size, 16+(max(multi_stage_recurse_noattr1.private_seg_size))
542+
; GCN: .set multi_stage_recurse_noattr2.uses_vcc, or(1, multi_stage_recurse_noattr1.uses_vcc)
543+
; GCN: .set multi_stage_recurse_noattr2.uses_flat_scratch, or(0, multi_stage_recurse_noattr1.uses_flat_scratch)
544+
; GCN: .set multi_stage_recurse_noattr2.has_dyn_sized_stack, or(0, multi_stage_recurse_noattr1.has_dyn_sized_stack)
545+
; GCN: .set multi_stage_recurse_noattr2.has_recursion, or(0, multi_stage_recurse_noattr1.has_recursion)
546+
; GCN: .set multi_stage_recurse_noattr2.has_indirect_call, or(0, multi_stage_recurse_noattr1.has_indirect_call)
547+
; GCN: TotalNumSgprs: multi_stage_recurse_noattr2.numbered_sgpr+(extrasgprs(multi_stage_recurse_noattr2.uses_vcc, multi_stage_recurse_noattr2.uses_flat_scratch, 1))
548+
; GCN: NumVgprs: max(41, multi_stage_recurse_noattr1.num_vgpr)
549+
; GCN: ScratchSize: 16+(max(multi_stage_recurse_noattr1.private_seg_size))
550+
; GCN-LABEL: {{^}}multi_stage_recurse_noattr1:
551+
; GCN: .set multi_stage_recurse_noattr1.num_vgpr, 41
552+
; GCN: .set multi_stage_recurse_noattr1.num_agpr, 0
553+
; GCN: .set multi_stage_recurse_noattr1.numbered_sgpr, 34
554+
; GCN: .set multi_stage_recurse_noattr1.private_seg_size, 16
555+
; GCN: .set multi_stage_recurse_noattr1.uses_vcc, 1
556+
; GCN: .set multi_stage_recurse_noattr1.uses_flat_scratch, 0
557+
; GCN: .set multi_stage_recurse_noattr1.has_dyn_sized_stack, 0
558+
; GCN: .set multi_stage_recurse_noattr1.has_recursion, 0
559+
; GCN: .set multi_stage_recurse_noattr1.has_indirect_call, 0
560+
; GCN: TotalNumSgprs: 38
561+
; GCN: NumVgprs: 41
562+
; GCN: ScratchSize: 16
563+
define void @multi_stage_recurse_noattr1(i32 %val) #0 {
564+
call void @multi_stage_recurse_noattr2(i32 %val)
565+
ret void
566+
}
567+
define void @multi_stage_recurse_noattr2(i32 %val) #0 {
568+
call void @multi_stage_recurse_noattr1(i32 %val)
569+
ret void
570+
}
571+
572+
; GCN-LABEL: {{^}}usage_multi_stage_recurse_noattrs:
573+
; GCN: .set usage_multi_stage_recurse_noattrs.num_vgpr, max(32, multi_stage_recurse_noattr1.num_vgpr)
574+
; GCN: .set usage_multi_stage_recurse_noattrs.num_agpr, max(0, multi_stage_recurse_noattr1.num_agpr)
575+
; GCN: .set usage_multi_stage_recurse_noattrs.numbered_sgpr, max(33, multi_stage_recurse_noattr1.numbered_sgpr)
576+
; GCN: .set usage_multi_stage_recurse_noattrs.private_seg_size, 0+(max(multi_stage_recurse_noattr1.private_seg_size))
577+
; GCN: .set usage_multi_stage_recurse_noattrs.uses_vcc, or(1, multi_stage_recurse_noattr1.uses_vcc)
578+
; GCN: .set usage_multi_stage_recurse_noattrs.uses_flat_scratch, or(1, multi_stage_recurse_noattr1.uses_flat_scratch)
579+
; GCN: .set usage_multi_stage_recurse_noattrs.has_dyn_sized_stack, or(0, multi_stage_recurse_noattr1.has_dyn_sized_stack)
580+
; GCN: .set usage_multi_stage_recurse_noattrs.has_recursion, or(0, multi_stage_recurse_noattr1.has_recursion)
581+
; GCN: .set usage_multi_stage_recurse_noattrs.has_indirect_call, or(0, multi_stage_recurse_noattr1.has_indirect_call)
582+
; GCN: TotalNumSgprs: 40
583+
; GCN: NumVgprs: 41
584+
; GCN: ScratchSize: 16
585+
define amdgpu_kernel void @usage_multi_stage_recurse_noattrs(i32 %n) #0 {
586+
call void @multi_stage_recurse_noattr1(i32 %n)
587+
ret void
588+
}
589+
590+
; GCN-LABEL: {{^}}multi_call_with_multi_stage_recurse:
591+
; GCN: .set multi_call_with_multi_stage_recurse.num_vgpr, max(41, use_stack0.num_vgpr, use_stack1.num_vgpr, multi_stage_recurse1.num_vgpr)
592+
; GCN: .set multi_call_with_multi_stage_recurse.num_agpr, max(0, use_stack0.num_agpr, use_stack1.num_agpr, multi_stage_recurse1.num_agpr)
593+
; GCN: .set multi_call_with_multi_stage_recurse.numbered_sgpr, max(43, use_stack0.numbered_sgpr, use_stack1.numbered_sgpr, multi_stage_recurse1.numbered_sgpr)
594+
; GCN: .set multi_call_with_multi_stage_recurse.private_seg_size, 0+(max(use_stack0.private_seg_size, use_stack1.private_seg_size, multi_stage_recurse1.private_seg_size))
595+
; GCN: .set multi_call_with_multi_stage_recurse.uses_vcc, or(1, use_stack0.uses_vcc, use_stack1.uses_vcc, multi_stage_recurse1.uses_vcc)
596+
; GCN: .set multi_call_with_multi_stage_recurse.uses_flat_scratch, or(1, use_stack0.uses_flat_scratch, use_stack1.uses_flat_scratch, multi_stage_recurse1.uses_flat_scratch)
597+
; GCN: .set multi_call_with_multi_stage_recurse.has_dyn_sized_stack, or(0, use_stack0.has_dyn_sized_stack, use_stack1.has_dyn_sized_stack, multi_stage_recurse1.has_dyn_sized_stack)
598+
; GCN: .set multi_call_with_multi_stage_recurse.has_recursion, or(1, use_stack0.has_recursion, use_stack1.has_recursion, multi_stage_recurse1.has_recursion)
599+
; GCN: .set multi_call_with_multi_stage_recurse.has_indirect_call, or(0, use_stack0.has_indirect_call, use_stack1.has_indirect_call, multi_stage_recurse1.has_indirect_call)
600+
; GCN: TotalNumSgprs: 49
601+
; GCN: NumVgprs: 41
602+
; GCN: ScratchSize: 2052
603+
define amdgpu_kernel void @multi_call_with_multi_stage_recurse(i32 %n) #0 {
604+
call void @use_stack0()
605+
call void @use_stack1()
606+
call void @multi_stage_recurse1(i32 %n)
607+
ret void
608+
}
609+
484610
; Make sure there's no assert when a sgpr96 is used.
485611
; GCN-LABEL: {{^}}count_use_sgpr96_external_call
486612
; GCN: .set count_use_sgpr96_external_call.num_vgpr, max(32, amdgpu.max_num_vgpr)
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx90a < %s | FileCheck %s
2+
3+
; CHECK-LABEL: {{^}}qux
4+
; CHECK: .set qux.num_vgpr, max(41, foo.num_vgpr)
5+
; CHECK: .set qux.num_agpr, max(0, foo.num_agpr)
6+
; CHECK: .set qux.numbered_sgpr, max(34, foo.numbered_sgpr)
7+
; CHECK: .set qux.private_seg_size, 16
8+
; CHECK: .set qux.uses_vcc, or(1, foo.uses_vcc)
9+
; CHECK: .set qux.uses_flat_scratch, or(0, foo.uses_flat_scratch)
10+
; CHECK: .set qux.has_dyn_sized_stack, or(0, foo.has_dyn_sized_stack)
11+
; CHECK: .set qux.has_recursion, or(1, foo.has_recursion)
12+
; CHECK: .set qux.has_indirect_call, or(0, foo.has_indirect_call)
13+
14+
; CHECK-LABEL: {{^}}baz
15+
; CHECK: .set baz.num_vgpr, max(42, qux.num_vgpr)
16+
; CHECK: .set baz.num_agpr, max(0, qux.num_agpr)
17+
; CHECK: .set baz.numbered_sgpr, max(34, qux.numbered_sgpr)
18+
; CHECK: .set baz.private_seg_size, 16+(max(qux.private_seg_size))
19+
; CHECK: .set baz.uses_vcc, or(1, qux.uses_vcc)
20+
; CHECK: .set baz.uses_flat_scratch, or(0, qux.uses_flat_scratch)
21+
; CHECK: .set baz.has_dyn_sized_stack, or(0, qux.has_dyn_sized_stack)
22+
; CHECK: .set baz.has_recursion, or(1, qux.has_recursion)
23+
; CHECK: .set baz.has_indirect_call, or(0, qux.has_indirect_call)
24+
25+
; CHECK-LABEL: {{^}}bar
26+
; CHECK: .set bar.num_vgpr, max(42, baz.num_vgpr)
27+
; CHECK: .set bar.num_agpr, max(0, baz.num_agpr)
28+
; CHECK: .set bar.numbered_sgpr, max(34, baz.numbered_sgpr)
29+
; CHECK: .set bar.private_seg_size, 16+(max(baz.private_seg_size))
30+
; CHECK: .set bar.uses_vcc, or(1, baz.uses_vcc)
31+
; CHECK: .set bar.uses_flat_scratch, or(0, baz.uses_flat_scratch)
32+
; CHECK: .set bar.has_dyn_sized_stack, or(0, baz.has_dyn_sized_stack)
33+
; CHECK: .set bar.has_recursion, or(1, baz.has_recursion)
34+
; CHECK: .set bar.has_indirect_call, or(0, baz.has_indirect_call)
35+
36+
; CHECK-LABEL: {{^}}foo
37+
; CHECK: .set foo.num_vgpr, 42
38+
; CHECK: .set foo.num_agpr, 0
39+
; CHECK: .set foo.numbered_sgpr, 34
40+
; CHECK: .set foo.private_seg_size, 16
41+
; CHECK: .set foo.uses_vcc, 1
42+
; CHECK: .set foo.uses_flat_scratch, 0
43+
; CHECK: .set foo.has_dyn_sized_stack, 0
44+
; CHECK: .set foo.has_recursion, 1
45+
; CHECK: .set foo.has_indirect_call, 0
46+
47+
define void @foo() {
48+
entry:
49+
call void @bar()
50+
ret void
51+
}
52+
53+
define void @bar() {
54+
entry:
55+
call void @baz()
56+
ret void
57+
}
58+
59+
define void @baz() {
60+
entry:
61+
call void @qux()
62+
ret void
63+
}
64+
65+
define void @qux() {
66+
entry:
67+
call void @foo()
68+
ret void
69+
}
70+
71+
; CHECK-LABEL: {{^}}usefoo
72+
; CHECK: .set usefoo.num_vgpr, max(32, foo.num_vgpr)
73+
; CHECK: .set usefoo.num_agpr, max(0, foo.num_agpr)
74+
; CHECK: .set usefoo.numbered_sgpr, max(33, foo.numbered_sgpr)
75+
; CHECK: .set usefoo.private_seg_size, 0+(max(foo.private_seg_size))
76+
; CHECK: .set usefoo.uses_vcc, or(1, foo.uses_vcc)
77+
; CHECK: .set usefoo.uses_flat_scratch, or(1, foo.uses_flat_scratch)
78+
; CHECK: .set usefoo.has_dyn_sized_stack, or(0, foo.has_dyn_sized_stack)
79+
; CHECK: .set usefoo.has_recursion, or(1, foo.has_recursion)
80+
; CHECK: .set usefoo.has_indirect_call, or(0, foo.has_indirect_call)
81+
define amdgpu_kernel void @usefoo() {
82+
call void @foo()
83+
ret void
84+
}
85+

0 commit comments

Comments
 (0)