1; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
2; RUN:   -mcpu=pwr10 -ppc-asm-full-reg-names < %s \
3; RUN:   | FileCheck %s --check-prefixes=CHECK-S,CHECK-ALL
4; RUN: llc -verify-machineinstrs -target-abi=elfv2 -mtriple=powerpc64-- \
5; RUN:   -mcpu=pwr10 -ppc-asm-full-reg-names < %s \
6; RUN:   | FileCheck %s --check-prefixes=CHECK-S,CHECK-ALL
7; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
8; RUN:   -mcpu=pwr9 -ppc-asm-full-reg-names < %s \
9; RUN:   | FileCheck %s --check-prefixes=CHECK-P9,CHECK-ALL
10
11@globalVar = common dso_local local_unnamed_addr global i32 0, align 4
12@externGlobalVar = external local_unnamed_addr global i32, align 4
13@indirectCall = common dso_local local_unnamed_addr global i32 (i32)* null, align 8
14
15; This funcion needs to remain as noinline.
16; The compiler needs to know this function is local but must be forced to call
17; it. The only thing we really need to check here is that st_other=0 and
18; so we make sure that there is no .localentry.
19define dso_local signext i32 @localCall(i32 signext %a) local_unnamed_addr #0 {
20; CHECK-ALL-LABEL: localCall:
21; CHECK-S-NOT:   .localentry
22; CHECK-S:         addi r3, r3, 5
23; CHECK-S-NEXT:    extsw r3, r3
24; CHECK-S-NEXT:    blr
25entry:
26  %add = add nsw i32 %a, 5
27  ret i32 %add
28}
29
30define dso_local signext i32 @DirectCallLocal1(i32 signext %a, i32 signext %b) local_unnamed_addr {
31; CHECK-ALL-LABEL: DirectCallLocal1:
32; CHECK-S:         .localentry     DirectCallLocal1
33; CHECK-S:       # %bb.0: # %entry
34; CHECK-S-NEXT:    mflr r0
35; CHECK-S-NEXT:    std r0, 16(r1)
36; CHECK-S-NEXT:    stdu r1, -32(r1)
37; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
38; CHECK-S-NEXT:    .cfi_offset lr, 16
39; CHECK-S-NEXT:    add r3, r4, r3
40; CHECK-S-NEXT:    extsw r3, r3
41; CHECK-S-NEXT:    bl localCall@notoc
42; CHECK-S-NEXT:    plwz r4, globalVar@PCREL(0), 1
43; CHECK-S-NEXT:    mullw r3, r4, r3
44; CHECK-S-NEXT:    extsw r3, r3
45; CHECK-S-NEXT:    addi r1, r1, 32
46; CHECK-S-NEXT:    ld r0, 16(r1)
47; CHECK-S-NEXT:    mtlr r0
48; CHECK-S-NEXT:    blr
49entry:
50  %add = add nsw i32 %b, %a
51  %call = tail call signext i32 @localCall(i32 signext %add)
52  %0 = load i32, i32* @globalVar, align 4
53  %mul = mul nsw i32 %0, %call
54  ret i32 %mul
55}
56
57define dso_local signext i32 @DirectCallLocal2(i32 signext %a, i32 signext %b) local_unnamed_addr {
58; CHECK-ALL-LABEL: DirectCallLocal2:
59; CHECK-S:         .localentry     DirectCallLocal2
60; CHECK-S:       # %bb.0: # %entry
61; CHECK-S-NEXT:    mflr r0
62; CHECK-S-NEXT:    std r0, 16(r1)
63; CHECK-S-NEXT:    stdu r1, -32(r1)
64; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
65; CHECK-S-NEXT:    .cfi_offset lr, 16
66; CHECK-S-NEXT:    add r3, r4, r3
67; CHECK-S-NEXT:    extsw r3, r3
68; CHECK-S-NEXT:    bl localCall@notoc
69; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
70; CHECK-S-NEXT: .Lpcrel:
71; CHECK-S-NEXT:    .reloc .Lpcrel-8,R_PPC64_PCREL_OPT,.-(.Lpcrel-8)
72; CHECK-S-NEXT:    lwz r4, 0(r4)
73; CHECK-S-NEXT:    mullw r3, r4, r3
74; CHECK-S-NEXT:    extsw r3, r3
75; CHECK-S-NEXT:    addi r1, r1, 32
76; CHECK-S-NEXT:    ld r0, 16(r1)
77; CHECK-S-NEXT:    mtlr r0
78; CHECK-S-NEXT:    blr
79entry:
80  %add = add nsw i32 %b, %a
81  %call = tail call signext i32 @localCall(i32 signext %add)
82  %0 = load i32, i32* @externGlobalVar, align 4
83  %mul = mul nsw i32 %0, %call
84  ret i32 %mul
85}
86
87define dso_local signext i32 @DirectCallLocalNoGlobal(i32 signext %a, i32 signext %b) local_unnamed_addr {
88; CHECK-ALL-LABEL: DirectCallLocalNoGlobal:
89; CHECK-S:         .localentry DirectCallLocalNoGlobal, 1
90; CHECK-S-NEXT:    # %bb.0: # %entry
91; CHECK-S-NEXT:    mflr r0
92; CHECK-S-NEXT:    .cfi_def_cfa_offset 48
93; CHECK-S-NEXT:    .cfi_offset lr, 16
94; CHECK-S-NEXT:    .cfi_offset r30, -16
95; CHECK-S-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
96; CHECK-S-NEXT:    std r0, 16(r1)
97; CHECK-S-NEXT:    stdu r1, -48(r1)
98; CHECK-S-NEXT:    mr r30, r4
99; CHECK-S-NEXT:    bl localCall@notoc
100; CHECK-S-NEXT:    add r3, r3, r30
101; CHECK-S-NEXT:    extsw r3, r3
102; CHECK-S-NEXT:    addi r1, r1, 48
103; CHECK-S-NEXT:    ld r0, 16(r1)
104; CHECK-S-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
105; CHECK-S-NEXT:    mtlr r0
106; CHECK-S-NEXT:    blr
107entry:
108  %call = tail call signext i32 @localCall(i32 signext %a)
109  %add = add nsw i32 %call, %b
110  ret i32 %add
111}
112
113define dso_local signext i32 @DirectCallExtern1(i32 signext %a, i32 signext %b) local_unnamed_addr {
114; CHECK-ALL-LABEL: DirectCallExtern1:
115; CHECK-S:         .localentry     DirectCallExtern1
116; CHECK-S:       # %bb.0: # %entry
117; CHECK-S-NEXT:    mflr r0
118; CHECK-S-NEXT:    std r0, 16(r1)
119; CHECK-S-NEXT:    stdu r1, -32(r1)
120; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
121; CHECK-S-NEXT:    .cfi_offset lr, 16
122; CHECK-S-NEXT:    add r3, r4, r3
123; CHECK-S-NEXT:    extsw r3, r3
124; CHECK-S-NEXT:    bl externCall@notoc
125; CHECK-S-NEXT:    plwz r4, globalVar@PCREL(0), 1
126; CHECK-S-NEXT:    mullw r3, r4, r3
127; CHECK-S-NEXT:    extsw r3, r3
128; CHECK-S-NEXT:    addi r1, r1, 32
129; CHECK-S-NEXT:    ld r0, 16(r1)
130; CHECK-S-NEXT:    mtlr r0
131; CHECK-S-NEXT:    blr
132entry:
133  %add = add nsw i32 %b, %a
134  %call = tail call signext i32 @externCall(i32 signext %add)
135  %0 = load i32, i32* @globalVar, align 4
136  %mul = mul nsw i32 %0, %call
137  ret i32 %mul
138}
139
140declare signext i32 @externCall(i32 signext) local_unnamed_addr
141
142define dso_local signext i32 @DirectCallExtern2(i32 signext %a, i32 signext %b) local_unnamed_addr {
143; CHECK-ALL-LABEL: DirectCallExtern2:
144; CHECK-S:         .localentry     DirectCallExtern2
145; CHECK-S:       # %bb.0: # %entry
146; CHECK-S-NEXT:    mflr r0
147; CHECK-S-NEXT:    std r0, 16(r1)
148; CHECK-S-NEXT:    stdu r1, -32(r1)
149; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
150; CHECK-S-NEXT:    .cfi_offset lr, 16
151; CHECK-S-NEXT:    add r3, r4, r3
152; CHECK-S-NEXT:    extsw r3, r3
153; CHECK-S-NEXT:    bl externCall@notoc
154; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
155; CHECK-S-NEXT:  .Lpcrel0:
156; CHECK-S-NEXT:    .reloc .Lpcrel0-8,R_PPC64_PCREL_OPT,.-(.Lpcrel0-8)
157; CHECK-S-NEXT:    lwz r4, 0(r4)
158; CHECK-S-NEXT:    mullw r3, r4, r3
159; CHECK-S-NEXT:    extsw r3, r3
160; CHECK-S-NEXT:    addi r1, r1, 32
161; CHECK-S-NEXT:    ld r0, 16(r1)
162; CHECK-S-NEXT:    mtlr r0
163; CHECK-S-NEXT:    blr
164entry:
165  %add = add nsw i32 %b, %a
166  %call = tail call signext i32 @externCall(i32 signext %add)
167  %0 = load i32, i32* @externGlobalVar, align 4
168  %mul = mul nsw i32 %0, %call
169  ret i32 %mul
170}
171
172define dso_local signext i32 @DirectCallExternNoGlobal(i32 signext %a, i32 signext %b) local_unnamed_addr {
173; CHECK-ALL-LABEL: DirectCallExternNoGlobal:
174; CHECK-S:         .localentry DirectCallExternNoGlobal, 1
175; CHECK-P9:        .localentry DirectCallExternNoGlobal, .Lfunc_lep6-.Lfunc_gep6
176; CHECK-ALL:       # %bb.0: # %entry
177; CHECK-S-NEXT:    mflr r0
178; CHECK-S-NEXT:    .cfi_def_cfa_offset 48
179; CHECK-S-NEXT:    .cfi_offset lr, 16
180; CHECK-S-NEXT:    .cfi_offset r30, -16
181; CHECK-S-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
182; CHECK-S-NEXT:    std r0, 16(r1)
183; CHECK-S-NEXT:    stdu r1, -48(r1)
184; CHECK-S-NEXT:    mr r30, r4
185; CHECK-S-NEXT:    bl externCall@notoc
186; CHECK-S-NEXT:    add r3, r3, r30
187; CHECK-S-NEXT:    extsw r3, r3
188; CHECK-S-NEXT:    addi r1, r1, 48
189; CHECK-S-NEXT:    ld r0, 16(r1)
190; CHECK-S-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
191; CHECK-S-NEXT:    mtlr r0
192; CHECK-S-NEXT:    blr
193entry:
194  %call = tail call signext i32 @externCall(i32 signext %a)
195  %add = add nsw i32 %call, %b
196  ret i32 %add
197}
198
199define dso_local signext i32 @TailCallLocal1(i32 signext %a) local_unnamed_addr {
200; CHECK-ALL-LABEL: TailCallLocal1:
201; CHECK-S:         .localentry     TailCallLocal1
202; CHECK-S:       # %bb.0: # %entry
203; CHECK-S:         plwz r4, globalVar@PCREL(0), 1
204; CHECK-S-NEXT:    add r3, r4, r3
205; CHECK-S-NEXT:    extsw r3, r3
206; CHECK-S-NEXT:    b localCall@notoc
207entry:
208  %0 = load i32, i32* @globalVar, align 4
209  %add = add nsw i32 %0, %a
210  %call = tail call signext i32 @localCall(i32 signext %add)
211  ret i32 %call
212}
213
214define dso_local signext i32 @TailCallLocal2(i32 signext %a) local_unnamed_addr {
215; CHECK-ALL-LABEL: TailCallLocal2:
216; CHECK-S:         .localentry     TailCallLocal2
217; CHECK-S:       # %bb.0: # %entry
218; CHECK-S:         pld r4, externGlobalVar@got@pcrel(0), 1
219; CHECK-S-NEXT:  .Lpcrel1:
220; CHECK-S-NEXT:    .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8)
221; CHECK-S-NEXT:    lwz r4, 0(r4)
222; CHECK-S-NEXT:    add r3, r4, r3
223; CHECK-S-NEXT:    extsw r3, r3
224; CHECK-S-NEXT:    b localCall@notoc
225entry:
226  %0 = load i32, i32* @externGlobalVar, align 4
227  %add = add nsw i32 %0, %a
228  %call = tail call signext i32 @localCall(i32 signext %add)
229  ret i32 %call
230}
231
232define dso_local signext i32 @TailCallLocalNoGlobal(i32 signext %a) local_unnamed_addr {
233; CHECK-ALL-LABEL: TailCallLocalNoGlobal:
234; CHECK-S:         .localentry TailCallLocalNoGlobal, 1
235; CHECK-P9:        .localentry TailCallLocalNoGlobal, .Lfunc_lep9-.Lfunc_gep9
236; CHECK-ALL:       # %bb.0: # %entry
237; CHECK-S:         b localCall@notoc
238entry:
239  %call = tail call signext i32 @localCall(i32 signext %a)
240  ret i32 %call
241}
242
243define dso_local signext i32 @TailCallExtern1(i32 signext %a) local_unnamed_addr {
244; CHECK-ALL-LABEL: TailCallExtern1:
245; CHECK-S:         .localentry     TailCallExtern1
246; CHECK-S:       # %bb.0: # %entry
247; CHECK-S:         plwz r4, globalVar@PCREL(0), 1
248; CHECK-S-NEXT:    add r3, r4, r3
249; CHECK-S-NEXT:    extsw r3, r3
250; CHECK-S-NEXT:    b externCall@notoc
251entry:
252  %0 = load i32, i32* @globalVar, align 4
253  %add = add nsw i32 %0, %a
254  %call = tail call signext i32 @externCall(i32 signext %add)
255  ret i32 %call
256}
257
258define dso_local signext i32 @TailCallExtern2(i32 signext %a) local_unnamed_addr {
259; CHECK-ALL-LABEL: TailCallExtern2:
260; CHECK-S:         .localentry     TailCallExtern2
261; CHECK-S:       # %bb.0: # %entry
262; CHECK-S:         pld r4, externGlobalVar@got@pcrel(0), 1
263; CHECK-S-NEXT:  .Lpcrel2:
264; CHECK-S-NEXT:    .reloc .Lpcrel2-8,R_PPC64_PCREL_OPT,.-(.Lpcrel2-8)
265; CHECK-S-NEXT:    lwz r4, 0(r4)
266; CHECK-S-NEXT:    add r3, r4, r3
267; CHECK-S-NEXT:    extsw r3, r3
268; CHECK-S-NEXT:    b externCall@notoc
269entry:
270  %0 = load i32, i32* @externGlobalVar, align 4
271  %add = add nsw i32 %0, %a
272  %call = tail call signext i32 @externCall(i32 signext %add)
273  ret i32 %call
274}
275
276define dso_local signext i32 @TailCallExternNoGlobal(i32 signext %a) local_unnamed_addr {
277; CHECK-ALL-LABEL: TailCallExternNoGlobal:
278; CHECK-S:         .localentry TailCallExternNoGlobal, 1
279; CHECK-S-NEXT:  # %bb.0: # %entry
280; CHECK-S-NEXT:    b externCall@notoc
281; CHECK-S-NEXT:    #TC_RETURNd8 externCall@notoc
282entry:
283  %call = tail call signext i32 @externCall(i32 signext %a)
284  ret i32 %call
285}
286
287define dso_local signext i32 @IndirectCall1(i32 signext %a, i32 signext %b) local_unnamed_addr {
288; CHECK-ALL-LABEL: IndirectCall1:
289; CHECK-S:       # %bb.0: # %entry
290; CHECK-S-NEXT:    mflr r0
291; CHECK-S-NEXT:    std r0, 16(r1)
292; CHECK-S-NEXT:    stdu r1, -32(r1)
293; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
294; CHECK-S-NEXT:    .cfi_offset lr, 16
295; CHECK-S-NEXT:    pld r12, indirectCall@PCREL(0), 1
296; CHECK-S-NEXT:    add r3, r4, r3
297; CHECK-S-NEXT:    extsw r3, r3
298; CHECK-S-NEXT:    mtctr r12
299; CHECK-S-NEXT:    bctrl
300; CHECK-S-NEXT:    plwz r4, globalVar@PCREL(0), 1
301; CHECK-S-NEXT:    mullw r3, r4, r3
302; CHECK-S-NEXT:    extsw r3, r3
303; CHECK-S-NEXT:    addi r1, r1, 32
304; CHECK-S-NEXT:    ld r0, 16(r1)
305; CHECK-S-NEXT:    mtlr r0
306; CHECK-S-NEXT:    blr
307entry:
308  %add = add nsw i32 %b, %a
309  %0 = load i32 (i32)*, i32 (i32)** @indirectCall, align 8
310  %call = tail call signext i32 %0(i32 signext %add)
311  %1 = load i32, i32* @globalVar, align 4
312  %mul = mul nsw i32 %1, %call
313  ret i32 %mul
314}
315
316define dso_local signext i32 @IndirectCall2(i32 signext %a, i32 signext %b) local_unnamed_addr {
317; CHECK-ALL-LABEL: IndirectCall2:
318; CHECK-S:       # %bb.0: # %entry
319; CHECK-S-NEXT:    mflr r0
320; CHECK-S-NEXT:    std r0, 16(r1)
321; CHECK-S-NEXT:    stdu r1, -32(r1)
322; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
323; CHECK-S-NEXT:    .cfi_offset lr, 16
324; CHECK-S-NEXT:    pld r12, indirectCall@PCREL(0), 1
325; CHECK-S-NEXT:    add r3, r4, r3
326; CHECK-S-NEXT:    extsw r3, r3
327; CHECK-S-NEXT:    mtctr r12
328; CHECK-S-NEXT:    bctrl
329; CHECK-S-NEXT:    pld r4, externGlobalVar@got@pcrel(0), 1
330; CHECK-S-NEXT:  .Lpcrel3:
331; CHECK-S-NEXT:    .reloc .Lpcrel3-8,R_PPC64_PCREL_OPT,.-(.Lpcrel3-8)
332; CHECK-S-NEXT:    lwz r4, 0(r4)
333; CHECK-S-NEXT:    mullw r3, r4, r3
334; CHECK-S-NEXT:    extsw r3, r3
335; CHECK-S-NEXT:    addi r1, r1, 32
336; CHECK-S-NEXT:    ld r0, 16(r1)
337; CHECK-S-NEXT:    mtlr r0
338; CHECK-S-NEXT:    blr
339entry:
340  %add = add nsw i32 %b, %a
341  %0 = load i32 (i32)*, i32 (i32)** @indirectCall, align 8
342  %call = tail call signext i32 %0(i32 signext %add)
343  %1 = load i32, i32* @externGlobalVar, align 4
344  %mul = mul nsw i32 %1, %call
345  ret i32 %mul
346}
347
348define dso_local signext i32 @IndirectCall3(i32 signext %a, i32 signext %b, i32 (i32)* nocapture %call_param) local_unnamed_addr {
349; CHECK-ALL-LABEL: IndirectCall3:
350; CHECK-S:       # %bb.0: # %entry
351; CHECK-S-NEXT:    mflr r0
352; CHECK-S-NEXT:    std r0, 16(r1)
353; CHECK-S-NEXT:    stdu r1, -32(r1)
354; CHECK-S-NEXT:    .cfi_def_cfa_offset 32
355; CHECK-S-NEXT:    .cfi_offset lr, 16
356; CHECK-S-NEXT:    mtctr r5
357; CHECK-S-NEXT:    add r3, r4, r3
358; CHECK-S-NEXT:    mr r12, r5
359; CHECK-S-NEXT:    extsw r3, r3
360; CHECK-S-NEXT:    bctrl
361; CHECK-S-NEXT:    plwz r4, globalVar@PCREL(0), 1
362; CHECK-S-NEXT:    mullw r3, r4, r3
363; CHECK-S-NEXT:    extsw r3, r3
364; CHECK-S-NEXT:    addi r1, r1, 32
365; CHECK-S-NEXT:    ld r0, 16(r1)
366; CHECK-S-NEXT:    mtlr r0
367; CHECK-S-NEXT:    blr
368entry:
369  %add = add nsw i32 %b, %a
370  %call = tail call signext i32 %call_param(i32 signext %add)
371  %0 = load i32, i32* @globalVar, align 4
372  %mul = mul nsw i32 %0, %call
373  ret i32 %mul
374}
375
376define dso_local signext i32 @IndirectCallNoGlobal(i32 signext %a, i32 signext %b, i32 (i32)* nocapture %call_param) local_unnamed_addr {
377; CHECK-ALL-LABEL: IndirectCallNoGlobal:
378; CHECK-S:       # %bb.0: # %entry
379; CHECK-S-NEXT:    mflr r0
380; CHECK-S-NEXT:    .cfi_def_cfa_offset 48
381; CHECK-S-NEXT:    .cfi_offset lr, 16
382; CHECK-S-NEXT:    .cfi_offset r30, -16
383; CHECK-S-NEXT:    std r30, -16(r1) # 8-byte Folded Spill
384; CHECK-S-NEXT:    std r0, 16(r1)
385; CHECK-S-NEXT:    stdu r1, -48(r1)
386; CHECK-S-NEXT:    mtctr r5
387; CHECK-S-NEXT:    mr r12, r5
388; CHECK-S-NEXT:    mr r30, r4
389; CHECK-S-NEXT:    bctrl
390; CHECK-S-NEXT:    add r3, r3, r30
391; CHECK-S-NEXT:    extsw r3, r3
392; CHECK-S-NEXT:    addi r1, r1, 48
393; CHECK-S-NEXT:    ld r0, 16(r1)
394; CHECK-S-NEXT:    ld r30, -16(r1) # 8-byte Folded Reload
395; CHECK-S-NEXT:    mtlr r0
396; CHECK-S-NEXT:    blr
397entry:
398  %call = tail call signext i32 %call_param(i32 signext %a)
399  %add = add nsw i32 %call, %b
400  ret i32 %add
401}
402
403define dso_local signext i32 @IndirectCallOnly(i32 signext %a, i32 (i32)* nocapture %call_param) local_unnamed_addr {
404; CHECK-ALL-LABEL: IndirectCallOnly:
405; CHECK-S:       # %bb.0: # %entry
406; CHECK-S-NEXT:    mtctr r4
407; CHECK-S-NEXT:    mr r12, r4
408; CHECK-S-NEXT:    bctr
409; CHECK-S-NEXT:    #TC_RETURNr8 ctr
410entry:
411  %call = tail call signext i32 %call_param(i32 signext %a)
412  ret i32 %call
413}
414
415attributes #0 = { noinline }
416
417