1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s --mtriple=wasm32-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=32 %s --check-prefix=CHECK-32 3; RUN: llc < %s --mtriple=wasm64-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=64 %s --check-prefix=CHECK-64 4 5declare void @ext_func(ptr %ptr) 6declare void @ext_func_i32(ptr %ptr) 7 8; Check that there is an extra local for the stack pointer. 9define void @alloca32() noredzone { 10; CHECK-32-LABEL: alloca32: 11; CHECK-32: .functype alloca32 () -> () 12; CHECK-32-NEXT: .local i32 13; CHECK-32-NEXT: # %bb.0: 14; CHECK-32-NEXT: global.get $push1=, __stack_pointer 15; CHECK-32-NEXT: i32.const $push2=, 16 16; CHECK-32-NEXT: i32.sub $push6=, $pop1, $pop2 17; CHECK-32-NEXT: local.tee $push5=, 0, $pop6 18; CHECK-32-NEXT: global.set __stack_pointer, $pop5 19; CHECK-32-NEXT: local.get $push7=, 0 20; CHECK-32-NEXT: i32.const $push0=, 0 21; CHECK-32-NEXT: i32.store 12($pop7), $pop0 22; CHECK-32-NEXT: local.get $push8=, 0 23; CHECK-32-NEXT: i32.const $push3=, 16 24; CHECK-32-NEXT: i32.add $push4=, $pop8, $pop3 25; CHECK-32-NEXT: global.set __stack_pointer, $pop4 26; CHECK-32-NEXT: return 27; 28; CHECK-64-LABEL: alloca32: 29; CHECK-64: .functype alloca32 () -> () 30; CHECK-64-NEXT: .local i64 31; CHECK-64-NEXT: # %bb.0: 32; CHECK-64-NEXT: global.get $push1=, __stack_pointer 33; CHECK-64-NEXT: i64.const $push2=, 16 34; CHECK-64-NEXT: i64.sub $push6=, $pop1, $pop2 35; CHECK-64-NEXT: local.tee $push5=, 0, $pop6 36; CHECK-64-NEXT: global.set __stack_pointer, $pop5 37; CHECK-64-NEXT: local.get $push7=, 0 38; CHECK-64-NEXT: i32.const $push0=, 0 39; CHECK-64-NEXT: i32.store 12($pop7), $pop0 40; CHECK-64-NEXT: local.get $push8=, 0 41; CHECK-64-NEXT: i64.const $push3=, 16 42; CHECK-64-NEXT: i64.add $push4=, $pop8, $pop3 43; CHECK-64-NEXT: global.set __stack_pointer, $pop4 44; CHECK-64-NEXT: return 45 %retval = alloca i32 46 store i32 0, ptr %retval 47 ret void 48} 49 50define void @alloca3264() { 51; CHECK-32-LABEL: alloca3264: 52; CHECK-32: .functype alloca3264 () -> () 53; CHECK-32-NEXT: .local i32 54; CHECK-32-NEXT: # %bb.0: 55; CHECK-32-NEXT: global.get $push2=, __stack_pointer 56; CHECK-32-NEXT: i32.const $push3=, 16 57; CHECK-32-NEXT: i32.sub $push5=, $pop2, $pop3 58; CHECK-32-NEXT: local.tee $push4=, 0, $pop5 59; CHECK-32-NEXT: i64.const $push0=, 0 60; CHECK-32-NEXT: i64.store 0($pop4), $pop0 61; CHECK-32-NEXT: local.get $push6=, 0 62; CHECK-32-NEXT: i32.const $push1=, 0 63; CHECK-32-NEXT: i32.store 12($pop6), $pop1 64; CHECK-32-NEXT: return 65; 66; CHECK-64-LABEL: alloca3264: 67; CHECK-64: .functype alloca3264 () -> () 68; CHECK-64-NEXT: .local i64 69; CHECK-64-NEXT: # %bb.0: 70; CHECK-64-NEXT: global.get $push2=, __stack_pointer 71; CHECK-64-NEXT: i64.const $push3=, 16 72; CHECK-64-NEXT: i64.sub $push5=, $pop2, $pop3 73; CHECK-64-NEXT: local.tee $push4=, 0, $pop5 74; CHECK-64-NEXT: i64.const $push0=, 0 75; CHECK-64-NEXT: i64.store 0($pop4), $pop0 76; CHECK-64-NEXT: local.get $push6=, 0 77; CHECK-64-NEXT: i32.const $push1=, 0 78; CHECK-64-NEXT: i32.store 12($pop6), $pop1 79; CHECK-64-NEXT: return 80 %r1 = alloca i32 81 %r2 = alloca double 82 store i32 0, ptr %r1 83 store double 0.0, ptr %r2 84 ret void 85} 86 87define void @allocarray() { 88; CHECK-32-LABEL: allocarray: 89; CHECK-32: .functype allocarray () -> () 90; CHECK-32-NEXT: .local i32 91; CHECK-32-NEXT: # %bb.0: 92; CHECK-32-NEXT: global.get $push3=, __stack_pointer 93; CHECK-32-NEXT: i32.const $push4=, 144 94; CHECK-32-NEXT: i32.sub $push9=, $pop3, $pop4 95; CHECK-32-NEXT: local.tee $push8=, 0, $pop9 96; CHECK-32-NEXT: global.set __stack_pointer, $pop8 97; CHECK-32-NEXT: local.get $push10=, 0 98; CHECK-32-NEXT: i32.const $push0=, 24 99; CHECK-32-NEXT: i32.add $push1=, $pop10, $pop0 100; CHECK-32-NEXT: i32.const $push2=, 1 101; CHECK-32-NEXT: i32.store 0($pop1), $pop2 102; CHECK-32-NEXT: local.get $push11=, 0 103; CHECK-32-NEXT: i32.const $push7=, 1 104; CHECK-32-NEXT: i32.store 12($pop11), $pop7 105; CHECK-32-NEXT: local.get $push12=, 0 106; CHECK-32-NEXT: i32.const $push5=, 144 107; CHECK-32-NEXT: i32.add $push6=, $pop12, $pop5 108; CHECK-32-NEXT: global.set __stack_pointer, $pop6 109; CHECK-32-NEXT: return 110; 111; CHECK-64-LABEL: allocarray: 112; CHECK-64: .functype allocarray () -> () 113; CHECK-64-NEXT: .local i64 114; CHECK-64-NEXT: # %bb.0: 115; CHECK-64-NEXT: global.get $push3=, __stack_pointer 116; CHECK-64-NEXT: i64.const $push4=, 144 117; CHECK-64-NEXT: i64.sub $push9=, $pop3, $pop4 118; CHECK-64-NEXT: local.tee $push8=, 0, $pop9 119; CHECK-64-NEXT: global.set __stack_pointer, $pop8 120; CHECK-64-NEXT: local.get $push10=, 0 121; CHECK-64-NEXT: i64.const $push0=, 24 122; CHECK-64-NEXT: i64.add $push1=, $pop10, $pop0 123; CHECK-64-NEXT: i32.const $push2=, 1 124; CHECK-64-NEXT: i32.store 0($pop1), $pop2 125; CHECK-64-NEXT: local.get $push11=, 0 126; CHECK-64-NEXT: i32.const $push7=, 1 127; CHECK-64-NEXT: i32.store 12($pop11), $pop7 128; CHECK-64-NEXT: local.get $push12=, 0 129; CHECK-64-NEXT: i64.const $push5=, 144 130; CHECK-64-NEXT: i64.add $push6=, $pop12, $pop5 131; CHECK-64-NEXT: global.set __stack_pointer, $pop6 132; CHECK-64-NEXT: return 133 %r = alloca [33 x i32] 134 store i32 1, ptr %r 135 %p2 = getelementptr [33 x i32], ptr %r, i32 0, i32 3 136 store i32 1, ptr %p2 137 ret void 138} 139 140define void @non_mem_use(ptr %addr) { 141; CHECK-32-LABEL: non_mem_use: 142; CHECK-32: .functype non_mem_use (i32) -> () 143; CHECK-32-NEXT: .local i32 144; CHECK-32-NEXT: # %bb.0: 145; CHECK-32-NEXT: global.get $push0=, __stack_pointer 146; CHECK-32-NEXT: i32.const $push1=, 48 147; CHECK-32-NEXT: i32.sub $push9=, $pop0, $pop1 148; CHECK-32-NEXT: local.tee $push8=, 1, $pop9 149; CHECK-32-NEXT: global.set __stack_pointer, $pop8 150; CHECK-32-NEXT: local.get $push10=, 1 151; CHECK-32-NEXT: i32.const $push6=, 8 152; CHECK-32-NEXT: i32.add $push7=, $pop10, $pop6 153; CHECK-32-NEXT: call ext_func, $pop7 154; CHECK-32-NEXT: local.get $push11=, 1 155; CHECK-32-NEXT: call ext_func, $pop11 156; CHECK-32-NEXT: local.get $push13=, 0 157; CHECK-32-NEXT: local.get $push12=, 1 158; CHECK-32-NEXT: i32.const $push4=, 16 159; CHECK-32-NEXT: i32.add $push5=, $pop12, $pop4 160; CHECK-32-NEXT: i32.store 0($pop13), $pop5 161; CHECK-32-NEXT: local.get $push14=, 1 162; CHECK-32-NEXT: i32.const $push2=, 48 163; CHECK-32-NEXT: i32.add $push3=, $pop14, $pop2 164; CHECK-32-NEXT: global.set __stack_pointer, $pop3 165; CHECK-32-NEXT: return 166; 167; CHECK-64-LABEL: non_mem_use: 168; CHECK-64: .functype non_mem_use (i64) -> () 169; CHECK-64-NEXT: .local i64 170; CHECK-64-NEXT: # %bb.0: 171; CHECK-64-NEXT: global.get $push0=, __stack_pointer 172; CHECK-64-NEXT: i64.const $push1=, 48 173; CHECK-64-NEXT: i64.sub $push9=, $pop0, $pop1 174; CHECK-64-NEXT: local.tee $push8=, 1, $pop9 175; CHECK-64-NEXT: global.set __stack_pointer, $pop8 176; CHECK-64-NEXT: local.get $push10=, 1 177; CHECK-64-NEXT: i64.const $push6=, 8 178; CHECK-64-NEXT: i64.add $push7=, $pop10, $pop6 179; CHECK-64-NEXT: call ext_func, $pop7 180; CHECK-64-NEXT: local.get $push11=, 1 181; CHECK-64-NEXT: call ext_func, $pop11 182; CHECK-64-NEXT: local.get $push13=, 0 183; CHECK-64-NEXT: local.get $push12=, 1 184; CHECK-64-NEXT: i64.const $push4=, 16 185; CHECK-64-NEXT: i64.add $push5=, $pop12, $pop4 186; CHECK-64-NEXT: i64.store 0($pop13), $pop5 187; CHECK-64-NEXT: local.get $push14=, 1 188; CHECK-64-NEXT: i64.const $push2=, 48 189; CHECK-64-NEXT: i64.add $push3=, $pop14, $pop2 190; CHECK-64-NEXT: global.set __stack_pointer, $pop3 191; CHECK-64-NEXT: return 192 %buf = alloca [27 x i8], align 16 193 %r = alloca i64 194 %r2 = alloca i64 195 ; %r is at SP+8 196 call void @ext_func(ptr %r) 197 ; %r2 is at SP+0, no add needed 198 call void @ext_func(ptr %r2) 199 ; Use as a value, but in a store 200 ; %buf is at SP+16 201 store ptr %buf, ptr %addr 202 ret void 203} 204 205define void @allocarray_inbounds() { 206; CHECK-32-LABEL: allocarray_inbounds: 207; CHECK-32: .functype allocarray_inbounds () -> () 208; CHECK-32-NEXT: .local i32 209; CHECK-32-NEXT: # %bb.0: 210; CHECK-32-NEXT: global.get $push2=, __stack_pointer 211; CHECK-32-NEXT: i32.const $push3=, 32 212; CHECK-32-NEXT: i32.sub $push8=, $pop2, $pop3 213; CHECK-32-NEXT: local.tee $push7=, 0, $pop8 214; CHECK-32-NEXT: global.set __stack_pointer, $pop7 215; CHECK-32-NEXT: local.get $push9=, 0 216; CHECK-32-NEXT: i32.const $push0=, 1 217; CHECK-32-NEXT: i32.store 24($pop9), $pop0 218; CHECK-32-NEXT: local.get $push10=, 0 219; CHECK-32-NEXT: i32.const $push6=, 1 220; CHECK-32-NEXT: i32.store 12($pop10), $pop6 221; CHECK-32-NEXT: i32.const $push1=, 0 222; CHECK-32-NEXT: call ext_func, $pop1 223; CHECK-32-NEXT: local.get $push11=, 0 224; CHECK-32-NEXT: i32.const $push4=, 32 225; CHECK-32-NEXT: i32.add $push5=, $pop11, $pop4 226; CHECK-32-NEXT: global.set __stack_pointer, $pop5 227; CHECK-32-NEXT: return 228; 229; CHECK-64-LABEL: allocarray_inbounds: 230; CHECK-64: .functype allocarray_inbounds () -> () 231; CHECK-64-NEXT: .local i64 232; CHECK-64-NEXT: # %bb.0: 233; CHECK-64-NEXT: global.get $push2=, __stack_pointer 234; CHECK-64-NEXT: i64.const $push3=, 32 235; CHECK-64-NEXT: i64.sub $push8=, $pop2, $pop3 236; CHECK-64-NEXT: local.tee $push7=, 0, $pop8 237; CHECK-64-NEXT: global.set __stack_pointer, $pop7 238; CHECK-64-NEXT: local.get $push9=, 0 239; CHECK-64-NEXT: i32.const $push0=, 1 240; CHECK-64-NEXT: i32.store 24($pop9), $pop0 241; CHECK-64-NEXT: local.get $push10=, 0 242; CHECK-64-NEXT: i32.const $push6=, 1 243; CHECK-64-NEXT: i32.store 12($pop10), $pop6 244; CHECK-64-NEXT: i64.const $push1=, 0 245; CHECK-64-NEXT: call ext_func, $pop1 246; CHECK-64-NEXT: local.get $push11=, 0 247; CHECK-64-NEXT: i64.const $push4=, 32 248; CHECK-64-NEXT: i64.add $push5=, $pop11, $pop4 249; CHECK-64-NEXT: global.set __stack_pointer, $pop5 250; CHECK-64-NEXT: return 251 %r = alloca [5 x i32] 252 store i32 1, ptr %r 253 ; This store should have both the GEP and the FI folded into it. 254 %p2 = getelementptr inbounds [5 x i32], ptr %r, i32 0, i32 3 255 store i32 1, ptr %p2 256 call void @ext_func(ptr null); 257 ret void 258} 259 260define void @dynamic_alloca(i32 %alloc) { 261 ; Target independent codegen bumps the stack pointer. 262 ; Check that SP is written back to memory after decrement 263; CHECK-32-LABEL: dynamic_alloca: 264; CHECK-32: .functype dynamic_alloca (i32) -> () 265; CHECK-32-NEXT: .local i32 266; CHECK-32-NEXT: # %bb.0: 267; CHECK-32-NEXT: global.get $push10=, __stack_pointer 268; CHECK-32-NEXT: local.tee $push9=, 1, $pop10 269; CHECK-32-NEXT: local.get $push11=, 0 270; CHECK-32-NEXT: i32.const $push0=, 2 271; CHECK-32-NEXT: i32.shl $push1=, $pop11, $pop0 272; CHECK-32-NEXT: i32.const $push2=, 15 273; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2 274; CHECK-32-NEXT: i32.const $push4=, -16 275; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4 276; CHECK-32-NEXT: i32.sub $push8=, $pop9, $pop5 277; CHECK-32-NEXT: local.tee $push7=, 0, $pop8 278; CHECK-32-NEXT: global.set __stack_pointer, $pop7 279; CHECK-32-NEXT: local.get $push12=, 0 280; CHECK-32-NEXT: call ext_func_i32, $pop12 281; CHECK-32-NEXT: local.get $push6=, 1 282; CHECK-32-NEXT: global.set __stack_pointer, $pop6 283; CHECK-32-NEXT: return 284; 285; CHECK-64-LABEL: dynamic_alloca: 286; CHECK-64: .functype dynamic_alloca (i32) -> () 287; CHECK-64-NEXT: .local i64, i64 288; CHECK-64-NEXT: # %bb.0: 289; CHECK-64-NEXT: global.get $push11=, __stack_pointer 290; CHECK-64-NEXT: local.tee $push10=, 1, $pop11 291; CHECK-64-NEXT: local.get $push12=, 0 292; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop12 293; CHECK-64-NEXT: i64.const $push1=, 2 294; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1 295; CHECK-64-NEXT: i64.const $push3=, 15 296; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3 297; CHECK-64-NEXT: i64.const $push5=, 34359738352 298; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5 299; CHECK-64-NEXT: i64.sub $push9=, $pop10, $pop6 300; CHECK-64-NEXT: local.tee $push8=, 2, $pop9 301; CHECK-64-NEXT: global.set __stack_pointer, $pop8 302; CHECK-64-NEXT: local.get $push13=, 2 303; CHECK-64-NEXT: call ext_func_i32, $pop13 304; CHECK-64-NEXT: local.get $push7=, 1 305; CHECK-64-NEXT: global.set __stack_pointer, $pop7 306; CHECK-64-NEXT: return 307 %r = alloca i32, i32 %alloc 308 ; Target-independent codegen also calculates the store addr 309 call void @ext_func_i32(ptr %r) 310 ret void 311} 312 313define void @dynamic_alloca_redzone(i32 %alloc) { 314 ; Target independent codegen bumps the stack pointer 315; CHECK-32-LABEL: dynamic_alloca_redzone: 316; CHECK-32: .functype dynamic_alloca_redzone (i32) -> () 317; CHECK-32-NEXT: .local i32 318; CHECK-32-NEXT: # %bb.0: 319; CHECK-32-NEXT: global.get $push8=, __stack_pointer 320; CHECK-32-NEXT: local.tee $push9=, 1, $pop8 321; CHECK-32-NEXT: drop $pop9 322; CHECK-32-NEXT: local.get $push11=, 1 323; CHECK-32-NEXT: local.get $push10=, 0 324; CHECK-32-NEXT: i32.const $push0=, 2 325; CHECK-32-NEXT: i32.shl $push1=, $pop10, $pop0 326; CHECK-32-NEXT: i32.const $push2=, 15 327; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2 328; CHECK-32-NEXT: i32.const $push4=, -16 329; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4 330; CHECK-32-NEXT: i32.sub $push7=, $pop11, $pop5 331; CHECK-32-NEXT: local.tee $push12=, 0, $pop7 332; CHECK-32-NEXT: drop $pop12 333; CHECK-32-NEXT: local.get $push13=, 0 334; CHECK-32-NEXT: i32.const $push6=, 0 335; CHECK-32-NEXT: i32.store 0($pop13), $pop6 336; CHECK-32-NEXT: return 337; 338; CHECK-64-LABEL: dynamic_alloca_redzone: 339; CHECK-64: .functype dynamic_alloca_redzone (i32) -> () 340; CHECK-64-NEXT: .local i64 341; CHECK-64-NEXT: # %bb.0: 342; CHECK-64-NEXT: global.get $push9=, __stack_pointer 343; CHECK-64-NEXT: local.tee $push10=, 1, $pop9 344; CHECK-64-NEXT: drop $pop10 345; CHECK-64-NEXT: local.get $push12=, 1 346; CHECK-64-NEXT: local.get $push11=, 0 347; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop11 348; CHECK-64-NEXT: i64.const $push1=, 2 349; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1 350; CHECK-64-NEXT: i64.const $push3=, 15 351; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3 352; CHECK-64-NEXT: i64.const $push5=, 34359738352 353; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5 354; CHECK-64-NEXT: i64.sub $push8=, $pop12, $pop6 355; CHECK-64-NEXT: local.tee $push13=, 1, $pop8 356; CHECK-64-NEXT: drop $pop13 357; CHECK-64-NEXT: local.get $push14=, 1 358; CHECK-64-NEXT: i32.const $push7=, 0 359; CHECK-64-NEXT: i32.store 0($pop14), $pop7 360; CHECK-64-NEXT: return 361 %r = alloca i32, i32 %alloc 362 store i32 0, ptr %r 363 ret void 364} 365 366define void @dynamic_static_alloca(i32 %alloc) noredzone { 367 ; Decrement SP in the prolog by the static amount and writeback to memory. 368 ; Alloc and write to a static alloca 369; CHECK-32-LABEL: dynamic_static_alloca: 370; CHECK-32: .functype dynamic_static_alloca (i32) -> () 371; CHECK-32-NEXT: .local i32, i32, i32 372; CHECK-32-NEXT: # %bb.0: 373; CHECK-32-NEXT: global.get $push11=, __stack_pointer 374; CHECK-32-NEXT: i32.const $push12=, 16 375; CHECK-32-NEXT: i32.sub $push25=, $pop11, $pop12 376; CHECK-32-NEXT: local.tee $push24=, 1, $pop25 377; CHECK-32-NEXT: global.set __stack_pointer, $pop24 378; CHECK-32-NEXT: local.get $push23=, 1 379; CHECK-32-NEXT: local.tee $push22=, 2, $pop23 380; CHECK-32-NEXT: i32.const $push0=, 101 381; CHECK-32-NEXT: i32.store 12($pop22), $pop0 382; CHECK-32-NEXT: local.get $push27=, 1 383; CHECK-32-NEXT: local.get $push26=, 0 384; CHECK-32-NEXT: i32.const $push1=, 2 385; CHECK-32-NEXT: i32.shl $push2=, $pop26, $pop1 386; CHECK-32-NEXT: i32.const $push3=, 15 387; CHECK-32-NEXT: i32.add $push4=, $pop2, $pop3 388; CHECK-32-NEXT: i32.const $push5=, -16 389; CHECK-32-NEXT: i32.and $push21=, $pop4, $pop5 390; CHECK-32-NEXT: local.tee $push20=, 0, $pop21 391; CHECK-32-NEXT: i32.sub $push19=, $pop27, $pop20 392; CHECK-32-NEXT: local.tee $push18=, 1, $pop19 393; CHECK-32-NEXT: local.tee $push17=, 3, $pop18 394; CHECK-32-NEXT: global.set __stack_pointer, $pop17 395; CHECK-32-NEXT: local.get $push28=, 2 396; CHECK-32-NEXT: i32.const $push6=, 102 397; CHECK-32-NEXT: i32.store 12($pop28), $pop6 398; CHECK-32-NEXT: local.get $push29=, 1 399; CHECK-32-NEXT: i32.const $push7=, 103 400; CHECK-32-NEXT: i32.store 0($pop29), $pop7 401; CHECK-32-NEXT: local.get $push31=, 3 402; CHECK-32-NEXT: local.get $push30=, 0 403; CHECK-32-NEXT: i32.sub $push16=, $pop31, $pop30 404; CHECK-32-NEXT: local.tee $push15=, 0, $pop16 405; CHECK-32-NEXT: global.set __stack_pointer, $pop15 406; CHECK-32-NEXT: local.get $push32=, 2 407; CHECK-32-NEXT: i32.const $push8=, 104 408; CHECK-32-NEXT: i32.store 12($pop32), $pop8 409; CHECK-32-NEXT: local.get $push33=, 1 410; CHECK-32-NEXT: i32.const $push9=, 105 411; CHECK-32-NEXT: i32.store 0($pop33), $pop9 412; CHECK-32-NEXT: local.get $push34=, 0 413; CHECK-32-NEXT: i32.const $push10=, 106 414; CHECK-32-NEXT: i32.store 0($pop34), $pop10 415; CHECK-32-NEXT: local.get $push35=, 2 416; CHECK-32-NEXT: i32.const $push13=, 16 417; CHECK-32-NEXT: i32.add $push14=, $pop35, $pop13 418; CHECK-32-NEXT: global.set __stack_pointer, $pop14 419; CHECK-32-NEXT: return 420; 421; CHECK-64-LABEL: dynamic_static_alloca: 422; CHECK-64: .functype dynamic_static_alloca (i32) -> () 423; CHECK-64-NEXT: .local i64, i64, i64, i64 424; CHECK-64-NEXT: # %bb.0: 425; CHECK-64-NEXT: global.get $push12=, __stack_pointer 426; CHECK-64-NEXT: i64.const $push13=, 16 427; CHECK-64-NEXT: i64.sub $push26=, $pop12, $pop13 428; CHECK-64-NEXT: local.tee $push25=, 1, $pop26 429; CHECK-64-NEXT: global.set __stack_pointer, $pop25 430; CHECK-64-NEXT: local.get $push24=, 1 431; CHECK-64-NEXT: local.tee $push23=, 2, $pop24 432; CHECK-64-NEXT: i32.const $push0=, 101 433; CHECK-64-NEXT: i32.store 12($pop23), $pop0 434; CHECK-64-NEXT: local.get $push28=, 1 435; CHECK-64-NEXT: local.get $push27=, 0 436; CHECK-64-NEXT: i64.extend_i32_u $push1=, $pop27 437; CHECK-64-NEXT: i64.const $push2=, 2 438; CHECK-64-NEXT: i64.shl $push3=, $pop1, $pop2 439; CHECK-64-NEXT: i64.const $push4=, 15 440; CHECK-64-NEXT: i64.add $push5=, $pop3, $pop4 441; CHECK-64-NEXT: i64.const $push6=, 34359738352 442; CHECK-64-NEXT: i64.and $push22=, $pop5, $pop6 443; CHECK-64-NEXT: local.tee $push21=, 3, $pop22 444; CHECK-64-NEXT: i64.sub $push20=, $pop28, $pop21 445; CHECK-64-NEXT: local.tee $push19=, 1, $pop20 446; CHECK-64-NEXT: local.tee $push18=, 4, $pop19 447; CHECK-64-NEXT: global.set __stack_pointer, $pop18 448; CHECK-64-NEXT: local.get $push29=, 2 449; CHECK-64-NEXT: i32.const $push7=, 102 450; CHECK-64-NEXT: i32.store 12($pop29), $pop7 451; CHECK-64-NEXT: local.get $push30=, 1 452; CHECK-64-NEXT: i32.const $push8=, 103 453; CHECK-64-NEXT: i32.store 0($pop30), $pop8 454; CHECK-64-NEXT: local.get $push32=, 4 455; CHECK-64-NEXT: local.get $push31=, 3 456; CHECK-64-NEXT: i64.sub $push17=, $pop32, $pop31 457; CHECK-64-NEXT: local.tee $push16=, 3, $pop17 458; CHECK-64-NEXT: global.set __stack_pointer, $pop16 459; CHECK-64-NEXT: local.get $push33=, 2 460; CHECK-64-NEXT: i32.const $push9=, 104 461; CHECK-64-NEXT: i32.store 12($pop33), $pop9 462; CHECK-64-NEXT: local.get $push34=, 1 463; CHECK-64-NEXT: i32.const $push10=, 105 464; CHECK-64-NEXT: i32.store 0($pop34), $pop10 465; CHECK-64-NEXT: local.get $push35=, 3 466; CHECK-64-NEXT: i32.const $push11=, 106 467; CHECK-64-NEXT: i32.store 0($pop35), $pop11 468; CHECK-64-NEXT: local.get $push36=, 2 469; CHECK-64-NEXT: i64.const $push14=, 16 470; CHECK-64-NEXT: i64.add $push15=, $pop36, $pop14 471; CHECK-64-NEXT: global.set __stack_pointer, $pop15 472; CHECK-64-NEXT: return 473 %static = alloca i32 474 store volatile i32 101, ptr %static 475 ; Decrement SP in the body by the dynamic amount. 476 %dynamic = alloca i32, i32 %alloc 477 ; Ensure we don't modify the frame pointer after assigning it. 478 ; Ensure the static address doesn't change after modifying the stack pointer. 479 store volatile i32 102, ptr %static 480 store volatile i32 103, ptr %dynamic 481 ; Decrement SP in the body by the dynamic amount. 482 %dynamic.2 = alloca i32, i32 %alloc 483 ; Ensure neither the static nor dynamic address changes after the second 484 ; modification of the stack pointer. 485 store volatile i32 104, ptr %static 486 store volatile i32 105, ptr %dynamic 487 store volatile i32 106, ptr %dynamic.2 488 ; Writeback to memory. 489 ret void 490} 491 492declare ptr @llvm.stacksave() 493declare void @llvm.stackrestore(ptr) 494 495define void @llvm_stack_builtins(i32 %alloc) noredzone { 496; CHECK-32-LABEL: llvm_stack_builtins: 497; CHECK-32: .functype llvm_stack_builtins (i32) -> () 498; CHECK-32-NEXT: .local i32, i32, i32 499; CHECK-32-NEXT: # %bb.0: 500; CHECK-32-NEXT: global.get $push7=, __stack_pointer 501; CHECK-32-NEXT: local.tee $push8=, 1, $pop7 502; CHECK-32-NEXT: local.set 2, $pop8 503; CHECK-32-NEXT: local.get $push9=, 1 504; CHECK-32-NEXT: local.set 3, $pop9 505; CHECK-32-NEXT: local.get $push11=, 1 506; CHECK-32-NEXT: local.get $push10=, 0 507; CHECK-32-NEXT: i32.const $push0=, 2 508; CHECK-32-NEXT: i32.shl $push1=, $pop10, $pop0 509; CHECK-32-NEXT: i32.const $push2=, 15 510; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2 511; CHECK-32-NEXT: i32.const $push4=, -16 512; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4 513; CHECK-32-NEXT: i32.sub $push6=, $pop11, $pop5 514; CHECK-32-NEXT: global.set __stack_pointer, $pop6 515; CHECK-32-NEXT: local.get $push12=, 3 516; CHECK-32-NEXT: drop $pop12 517; CHECK-32-NEXT: local.get $push13=, 2 518; CHECK-32-NEXT: global.set __stack_pointer, $pop13 519; CHECK-32-NEXT: return 520; 521; CHECK-64-LABEL: llvm_stack_builtins: 522; CHECK-64: .functype llvm_stack_builtins (i32) -> () 523; CHECK-64-NEXT: .local i64, i64, i64 524; CHECK-64-NEXT: # %bb.0: 525; CHECK-64-NEXT: global.get $push8=, __stack_pointer 526; CHECK-64-NEXT: local.tee $push9=, 1, $pop8 527; CHECK-64-NEXT: local.set 2, $pop9 528; CHECK-64-NEXT: local.get $push10=, 1 529; CHECK-64-NEXT: local.set 3, $pop10 530; CHECK-64-NEXT: local.get $push12=, 1 531; CHECK-64-NEXT: local.get $push11=, 0 532; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop11 533; CHECK-64-NEXT: i64.const $push1=, 2 534; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1 535; CHECK-64-NEXT: i64.const $push3=, 15 536; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3 537; CHECK-64-NEXT: i64.const $push5=, 34359738352 538; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5 539; CHECK-64-NEXT: i64.sub $push7=, $pop12, $pop6 540; CHECK-64-NEXT: global.set __stack_pointer, $pop7 541; CHECK-64-NEXT: local.get $push13=, 3 542; CHECK-64-NEXT: drop $pop13 543; CHECK-64-NEXT: local.get $push14=, 2 544; CHECK-64-NEXT: global.set __stack_pointer, $pop14 545; CHECK-64-NEXT: return 546 %stack = call ptr @llvm.stacksave() 547 ; Ensure we don't reassign the stacksave local 548 %dynamic = alloca i32, i32 %alloc 549 call void @llvm.stackrestore(ptr %stack) 550 ret void 551} 552 553; Use of stacksave requires local SP definition even without dymamic alloca. 554; CHECK-LABEL: llvm_stacksave_noalloca: 555define void @llvm_stacksave_noalloca() noredzone { 556 ; CHECK: global.get $push[[L11:.+]]=, __stack_pointer{{$}} 557 %stack = call ptr @llvm.stacksave() 558 559 ; CHECK-NEXT: call use_i8_star, $pop[[L11:.+]] 560 call void @use_i8_star(ptr %stack) 561 562 ret void 563} 564 565; Not actually using the alloca'd variables exposed an issue with register 566; stackification, where copying the stack pointer into the frame pointer was 567; moved after the stack pointer was updated for the dynamic alloca. 568define void @dynamic_alloca_nouse(i32 %alloc) noredzone { 569; CHECK-32-LABEL: dynamic_alloca_nouse: 570; CHECK-32: .functype dynamic_alloca_nouse (i32) -> () 571; CHECK-32-NEXT: .local i32, i32 572; CHECK-32-NEXT: # %bb.0: 573; CHECK-32-NEXT: global.get $push7=, __stack_pointer 574; CHECK-32-NEXT: local.tee $push8=, 1, $pop7 575; CHECK-32-NEXT: local.set 2, $pop8 576; CHECK-32-NEXT: local.get $push10=, 1 577; CHECK-32-NEXT: local.get $push9=, 0 578; CHECK-32-NEXT: i32.const $push0=, 2 579; CHECK-32-NEXT: i32.shl $push1=, $pop9, $pop0 580; CHECK-32-NEXT: i32.const $push2=, 15 581; CHECK-32-NEXT: i32.add $push3=, $pop1, $pop2 582; CHECK-32-NEXT: i32.const $push4=, -16 583; CHECK-32-NEXT: i32.and $push5=, $pop3, $pop4 584; CHECK-32-NEXT: i32.sub $push6=, $pop10, $pop5 585; CHECK-32-NEXT: global.set __stack_pointer, $pop6 586; CHECK-32-NEXT: local.get $push11=, 2 587; CHECK-32-NEXT: global.set __stack_pointer, $pop11 588; CHECK-32-NEXT: return 589; 590; CHECK-64-LABEL: dynamic_alloca_nouse: 591; CHECK-64: .functype dynamic_alloca_nouse (i32) -> () 592; CHECK-64-NEXT: .local i64, i64 593; CHECK-64-NEXT: # %bb.0: 594; CHECK-64-NEXT: global.get $push8=, __stack_pointer 595; CHECK-64-NEXT: local.tee $push9=, 1, $pop8 596; CHECK-64-NEXT: local.set 2, $pop9 597; CHECK-64-NEXT: local.get $push11=, 1 598; CHECK-64-NEXT: local.get $push10=, 0 599; CHECK-64-NEXT: i64.extend_i32_u $push0=, $pop10 600; CHECK-64-NEXT: i64.const $push1=, 2 601; CHECK-64-NEXT: i64.shl $push2=, $pop0, $pop1 602; CHECK-64-NEXT: i64.const $push3=, 15 603; CHECK-64-NEXT: i64.add $push4=, $pop2, $pop3 604; CHECK-64-NEXT: i64.const $push5=, 34359738352 605; CHECK-64-NEXT: i64.and $push6=, $pop4, $pop5 606; CHECK-64-NEXT: i64.sub $push7=, $pop11, $pop6 607; CHECK-64-NEXT: global.set __stack_pointer, $pop7 608; CHECK-64-NEXT: local.get $push12=, 2 609; CHECK-64-NEXT: global.set __stack_pointer, $pop12 610; CHECK-64-NEXT: return 611 %dynamic = alloca i32, i32 %alloc 612 ret void 613} 614 615; The use of the alloca in a phi causes a CopyToReg DAG node to be generated, 616; which has to have special handling because CopyToReg can't have a FI operand 617define void @copytoreg_fi(i1 %cond, ptr %b) { 618; CHECK-32-LABEL: copytoreg_fi: 619; CHECK-32: .functype copytoreg_fi (i32, i32) -> () 620; CHECK-32-NEXT: .local i32 621; CHECK-32-NEXT: # %bb.0: # %entry 622; CHECK-32-NEXT: global.get $push0=, __stack_pointer 623; CHECK-32-NEXT: i32.const $push1=, 16 624; CHECK-32-NEXT: i32.sub $push3=, $pop0, $pop1 625; CHECK-32-NEXT: i32.const $push2=, 12 626; CHECK-32-NEXT: i32.add $push6=, $pop3, $pop2 627; CHECK-32-NEXT: local.set 2, $pop6 628; CHECK-32-NEXT: local.get $push8=, 0 629; CHECK-32-NEXT: i32.const $push4=, 1 630; CHECK-32-NEXT: i32.and $push7=, $pop8, $pop4 631; CHECK-32-NEXT: local.set 0, $pop7 632; CHECK-32-NEXT: # %body 633; CHECK-32-NEXT: # =>This Inner Loop Header: Depth=1 634; CHECK-32-NEXT: loop # label0: 635; CHECK-32-NEXT: local.get $push9=, 2 636; CHECK-32-NEXT: i32.const $push5=, 1 637; CHECK-32-NEXT: i32.store 0($pop9), $pop5 638; CHECK-32-NEXT: local.get $push10=, 1 639; CHECK-32-NEXT: local.set 2, $pop10 640; CHECK-32-NEXT: local.get $push11=, 0 641; CHECK-32-NEXT: br_if 0, $pop11 # 0: up to label0 642; CHECK-32-NEXT: # %bb.2: # %exit 643; CHECK-32-NEXT: end_loop 644; CHECK-32-NEXT: return 645; 646; CHECK-64-LABEL: copytoreg_fi: 647; CHECK-64: .functype copytoreg_fi (i32, i64) -> () 648; CHECK-64-NEXT: .local i64 649; CHECK-64-NEXT: # %bb.0: # %entry 650; CHECK-64-NEXT: global.get $push0=, __stack_pointer 651; CHECK-64-NEXT: i64.const $push1=, 16 652; CHECK-64-NEXT: i64.sub $push3=, $pop0, $pop1 653; CHECK-64-NEXT: i64.const $push2=, 12 654; CHECK-64-NEXT: i64.add $push6=, $pop3, $pop2 655; CHECK-64-NEXT: local.set 2, $pop6 656; CHECK-64-NEXT: local.get $push8=, 0 657; CHECK-64-NEXT: i32.const $push4=, 1 658; CHECK-64-NEXT: i32.and $push7=, $pop8, $pop4 659; CHECK-64-NEXT: local.set 0, $pop7 660; CHECK-64-NEXT: # %body 661; CHECK-64-NEXT: # =>This Inner Loop Header: Depth=1 662; CHECK-64-NEXT: loop # label0: 663; CHECK-64-NEXT: local.get $push9=, 2 664; CHECK-64-NEXT: i32.const $push5=, 1 665; CHECK-64-NEXT: i32.store 0($pop9), $pop5 666; CHECK-64-NEXT: local.get $push10=, 1 667; CHECK-64-NEXT: local.set 2, $pop10 668; CHECK-64-NEXT: local.get $push11=, 0 669; CHECK-64-NEXT: br_if 0, $pop11 # 0: up to label0 670; CHECK-64-NEXT: # %bb.2: # %exit 671; CHECK-64-NEXT: end_loop 672; CHECK-64-NEXT: return 673entry: 674 %addr = alloca i32 675 br label %body 676body: 677 %a = phi ptr [%addr, %entry], [%b, %body] 678 store i32 1, ptr %a 679 br i1 %cond, label %body, label %exit 680exit: 681 ret void 682} 683 684declare void @use_i8_star(ptr) 685declare ptr @llvm.frameaddress(i32) 686 687; Test __builtin_frame_address(0). 688define void @frameaddress_0() { 689; CHECK-32-LABEL: frameaddress_0: 690; CHECK-32: .functype frameaddress_0 () -> () 691; CHECK-32-NEXT: .local i32 692; CHECK-32-NEXT: # %bb.0: 693; CHECK-32-NEXT: global.get $push1=, __stack_pointer 694; CHECK-32-NEXT: local.tee $push0=, 0, $pop1 695; CHECK-32-NEXT: call use_i8_star, $pop0 696; CHECK-32-NEXT: local.get $push2=, 0 697; CHECK-32-NEXT: global.set __stack_pointer, $pop2 698; CHECK-32-NEXT: return 699; 700; CHECK-64-LABEL: frameaddress_0: 701; CHECK-64: .functype frameaddress_0 () -> () 702; CHECK-64-NEXT: .local i64 703; CHECK-64-NEXT: # %bb.0: 704; CHECK-64-NEXT: global.get $push1=, __stack_pointer 705; CHECK-64-NEXT: local.tee $push0=, 0, $pop1 706; CHECK-64-NEXT: call use_i8_star, $pop0 707; CHECK-64-NEXT: local.get $push2=, 0 708; CHECK-64-NEXT: global.set __stack_pointer, $pop2 709; CHECK-64-NEXT: return 710 %t = call ptr @llvm.frameaddress(i32 0) 711 call void @use_i8_star(ptr %t) 712 ret void 713} 714 715; Test __builtin_frame_address(1). 716define void @frameaddress_1() { 717; CHECK-32-LABEL: frameaddress_1: 718; CHECK-32: .functype frameaddress_1 () -> () 719; CHECK-32-NEXT: # %bb.0: 720; CHECK-32-NEXT: i32.const $push0=, 0 721; CHECK-32-NEXT: call use_i8_star, $pop0 722; CHECK-32-NEXT: return 723; 724; CHECK-64-LABEL: frameaddress_1: 725; CHECK-64: .functype frameaddress_1 () -> () 726; CHECK-64-NEXT: # %bb.0: 727; CHECK-64-NEXT: i64.const $push0=, 0 728; CHECK-64-NEXT: call use_i8_star, $pop0 729; CHECK-64-NEXT: return 730 %t = call ptr @llvm.frameaddress(i32 1) 731 call void @use_i8_star(ptr %t) 732 ret void 733} 734 735; Test a stack address passed to an inline asm. 736define void @inline_asm() { 737; CHECK-32-LABEL: inline_asm: 738; CHECK-32: .functype inline_asm () -> () 739; CHECK-32-NEXT: .local i32 740; CHECK-32-NEXT: # %bb.0: 741; CHECK-32-NEXT: global.get $push0=, __stack_pointer 742; CHECK-32-NEXT: i32.const $push1=, 16 743; CHECK-32-NEXT: i32.sub $push3=, $pop0, $pop1 744; CHECK-32-NEXT: i32.const $push2=, 15 745; CHECK-32-NEXT: i32.add $push4=, $pop3, $pop2 746; CHECK-32-NEXT: local.set 0, $pop4 747; CHECK-32-NEXT: #APP 748; CHECK-32-NEXT: # %0 749; CHECK-32-NEXT: #NO_APP 750; CHECK-32-NEXT: return 751; 752; CHECK-64-LABEL: inline_asm: 753; CHECK-64: .functype inline_asm () -> () 754; CHECK-64-NEXT: .local i64 755; CHECK-64-NEXT: # %bb.0: 756; CHECK-64-NEXT: global.get $push0=, __stack_pointer 757; CHECK-64-NEXT: i64.const $push1=, 16 758; CHECK-64-NEXT: i64.sub $push3=, $pop0, $pop1 759; CHECK-64-NEXT: i64.const $push2=, 15 760; CHECK-64-NEXT: i64.add $push4=, $pop3, $pop2 761; CHECK-64-NEXT: local.set 0, $pop4 762; CHECK-64-NEXT: #APP 763; CHECK-64-NEXT: # %0 764; CHECK-64-NEXT: #NO_APP 765; CHECK-64-NEXT: return 766 %tmp = alloca i8 767 call void asm sideeffect "# %0", "r"(ptr %tmp) 768 ret void 769} 770 771; We optimize the format of "frame offset + operand" by folding it, but this is 772; only possible when that operand is an immediate. In this example it is a 773; global address, so we should not fold it. 774@str = local_unnamed_addr global [3 x i8] c"abc", align 16 775define i8 @frame_offset_with_global_address() { 776; CHECK-32-LABEL: frame_offset_with_global_address: 777; CHECK-32: .functype frame_offset_with_global_address () -> (i32) 778; CHECK-32-NEXT: # %bb.0: 779; CHECK-32-NEXT: i32.const $push0=, str 780; CHECK-32-NEXT: global.get $push5=, __stack_pointer 781; CHECK-32-NEXT: i32.const $push6=, 16 782; CHECK-32-NEXT: i32.sub $push9=, $pop5, $pop6 783; CHECK-32-NEXT: i32.const $push7=, 12 784; CHECK-32-NEXT: i32.add $push8=, $pop9, $pop7 785; CHECK-32-NEXT: i32.add $push1=, $pop0, $pop8 786; CHECK-32-NEXT: i32.load8_u $push2=, 0($pop1) 787; CHECK-32-NEXT: i32.const $push3=, 67 788; CHECK-32-NEXT: i32.and $push4=, $pop2, $pop3 789; CHECK-32-NEXT: return $pop4 790; 791; CHECK-64-LABEL: frame_offset_with_global_address: 792; CHECK-64: .functype frame_offset_with_global_address () -> (i32) 793; CHECK-64-NEXT: # %bb.0: 794; CHECK-64-NEXT: i64.const $push1=, str 795; CHECK-64-NEXT: global.get $push6=, __stack_pointer 796; CHECK-64-NEXT: i64.const $push7=, 16 797; CHECK-64-NEXT: i64.sub $push10=, $pop6, $pop7 798; CHECK-64-NEXT: i64.const $push8=, 12 799; CHECK-64-NEXT: i64.add $push9=, $pop10, $pop8 800; CHECK-64-NEXT: i64.extend32_s $push0=, $pop9 801; CHECK-64-NEXT: i64.add $push2=, $pop1, $pop0 802; CHECK-64-NEXT: i32.load8_u $push3=, 0($pop2) 803; CHECK-64-NEXT: i32.const $push4=, 67 804; CHECK-64-NEXT: i32.and $push5=, $pop3, $pop4 805; CHECK-64-NEXT: return $pop5 806 %1 = alloca i8, align 4 807 %2 = ptrtoint ptr %1 to i32 808 ;; Here @str is a global address and not an immediate, so cannot be folded 809 %3 = getelementptr [3 x i8], ptr @str, i32 0, i32 %2 810 %4 = load i8, ptr %3, align 8 811 %5 = and i8 %4, 67 812 ret i8 %5 813} 814 815; TODO: test over-aligned alloca 816