xref: /llvm-project/llvm/test/CodeGen/X86/base-pointer-and-mwaitx.ll (revision 2f448bf509432c1a19ec46ab8cbc7353c03c6280)
1; RUN: split-file %s %t
2; RUN: cat %t/main.ll %t/_align32.ll > %t/align32.ll
3; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign %t/align32.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_64 %s
4; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true -stackrealign %t/align32.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=USE_BASE_32 %s
5; RUN: llc -mtriple=x86_64-pc-linux-gnu -mattr=+mwaitx -x86-use-base-pointer=true %t/main.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_64 %s
6; RUN: llc -mtriple=x86_64-pc-linux-gnux32 -mattr=+mwaitx -x86-use-base-pointer=true %t/main.ll -o - | FileCheck --check-prefix=CHECK --check-prefix=NO_BASE_32 %s
7
8;--- main.ll
9
10; This test checks that we save and restore the base pointer (ebx or rbx) in the
11; presence of the mwaitx intrinsic which requires to use ebx for one of its
12; argument.
13; This function uses a dynamically allocated stack to force the use
14; of a base pointer.
15; After the call to the mwaitx intrinsic we do a volatile store to the
16; dynamically allocated memory which will require the use of the base pointer.
17; The base pointer should therefore be restored straight after the mwaitx
18; instruction.
19
20define void @test_baseptr(i64 %x, i64 %y, i32 %E, i32 %H, i32 %C) nounwind {
21entry:
22  %ptr = alloca ptr, align 8
23  %0 = alloca i8, i64 %x, align 16
24  store ptr %0, ptr %ptr, align 8
25  call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C)
26  %1 = load ptr, ptr %ptr, align 8
27  %arrayidx = getelementptr inbounds i8, ptr %1, i64 %y
28  store volatile i8 42, ptr %arrayidx, align 1
29  ret void
30}
31; CHECK-LABEL: test_baseptr:
32; USE_BASE_64: movq %rsp, %rbx
33; Pass mwaitx first 2 arguments in eax and ecx respectively.
34; USE_BASE_64: movl %ecx, %eax
35; USE_BASE_64: movl %edx, %ecx
36; Save base pointer.
37; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]]
38; Set mwaitx ebx argument.
39; USE_BASE_64: movl %r8d, %ebx
40; USE_BASE_64-NEXT: mwaitx
41; Restore base pointer.
42; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx
43
44; USE_BASE_32: movl %esp, %ebx
45; Pass mwaitx first 2 arguments in eax and ecx respectively.
46; USE_BASE_32: movl %ecx, %eax
47; USE_BASE_32: movl %edx, %ecx
48; Save base pointer.
49; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]]
50; Set mwaitx ebx argument.
51; USE_BASE_32: movl %r8d, %ebx
52; USE_BASE_32-NEXT: mwaitx
53; Restore base pointer.
54; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx
55
56; Pass mwaitx 3 arguments in eax, ecx, ebx
57; NO_BASE_64: movl %r8d, %ebx
58; NO_BASE_64: movl %ecx, %eax
59; NO_BASE_64: movl %edx, %ecx
60; No need to save base pointer.
61; NO_BASE_64-NOT: movq %rbx
62; NO_BASE_64: mwaitx
63; No need to restore base pointer.
64; NO_BASE_64-NOT: movq {{.*}}, %rbx
65; NO_BASE_64-NEXT: {{.+$}}
66
67; Pass mwaitx 3 arguments in eax, ecx, ebx
68; NO_BASE_32: movl %r8d, %ebx
69; NO_BASE_32: movl %ecx, %eax
70; NO_BASE_32: movl %edx, %ecx
71; No need to save base pointer.
72; NO_BASE_32-NOT: movl %ebx
73; NO_BASE_32: mwaitx
74; No need to restore base pointer.
75; NO_BASE_32-NOT: movl {{.*}}, %ebx
76; NO_BASE_32-NEXT: {{.+$}}
77
78; Test of the case where an opaque sp adjustement is introduced by a separate
79; basic block which, combined with stack realignment, requires a base pointer.
80@g = global i32 0, align 8
81
82define void @test_opaque_sp_adjustment(i32 %E, i32 %H, i32 %C, i64 %x) {
83entry:
84  %ptr = alloca ptr, align 8
85  call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C)
86  %g = load i32, ptr @g, align 4
87  %tobool = icmp ne i32 %g, 0
88  br i1 %tobool, label %if.then, label %if.end
89
90if.then:
91  call void asm sideeffect "", "~{rsp},~{esp},~{dirflag},~{fpsr},~{flags}"()
92  br label %if.end
93
94if.end:
95  %ptr2 = load ptr, ptr %ptr, align 8
96  %arrayidx = getelementptr inbounds i8, ptr %ptr2, i64 %x
97  store volatile i8 42, ptr %arrayidx, align 1
98  ret void
99}
100; CHECK-LABEL: test_opaque_sp_adjustment:
101; USE_BASE_64: movq %rsp, %rbx
102; Pass mwaitx first 2 arguments in eax and ecx respectively.
103; USE_BASE_64: movl %esi, %eax
104; USE_BASE_64: movl %edi, %ecx
105; Save base pointer.
106; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]]
107; Set mwaitx ebx argument.
108; USE_BASE_64: movl %edx, %ebx
109; USE_BASE_64-NEXT: mwaitx
110; Restore base pointer.
111; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx
112
113; USE_BASE_32: movl %esp, %ebx
114; Pass mwaitx first 2 arguments in eax and ecx respectively.
115; USE_BASE_32: movl %esi, %eax
116; USE_BASE_32: movl %edi, %ecx
117; Save base pointer.
118; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]]
119; Set mwaitx ebx argument.
120; USE_BASE_32: movl %edx, %ebx
121; USE_BASE_32-NEXT: mwaitx
122; Restore base pointer.
123; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx
124
125; Pass mwaitx 3 arguments in eax, ecx, ebx
126; NO_BASE_64: movl %edx, %ebx
127; NO_BASE_64: movl %esi, %eax
128; NO_BASE_64: movl %edi, %ecx
129; No need to save base pointer.
130; NO_BASE_64-NOT: movq %rbx
131; NO_BASE_64: mwaitx
132; NO_BASE_64-NOT: movq {{.*}}, %rbx
133; NO_BASE_64-NEXT: {{.+$}}
134
135; Pass mwaitx 3 arguments in eax, ecx, ebx
136; NO_BASE_32: movl %edx, %ebx
137; NO_BASE_32: movl %esi, %eax
138; NO_BASE_32: movl %edi, %ecx
139; No need to save base pointer.
140; NO_BASE_32-NOT: movl %ebx
141; NO_BASE_32: mwaitx
142; No need to restore base pointer.
143; NO_BASE_32-NOT: movl {{.*}}, %ebx
144; NO_BASE_32-NEXT: {{.+$}}
145
146; Test of the case where a variable size object is introduced by a separate
147; basic block which, combined with stack realignment, requires a base pointer.
148define void @test_variable_size_object(i32 %E, i32 %H, i32 %C, i64 %x) {
149entry:
150  %ptr = alloca ptr, align 8
151  call void @llvm.x86.mwaitx(i32 %E, i32 %H, i32 %C)
152  %g = load i32, ptr @g, align 4
153  %tobool = icmp ne i32 %g, 0
154  br i1 %tobool, label %if.then, label %if.end
155
156if.then:
157  %i5 = alloca i8, i64 %x, align 16
158  store ptr %i5, ptr %ptr, align 8
159  br label %if.end
160
161if.end:
162  %ptr2 = load ptr, ptr %ptr, align 8
163  %arrayidx = getelementptr inbounds i8, ptr %ptr2, i64 %x
164  store volatile i8 42, ptr %arrayidx, align 1
165  ret void
166}
167
168; CHECK-LABEL: test_variable_size_object:
169; USE_BASE_64: movq %rsp, %rbx
170; Pass mwaitx first 2 arguments in eax and ecx respectively.
171; USE_BASE_64: movl %esi, %eax
172; USE_BASE_64: movl %edi, %ecx
173; Save base pointer.
174; USE_BASE_64: movq %rbx, [[SAVE_rbx:%r([8-9]|1[0-5]|di|si)]]
175; Set mwaitx ebx argument.
176; USE_BASE_64: movl %edx, %ebx
177; USE_BASE_64-NEXT: mwaitx
178; Restore base pointer.
179; USE_BASE_64-NEXT: movq [[SAVE_rbx]], %rbx
180
181; USE_BASE_32: movl %esp, %ebx
182; Pass mwaitx first 2 arguments in eax and ecx respectively.
183; USE_BASE_32: movl %esi, %eax
184; USE_BASE_32: movl %edi, %ecx
185; Save base pointer.
186; USE_BASE_32: movq %rbx, [[SAVE_rbx:%r(di|si)]]
187; Set mwaitx ebx argument.
188; USE_BASE_32: movl %edx, %ebx
189; USE_BASE_32-NEXT: mwaitx
190; Restore base pointer.
191; USE_BASE_32-NEXT: movq [[SAVE_rbx]], %rbx
192
193; Pass mwaitx 3 arguments in eax, ecx, ebx
194; NO_BASE_64: movl %edx, %ebx
195; NO_BASE_64: movl %esi, %eax
196; NO_BASE_64: movl %edi, %ecx
197; No need to save base pointer.
198; NO_BASE_64-NOT: movq %rbx
199; NO_BASE_64: mwaitx
200; NO_BASE_64-NOT: movq {{.*}}, %rbx
201; NO_BASE_64-NEXT: {{.+$}}
202
203; Pass mwaitx 3 arguments in eax, ecx, ebx
204; NO_BASE_32: movl %edx, %ebx
205; NO_BASE_32: movl %esi, %eax
206; NO_BASE_32: movl %edi, %ecx
207; No need to save base pointer.
208; NO_BASE_32-NOT: movl %ebx
209; NO_BASE_32: mwaitx
210; No need to restore base pointer.
211; NO_BASE_32-NOT: movl {{.*}}, %ebx
212; NO_BASE_32-NEXT: {{.+$}}
213
214declare void @llvm.x86.mwaitx(i32, i32, i32) nounwind
215;--- _align32.ll
216!llvm.module.flags = !{!0}
217!0 = !{i32 2, !"override-stack-alignment", i32 32}
218