|  | ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py | 
|  | ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=32 %s --check-prefix=CHECK-32 | 
|  | ; RUN: llc < %s --mtriple=wasm64-unknown-unknown -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck -DPTR=64 %s --check-prefix=CHECK-64 | 
|  |  | 
|  | declare void @ext_func(ptr %ptr) | 
|  | declare void @ext_func_i32(ptr %ptr) | 
|  |  | 
|  | ; Check that there is an extra local for the stack pointer. | 
|  | define void @alloca32() noredzone { | 
|  | ; CHECK-32-LABEL: alloca32: | 
|  | ; CHECK-32:         .functype alloca32 () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push1=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push6=, $pop1, $pop2 | 
|  | ; CHECK-32-NEXT:    local.tee $push5=, 0, $pop6 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop5 | 
|  | ; CHECK-32-NEXT:    local.get $push7=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 0 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop7), $pop0 | 
|  | ; CHECK-32-NEXT:    local.get $push8=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push3=, 16 | 
|  | ; CHECK-32-NEXT:    i32.add $push4=, $pop8, $pop3 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop4 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: alloca32: | 
|  | ; CHECK-64:         .functype alloca32 () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push1=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push2=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push6=, $pop1, $pop2 | 
|  | ; CHECK-64-NEXT:    local.tee $push5=, 0, $pop6 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop5 | 
|  | ; CHECK-64-NEXT:    local.get $push7=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push0=, 0 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop7), $pop0 | 
|  | ; CHECK-64-NEXT:    local.get $push8=, 0 | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 16 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop8, $pop3 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop4 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %retval = alloca i32 | 
|  | store i32 0, ptr %retval | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @alloca3264() { | 
|  | ; CHECK-32-LABEL: alloca3264: | 
|  | ; CHECK-32:         .functype alloca3264 () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push2=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push3=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push5=, $pop2, $pop3 | 
|  | ; CHECK-32-NEXT:    local.tee $push4=, 0, $pop5 | 
|  | ; CHECK-32-NEXT:    i64.const $push0=, 0 | 
|  | ; CHECK-32-NEXT:    i64.store 0($pop4), $pop0 | 
|  | ; CHECK-32-NEXT:    local.get $push6=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 0 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop6), $pop1 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: alloca3264: | 
|  | ; CHECK-64:         .functype alloca3264 () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push2=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push5=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    local.tee $push4=, 0, $pop5 | 
|  | ; CHECK-64-NEXT:    i64.const $push0=, 0 | 
|  | ; CHECK-64-NEXT:    i64.store 0($pop4), $pop0 | 
|  | ; CHECK-64-NEXT:    local.get $push6=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push1=, 0 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop6), $pop1 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %r1 = alloca i32 | 
|  | %r2 = alloca double | 
|  | store i32 0, ptr %r1 | 
|  | store double 0.0, ptr %r2 | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @allocarray() { | 
|  | ; CHECK-32-LABEL: allocarray: | 
|  | ; CHECK-32:         .functype allocarray () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push3=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, 144 | 
|  | ; CHECK-32-NEXT:    i32.sub $push9=, $pop3, $pop4 | 
|  | ; CHECK-32-NEXT:    local.tee $push8=, 0, $pop9 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop8 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 24 | 
|  | ; CHECK-32-NEXT:    i32.add $push1=, $pop10, $pop0 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 1 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop1), $pop2 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push7=, 1 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop11), $pop7 | 
|  | ; CHECK-32-NEXT:    local.get $push12=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push5=, 144 | 
|  | ; CHECK-32-NEXT:    i32.add $push6=, $pop12, $pop5 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop6 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: allocarray: | 
|  | ; CHECK-64:         .functype allocarray () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push3=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push4=, 144 | 
|  | ; CHECK-64-NEXT:    i64.sub $push9=, $pop3, $pop4 | 
|  | ; CHECK-64-NEXT:    local.tee $push8=, 0, $pop9 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop8 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-64-NEXT:    i64.const $push0=, 24 | 
|  | ; CHECK-64-NEXT:    i64.add $push1=, $pop10, $pop0 | 
|  | ; CHECK-64-NEXT:    i32.const $push2=, 1 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop1), $pop2 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push7=, 1 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop11), $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 0 | 
|  | ; CHECK-64-NEXT:    i64.const $push5=, 144 | 
|  | ; CHECK-64-NEXT:    i64.add $push6=, $pop12, $pop5 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop6 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %r = alloca [33 x i32] | 
|  | store i32 1, ptr %r | 
|  | %p2 = getelementptr [33 x i32], ptr %r, i32 0, i32 3 | 
|  | store i32 1, ptr %p2 | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @non_mem_use(ptr %addr) { | 
|  | ; CHECK-32-LABEL: non_mem_use: | 
|  | ; CHECK-32:         .functype non_mem_use (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 48 | 
|  | ; CHECK-32-NEXT:    i32.sub $push9=, $pop0, $pop1 | 
|  | ; CHECK-32-NEXT:    local.tee $push8=, 1, $pop9 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop8 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, 8 | 
|  | ; CHECK-32-NEXT:    i32.add $push5=, $pop10, $pop4 | 
|  | ; CHECK-32-NEXT:    call ext_func, $pop5 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 1 | 
|  | ; CHECK-32-NEXT:    call ext_func, $pop11 | 
|  | ; CHECK-32-NEXT:    local.get $push13=, 0 | 
|  | ; CHECK-32-NEXT:    local.get $push12=, 1 | 
|  | ; CHECK-32-NEXT:    i32.const $push6=, 16 | 
|  | ; CHECK-32-NEXT:    i32.add $push7=, $pop12, $pop6 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop13), $pop7 | 
|  | ; CHECK-32-NEXT:    local.get $push14=, 1 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 48 | 
|  | ; CHECK-32-NEXT:    i32.add $push3=, $pop14, $pop2 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop3 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: non_mem_use: | 
|  | ; CHECK-64:         .functype non_mem_use (i64) -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 48 | 
|  | ; CHECK-64-NEXT:    i64.sub $push9=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    local.tee $push8=, 1, $pop9 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop8 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-64-NEXT:    i64.const $push4=, 8 | 
|  | ; CHECK-64-NEXT:    i64.add $push5=, $pop10, $pop4 | 
|  | ; CHECK-64-NEXT:    call ext_func, $pop5 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 1 | 
|  | ; CHECK-64-NEXT:    call ext_func, $pop11 | 
|  | ; CHECK-64-NEXT:    local.get $push13=, 0 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 1 | 
|  | ; CHECK-64-NEXT:    i64.const $push6=, 16 | 
|  | ; CHECK-64-NEXT:    i64.add $push7=, $pop12, $pop6 | 
|  | ; CHECK-64-NEXT:    i64.store 0($pop13), $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push14=, 1 | 
|  | ; CHECK-64-NEXT:    i64.const $push2=, 48 | 
|  | ; CHECK-64-NEXT:    i64.add $push3=, $pop14, $pop2 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop3 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %buf = alloca [27 x i8], align 16 | 
|  | %r = alloca i64 | 
|  | %r2 = alloca i64 | 
|  | ; %r is at SP+8 | 
|  | call void @ext_func(ptr %r) | 
|  | ; %r2 is at SP+0, no add needed | 
|  | call void @ext_func(ptr %r2) | 
|  | ; Use as a value, but in a store | 
|  | ; %buf is at SP+16 | 
|  | store ptr %buf, ptr %addr | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @allocarray_inbounds() { | 
|  | ; CHECK-32-LABEL: allocarray_inbounds: | 
|  | ; CHECK-32:         .functype allocarray_inbounds () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push2=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push3=, 32 | 
|  | ; CHECK-32-NEXT:    i32.sub $push8=, $pop2, $pop3 | 
|  | ; CHECK-32-NEXT:    local.tee $push7=, 0, $pop8 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-32-NEXT:    local.get $push9=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 1 | 
|  | ; CHECK-32-NEXT:    i32.store 24($pop9), $pop0 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push6=, 1 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop10), $pop6 | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 0 | 
|  | ; CHECK-32-NEXT:    call ext_func, $pop1 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, 32 | 
|  | ; CHECK-32-NEXT:    i32.add $push5=, $pop11, $pop4 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop5 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: allocarray_inbounds: | 
|  | ; CHECK-64:         .functype allocarray_inbounds () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push2=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 32 | 
|  | ; CHECK-64-NEXT:    i64.sub $push8=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    local.tee $push7=, 0, $pop8 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push9=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push0=, 1 | 
|  | ; CHECK-64-NEXT:    i32.store 24($pop9), $pop0 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push6=, 1 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop10), $pop6 | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 0 | 
|  | ; CHECK-64-NEXT:    call ext_func, $pop1 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-64-NEXT:    i64.const $push4=, 32 | 
|  | ; CHECK-64-NEXT:    i64.add $push5=, $pop11, $pop4 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop5 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %r = alloca [5 x i32] | 
|  | store i32 1, ptr %r | 
|  | ; This store should have both the GEP and the FI folded into it. | 
|  | %p2 = getelementptr inbounds [5 x i32], ptr %r, i32 0, i32 3 | 
|  | store i32 1, ptr %p2 | 
|  | call void @ext_func(ptr null); | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @dynamic_alloca(i32 %alloc) { | 
|  | ; Target independent codegen bumps the stack pointer. | 
|  | ; Check that SP is written back to memory after decrement | 
|  | ; CHECK-32-LABEL: dynamic_alloca: | 
|  | ; CHECK-32:         .functype dynamic_alloca (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push10=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    local.tee $push9=, 1, $pop10 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 2 | 
|  | ; CHECK-32-NEXT:    i32.shl $push1=, $pop11, $pop0 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push3=, $pop1, $pop2 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, -16 | 
|  | ; CHECK-32-NEXT:    i32.and $push5=, $pop3, $pop4 | 
|  | ; CHECK-32-NEXT:    i32.sub $push8=, $pop9, $pop5 | 
|  | ; CHECK-32-NEXT:    local.tee $push7=, 0, $pop8 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-32-NEXT:    local.get $push12=, 0 | 
|  | ; CHECK-32-NEXT:    call ext_func_i32, $pop12 | 
|  | ; CHECK-32-NEXT:    local.get $push6=, 1 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop6 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: dynamic_alloca: | 
|  | ; CHECK-64:         .functype dynamic_alloca (i32) -> () | 
|  | ; CHECK-64-NEXT:    .local i64, i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push11=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    local.tee $push10=, 1, $pop11 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 0 | 
|  | ; CHECK-64-NEXT:    i64.extend_i32_u $push0=, $pop12 | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 2 | 
|  | ; CHECK-64-NEXT:    i64.shl $push2=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    i64.const $push5=, 34359738352 | 
|  | ; CHECK-64-NEXT:    i64.and $push6=, $pop4, $pop5 | 
|  | ; CHECK-64-NEXT:    i64.sub $push9=, $pop10, $pop6 | 
|  | ; CHECK-64-NEXT:    local.tee $push8=, 2, $pop9 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop8 | 
|  | ; CHECK-64-NEXT:    local.get $push13=, 2 | 
|  | ; CHECK-64-NEXT:    call ext_func_i32, $pop13 | 
|  | ; CHECK-64-NEXT:    local.get $push7=, 1 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %r = alloca i32, i32 %alloc | 
|  | ; Target-independent codegen also calculates the store addr | 
|  | call void @ext_func_i32(ptr %r) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @dynamic_alloca_redzone(i32 %alloc) { | 
|  | ; Target independent codegen bumps the stack pointer | 
|  | ; CHECK-32-LABEL: dynamic_alloca_redzone: | 
|  | ; CHECK-32:         .functype dynamic_alloca_redzone (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push8=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    local.tee $push9=, 1, $pop8 | 
|  | ; CHECK-32-NEXT:    drop $pop9 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 1 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 2 | 
|  | ; CHECK-32-NEXT:    i32.shl $push1=, $pop10, $pop0 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push3=, $pop1, $pop2 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, -16 | 
|  | ; CHECK-32-NEXT:    i32.and $push5=, $pop3, $pop4 | 
|  | ; CHECK-32-NEXT:    i32.sub $push7=, $pop11, $pop5 | 
|  | ; CHECK-32-NEXT:    local.tee $push12=, 0, $pop7 | 
|  | ; CHECK-32-NEXT:    drop $pop12 | 
|  | ; CHECK-32-NEXT:    local.get $push13=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push6=, 0 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop13), $pop6 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: dynamic_alloca_redzone: | 
|  | ; CHECK-64:         .functype dynamic_alloca_redzone (i32) -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push9=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    local.tee $push10=, 1, $pop9 | 
|  | ; CHECK-64-NEXT:    drop $pop10 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 1 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-64-NEXT:    i64.extend_i32_u $push0=, $pop11 | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 2 | 
|  | ; CHECK-64-NEXT:    i64.shl $push2=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    i64.const $push5=, 34359738352 | 
|  | ; CHECK-64-NEXT:    i64.and $push6=, $pop4, $pop5 | 
|  | ; CHECK-64-NEXT:    i64.sub $push8=, $pop12, $pop6 | 
|  | ; CHECK-64-NEXT:    local.tee $push13=, 1, $pop8 | 
|  | ; CHECK-64-NEXT:    drop $pop13 | 
|  | ; CHECK-64-NEXT:    local.get $push14=, 1 | 
|  | ; CHECK-64-NEXT:    i32.const $push7=, 0 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop14), $pop7 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %r = alloca i32, i32 %alloc | 
|  | store i32 0, ptr %r | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @dynamic_static_alloca(i32 %alloc) noredzone { | 
|  | ; Decrement SP in the prolog by the static amount and writeback to memory. | 
|  | ; Alloc and write to a static alloca | 
|  | ; CHECK-32-LABEL: dynamic_static_alloca: | 
|  | ; CHECK-32:         .functype dynamic_static_alloca (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32, i32, i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push11=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push12=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push25=, $pop11, $pop12 | 
|  | ; CHECK-32-NEXT:    local.tee $push24=, 1, $pop25 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop24 | 
|  | ; CHECK-32-NEXT:    local.get $push23=, 1 | 
|  | ; CHECK-32-NEXT:    local.tee $push22=, 2, $pop23 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 101 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop22), $pop0 | 
|  | ; CHECK-32-NEXT:    local.get $push27=, 1 | 
|  | ; CHECK-32-NEXT:    local.get $push26=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 2 | 
|  | ; CHECK-32-NEXT:    i32.shl $push2=, $pop26, $pop1 | 
|  | ; CHECK-32-NEXT:    i32.const $push3=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push4=, $pop2, $pop3 | 
|  | ; CHECK-32-NEXT:    i32.const $push5=, -16 | 
|  | ; CHECK-32-NEXT:    i32.and $push21=, $pop4, $pop5 | 
|  | ; CHECK-32-NEXT:    local.tee $push20=, 0, $pop21 | 
|  | ; CHECK-32-NEXT:    i32.sub $push19=, $pop27, $pop20 | 
|  | ; CHECK-32-NEXT:    local.tee $push18=, 1, $pop19 | 
|  | ; CHECK-32-NEXT:    local.tee $push17=, 3, $pop18 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop17 | 
|  | ; CHECK-32-NEXT:    local.get $push28=, 2 | 
|  | ; CHECK-32-NEXT:    i32.const $push6=, 102 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop28), $pop6 | 
|  | ; CHECK-32-NEXT:    local.get $push29=, 1 | 
|  | ; CHECK-32-NEXT:    i32.const $push7=, 103 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop29), $pop7 | 
|  | ; CHECK-32-NEXT:    local.get $push31=, 3 | 
|  | ; CHECK-32-NEXT:    local.get $push30=, 0 | 
|  | ; CHECK-32-NEXT:    i32.sub $push16=, $pop31, $pop30 | 
|  | ; CHECK-32-NEXT:    local.tee $push15=, 0, $pop16 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop15 | 
|  | ; CHECK-32-NEXT:    local.get $push32=, 2 | 
|  | ; CHECK-32-NEXT:    i32.const $push8=, 104 | 
|  | ; CHECK-32-NEXT:    i32.store 12($pop32), $pop8 | 
|  | ; CHECK-32-NEXT:    local.get $push33=, 1 | 
|  | ; CHECK-32-NEXT:    i32.const $push9=, 105 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop33), $pop9 | 
|  | ; CHECK-32-NEXT:    local.get $push34=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push10=, 106 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop34), $pop10 | 
|  | ; CHECK-32-NEXT:    local.get $push35=, 2 | 
|  | ; CHECK-32-NEXT:    i32.const $push13=, 16 | 
|  | ; CHECK-32-NEXT:    i32.add $push14=, $pop35, $pop13 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop14 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: dynamic_static_alloca: | 
|  | ; CHECK-64:         .functype dynamic_static_alloca (i32) -> () | 
|  | ; CHECK-64-NEXT:    .local i64, i64, i64, i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push12=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push13=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push26=, $pop12, $pop13 | 
|  | ; CHECK-64-NEXT:    local.tee $push25=, 1, $pop26 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop25 | 
|  | ; CHECK-64-NEXT:    local.get $push24=, 1 | 
|  | ; CHECK-64-NEXT:    local.tee $push23=, 2, $pop24 | 
|  | ; CHECK-64-NEXT:    i32.const $push0=, 101 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop23), $pop0 | 
|  | ; CHECK-64-NEXT:    local.get $push28=, 1 | 
|  | ; CHECK-64-NEXT:    local.get $push27=, 0 | 
|  | ; CHECK-64-NEXT:    i64.extend_i32_u $push1=, $pop27 | 
|  | ; CHECK-64-NEXT:    i64.const $push2=, 2 | 
|  | ; CHECK-64-NEXT:    i64.shl $push3=, $pop1, $pop2 | 
|  | ; CHECK-64-NEXT:    i64.const $push4=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push5=, $pop3, $pop4 | 
|  | ; CHECK-64-NEXT:    i64.const $push6=, 34359738352 | 
|  | ; CHECK-64-NEXT:    i64.and $push22=, $pop5, $pop6 | 
|  | ; CHECK-64-NEXT:    local.tee $push21=, 3, $pop22 | 
|  | ; CHECK-64-NEXT:    i64.sub $push20=, $pop28, $pop21 | 
|  | ; CHECK-64-NEXT:    local.tee $push19=, 1, $pop20 | 
|  | ; CHECK-64-NEXT:    local.tee $push18=, 4, $pop19 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop18 | 
|  | ; CHECK-64-NEXT:    local.get $push29=, 2 | 
|  | ; CHECK-64-NEXT:    i32.const $push7=, 102 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop29), $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push30=, 1 | 
|  | ; CHECK-64-NEXT:    i32.const $push8=, 103 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop30), $pop8 | 
|  | ; CHECK-64-NEXT:    local.get $push32=, 4 | 
|  | ; CHECK-64-NEXT:    local.get $push31=, 3 | 
|  | ; CHECK-64-NEXT:    i64.sub $push17=, $pop32, $pop31 | 
|  | ; CHECK-64-NEXT:    local.tee $push16=, 3, $pop17 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop16 | 
|  | ; CHECK-64-NEXT:    local.get $push33=, 2 | 
|  | ; CHECK-64-NEXT:    i32.const $push9=, 104 | 
|  | ; CHECK-64-NEXT:    i32.store 12($pop33), $pop9 | 
|  | ; CHECK-64-NEXT:    local.get $push34=, 1 | 
|  | ; CHECK-64-NEXT:    i32.const $push10=, 105 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop34), $pop10 | 
|  | ; CHECK-64-NEXT:    local.get $push35=, 3 | 
|  | ; CHECK-64-NEXT:    i32.const $push11=, 106 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop35), $pop11 | 
|  | ; CHECK-64-NEXT:    local.get $push36=, 2 | 
|  | ; CHECK-64-NEXT:    i64.const $push14=, 16 | 
|  | ; CHECK-64-NEXT:    i64.add $push15=, $pop36, $pop14 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop15 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %static = alloca i32 | 
|  | store volatile i32 101, ptr %static | 
|  | ; Decrement SP in the body by the dynamic amount. | 
|  | %dynamic = alloca i32, i32 %alloc | 
|  | ; Ensure we don't modify the frame pointer after assigning it. | 
|  | ; Ensure the static address doesn't change after modifying the stack pointer. | 
|  | store volatile i32 102, ptr %static | 
|  | store volatile i32 103, ptr %dynamic | 
|  | ; Decrement SP in the body by the dynamic amount. | 
|  | %dynamic.2 = alloca i32, i32 %alloc | 
|  | ; Ensure neither the static nor dynamic address changes after the second | 
|  | ; modification of the stack pointer. | 
|  | store volatile i32 104, ptr %static | 
|  | store volatile i32 105, ptr %dynamic | 
|  | store volatile i32 106, ptr %dynamic.2 | 
|  | ; Writeback to memory. | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare ptr @llvm.stacksave() | 
|  | declare void @llvm.stackrestore(ptr) | 
|  |  | 
|  | define void @llvm_stack_builtins(i32 %alloc) noredzone { | 
|  | ; CHECK-32-LABEL: llvm_stack_builtins: | 
|  | ; CHECK-32:         .functype llvm_stack_builtins (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32, i32, i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push7=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    local.tee $push8=, 1, $pop7 | 
|  | ; CHECK-32-NEXT:    local.set 2, $pop8 | 
|  | ; CHECK-32-NEXT:    local.get $push9=, 1 | 
|  | ; CHECK-32-NEXT:    local.set 3, $pop9 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 1 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 2 | 
|  | ; CHECK-32-NEXT:    i32.shl $push1=, $pop10, $pop0 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push3=, $pop1, $pop2 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, -16 | 
|  | ; CHECK-32-NEXT:    i32.and $push5=, $pop3, $pop4 | 
|  | ; CHECK-32-NEXT:    i32.sub $push6=, $pop11, $pop5 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop6 | 
|  | ; CHECK-32-NEXT:    local.get $push12=, 3 | 
|  | ; CHECK-32-NEXT:    drop $pop12 | 
|  | ; CHECK-32-NEXT:    local.get $push13=, 2 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop13 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: llvm_stack_builtins: | 
|  | ; CHECK-64:         .functype llvm_stack_builtins (i32) -> () | 
|  | ; CHECK-64-NEXT:    .local i64, i64, i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push8=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    local.tee $push9=, 1, $pop8 | 
|  | ; CHECK-64-NEXT:    local.set 2, $pop9 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-64-NEXT:    local.set 3, $pop10 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 1 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-64-NEXT:    i64.extend_i32_u $push0=, $pop11 | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 2 | 
|  | ; CHECK-64-NEXT:    i64.shl $push2=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    i64.const $push5=, 34359738352 | 
|  | ; CHECK-64-NEXT:    i64.and $push6=, $pop4, $pop5 | 
|  | ; CHECK-64-NEXT:    i64.sub $push7=, $pop12, $pop6 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push13=, 3 | 
|  | ; CHECK-64-NEXT:    drop $pop13 | 
|  | ; CHECK-64-NEXT:    local.get $push14=, 2 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop14 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %stack = call ptr @llvm.stacksave() | 
|  | ; Ensure we don't reassign the stacksave local | 
|  | %dynamic = alloca i32, i32 %alloc | 
|  | call void @llvm.stackrestore(ptr %stack) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Not actually using the alloca'd variables exposed an issue with register | 
|  | ; stackification, where copying the stack pointer into the frame pointer was | 
|  | ; moved after the stack pointer was updated for the dynamic alloca. | 
|  | define void @dynamic_alloca_nouse(i32 %alloc) noredzone { | 
|  | ; CHECK-32-LABEL: dynamic_alloca_nouse: | 
|  | ; CHECK-32:         .functype dynamic_alloca_nouse (i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32, i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push7=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    local.tee $push8=, 1, $pop7 | 
|  | ; CHECK-32-NEXT:    local.set 2, $pop8 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-32-NEXT:    local.get $push9=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 2 | 
|  | ; CHECK-32-NEXT:    i32.shl $push1=, $pop9, $pop0 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push3=, $pop1, $pop2 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, -16 | 
|  | ; CHECK-32-NEXT:    i32.and $push5=, $pop3, $pop4 | 
|  | ; CHECK-32-NEXT:    i32.sub $push6=, $pop10, $pop5 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop6 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 2 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop11 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: dynamic_alloca_nouse: | 
|  | ; CHECK-64:         .functype dynamic_alloca_nouse (i32) -> () | 
|  | ; CHECK-64-NEXT:    .local i64, i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push8=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    local.tee $push9=, 1, $pop8 | 
|  | ; CHECK-64-NEXT:    local.set 2, $pop9 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 1 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 0 | 
|  | ; CHECK-64-NEXT:    i64.extend_i32_u $push0=, $pop10 | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 2 | 
|  | ; CHECK-64-NEXT:    i64.shl $push2=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push3=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop2, $pop3 | 
|  | ; CHECK-64-NEXT:    i64.const $push5=, 34359738352 | 
|  | ; CHECK-64-NEXT:    i64.and $push6=, $pop4, $pop5 | 
|  | ; CHECK-64-NEXT:    i64.sub $push7=, $pop11, $pop6 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop7 | 
|  | ; CHECK-64-NEXT:    local.get $push12=, 2 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop12 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %dynamic = alloca i32, i32 %alloc | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; The use of the alloca in a phi causes a CopyToReg DAG node to be generated, | 
|  | ; which has to have special handling because CopyToReg can't have a FI operand | 
|  | define void @copytoreg_fi(i1 %cond, ptr %b) { | 
|  | ; CHECK-32-LABEL: copytoreg_fi: | 
|  | ; CHECK-32:         .functype copytoreg_fi (i32, i32) -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: # %entry | 
|  | ; CHECK-32-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push3=, $pop0, $pop1 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 12 | 
|  | ; CHECK-32-NEXT:    i32.add $push6=, $pop3, $pop2 | 
|  | ; CHECK-32-NEXT:    local.set 2, $pop6 | 
|  | ; CHECK-32-NEXT:    local.get $push8=, 0 | 
|  | ; CHECK-32-NEXT:    i32.const $push4=, 1 | 
|  | ; CHECK-32-NEXT:    i32.and $push7=, $pop8, $pop4 | 
|  | ; CHECK-32-NEXT:    local.set 0, $pop7 | 
|  | ; CHECK-32-NEXT:  .LBB10_1: # %body | 
|  | ; CHECK-32-NEXT:    # =>This Inner Loop Header: Depth=1 | 
|  | ; CHECK-32-NEXT:    loop # label0: | 
|  | ; CHECK-32-NEXT:    local.get $push9=, 2 | 
|  | ; CHECK-32-NEXT:    i32.const $push5=, 1 | 
|  | ; CHECK-32-NEXT:    i32.store 0($pop9), $pop5 | 
|  | ; CHECK-32-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-32-NEXT:    local.set 2, $pop10 | 
|  | ; CHECK-32-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-32-NEXT:    br_if 0, $pop11 # 0: up to label0 | 
|  | ; CHECK-32-NEXT:  # %bb.2: # %exit | 
|  | ; CHECK-32-NEXT:    end_loop | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: copytoreg_fi: | 
|  | ; CHECK-64:         .functype copytoreg_fi (i32, i64) -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: # %entry | 
|  | ; CHECK-64-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push3=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push2=, 12 | 
|  | ; CHECK-64-NEXT:    i64.add $push6=, $pop3, $pop2 | 
|  | ; CHECK-64-NEXT:    local.set 2, $pop6 | 
|  | ; CHECK-64-NEXT:    local.get $push8=, 0 | 
|  | ; CHECK-64-NEXT:    i32.const $push4=, 1 | 
|  | ; CHECK-64-NEXT:    i32.and $push7=, $pop8, $pop4 | 
|  | ; CHECK-64-NEXT:    local.set 0, $pop7 | 
|  | ; CHECK-64-NEXT:  .LBB10_1: # %body | 
|  | ; CHECK-64-NEXT:    # =>This Inner Loop Header: Depth=1 | 
|  | ; CHECK-64-NEXT:    loop # label0: | 
|  | ; CHECK-64-NEXT:    local.get $push9=, 2 | 
|  | ; CHECK-64-NEXT:    i32.const $push5=, 1 | 
|  | ; CHECK-64-NEXT:    i32.store 0($pop9), $pop5 | 
|  | ; CHECK-64-NEXT:    local.get $push10=, 1 | 
|  | ; CHECK-64-NEXT:    local.set 2, $pop10 | 
|  | ; CHECK-64-NEXT:    local.get $push11=, 0 | 
|  | ; CHECK-64-NEXT:    br_if 0, $pop11 # 0: up to label0 | 
|  | ; CHECK-64-NEXT:  # %bb.2: # %exit | 
|  | ; CHECK-64-NEXT:    end_loop | 
|  | ; CHECK-64-NEXT:    return | 
|  | entry: | 
|  | %addr = alloca i32 | 
|  | br label %body | 
|  | body: | 
|  | %a = phi ptr [%addr, %entry], [%b, %body] | 
|  | store i32 1, ptr %a | 
|  | br i1 %cond, label %body, label %exit | 
|  | exit: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @use_i8_star(ptr) | 
|  | declare ptr @llvm.frameaddress(i32) | 
|  |  | 
|  | ; Test __builtin_frame_address(0). | 
|  | define void @frameaddress_0() { | 
|  | ; CHECK-32-LABEL: frameaddress_0: | 
|  | ; CHECK-32:         .functype frameaddress_0 () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push1=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    local.tee $push0=, 0, $pop1 | 
|  | ; CHECK-32-NEXT:    call use_i8_star, $pop0 | 
|  | ; CHECK-32-NEXT:    local.get $push2=, 0 | 
|  | ; CHECK-32-NEXT:    global.set __stack_pointer, $pop2 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: frameaddress_0: | 
|  | ; CHECK-64:         .functype frameaddress_0 () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push1=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    local.tee $push0=, 0, $pop1 | 
|  | ; CHECK-64-NEXT:    call use_i8_star, $pop0 | 
|  | ; CHECK-64-NEXT:    local.get $push2=, 0 | 
|  | ; CHECK-64-NEXT:    global.set __stack_pointer, $pop2 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %t = call ptr @llvm.frameaddress(i32 0) | 
|  | call void @use_i8_star(ptr %t) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Test __builtin_frame_address(1). | 
|  | define void @frameaddress_1() { | 
|  | ; CHECK-32-LABEL: frameaddress_1: | 
|  | ; CHECK-32:         .functype frameaddress_1 () -> () | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, 0 | 
|  | ; CHECK-32-NEXT:    call use_i8_star, $pop0 | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: frameaddress_1: | 
|  | ; CHECK-64:         .functype frameaddress_1 () -> () | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    i64.const $push0=, 0 | 
|  | ; CHECK-64-NEXT:    call use_i8_star, $pop0 | 
|  | ; CHECK-64-NEXT:    return | 
|  | %t = call ptr @llvm.frameaddress(i32 1) | 
|  | call void @use_i8_star(ptr %t) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; Test a stack address passed to an inline asm. | 
|  | define void @inline_asm() { | 
|  | ; CHECK-32-LABEL: inline_asm: | 
|  | ; CHECK-32:         .functype inline_asm () -> () | 
|  | ; CHECK-32-NEXT:    .local i32 | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push1=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push3=, $pop0, $pop1 | 
|  | ; CHECK-32-NEXT:    i32.const $push2=, 15 | 
|  | ; CHECK-32-NEXT:    i32.add $push4=, $pop3, $pop2 | 
|  | ; CHECK-32-NEXT:    local.set 0, $pop4 | 
|  | ; CHECK-32-NEXT:    #APP | 
|  | ; CHECK-32-NEXT:    # %0 | 
|  | ; CHECK-32-NEXT:    #NO_APP | 
|  | ; CHECK-32-NEXT:    return | 
|  | ; | 
|  | ; CHECK-64-LABEL: inline_asm: | 
|  | ; CHECK-64:         .functype inline_asm () -> () | 
|  | ; CHECK-64-NEXT:    .local i64 | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    global.get $push0=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push3=, $pop0, $pop1 | 
|  | ; CHECK-64-NEXT:    i64.const $push2=, 15 | 
|  | ; CHECK-64-NEXT:    i64.add $push4=, $pop3, $pop2 | 
|  | ; CHECK-64-NEXT:    local.set 0, $pop4 | 
|  | ; CHECK-64-NEXT:    #APP | 
|  | ; CHECK-64-NEXT:    # %0 | 
|  | ; CHECK-64-NEXT:    #NO_APP | 
|  | ; CHECK-64-NEXT:    return | 
|  | %tmp = alloca i8 | 
|  | call void asm sideeffect "# %0", "r"(ptr %tmp) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | ; We optimize the format of "frame offset + operand" by folding it, but this is | 
|  | ; only possible when that operand is an immediate. In this example it is a | 
|  | ; global address, so we should not fold it. | 
|  | @str = local_unnamed_addr global [3 x i8] c"abc", align 16 | 
|  | define i8 @frame_offset_with_global_address() { | 
|  | ; CHECK-32-LABEL: frame_offset_with_global_address: | 
|  | ; CHECK-32:         .functype frame_offset_with_global_address () -> (i32) | 
|  | ; CHECK-32-NEXT:  # %bb.0: | 
|  | ; CHECK-32-NEXT:    i32.const $push0=, str | 
|  | ; CHECK-32-NEXT:    global.get $push5=, __stack_pointer | 
|  | ; CHECK-32-NEXT:    i32.const $push6=, 16 | 
|  | ; CHECK-32-NEXT:    i32.sub $push9=, $pop5, $pop6 | 
|  | ; CHECK-32-NEXT:    i32.const $push7=, 12 | 
|  | ; CHECK-32-NEXT:    i32.add $push8=, $pop9, $pop7 | 
|  | ; CHECK-32-NEXT:    i32.add $push1=, $pop0, $pop8 | 
|  | ; CHECK-32-NEXT:    i32.load8_u $push2=, 0($pop1) | 
|  | ; CHECK-32-NEXT:    i32.const $push3=, 67 | 
|  | ; CHECK-32-NEXT:    i32.and $push4=, $pop2, $pop3 | 
|  | ; CHECK-32-NEXT:    return $pop4 | 
|  | ; | 
|  | ; CHECK-64-LABEL: frame_offset_with_global_address: | 
|  | ; CHECK-64:         .functype frame_offset_with_global_address () -> (i32) | 
|  | ; CHECK-64-NEXT:  # %bb.0: | 
|  | ; CHECK-64-NEXT:    i64.const $push1=, str | 
|  | ; CHECK-64-NEXT:    global.get $push6=, __stack_pointer | 
|  | ; CHECK-64-NEXT:    i64.const $push7=, 16 | 
|  | ; CHECK-64-NEXT:    i64.sub $push10=, $pop6, $pop7 | 
|  | ; CHECK-64-NEXT:    i64.const $push8=, 12 | 
|  | ; CHECK-64-NEXT:    i64.add $push9=, $pop10, $pop8 | 
|  | ; CHECK-64-NEXT:    i64.extend32_s $push0=, $pop9 | 
|  | ; CHECK-64-NEXT:    i64.add $push2=, $pop1, $pop0 | 
|  | ; CHECK-64-NEXT:    i32.load8_u $push3=, 0($pop2) | 
|  | ; CHECK-64-NEXT:    i32.const $push4=, 67 | 
|  | ; CHECK-64-NEXT:    i32.and $push5=, $pop3, $pop4 | 
|  | ; CHECK-64-NEXT:    return $pop5 | 
|  | %1 = alloca i8, align 4 | 
|  | %2 = ptrtoint ptr %1 to i32 | 
|  | ;; Here @str is a global address and not an immediate, so cannot be folded | 
|  | %3 = getelementptr [3 x i8], ptr @str, i32 0, i32 %2 | 
|  | %4 = load i8, ptr %3, align 8 | 
|  | %5 = and i8 %4, 67 | 
|  | ret i8 %5 | 
|  | } | 
|  |  | 
|  | ; TODO: test over-aligned alloca |