summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2017-09-28 19:04:30 +0000
committerMartin Storsjo <martin@martin.st>2017-09-28 19:04:30 +0000
commitd6218cc385920a462a99d28e0959c7300b25468a (patch)
treea5da2ad7ef083d11651cccbc46139e8a380fd68b
parentadceba59a2d6a0f083d02c6212a84b7b6aec206c (diff)
downloadbcm5719-llvm-d6218cc385920a462a99d28e0959c7300b25468a.tar.gz
bcm5719-llvm-d6218cc385920a462a99d28e0959c7300b25468a.zip
[ARM] Restore the right frame pointer register in Int_eh_sjlj_longjmp
In setupEntryBlockAndCallSites in CodeGen/SjLjEHPrepare.cpp, we fetch and store the actual frame pointer, but on return via the longjmp intrinsic, it always was restored into the r7 variable. On windows, the frame pointer should be restored into r11 instead of r7. On Darwin (where sjlj exception handling is used by default), the frame pointer is always r7, both in arm and thumb mode, and likewise, on windows, the frame pointer always is r11. On linux however, if sjlj exception handling is enabled (which it isn't by default), libcxxabi and the user code can be built in differing modes using different registers as frame pointer. Therefore, when restoring registers on a platform where we don't always use the same register depending on code mode, restore both r7 and r11. Differential Revision: https://reviews.llvm.org/D38253 llvm-svn: 314451
-rw-r--r--llvm/lib/Target/ARM/ARMAsmPrinter.cpp72
-rw-r--r--llvm/test/CodeGen/ARM/setjmp_longjmp.ll12
2 files changed, 70 insertions, 14 deletions
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index 13335a84f6d..2147c1cfcf8 100644
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -1204,6 +1204,10 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
MCTargetStreamer &TS = *OutStreamer->getTargetStreamer();
ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS);
+ const MachineFunction &MF = *MI->getParent()->getParent();
+ const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>();
+ unsigned FramePtr = STI.useR7AsFramePointer() ? ARM::R7 : ARM::R11;
+
// If we just ended a constant pool, mark it as such.
if (InConstantPool && MI->getOpcode() != ARM::CONSTPOOL_ENTRY) {
OutStreamer->EmitDataRegion(MCDR_DataRegionEnd);
@@ -1884,13 +1888,33 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addImm(ARMCC::AL)
.addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
- .addReg(ARM::R7)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
+ if (STI.isTargetDarwin() || STI.isTargetWindows()) {
+ // These platforms always use the same frame register
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
+ .addReg(FramePtr)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ } else {
+ // If the calling code might use either R7 or R11 as
+ // frame pointer register, restore it into both.
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
+ .addReg(ARM::R7)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::LDRi12)
+ .addReg(ARM::R11)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ }
assert(Subtarget->hasV4TOps());
EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::BX)
@@ -1934,13 +1958,33 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
.addImm(ARMCC::AL)
.addReg(0));
- EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
- .addReg(ARM::R7)
- .addReg(SrcReg)
- .addImm(0)
- // Predicate.
- .addImm(ARMCC::AL)
- .addReg(0));
+ if (STI.isTargetDarwin() || STI.isTargetWindows()) {
+ // These platforms always use the same frame register
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
+ .addReg(FramePtr)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ } else {
+ // If the calling code might use either R7 or R11 as
+ // frame pointer register, restore it into both.
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
+ .addReg(ARM::R7)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tLDRi)
+ .addReg(ARM::R11)
+ .addReg(SrcReg)
+ .addImm(0)
+ // Predicate.
+ .addImm(ARMCC::AL)
+ .addReg(0));
+ }
EmitToStreamer(*OutStreamer, MCInstBuilder(ARM::tBX)
.addReg(ScratchReg)
diff --git a/llvm/test/CodeGen/ARM/setjmp_longjmp.ll b/llvm/test/CodeGen/ARM/setjmp_longjmp.ll
index 7100175a97a..37ef1f43519 100644
--- a/llvm/test/CodeGen/ARM/setjmp_longjmp.ll
+++ b/llvm/test/CodeGen/ARM/setjmp_longjmp.ll
@@ -1,4 +1,6 @@
; RUN: llc %s -o - | FileCheck %s
+; RUN: llc -mtriple=armv7-linux -exception-model sjlj %s -o - | FileCheck %s -check-prefix CHECK-LINUX
+; RUN: llc -mtriple=thumbv7-win32 -exception-model sjlj %s -o - | FileCheck %s -check-prefix CHECK-WIN32
target triple = "armv7-apple-ios"
declare i32 @llvm.eh.sjlj.setjmp(i8*)
@@ -28,6 +30,16 @@ declare i8* @llvm.stacksave()
; CHECK-NEXT: ldr [[DESTREG:r[0-9]+]], {{\[}}[[BUFREG]], #4]
; CHECK-NEXT: ldr r7, {{\[}}[[BUFREG]]{{\]}}
; CHECK-NEXT: bx [[DESTREG]]
+
+; CHECK-LINUX: ldr sp, [{{\s*}}[[BUFREG:r[0-9]+]], #8]
+; CHECK-LINUX-NEXT: ldr [[DESTREG:r[0-9]+]], {{\[}}[[BUFREG]], #4]
+; CHECK-LINUX-NEXT: ldr r7, {{\[}}[[BUFREG]]{{\]}}
+; CHECK-LINUX-NEXT: ldr r11, {{\[}}[[BUFREG]]{{\]}}
+; CHECK-LINUX-NEXT: bx [[DESTREG]]
+
+; CHECK-WIN32: ldr.w r11, [{{\s*}}[[BUFREG:r[0-9]+]]]
+; CHECK-WIN32-NEXT: ldr.w sp, {{\[}}[[BUFREG]], #8]
+; CHECK-WIN32-NEXT: ldr.w pc, {{\[}}[[BUFREG]], #4]
define void @foobar() {
entry:
%buf = alloca [5 x i8*], align 4
OpenPOWER on IntegriCloud