Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -31,6 +31,7 @@ class MCInst; class MCInstPrinter; class MCSection; +class MCSubtargetInfo; class MCStreamer; class MCSymbol; class StringRef; @@ -74,6 +75,9 @@ // Allow a target to add behavior to the EmitLabel of MCStreamer. virtual void emitLabel(MCSymbol *Symbol); + + // Allow a target to add behavior to the EmitInlineAsmEnd of MCStreamer. + virtual void emitInlineAsmEnd(const MCSubtargetInfo* STI) {} }; // FIXME: declared here because it is used from Index: include/llvm/MC/MCTargetAsmParser.h =================================================================== --- include/llvm/MC/MCTargetAsmParser.h +++ include/llvm/MC/MCTargetAsmParser.h @@ -182,6 +182,10 @@ return 0; } + /// Allow a target to perform any actions after parsing inline assembly. + /// For example, to restore the ARM mode. + virtual void finishInlineAsm() {} + /// Allow a target to perform any actions after the parse completes /// successfully. For example, to write out constant pools for ldr pseudo on /// ARM. Index: lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ 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,9 @@ // system assembler does. if (OutStreamer.hasRawTextSupport()) { OutStreamer.EmitRawText(Str); + MCTargetStreamer* TS = OutStreamer.getTargetStreamer(); + if (TS) + TS->emitInlineAsmEnd(TM.getSubtargetImpl()); return; } @@ -115,14 +119,12 @@ 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 - STI(TM.getTarget().createMCSubtargetInfo(TM.getTargetTriple(), - TM.getTargetCPU(), - TM.getTargetFeatureString())); + // Reuse the existing Subtarget, because the AsmParser will + // modify it. For example, when switching between ARM and + // Thumb mode. + const MCSubtargetInfo* STC = TM.getSubtargetImpl(); + MCSubtargetInfo* STI = const_cast(STC); + OwningPtr TAP(TM.getTarget().createMCAsmParser(*STI, *Parser, *MII)); if (!TAP) @@ -136,6 +138,10 @@ /*NoFinalize*/ true); if (Res && !HasDiagHandler) report_fatal_error("Error parsing inline asm\n"); + + // Give the target parser the opportunity to restore system state. + // For example, restore ARM mode. + TAP->finishInlineAsm(); } static void EmitMSInlineAsmStr(const char *AsmStr, const MachineInstr *MI, Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -201,6 +201,9 @@ bool NextSymbolIsThumb; + // Was this parser initialized in thumb mode? + bool WasThumb; + struct { ARMCC::CondCodes Cond; // Condition for IT block. unsigned Mask:4; // Condition mask for instructions. @@ -405,6 +408,8 @@ ITState.CurPosition = ~0U; NextSymbolIsThumb = false; + + WasThumb = isThumb(); } // Implementation of the MCTargetAsmParser interface: @@ -422,6 +427,13 @@ MCStreamer &Out, unsigned &ErrorInfo, bool MatchingInlineAsm); void onLabelParsed(MCSymbol *Symbol); + + void emitMode(bool WantThumb, SMLoc L); + + void finishInlineAsm() { + emitMode(WasThumb, Parser.getTok().getLoc()); + } + void finishParse(); }; } // end anonymous namespace @@ -8139,6 +8151,22 @@ } } +void ARMAsmParser::emitMode(bool WantThumb, SMLoc L) { + if (WantThumb && !hasThumb()) { + Error(L, "target does not support Thumb mode"); + return; + } else if (!WantThumb && !hasARM()) { + Error(L, "target does not support ARM mode"); + return; + } + + if (WantThumb != isThumb()) + SwitchMode(); + + MCAssemblerFlag Flag = WantThumb ? MCAF_Code16 : MCAF_Code32; + getParser().getStreamer().EmitAssemblerFlag(Flag); +} + /// parseDirectiveThumbFunc /// ::= .thumbfunc symbol_name bool ARMAsmParser::parseDirectiveThumbFunc(SMLoc L) { @@ -8224,25 +8252,7 @@ } Parser.Lex(); - if (Val == 16) { - if (!hasThumb()) { - Error(L, "target does not support Thumb mode"); - return false; - } - - if (!isThumb()) - SwitchMode(); - getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); - } else { - if (!hasARM()) { - Error(L, "target does not support ARM mode"); - return false; - } - - if (isThumb()) - SwitchMode(); - getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32); - } + emitMode(Val == 16, L); return false; } Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -131,6 +131,17 @@ virtual void emitArch(unsigned Arch); virtual void emitFPU(unsigned FPU); virtual void emitInst(uint32_t Inst, char Suffix = '\0'); + + virtual void emitInlineAsmEnd(const MCSubtargetInfo *STI) { + bool IsThumb = STI->getFeatureBits() & ARM::ModeThumb; + if (IsThumb) + emitThumbDirective(); + else + emitARMDirective(); + } + virtual void emitARMDirective(); + virtual void emitThumbDirective(); + virtual void finishAttributeSection(); public: @@ -228,6 +239,12 @@ void ARMTargetAsmStreamer::emitFPU(unsigned FPU) { OS << "\t.fpu\t" << GetFPUName(FPU) << "\n"; } +void ARMTargetAsmStreamer::emitARMDirective() { + OS << "\t.arm\n"; +} +void ARMTargetAsmStreamer::emitThumbDirective() { + OS << "\t.thumb\n"; +} void ARMTargetAsmStreamer::finishAttributeSection() { } Index: test/CodeGen/ARM/inlineasm-switch-mode-oneway-from-arm.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/inlineasm-switch-mode-oneway-from-arm.ll @@ -0,0 +1,15 @@ +;RUN: llc -mtriple=armv7-linux-gnueabi -filetype=obj < %s | llvm-objdump -triple=armv7 -d - | FileCheck %s +;RUN: llc -mtriple=armv7-linux-gnueabi < %s | FileCheck %s -check-prefix=ASM + +target triple = "armv7-none-linux-gnueabi" + +define hidden void @bah(i8* %start) #0 align 2 { + %1 = ptrtoint i8* %start to i32 + %2 = tail call i32 asm sideeffect "@ Enter THUMB Mode\0A\09adr r3, 2f+1 \0A\09bx r3 \0A\09.code 16 \0A2: push {r7} \0A\09mov r7, $4 \0A\09svc 0x0 \0A\09pop {r7} \0A\09", "={r0},{r0},{r1},{r2},r,~{r3}"(i32 %1, i32 %1, i32 0, i32 983042) #3 + ret void +} +; CHECK: $t +; CHECK: $a + +; ASM: .code 16 +; ASM: .arm Index: test/CodeGen/ARM/inlineasm-switch-mode-oneway-from-thumb.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/inlineasm-switch-mode-oneway-from-thumb.ll @@ -0,0 +1,15 @@ +;RUN: llc -mtriple=thumbv7-linux-gnueabi -filetype=obj < %s | llvm-objdump -triple=thumbv7 -d - | FileCheck %s +;RUN: llc -mtriple=thumbv7-linux-gnueabi < %s | FileCheck %s -check-prefix=ASM + +target triple = "thumbv7--linux-gnueabi" + +define hidden void @bah(i8* %start) #0 align 2 { + %1 = ptrtoint i8* %start to i32 + %2 = tail call i32 asm sideeffect "@ Enter ARM Mode \0A\09adr r3, 1f \0A\09bx r3 \0A\09.align 2 \0A\09.code 32 \0A1: push {r7} \0A\09mov r7, $4 \0A\09svc 0x0 \0A\09pop {r7} \0A\09", "={r0},{r0},{r1},{r2},r,~{r3}"(i32 %1, i32 %1, i32 0, i32 983042) #3 + ret void +} +; CHECK: $a +; CHECK: $t + +; ASM: .code 32 +; ASM: .thumb Index: test/CodeGen/ARM/inlineasm-switch-mode.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/inlineasm-switch-mode.ll @@ -0,0 +1,13 @@ +;RUN: llc -mtriple=thumbv7-linux-gnueabi -filetype=obj < %s | llvm-objdump -arch=thumb -d - | FileCheck %s + +target triple = "thumbv7--linux-gnueabi" + +define hidden void @bah(i8* %start) #0 align 2 { + %1 = ptrtoint i8* %start to i32 + %2 = tail call i32 asm sideeffect "@ Enter ARM Mode \0A\09adr r3, 1f \0A\09bx r3 \0A\09.align 2 \0A\09.code 32 \0A1: push {r7} \0A\09mov r7, $4 \0A\09svc 0x0 \0A\09pop {r7} \0A\09@ Enter THUMB Mode\0A\09adr r3, 2f+1 \0A\09bx r3 \0A\09.code 16 \0A2: \0A\09", "={r0},{r0},{r1},{r2},r,~{r3}"(i32 %1, i32 %1, i32 0, i32 983042) #3 + ret void +} +; CHECK: $a +; CHECK-NEXT: 04 70 +; CHECK-NEXT: 2d e5 +; CHECK: $t