diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -614,24 +614,33 @@ const std::vector &Epilog = info->EpilogMap.begin()->second; + // Check that the epilog actually is at the very end of the function, + // otherwise it can't be packed. + uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference( + streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first); + if (DistanceFromEnd / 4 != Epilog.size()) + return -1; + + int RetVal = -1; + // Even if we don't end up sharing opcodes with the prolog, we can still + // write the offset as a packed offset, if the single epilog is located at + // the end of the function and the offset (pointing after the prolog) fits + // as a packed offset. + if (PrologCodeBytes <= 31 && + PrologCodeBytes + ARM64CountOfUnwindCodes(Epilog) <= 124) + RetVal = PrologCodeBytes; + // Can pack if the epilog is a subset of the prolog but not vice versa if (Epilog.size() > info->Instructions.size()) - return -1; + return RetVal; // Check that the epilog actually is a perfect match for the end (backwrds) // of the prolog. for (int I = Epilog.size() - 1; I >= 0; I--) { if (info->Instructions[I] != Epilog[Epilog.size() - 1 - I]) - return -1; + return RetVal; } - // Check that the epilog actually is at the very end of the function, - // otherwise it can't be packed. - uint32_t DistanceFromEnd = (uint32_t)GetAbsDifference( - streamer, info->FuncletOrFuncEnd, info->EpilogMap.begin()->first); - if (DistanceFromEnd / 4 != Epilog.size()) - return -1; - int Offset = Epilog.size() == info->Instructions.size() ? 0 : ARM64CountOfUnwindCodes(ArrayRef( @@ -642,8 +651,10 @@ // unclear whether the epilog count in the extension word can be taken // as packed epilog offset. if (Offset > 31 || PrologCodeBytes > 124) - return -1; + return RetVal; + // As we choose to express the epilog as part of the prolog, remove the + // epilog from the map, so we don't try to emit its opcodes. info->EpilogMap.clear(); return Offset; } @@ -952,8 +963,9 @@ int PackedEpilogOffset = checkPackedEpilog(streamer, info, PrologCodeBytes); - if (PackedEpilogOffset >= 0 && !info->HandlesExceptions && - FuncLength <= 0x7ff && TryPacked) { + if (PackedEpilogOffset >= 0 && + uint32_t(PackedEpilogOffset) < PrologCodeBytes && + !info->HandlesExceptions && FuncLength <= 0x7ff && TryPacked) { // Matching prolog/epilog and no exception handlers; check if the // prolog matches the patterns that can be described by the packed // format. @@ -1025,17 +1037,19 @@ streamer.emitInt32(row2); } - // Epilog Start Index, Epilog Start Offset - for (auto &I : EpilogInfo) { - MCSymbol *EpilogStart = I.first; - uint32_t EpilogIndex = I.second; - uint32_t EpilogOffset = - (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); - if (EpilogOffset) - EpilogOffset /= 4; - uint32_t row3 = EpilogOffset; - row3 |= (EpilogIndex & 0x3FF) << 22; - streamer.emitInt32(row3); + if (PackedEpilogOffset < 0) { + // Epilog Start Index, Epilog Start Offset + for (auto &I : EpilogInfo) { + MCSymbol *EpilogStart = I.first; + uint32_t EpilogIndex = I.second; + uint32_t EpilogOffset = + (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin); + if (EpilogOffset) + EpilogOffset /= 4; + uint32_t row3 = EpilogOffset; + row3 |= (EpilogIndex & 0x3FF) << 22; + streamer.emitInt32(row3); + } } // Emit prolog unwind instructions (in reverse order). diff --git a/llvm/test/CodeGen/AArch64/wineh1.mir b/llvm/test/CodeGen/AArch64/wineh1.mir --- a/llvm/test/CodeGen/AArch64/wineh1.mir +++ b/llvm/test/CodeGen/AArch64/wineh1.mir @@ -16,8 +16,8 @@ # CHECK-NEXT: FunctionLength: 96 # CHECK-NEXT: Version: 0 # CHECK-NEXT: ExceptionData: No -# CHECK-NEXT: EpiloguePacked: No -# CHECK-NEXT: EpilogueScopes: 1 +# CHECK-NEXT: EpiloguePacked: Yes +# CHECK-NEXT: EpilogueOffset: 13 # CHECK-NEXT: ByteCodeLength: 28 # CHECK-NEXT: Prologue [ # CHECK-NEXT: 0xc808 ; stp x19, x20, [sp, #64] @@ -28,21 +28,15 @@ # CHECK-NEXT: 0xce09 ; stp x27, x28, [sp, #-80]! # CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] -# CHECK-NEXT: EpilogueScopes [ -# CHECK-NEXT: EpilogueScope { -# CHECK-NEXT: StartOffset: 16 -# CHECK-NEXT: EpilogueStartIndex: 13 -# CHECK-NEXT: Opcodes [ -# CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64] -# CHECK-NEXT: 0xd086 ; ldr x21, [sp, #48] -# CHECK-NEXT: 0xe3 ; nop -# CHECK-NEXT: 0xd0c7 ; ldr x22, [sp, #56] -# CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32] -# CHECK-NEXT: 0xc982 ; ldp x25, x26, [sp, #16] -# CHECK-NEXT: 0xce09 ; ldp x27, x28, [sp], #80 -# CHECK-NEXT: 0xe4 ; end -# CHECK-NEXT: ] -# CHECK-NEXT: } +# CHECK-NEXT: Epilogue [ +# CHECK-NEXT: 0xc808 ; ldp x19, x20, [sp, #64] +# CHECK-NEXT: 0xd086 ; ldr x21, [sp, #48] +# CHECK-NEXT: 0xe3 ; nop +# CHECK-NEXT: 0xd0c7 ; ldr x22, [sp, #56] +# CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32] +# CHECK-NEXT: 0xc982 ; ldp x25, x26, [sp, #16] +# CHECK-NEXT: 0xce09 ; ldp x27, x28, [sp], #80 +# CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] # CHECK-NEXT: } diff --git a/llvm/test/CodeGen/AArch64/wineh2.mir b/llvm/test/CodeGen/AArch64/wineh2.mir --- a/llvm/test/CodeGen/AArch64/wineh2.mir +++ b/llvm/test/CodeGen/AArch64/wineh2.mir @@ -6,8 +6,8 @@ # CHECK-NEXT: FunctionLength: 144 # CHECK-NEXT: Version: 0 # CHECK-NEXT: ExceptionData: No -# CHECK-NEXT: EpiloguePacked: No -# CHECK-NEXT: EpilogueScopes: 1 +# CHECK-NEXT: EpiloguePacked: Yes +# CHECK-NEXT: EpilogueOffset: 19 # CHECK-NEXT: ByteCodeLength: 40 # CHECK-NEXT: Prologue [ # CHECK-NEXT: 0xc80e ; stp x19, x20, [sp, #112] @@ -21,23 +21,17 @@ # CHECK-NEXT: 0xde8f ; str d12, [sp, #-128]! # CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] -# CHECK-NEXT: EpilogueScopes [ -# CHECK-NEXT: EpilogueScope { -# CHECK-NEXT: StartOffset: 26 -# CHECK-NEXT: EpilogueStartIndex: 19 -# CHECK-NEXT: Opcodes [ -# CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112] -# CHECK-NEXT: 0xc88c ; ldp x21, x22, [sp, #96] -# CHECK-NEXT: 0xc90a ; ldp x23, x24, [sp, #80] -# CHECK-NEXT: 0xc988 ; ldp x25, x26, [sp, #64] -# CHECK-NEXT: 0xca06 ; ldp x27, x28, [sp, #48] -# CHECK-NEXT: 0xdc04 ; ldr d8, [sp, #32] -# CHECK-NEXT: 0xdc45 ; ldr d9, [sp, #40] -# CHECK-NEXT: 0xd882 ; ldp d10, d11, [sp, #16] -# CHECK-NEXT: 0xde8f ; ldr d12, [sp], #128 -# CHECK-NEXT: 0xe4 ; end -# CHECK-NEXT: ] -# CHECK-NEXT: } +# CHECK-NEXT: Epilogue [ +# CHECK-NEXT: 0xc80e ; ldp x19, x20, [sp, #112] +# CHECK-NEXT: 0xc88c ; ldp x21, x22, [sp, #96] +# CHECK-NEXT: 0xc90a ; ldp x23, x24, [sp, #80] +# CHECK-NEXT: 0xc988 ; ldp x25, x26, [sp, #64] +# CHECK-NEXT: 0xca06 ; ldp x27, x28, [sp, #48] +# CHECK-NEXT: 0xdc04 ; ldr d8, [sp, #32] +# CHECK-NEXT: 0xdc45 ; ldr d9, [sp, #40] +# CHECK-NEXT: 0xd882 ; ldp d10, d11, [sp, #16] +# CHECK-NEXT: 0xde8f ; ldr d12, [sp], #128 +# CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] # CHECK-NEXT: } ... diff --git a/llvm/test/CodeGen/AArch64/wineh5.mir b/llvm/test/CodeGen/AArch64/wineh5.mir --- a/llvm/test/CodeGen/AArch64/wineh5.mir +++ b/llvm/test/CodeGen/AArch64/wineh5.mir @@ -7,8 +7,8 @@ # CHECK-NEXT: FunctionLength: 156 # CHECK-NEXT: Version: 0 # CHECK-NEXT: ExceptionData: No -# CHECK-NEXT: EpiloguePacked: No -# CHECK-NEXT: EpilogueScopes: 1 +# CHECK-NEXT: EpiloguePacked: Yes +# CHECK-NEXT: EpilogueOffset: 10 # CHECK-NEXT: ByteCodeLength: 20 # CHECK-NEXT: Prologue [ # CHECK-NEXT: 0xe002dac9 ; sub sp, #2993296 @@ -18,18 +18,12 @@ # CHECK-NEXT: 0xd53f ; str x28, [sp, #-256]! # CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] -# CHECK-NEXT: EpilogueScopes [ -# CHECK-NEXT: EpilogueScope { -# CHECK-NEXT: StartOffset: 34 -# CHECK-NEXT: EpilogueStartIndex: 10 -# CHECK-NEXT: Opcodes [ -# CHECK-NEXT: 0xe002da00 ; add sp, #2990080 -# CHECK-NEXT: 0xc0c9 ; add sp, #3216 -# CHECK-NEXT: 0x42 ; ldp x29, x30, [sp, #16] -# CHECK-NEXT: 0xd53f ; ldr x28, [sp], #256 -# CHECK-NEXT: 0xe4 ; end -# CHECK-NEXT: ] -# CHECK-NEXT: } +# CHECK-NEXT: Epilogue [ +# CHECK-NEXT: 0xe002da00 ; add sp, #2990080 +# CHECK-NEXT: 0xc0c9 ; add sp, #3216 +# CHECK-NEXT: 0x42 ; ldp x29, x30, [sp, #16] +# CHECK-NEXT: 0xd53f ; ldr x28, [sp], #256 +# CHECK-NEXT: 0xe4 ; end # CHECK-NEXT: ] # CHECK-NEXT: } diff --git a/llvm/test/MC/AArch64/seh-optimize.s b/llvm/test/MC/AArch64/seh-optimize.s --- a/llvm/test/MC/AArch64/seh-optimize.s +++ b/llvm/test/MC/AArch64/seh-optimize.s @@ -27,17 +27,13 @@ // CHECK-NEXT: 0xe201 ; add fp, sp, #8 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] -// CHECK-NEXT: EpilogueScopes [ -// CHECK-NEXT: EpilogueScope { -// CHECK: Opcodes [ -// CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32] -// CHECK-NEXT: 0xe6 ; restore next -// CHECK-NEXT: 0xcc83 ; ldp x21, x22, [sp], #32 -// CHECK-NEXT: 0x24 ; ldp x19, x20, [sp], #32 -// CHECK-NEXT: 0xcc1f ; ldp x19, x20, [sp], #256 -// CHECK-NEXT: 0xe4 ; end -// CHECK-NEXT: ] -// CHECK-NEXT: } +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: 0xc904 ; ldp x23, x24, [sp, #32] +// CHECK-NEXT: 0xe6 ; restore next +// CHECK-NEXT: 0xcc83 ; ldp x21, x22, [sp], #32 +// CHECK-NEXT: 0x24 ; ldp x19, x20, [sp], #32 +// CHECK-NEXT: 0xcc1f ; ldp x19, x20, [sp], #256 +// CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: } diff --git a/llvm/test/MC/AArch64/seh-packed-epilog.s b/llvm/test/MC/AArch64/seh-packed-epilog.s --- a/llvm/test/MC/AArch64/seh-packed-epilog.s +++ b/llvm/test/MC/AArch64/seh-packed-epilog.s @@ -43,6 +43,13 @@ // CHECK-NEXT: ExceptionData { // CHECK: ExceptionData: // CHECK-NEXT: EpiloguePacked: Yes +// CHECK-NEXT: EpilogueOffset: 0 +// CHECK-NEXT: ByteCodeLength: 4 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: 0x83 ; stp x29, x30, [sp, #-32]! +// CHECK-NEXT: 0x03 ; sub sp, #48 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] // CHECK: RuntimeFunction { // CHECK-NEXT: Function: nonpacked1 // CHECK-NEXT: ExceptionRecord: @@ -50,17 +57,42 @@ // CHECK: ExceptionData: // CHECK-NEXT: EpiloguePacked: No // CHECK: RuntimeFunction { -// CHECK-NEXT: Function: nonpacked2 +// CHECK-NEXT: Function: nonshared2 // CHECK-NEXT: ExceptionRecord: // CHECK-NEXT: ExceptionData { // CHECK: ExceptionData: -// CHECK-NEXT: EpiloguePacked: No +// CHECK-NEXT: EpiloguePacked: Yes +// CHECK-NEXT: EpilogueOffset: 3 +// CHECK-NEXT: ByteCodeLength: 8 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: 0x02 ; sub sp, #32 +// CHECK-NEXT: 0x03 ; sub sp, #48 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: 0x01 ; add sp, #16 +// CHECK-NEXT: 0x03 ; add sp, #48 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] // CHECK: RuntimeFunction { -// CHECK-NEXT: Function: nonpacked3 +// CHECK-NEXT: Function: nonshared3 // CHECK-NEXT: ExceptionRecord: // CHECK-NEXT: ExceptionData { // CHECK: ExceptionData: -// CHECK-NEXT: EpiloguePacked: No +// CHECK-NEXT: EpiloguePacked: Yes +// CHECK-NEXT: EpilogueOffset: 3 +// CHECK-NEXT: ByteCodeLength: 8 +// CHECK-NEXT: Prologue [ +// CHECK-NEXT: 0x02 ; sub sp, #32 +// CHECK-NEXT: 0x03 ; sub sp, #48 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] +// CHECK-NEXT: Epilogue [ +// CHECK-NEXT: 0xe1 ; mov sp, fp +// CHECK-NEXT: 0x02 ; add sp, #32 +// CHECK-NEXT: 0x03 ; add sp, #48 +// CHECK-NEXT: 0xe4 ; end +// CHECK-NEXT: ] .text .globl func @@ -146,8 +178,8 @@ .seh_endproc - .seh_proc nonpacked2 -nonpacked2: + .seh_proc nonshared2 +nonshared2: sub sp, sp, #48 .seh_stackalloc 48 sub sp, sp, #32 @@ -156,7 +188,7 @@ nop .seh_startepilogue - // Not packed; the epilogue mismatches at the second opcode. + // Not shared; the epilogue mismatches at the second opcode. add sp, sp, #16 .seh_stackalloc 16 add sp, sp, #48 @@ -165,8 +197,8 @@ ret .seh_endproc - .seh_proc nonpacked3 -nonpacked3: + .seh_proc nonshared3 +nonshared3: sub sp, sp, #48 .seh_stackalloc 48 sub sp, sp, #32 @@ -175,7 +207,7 @@ nop .seh_startepilogue - // Not packed; the epilogue is longer than the prologue. + // Not shared; the epilogue is longer than the prologue. mov sp, x29 .seh_set_fp add sp, sp, #32