diff --git a/llvm/include/llvm/Support/ARMWinEH.h b/llvm/include/llvm/Support/ARMWinEH.h --- a/llvm/include/llvm/Support/ARMWinEH.h +++ b/llvm/include/llvm/Support/ARMWinEH.h @@ -199,13 +199,14 @@ inline uint16_t StackAdjustment(const RuntimeFunction &RF) { uint16_t Adjustment = RF.StackAdjust(); if (Adjustment >= 0x3f4) - return (Adjustment & 0x3) ? ((Adjustment & 0x3) << 2) - 1 : 0; + return (Adjustment & 0x3) + 1; return Adjustment; } /// SavedRegisterMask - Utility function to calculate the set of saved general /// purpose (r0-r15) and VFP (d0-d31) registers. -std::pair SavedRegisterMask(const RuntimeFunction &RF); +std::pair SavedRegisterMask(const RuntimeFunction &RF, + bool Prologue = true); /// RuntimeFunctionARM64 - An entry in the table of procedure data (.pdata) /// diff --git a/llvm/lib/Support/ARMWinEH.cpp b/llvm/lib/Support/ARMWinEH.cpp --- a/llvm/lib/Support/ARMWinEH.cpp +++ b/llvm/lib/Support/ARMWinEH.cpp @@ -11,22 +11,35 @@ namespace llvm { namespace ARM { namespace WinEH { -std::pair SavedRegisterMask(const RuntimeFunction &RF) { +std::pair SavedRegisterMask(const RuntimeFunction &RF, + bool Prologue) { uint8_t NumRegisters = RF.Reg(); uint8_t RegistersVFP = RF.R(); uint8_t LinkRegister = RF.L(); uint8_t ChainedFrame = RF.C(); - uint16_t GPRMask = (ChainedFrame << 11) | (LinkRegister << 14); + uint16_t GPRMask = (ChainedFrame << 11); uint32_t VFPMask = 0; + if (Prologue) { + GPRMask |= (LinkRegister << 14); + } else { + // If Ret != 0, we pop into Lr and return later + if (RF.Ret() != ReturnType::RT_POP) + GPRMask |= (LinkRegister << 14); + else if (!RF.H()) // If H == 0, we pop directly into Pc + GPRMask |= (LinkRegister << 15); + // else, Ret == 0 && H == 1, we pop into Pc separately afterwards + } + if (RegistersVFP) VFPMask |= (((1 << ((NumRegisters + 1) % 8)) - 1) << 8); else GPRMask |= (((1 << (NumRegisters + 1)) - 1) << 4); - if (PrologueFolding(RF)) - GPRMask |= (((1 << (NumRegisters + 1)) - 1) << (~RF.StackAdjust() & 0x3)); + if ((PrologueFolding(RF) && Prologue) || (EpilogueFolding(RF) && !Prologue)) + GPRMask |= (((1 << ((RF.StackAdjust() & 0x3) + 1)) - 1) + << (~RF.StackAdjust() & 0x3)); return std::make_pair(GPRMask, VFPMask); } diff --git a/llvm/test/tools/llvm-readobj/COFF/arm-unwind-packed.s b/llvm/test/tools/llvm-readobj/COFF/arm-unwind-packed.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/COFF/arm-unwind-packed.s @@ -0,0 +1,704 @@ +// REQUIRES: arm-registered-target +// RUN: llvm-mc -filetype=obj -triple thumbv7-windows-gnu %s -o %t.o +// RUN: llvm-readobj --unwind %t.o | FileCheck --strict-whitespace %s + +// CHECK: RuntimeFunction { +// CHECK-NEXT: Function: func6 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 0 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func7 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 0 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r4} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r4} +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func8 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 10 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 0 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r4, lr} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r4, lr} +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func9 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 24 +// CHECK-NEXT: ReturnType: b.w +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 32 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {lr} +// CHECK-NEXT: vpush {d8} +// CHECK-NEXT: sub sp, sp, #32 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #32 +// CHECK-NEXT: vpop {d8} +// CHECK-NEXT: pop {lr} +// CHECK-NEXT: b.w +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func10 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 26 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 1 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r11, lr} +// CHECK-NEXT: mov r11, sp +// CHECK-NEXT: vpush {d8-d9} +// CHECK-NEXT: sub sp, sp, #16 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: vpop {d8-d9} +// CHECK-NEXT: pop {r11, lr} +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func11 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 24 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 1 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r11, lr} +// CHECK-NEXT: mov r11, sp +// CHECK-NEXT: vpush {d8-d9} +// CHECK-NEXT: sub sp, sp, #16 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: vpop {d8-d9} +// CHECK-NEXT: pop {r11, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func12 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 18 +// CHECK-NEXT: ReturnType: b.w +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 6 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: vpush {d8-d14} +// CHECK-NEXT: sub sp, sp, #16 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: vpop {d8-d14} +// CHECK-NEXT: b.w +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func13 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 18 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 6 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 20 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r4-r11, lr} +// CHECK-NEXT: add.w r11, sp, #28 +// CHECK-NEXT: sub sp, sp, #20 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #20 +// CHECK-NEXT: pop {r4-r11, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func14 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 14 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 20 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r4-r11, lr} +// CHECK-NEXT: sub sp, sp, #20 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #20 +// CHECK-NEXT: pop {r4-r11, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func15 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 20 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 512 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r4, lr} +// CHECK-NEXT: sub sp, sp, #512 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #512 +// CHECK-NEXT: pop {r4} +// CHECK-NEXT: ldr pc, [sp], #20 +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func16 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 20 +// CHECK-NEXT: ReturnType: b.w +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 0 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r11, lr} +// CHECK-NEXT: mov r11, sp +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r11, lr} +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: b.w +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func17 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 20 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 512 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r4} +// CHECK-NEXT: sub sp, sp, #512 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #512 +// CHECK-NEXT: pop {r4} +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func18 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 6 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 4 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r3, lr} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r3, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func19 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 12 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r0-r4} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r0-r4} +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func20 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 14 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r0-r4} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: pop {r4} +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func21 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 14 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 16 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r4} +// CHECK-NEXT: sub sp, sp, #16 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r0-r4} +// CHECK-NEXT: add sp, sp, #16 +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func22 +// CHECK-NEXT: Fragment: Yes +// CHECK-NEXT: FunctionLength: 14 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 512 +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #512 +// CHECK-NEXT: pop {r4} +// CHECK-NEXT: ldr pc, [sp], #20 +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func23 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 12 +// CHECK-NEXT: ReturnType: (no epilogue) +// CHECK-NEXT: HomedParameters: Yes +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 512 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r0-r3} +// CHECK-NEXT: push {r4, lr} +// CHECK-NEXT: sub sp, sp, #512 +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func24 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 16 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 3 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 8 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r2-r7, r11, lr} +// CHECK-NEXT: add.w r11, sp, #24 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #8 +// CHECK-NEXT: pop {r4-r7, r11, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func25 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 16 +// CHECK-NEXT: ReturnType: pop {pc} +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 3 +// CHECK-NEXT: R: 0 +// CHECK-NEXT: LinkRegister: Yes +// CHECK-NEXT: Chaining: Yes +// CHECK-NEXT: StackAdjustment: 8 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r4-r7, r11, lr} +// CHECK-NEXT: add.w r11, sp, #16 +// CHECK-NEXT: sub sp, sp, #8 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r2-r7, r11, pc} +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func26 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 12 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r1-r3} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: add sp, sp, #12 +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func27 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 7 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 12 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: sub sp, sp, #12 +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: pop {r1-r3} +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } +// CHECK-NEXT: RuntimeFunction { +// CHECK-NEXT: Function: func28 +// CHECK-NEXT: Fragment: No +// CHECK-NEXT: FunctionLength: 8 +// CHECK-NEXT: ReturnType: bx +// CHECK-NEXT: HomedParameters: No +// CHECK-NEXT: Reg: 0 +// CHECK-NEXT: R: 1 +// CHECK-NEXT: LinkRegister: No +// CHECK-NEXT: Chaining: No +// CHECK-NEXT: StackAdjustment: 4 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: push {r3} +// CHECK-NEXT: vpush {d8} +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: vpop {d8} +// CHECK-NEXT: pop {r3} +// CHECK-NEXT: bx +// CHECK-NEXT: ] +// CHECK-NEXT: } + + .thumb + .syntax unified + +func6: + nop + nop + nop + bx lr + +func7: + push {r4} + nop + pop {r4} + bx lr + +func8: + push {r4,lr} + nop + pop {r4,lr} + bx lr + +func9: + push {lr} + vpush {d8} + sub sp, sp, #32 + nop + add sp, sp, #32 + vpop {d8} + pop {lr} + b tailcall + +func10: + push {r11,lr} + mov r11, sp + vpush {d8-d9} + sub sp, sp, #16 + nop + add sp, sp, #16 + vpop {d8-d9} + pop {r11,lr} + bx lr + +func11: + push {r11,lr} + mov r11, sp + vpush {d8-d9} + sub sp, sp, #16 + nop + add sp, sp, #16 + vpop {d8-d9} + pop {r11,pc} + +func12: + vpush {d8-d14} + sub sp, sp, #16 + nop + add sp, sp, #16 + vpop {d8-d14} + b tailcall + +func13: + push {r4-r11,lr} + add r11, sp, #0x1c + sub sp, sp, #20 + nop + add sp, sp, #20 + pop {r4-r11,pc} + +func14: + push {r4-r11,lr} + sub sp, sp, #20 + nop + add sp, sp, #20 + pop {r4-r11,pc} + +func15: + push {r0-r3} + push {r4,lr} + sub sp, sp, #512 + nop + add sp, sp, #512 + pop {r4} + ldr pc, [sp], #20 + +func16: + push {r0-r3} + push {r11,lr} + mov r11, sp + nop + pop {r11, lr} + add sp, sp, #16 + b tailcall + +func17: + push {r0-r3} + push {r4} + sub sp, sp, #512 + nop + add sp, sp, #512 + pop {r4} + add sp, sp, #16 + bx lr + +func18: + push {r3,lr} + nop + pop {r3,pc} + +func19: + push {r0-r3} + push {r0-r4} + nop + pop {r0-r4} + add sp, sp, #16 + bx lr + +func20: + push {r0-r3} + push {r0-r4} + nop + add sp, sp, #16 + pop {r4} + add sp, sp, #16 + bx lr + +func21: + push {r0-r3} + push {r4} + sub sp, sp, #16 + nop + pop {r0-r4} + add sp, sp, #16 + bx lr + +func22: + nop + nop + add sp, sp, #512 + pop {r4} + ldr pc, [sp], #20 + +func23: + push {r0-r3} + push {r4,lr} + sub sp, sp, #512 + nop + nop + +func24: + push {r2-r7,r11,lr} + add r11, sp, #24 + nop + add sp, sp, #8 + pop {r4-r7,r11,pc} + +func25: + push {r4-r7,r11,lr} + add r11, sp, #16 + sub sp, sp, #8 + nop + pop {r2-r7,r11,pc} + +func26: + push {r1-r3} + nop + add sp, sp, #12 + bx lr + +func27: + sub sp, sp, #12 + nop + pop {r1-r3} + bx lr + +func28: + push {r3} + vpush {d8} + nop + vpop {d8} + pop {r3} + bx lr + + .section .pdata,"dr" + .rva func6 + .long 0x000f2011 + .rva func7 + .long 0x00002011 + .rva func8 + .long 0x00102015 + .rva func9 + .long 0x02184031 + .rva func10 + .long 0x01392035 + .rva func11 + .long 0x01390031 + .rva func12 + .long 0x010e4025 + .rva func13 + .long 0x01760025 + .rva func14 + .long 0x0157001d + .rva func15 + .long 0x20108029 + .rva func16 + .long 0x003fc029 + .rva func17 + .long 0x2000a029 + .rva func18 + .long 0xff1f000d + .rva func19 + .long 0xffc0a019 + .rva func20 + .long 0xfdc0a01d + .rva func21 + .long 0xfec0a01d + .rva func22 + .long 0x2010801e + .rva func23 + .long 0x2010e019 + .rva func24 + .long 0xfd730021 + .rva func25 + .long 0xfe730021 + .rva func26 + .long 0xfd8f2011 + .rva func27 + .long 0xfe8f2011 + .rva func28 + .long 0xff082011 diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -133,7 +133,8 @@ void decodeOpcodes(ArrayRef Opcodes, unsigned Offset, bool Prologue); - void printRegisters(const std::pair &RegisterMask); + void printGPRMask(uint16_t Mask); + void printVFPMask(uint32_t Mask); ErrorOr getSectionContaining(const object::COFFObjectFile &COFF, uint64_t Address); diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -200,15 +200,10 @@ printRange(OS, LS, First, End, Letter); } -void Decoder::printRegisters( - const std::pair &RegisterMask) { - const uint16_t GPRMask = std::get<0>(RegisterMask); - const uint32_t VFPMask = std::get<1>(RegisterMask); - +void Decoder::printGPRMask(uint16_t GPRMask) { OS << '{'; ListSeparator LS; printRange(OS, GPRMask, LS, 0, 12, 'r'); - printRange(OS, VFPMask, LS, 0, 31, 'd'); if (GPRMask & (1 << 14)) OS << LS << "lr"; if (GPRMask & (1 << 15)) @@ -216,6 +211,13 @@ OS << '}'; } +void Decoder::printVFPMask(uint32_t VFPMask) { + OS << '{'; + ListSeparator LS; + printRange(OS, VFPMask, LS, 0, 31, 'd'); + OS << '}'; +} + ErrorOr Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { for (const auto &Section : COFF.sections()) { @@ -344,7 +346,7 @@ SW.startLine() << format("0x%02x 0x%02x ; %s.w ", OC[Offset + 0], OC[Offset + 1], Prologue ? "push" : "pop"); - printRegisters(std::make_pair(RegisterMask, 0)); + printGPRMask(RegisterMask); OS << '\n'; Offset += 2; @@ -373,7 +375,7 @@ SW.startLine() << format("0x%02x ; %s ", OC[Offset], Prologue ? "push" : "pop"); - printRegisters(std::make_pair(GPRMask, 0)); + printGPRMask(GPRMask); OS << '\n'; ++Offset; @@ -390,7 +392,7 @@ SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], Prologue ? "push" : "pop"); - printRegisters(std::make_pair(GPRMask, 0)); + printGPRMask(GPRMask); OS << '\n'; ++Offset; @@ -404,7 +406,7 @@ SW.startLine() << format("0x%02x ; %s ", OC[Offset], Prologue ? "vpush" : "vpop"); - printRegisters(std::make_pair(0, VFPMask)); + printVFPMask(VFPMask); OS << '\n'; ++Offset; @@ -431,7 +433,7 @@ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], OC[Offset + 1], Prologue ? "push" : "pop"); - printRegisters(std::make_pair(GPRMask, 0)); + printGPRMask(GPRMask); OS << '\n'; Offset += 2; @@ -480,7 +482,7 @@ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], OC[Offset + 1], Prologue ? "vpush" : "vpop"); - printRegisters(std::make_pair(0, VFPMask)); + printVFPMask(VFPMask); OS << '\n'; Offset += 2; @@ -495,7 +497,7 @@ SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], OC[Offset + 1], Prologue ? "vpush" : "vpop"); - printRegisters(std::make_pair(0, VFPMask)); + printVFPMask(VFPMask); OS << '\n'; Offset += 2; @@ -1132,17 +1134,75 @@ SW.printString("Function", formatSymbol(FunctionName, FunctionAddress, FunctionOffset)); - if (!isAArch64) - SW.printBoolean("Fragment", - RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); + SW.printBoolean("Fragment", + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); SW.printNumber("FunctionLength", RF.FunctionLength()); SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; SW.printBoolean("HomedParameters", RF.H()); - SW.startLine() << "SavedRegisters: "; - printRegisters(SavedRegisterMask(RF)); - OS << '\n'; + SW.printNumber("Reg", RF.Reg()); + SW.printNumber("R", RF.R()); + SW.printBoolean("LinkRegister", RF.L()); + SW.printBoolean("Chaining", RF.C()); SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); + if (RF.Flag() != RuntimeFunctionFlag::RFF_PackedFragment) { + ListScope PS(SW, "Prologue"); + + uint16_t GPRMask, VFPMask; + std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/true); + + if (RF.H()) + SW.startLine() << "push {r0-r3}\n"; + if (GPRMask) { + SW.startLine() << "push "; + printGPRMask(GPRMask); + OS << "\n"; + } + if (RF.C()) { + // Count the number of registers pushed below R11 + int FpOffset = 4 * countPopulation(GPRMask & ((1U << 11) - 1)); + if (FpOffset) + SW.startLine() << "add.w r11, sp, #" << FpOffset << "\n"; + else + SW.startLine() << "mov r11, sp\n"; + } + if (VFPMask) { + SW.startLine() << "vpush "; + printVFPMask(VFPMask); + OS << "\n"; + } + if (StackAdjustment(RF) && !PrologueFolding(RF)) + SW.startLine() << "sub sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; + } + + if (RF.Ret() != ReturnType::RT_NoEpilogue) { + ListScope PS(SW, "Epilogue"); + + uint16_t GPRMask, VFPMask; + std::tie(GPRMask, VFPMask) = SavedRegisterMask(RF, /*Prologue=*/false); + + if (StackAdjustment(RF) && !EpilogueFolding(RF)) + SW.startLine() << "add sp, sp, #" << StackAdjustment(RF) * 4 << "\n"; + if (VFPMask) { + SW.startLine() << "vpop "; + printVFPMask(VFPMask); + OS << "\n"; + } + if (GPRMask) { + SW.startLine() << "pop "; + printGPRMask(GPRMask); + OS << "\n"; + } + if (RF.H()) { + if (RF.L() == 0 || RF.Ret() != ReturnType::RT_POP) + SW.startLine() << "add sp, sp, #16\n"; + else + SW.startLine() << "ldr pc, [sp], #20\n"; + } + if (RF.Ret() != ReturnType::RT_POP) + SW.startLine() << RF.Ret() << '\n'; + } + return true; }