1; RUN: llc -mtriple=i686-windows < %s | FileCheck %s 2 3declare void @addrof_i1(i1*) 4declare void @addrof_i32(i32*) 5declare void @addrof_i64(i64*) 6declare void @addrof_i128(i128*) 7declare void @addrof_i32_x3(i32*, i32*, i32*) 8 9define void @simple(i32 %x) { 10entry: 11 %x.addr = alloca i32 12 store i32 %x, i32* %x.addr 13 call void @addrof_i32(i32* %x.addr) 14 ret void 15} 16 17; CHECK-LABEL: _simple: 18; CHECK: leal 4(%esp), %[[reg:[^ ]*]] 19; CHECK: pushl %[[reg]] 20; CHECK: calll _addrof_i32 21; CHECK: retl 22 23 24; We need to load %x before calling addrof_i32 now because it could mutate %x in 25; place. 26 27define i32 @use_arg(i32 %x) { 28entry: 29 %x.addr = alloca i32 30 store i32 %x, i32* %x.addr 31 call void @addrof_i32(i32* %x.addr) 32 ret i32 %x 33} 34 35; CHECK-LABEL: _use_arg: 36; CHECK: pushl %[[csr:[^ ]*]] 37; CHECK-DAG: movl 8(%esp), %[[csr]] 38; CHECK-DAG: leal 8(%esp), %[[reg:[^ ]*]] 39; CHECK: pushl %[[reg]] 40; CHECK: calll _addrof_i32 41; CHECK: movl %[[csr]], %eax 42; CHECK: popl %[[csr]] 43; CHECK: retl 44 45; We won't copy elide for types needing legalization such as i64 or i1. 46 47define i64 @split_i64(i64 %x) { 48entry: 49 %x.addr = alloca i64, align 4 50 store i64 %x, i64* %x.addr, align 4 51 call void @addrof_i64(i64* %x.addr) 52 ret i64 %x 53} 54 55; CHECK-LABEL: _split_i64: 56; CHECK: pushl %ebp 57; CHECK: movl %esp, %ebp 58; CHECK: pushl %[[csr2:[^ ]*]] 59; CHECK: pushl %[[csr1:[^ ]*]] 60; CHECK: andl $-8, %esp 61; CHECK-DAG: movl 8(%ebp), %[[csr1]] 62; CHECK-DAG: movl 12(%ebp), %[[csr2]] 63; CHECK-DAG: leal 8(%ebp), %[[reg:[^ ]*]] 64; CHECK: pushl %[[reg]] 65; CHECK: calll _addrof_i64 66; CHECK-DAG: movl %[[csr1]], %eax 67; CHECK-DAG: movl %[[csr2]], %edx 68; CHECK: leal -8(%ebp), %esp 69; CHECK: popl %[[csr1]] 70; CHECK: popl %[[csr2]] 71; CHECK: popl %ebp 72; CHECK: retl 73 74define i1 @i1_arg(i1 %x) { 75 %x.addr = alloca i1 76 store i1 %x, i1* %x.addr 77 call void @addrof_i1(i1* %x.addr) 78 ret i1 %x 79} 80 81; CHECK-LABEL: _i1_arg: 82; CHECK: pushl %ebx 83; CHECK: movb 8(%esp), %bl 84; CHECK: leal 8(%esp), %eax 85; CHECK: pushl %eax 86; CHECK: calll _addrof_i1 87; CHECK: addl $4, %esp 88; CHECK: movl %ebx, %eax 89; CHECK: popl %ebx 90; CHECK: retl 91 92; We can't copy elide when an i64 is split between registers and memory in a 93; fastcc function. 94 95define fastcc i64 @fastcc_split_i64(i64* %p, i64 %x) { 96entry: 97 %x.addr = alloca i64, align 4 98 store i64 %x, i64* %x.addr, align 4 99 call void @addrof_i64(i64* %x.addr) 100 ret i64 %x 101} 102 103; CHECK-LABEL: _fastcc_split_i64: 104; CHECK: pushl %ebp 105; CHECK: movl %esp, %ebp 106; CHECK-DAG: movl %edx, %[[r1:[^ ]*]] 107; CHECK-DAG: movl 8(%ebp), %[[r2:[^ ]*]] 108; CHECK-DAG: movl %[[r2]], 4(%esp) 109; CHECK-DAG: movl %edx, (%esp) 110; CHECK: movl %esp, %[[reg:[^ ]*]] 111; CHECK: pushl %[[reg]] 112; CHECK: calll _addrof_i64 113; CHECK: popl %ebp 114; CHECK: retl 115 116 117; We can't copy elide when it would reduce the user requested alignment. 118 119define void @high_alignment(i32 %x) { 120entry: 121 %x.p = alloca i32, align 128 122 store i32 %x, i32* %x.p 123 call void @addrof_i32(i32* %x.p) 124 ret void 125} 126 127; CHECK-LABEL: _high_alignment: 128; CHECK: andl $-128, %esp 129; CHECK: movl 8(%ebp), %[[reg:[^ ]*]] 130; CHECK: movl %[[reg]], (%esp) 131; CHECK: movl %esp, %[[reg:[^ ]*]] 132; CHECK: pushl %[[reg]] 133; CHECK: calll _addrof_i32 134; CHECK: retl 135 136 137; We can't copy elide when it would reduce the ABI required alignment. 138; FIXME: We should lower the ABI alignment of i64 on Windows, since MSVC 139; doesn't guarantee it. 140 141define void @abi_alignment(i64 %x) { 142entry: 143 %x.p = alloca i64 144 store i64 %x, i64* %x.p 145 call void @addrof_i64(i64* %x.p) 146 ret void 147} 148 149; CHECK-LABEL: _abi_alignment: 150; CHECK: andl $-8, %esp 151; CHECK: movl 8(%ebp), %[[reg:[^ ]*]] 152; CHECK: movl %[[reg]], (%esp) 153; CHECK: movl %esp, %[[reg:[^ ]*]] 154; CHECK: pushl %[[reg]] 155; CHECK: calll _addrof_i64 156; CHECK: retl 157 158 159; The code we generate for this is unimportant. This is mostly a crash test. 160 161define void @split_i128(i128* %sret, i128 %x) { 162entry: 163 %x.addr = alloca i128 164 store i128 %x, i128* %x.addr 165 call void @addrof_i128(i128* %x.addr) 166 store i128 %x, i128* %sret 167 ret void 168} 169 170; CHECK-LABEL: _split_i128: 171; CHECK: pushl %ebp 172; CHECK: calll _addrof_i128 173; CHECK: retl 174 175 176; Check that we load all of x, y, and z before the call. 177 178define i32 @three_args(i32 %x, i32 %y, i32 %z) { 179entry: 180 %z.addr = alloca i32, align 4 181 %y.addr = alloca i32, align 4 182 %x.addr = alloca i32, align 4 183 store i32 %z, i32* %z.addr, align 4 184 store i32 %y, i32* %y.addr, align 4 185 store i32 %x, i32* %x.addr, align 4 186 call void @addrof_i32_x3(i32* %x.addr, i32* %y.addr, i32* %z.addr) 187 %s1 = add i32 %x, %y 188 %sum = add i32 %s1, %z 189 ret i32 %sum 190} 191 192; CHECK-LABEL: _three_args: 193; CHECK: pushl %[[csr:[^ ]*]] 194; CHECK-DAG: movl {{[0-9]+}}(%esp), %[[csr]] 195; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]] 196; CHECK-DAG: addl {{[0-9]+}}(%esp), %[[csr]] 197; CHECK-DAG: leal 8(%esp), %[[x:[^ ]*]] 198; CHECK-DAG: leal 12(%esp), %[[y:[^ ]*]] 199; CHECK-DAG: leal 16(%esp), %[[z:[^ ]*]] 200; CHECK: pushl %[[z]] 201; CHECK: pushl %[[y]] 202; CHECK: pushl %[[x]] 203; CHECK: calll _addrof_i32_x3 204; CHECK: movl %[[csr]], %eax 205; CHECK: popl %[[csr]] 206; CHECK: retl 207 208 209define void @two_args_same_alloca(i32 %x, i32 %y) { 210entry: 211 %x.addr = alloca i32 212 store i32 %x, i32* %x.addr 213 store i32 %y, i32* %x.addr 214 call void @addrof_i32(i32* %x.addr) 215 ret void 216} 217 218; CHECK-LABEL: _two_args_same_alloca: 219; CHECK: movl 8(%esp), {{.*}} 220; CHECK: movl {{.*}}, 4(%esp) 221; CHECK: leal 4(%esp), %[[reg:[^ ]*]] 222; CHECK: pushl %[[reg]] 223; CHECK: calll _addrof_i32 224; CHECK: retl 225 226 227define void @avoid_byval(i32* byval %x) { 228entry: 229 %x.p.p = alloca i32* 230 store i32* %x, i32** %x.p.p 231 call void @addrof_i32(i32* %x) 232 ret void 233} 234 235; CHECK-LABEL: _avoid_byval: 236; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]] 237; CHECK: pushl %[[reg]] 238; CHECK: calll _addrof_i32 239; CHECK: retl 240 241 242define void @avoid_inalloca(i32* inalloca %x) { 243entry: 244 %x.p.p = alloca i32* 245 store i32* %x, i32** %x.p.p 246 call void @addrof_i32(i32* %x) 247 ret void 248} 249 250; CHECK-LABEL: _avoid_inalloca: 251; CHECK: leal {{[0-9]+}}(%esp), %[[reg:[^ ]*]] 252; CHECK: pushl %[[reg]] 253; CHECK: calll _addrof_i32 254; CHECK: retl 255 256; Don't elide the copy when the alloca is escaped with a store. 257define void @escape_with_store(i32 %x) { 258 %x1 = alloca i32 259 %x2 = alloca i32* 260 store i32* %x1, i32** %x2 261 %x3 = load i32*, i32** %x2 262 store i32 0, i32* %x3 263 store i32 %x, i32* %x1 264 call void @addrof_i32(i32* %x1) 265 ret void 266} 267 268; CHECK-LABEL: _escape_with_store: 269; CHECK: movl {{.*}}(%esp), %[[reg:[^ ]*]] 270; CHECK: movl %[[reg]], [[offs:[0-9]*]](%esp) 271; CHECK: calll _addrof_i32 272 273 274; This test case exposed issues with the use of TokenFactor. 275 276define void @sret_and_elide(i32* sret %sret, i32 %v) { 277 %v.p = alloca i32 278 store i32 %v, i32* %v.p 279 call void @addrof_i32(i32* %v.p) 280 store i32 %v, i32* %sret 281 ret void 282} 283 284; CHECK-LABEL: _sret_and_elide: 285; CHECK: pushl 286; CHECK: pushl 287; CHECK: movl 12(%esp), %[[sret:[^ ]*]] 288; CHECK: movl 16(%esp), %[[v:[^ ]*]] 289; CHECK: leal 16(%esp), %[[reg:[^ ]*]] 290; CHECK: pushl %[[reg]] 291; CHECK: calll _addrof_i32 292; CHECK: movl %[[v]], (%[[sret]]) 293; CHECK: movl %[[sret]], %eax 294; CHECK: popl 295; CHECK: popl 296; CHECK: retl 297