1; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s --check-prefix=CHECK --check-prefix=PUSHF
2; RUN: llc < %s -mtriple=x86_64-pc-win32 -mattr=+sahf | FileCheck %s --check-prefix=SAHF
3
4define i32 @f1(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) "no-frame-pointer-elim"="true" {
5  ; CHECK-LABEL: f1:
6  ; CHECK:       movl    48(%rbp), %eax
7  ret i32 %p5
8}
9
10define void @f2(i32 %p, ...) "no-frame-pointer-elim"="true" {
11  ; CHECK-LABEL: f2:
12  ; CHECK:      .seh_stackalloc 8
13  ; CHECK:      movq    %rsp, %rbp
14  ; CHECK:      .seh_setframe 5, 0
15  ; CHECK:      movq    %rdx, 32(%rbp)
16  ; CHECK:      leaq    32(%rbp), %rax
17  %ap = alloca i8, align 8
18  call void @llvm.va_start(i8* %ap)
19  ret void
20}
21
22define i8* @f3() "no-frame-pointer-elim"="true" {
23  ; CHECK-LABEL: f3:
24  ; CHECK:      movq    %rsp, %rbp
25  ; CHECK:      .seh_setframe 5, 0
26  ; CHECK:      movq    8(%rbp), %rax
27  %ra = call i8* @llvm.returnaddress(i32 0)
28  ret i8* %ra
29}
30
31define i8* @f4() "no-frame-pointer-elim"="true" {
32  ; CHECK-LABEL: f4:
33  ; CHECK:      pushq   %rbp
34  ; CHECK:      .seh_pushreg 5
35  ; CHECK:      subq    $304, %rsp
36  ; CHECK:      .seh_stackalloc 304
37  ; CHECK:      leaq    128(%rsp), %rbp
38  ; CHECK:      .seh_setframe 5, 128
39  ; CHECK:      .seh_endprologue
40  ; CHECK:      movq    184(%rbp), %rax
41  alloca [300 x i8]
42  %ra = call i8* @llvm.returnaddress(i32 0)
43  ret i8* %ra
44}
45
46declare void @external(i8*)
47
48define void @f5() "no-frame-pointer-elim"="true" {
49  ; CHECK-LABEL: f5:
50  ; CHECK:      subq    $336, %rsp
51  ; CHECK:      .seh_stackalloc 336
52  ; CHECK:      leaq    128(%rsp), %rbp
53  ; CHECK:      .seh_setframe 5, 128
54  ; CHECK:      leaq    -92(%rbp), %rcx
55  ; CHECK:      callq   external
56  %a = alloca [300 x i8]
57  %gep = getelementptr [300 x i8], [300 x i8]* %a, i32 0, i32 0
58  call void @external(i8* %gep)
59  ret void
60}
61
62define void @f6(i32 %p, ...) "no-frame-pointer-elim"="true" {
63  ; CHECK-LABEL: f6:
64  ; CHECK:      subq    $336, %rsp
65  ; CHECK:      .seh_stackalloc 336
66  ; CHECK:      leaq    128(%rsp), %rbp
67  ; CHECK:      .seh_setframe 5, 128
68  ; CHECK:      leaq    -92(%rbp), %rcx
69  ; CHECK:      callq   external
70  %a = alloca [300 x i8]
71  %gep = getelementptr [300 x i8], [300 x i8]* %a, i32 0, i32 0
72  call void @external(i8* %gep)
73  ret void
74}
75
76define i32 @f7(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "no-frame-pointer-elim"="true" {
77  ; CHECK-LABEL: f7:
78  ; CHECK:      pushq   %rbp
79  ; CHECK:      .seh_pushreg 5
80  ; CHECK:      subq    $304, %rsp
81  ; CHECK:      .seh_stackalloc 304
82  ; CHECK:      leaq    128(%rsp), %rbp
83  ; CHECK:      .seh_setframe 5, 128
84  ; CHECK:      andq    $-64, %rsp
85  ; CHECK:      movl    224(%rbp), %eax
86  ; CHECK:      leaq    176(%rbp), %rsp
87  alloca [300 x i8], align 64
88  ret i32 %e
89}
90
91define i32 @f8(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "no-frame-pointer-elim"="true" {
92  ; CHECK-LABEL: f8:
93  ; CHECK:        subq    $352, %rsp
94  ; CHECK:        .seh_stackalloc 352
95  ; CHECK:        leaq    128(%rsp), %rbp
96  ; CHECK:        .seh_setframe 5, 128
97
98  %alloca = alloca [300 x i8], align 64
99  ; CHECK:        andq    $-64, %rsp
100  ; CHECK:        movq    %rsp, %rbx
101
102  alloca i32, i32 %a
103  ; CHECK:        movl    %ecx, %eax
104  ; CHECK:        leaq    15(,%rax,4), %rcx
105  ; CHECK:        movabsq $34359738352, %rax
106  ; CHECK:        andq    %rcx, %rax
107  ; CHECK:        callq   __chkstk
108  ; CHECK:        subq    %rax, %rsp
109
110  %gep = getelementptr [300 x i8], [300 x i8]* %alloca, i32 0, i32 0
111  call void @external(i8* %gep)
112  ; CHECK:        subq    $32, %rsp
113  ; CHECK:        leaq    (%rbx), %rcx
114  ; CHECK:        callq   external
115  ; CHECK:        addq    $32, %rsp
116
117  ret i32 %e
118  ; CHECK:        movl    %esi, %eax
119  ; CHECK:        leaq    224(%rbp), %rsp
120}
121
122define i64 @f9() {
123entry:
124  ; CHECK-LABEL: f9:
125  ; CHECK:      pushq   %rbp
126  ; CHECK:      .seh_pushreg 5
127  ; CHECK-NEXT: movq    %rsp, %rbp
128  ; CHECK:      .seh_setframe 5, 0
129  ; CHECK:      .seh_endprologue
130
131  %call = call i64 @llvm.x86.flags.read.u64()
132  ; CHECK-NEXT: pushfq
133  ; CHECK-NEXT: popq    %rax
134
135  ret i64 %call
136  ; CHECK-NEXT: popq    %rbp
137  ; CHECK-NEXT: retq
138}
139
140declare i64 @dummy()
141
142define i64 @f10(i64* %foo, i64 %bar, i64 %baz) {
143  ; CHECK-LABEL: f10:
144  ; CHECK:      pushq   %rbp
145  ; CHECK:      .seh_pushreg 5
146  ; CHECK:      pushq   %rsi
147  ; CHECK:      .seh_pushreg 6
148  ; CHECK:      pushq   %rdi
149  ; CHECK:      .seh_pushreg 7
150  ; CHECK:      subq    $32, %rsp
151  ; CHECK:      .seh_stackalloc 32
152  ; CHECK:      leaq    32(%rsp), %rbp
153  ; CHECK:      .seh_setframe 5, 32
154  ; CHECK:      .seh_endprologue
155
156  %cx = cmpxchg i64* %foo, i64 %bar, i64 %baz seq_cst seq_cst
157  ; PUSHF:      lock cmpxchgq
158  ; PUSHF-NEXT: pushfq
159  ; PUSHF-NEXT: popq %[[REG:.*]]
160  ; SAHF:       lock cmpxchgq
161  ; SAHF-NEXT:  seto    %al
162  ; SAHF-NEXT:  lahf
163
164  %v = extractvalue { i64, i1 } %cx, 0
165  %p = extractvalue { i64, i1 } %cx, 1
166
167  %call = call i64 @dummy()
168  ; PUSHF:      callq dummy
169  ; PUSHF-NEXT: pushq %[[REG]]
170  ; PUSHF-NEXT: popfq
171  ; SAHF:       callq dummy
172  ; SAHF-NEXT:  pushq
173  ; SAHF:       addb $127, %al
174  ; SAHF-NEXT:  sahf
175  ; SAHF-NEXT:  popq
176
177  %sel = select i1 %p, i64 %call, i64 %bar
178  ; CHECK-NEXT: cmovneq
179
180  ret i64 %sel
181  ; CHECK-NEXT: addq    $32, %rsp
182  ; CHECK-NEXT: popq    %rdi
183  ; CHECK-NEXT: popq    %rsi
184  ; CHECK-NEXT: popq    %rbp
185}
186
187declare i8* @llvm.returnaddress(i32) nounwind readnone
188declare i64 @llvm.x86.flags.read.u64()
189
190declare void @llvm.va_start(i8*) nounwind
191