summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
authorGreg Fitzgerald <gregf@codeaurora.org>2014-01-22 18:32:35 +0000
committerGreg Fitzgerald <gregf@codeaurora.org>2014-01-22 18:32:35 +0000
commit1f6a6086aedbb08e6cd788de5ee85c7ac99c7175 (patch)
tree74f2a5ec17177e836a73add0f866d7f8d1cd1b1a /llvm/lib
parent6b70ec0d4605be6901c254510698517e42e42cdd (diff)
downloadbcm5719-llvm-1f6a6086aedbb08e6cd788de5ee85c7ac99c7175.tar.gz
bcm5719-llvm-1f6a6086aedbb08e6cd788de5ee85c7ac99c7175.zip
Fix inline assembly that switches between ARM and Thumb modes
This patch restores the ARM mode if the user's inline assembly does not. In the object streamer, it ensures that instructions following the inline assembly are encoded correctly and that correct mapping symbols are emitted. For the asm streamer, it emits a .arm or .thumb directive. This patch does not ensure that the inline assembly contains the ADR instruction to switch modes at runtime. The problem we need to solve is code like this: int foo(int a, int b) { int r = a + b; asm volatile( ".align 2 \n" ".arm \n" "add r0,r0,r0 \n" : : "r"(r)); return r+1; } If we compile this function in thumb mode then the inline assembly will switch to arm mode. We need to make sure that we switch back to thumb mode after emitting the inline assembly or we will incorrectly encode the instructions that follow (i.e. the assembly instructions for return r+1). Based on patch by David Peixotto Change-Id: Ib57f6d2d78a22afad5de8693fba6230ff56ba48b llvm-svn: 199818
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp21
-rw-r--r--llvm/lib/MC/MCStreamer.cpp1
-rw-r--r--llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp19
3 files changed, 32 insertions, 9 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
index cd1e4102761..d679bff4cb5 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
@@ -34,6 +34,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
namespace {
@@ -83,6 +84,7 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode,
// system assembler does.
if (OutStreamer.hasRawTextSupport()) {
OutStreamer.EmitRawText(Str);
+ OutStreamer.EmitInlineAsmEnd(TM.getSubtarget<MCSubtargetInfo>(), 0);
return;
}
@@ -115,14 +117,16 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode,
OutContext, OutStreamer,
*MAI));
- // FIXME: It would be nice if we can avoid createing a new instance of
- // MCSubtargetInfo here given TargetSubtargetInfo is available. However,
- // we have to watch out for asm directives which can change subtarget
- // state. e.g. .code 16, .code 32.
- OwningPtr<MCSubtargetInfo>
- STI(TM.getTarget().createMCSubtargetInfo(TM.getTargetTriple(),
- TM.getTargetCPU(),
- TM.getTargetFeatureString()));
+ // Reuse the existing Subtarget, because the AsmParser may need to
+ // modify it. For example, when switching between ARM and
+ // Thumb mode.
+ MCSubtargetInfo* STI =
+ const_cast<MCSubtargetInfo*>(&TM.getSubtarget<MCSubtargetInfo>());
+
+ // Preserve a copy of the original STI because the parser may modify it.
+ // The target can restore the original state in EmitInlineAsmEnd().
+ MCSubtargetInfo STIOrig = *STI;
+
OwningPtr<MCTargetAsmParser>
TAP(TM.getTarget().createMCAsmParser(*STI, *Parser, *MII));
if (!TAP)
@@ -134,6 +138,7 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode,
// Don't implicitly switch to the text section before the asm.
int Res = Parser->Run(/*NoInitialTextSection*/ true,
/*NoFinalize*/ true);
+ OutStreamer.EmitInlineAsmEnd(STIOrig, STI);
if (Res && !HasDiagHandler)
report_fatal_error("Error parsing inline asm\n");
}
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 11b9c58957e..5ba28d2099d 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -25,7 +25,6 @@ using namespace llvm;
// Pin the vtables to this file.
MCTargetStreamer::~MCTargetStreamer() {}
void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {}
-void ARMTargetStreamer::anchor() {}
MCStreamer::MCStreamer(MCContext &Ctx, MCTargetStreamer *TargetStreamer)
: Context(Ctx), TargetStreamer(TargetStreamer), EmitEHFrame(true),
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
index 79d5619b764..e9ffc5890ad 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp
@@ -104,6 +104,25 @@ static unsigned GetArchDefaultCPUArch(unsigned ID) {
return 0;
}
+static bool isThumb(const MCSubtargetInfo& STI) {
+ return (STI.getFeatureBits() & ARM::ModeThumb) != 0;
+}
+
+void ARMTargetStreamer::anchor() {}
+
+void ARMTargetStreamer::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
+ MCSubtargetInfo *EndInfo) {
+ // If either end mode is unknown (EndInfo == NULL) or different than
+ // the start mode, then restore the start mode.
+ const bool WasThumb = isThumb(StartInfo);
+ if (EndInfo == NULL || WasThumb != isThumb(*EndInfo)) {
+ assert(Streamer);
+ Streamer->EmitAssemblerFlag(WasThumb ? MCAF_Code16 : MCAF_Code32);
+ if (EndInfo)
+ EndInfo->ToggleFeature(ARM::ModeThumb);
+ }
+}
+
namespace {
class ARMELFStreamer;
OpenPOWER on IntegriCloud