llvm/llvm/test/MC/ARM/seh-epilog-packing.s

// This test checks various cases around sharing opcodes between epilogue and prologue

// RUN: llvm-mc -triple thumbv7-pc-win32 -filetype=obj %s | llvm-readobj -u - | FileCheck %s

// CHECK:       RuntimeFunction {
// CHECK-NEXT:    Function: func1
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: Yes
// CHECK-NEXT:      Fragment: No
// CHECK-NEXT:      EpilogueOffset: 2
// CHECK-NEXT:      ByteCodeLength:
// CHECK-NEXT:      Prologue [
// CHECK-NEXT:        0xf5 0x15           ; vpush {d1-d5}
// CHECK-NEXT:        0x05                ; sub sp, #(5 * 4)
// CHECK-NEXT:        0xa0 0xf0           ; push.w {r4-r7, lr}
// CHECK-NEXT:        0xfe                ; b.w <target>
// CHECK-NEXT:      ]
// CHECK-NEXT:      Epilogue [
// CHECK-NEXT:        0x05                ; add sp, #(5 * 4)
// CHECK-NEXT:        0xa0 0xf0           ; pop.w {r4-r7, pc}
// CHECK-NEXT:        0xfe                ; b.w <target>
// CHECK-NEXT:      ]
// CHECK-NEXT:    }
// CHECK-NEXT:  }
// CHECK-NEXT:  RuntimeFunction {
// CHECK-NEXT:    Function: func2
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: Yes
// CHECK-NEXT:      Fragment: No
// CHECK-NEXT:      EpilogueOffset: 0
// CHECK-NEXT:      ByteCodeLength: 4
// CHECK-NEXT:      Prologue [
// CHECK-NEXT:        0xd2                ; push {r4-r6}
// CHECK-NEXT:        0x04                ; sub sp, #(4 * 4)
// CHECK-NEXT:        0xfd                ; bx <reg>
// CHECK-NEXT:      ]
// CHECK-NEXT:    }
// CHECK-NEXT:  }
// CHECK-NEXT:  RuntimeFunction {
// CHECK-NEXT:    Function: func3
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: Yes
// CHECK-NEXT:      Fragment: No
// CHECK-NEXT:      EpilogueOffset: 0
// CHECK-NEXT:      ByteCodeLength: 4
// CHECK-NEXT:      Prologue [
// CHECK-NEXT:        0xe1                ; vpush {d8-d9}
// CHECK-NEXT:        0xdf                ; push.w {r4-r11, lr}
// CHECK-NEXT:      ]
// CHECK-NEXT:    }
// CHECK-NEXT:  }
// CHECK-NEXT:  RuntimeFunction {
// CHECK-NEXT:    Function: notshared1
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: Yes
// CHECK-NEXT:      Fragment:
// CHECK-NEXT:      EpilogueOffset: 2
// CHECK-NEXT:      ByteCodeLength: 4
// CHECK-NEXT:      Prologue [
// CHECK-NEXT:        0xdf                ; push.w {r4-r11, lr}
// CHECK-NEXT:      ]
// CHECK-NEXT:      Epilogue [
// CHECK-NEXT:        0xdb                ; pop.w {r4-r11}
// CHECK-NEXT:        0xfd                ; bx <reg>
// CHECK-NEXT:      ]
// CHECK:       RuntimeFunction {
// CHECK-NEXT:    Function: notpacked2
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: No
// CHECK:       RuntimeFunction {
// CHECK-NEXT:    Function: notpacked3
// CHECK-NEXT:    ExceptionRecord:
// CHECK-NEXT:    ExceptionData {
// CHECK-NEXT:      FunctionLength:
// CHECK-NEXT:      Version:
// CHECK-NEXT:      ExceptionData:
// CHECK-NEXT:      EpiloguePacked: No

        .text
        .syntax unified
        .seh_proc func1
func1:
        push.w {r4-r7,lr}
        .seh_save_regs_w {r4-r7,lr}
        sub sp, sp, #20
        .seh_stackalloc 20
        vpush {d1-d5}
        .seh_save_fregs {d1-d5}
        .seh_endprologue
        nop
        .seh_startepilogue
        add sp, sp, #20
        .seh_stackalloc 20
        // As we're popping into lr instead of directly into pc, this pop
        // becomes a wide instruction. To match prologue vs epilogue, the
        // push in the prologue has been made wide too.
        pop.w {r4-r7,lr}
        .seh_save_regs_w {r4-r7,lr}
        b.w tailcall
        .seh_nop_w
        .seh_endepilogue
        .seh_endproc

        .seh_proc func2
func2:
        sub sp, sp, #16
        .seh_stackalloc 16
        push {r4-r6}
        .seh_save_regs {r4-r6}
        .seh_endprologue
        nop
        .seh_startepilogue
        pop {r4-r6}
        .seh_save_regs {r4-r6}
        add sp, sp, #16
        .seh_stackalloc 16
        bx lr
        .seh_nop
        .seh_endepilogue
        .seh_endproc

        .seh_proc func3
func3:
        push {r4-r11,lr}
        .seh_save_regs_w {r4-r11,lr}
        vpush {d8-d9}
        .seh_save_fregs {d8-d9}
        .seh_endprologue
        nop
        .seh_startepilogue
        vpop {d8-d9}
        .seh_save_fregs {d8-d9}
        pop {r4-r11,pc}
        .seh_save_regs_w {r4-r11,pc}
        .seh_endepilogue
        .seh_endproc

        .seh_proc notshared1
notshared1:
        push {r4-r11,lr}
        .seh_save_regs_w {r4-r11,lr}
        .seh_endprologue
        nop
        .seh_startepilogue
        // Packed, but not shared as this opcode doesn't match the prolog
        pop {r4-r11}
        .seh_save_regs_w {r4-r11}
        bx lr
        .seh_nop
        .seh_endepilogue
        .seh_endproc

        .seh_proc notpacked2
notpacked2:
        push {r4-r11}
        .seh_save_regs_w {r4-r11}
        vpush {d8-d9}
        .seh_save_fregs {d8-d9}
        .seh_endprologue
        nop
        .seh_startepilogue
        vpop {d8-d9}
        .seh_save_fregs {d8-d9}
        pop {r4-r11}
        .seh_save_regs_w {r4-r11}
        bx lr
        .seh_nop
        .seh_endepilogue
        // Not packed, as the epilog isn't at the end of the function
        nop
        .seh_endproc

        .seh_proc notpacked3
notpacked3:
        push {r4-r11,lr}
        .seh_save_regs_w {r4-r11,lr}
        .seh_endprologue
        nop
        it ge
        // Not packed, as the epilog is conditional
        .seh_startepilogue_cond ge
        popge {r4-r11,pc}
        .seh_save_regs_w {r4-r11,pc}
        .seh_endepilogue
        .seh_endproc