llvm.org GIT mirror llvm / 148c7f2
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199818 91177308-0d34-0410-b5e6-96231b3b80d8 Greg Fitzgerald 6 years ago
7 changed file(s) with 112 addition(s) and 9 deletion(s). Raw diff Collapse all Expand all
3232 class MCSection;
3333 class MCStreamer;
3434 class MCSymbol;
35 class MCSubtargetInfo;
3536 class StringRef;
3637 class Twine;
3738 class raw_ostream;
7374
7475 // Allow a target to add behavior to the EmitLabel of MCStreamer.
7576 virtual void emitLabel(MCSymbol *Symbol);
77
78 /// Let the target do anything it needs to do after emitting inlineasm.
79 /// This callback can be used restore the original mode in case the
80 /// inlineasm contains directives to switch modes.
81 /// \p StartInfo - the original subtarget info before inline asm
82 /// \p EndInfo - the final subtarget info after parsing the inline asm,
83 // or NULL if the value is unknown.
84 virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
85 MCSubtargetInfo *EndInfo) {}
7686 };
7787
7888 // FIXME: declared here because it is used from
103113 virtual void emitArch(unsigned Arch) = 0;
104114 virtual void finishAttributeSection() = 0;
105115 virtual void emitInst(uint32_t Inst, char Suffix = '\0') = 0;
116 virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
117 MCSubtargetInfo *EndInfo);
106118 };
107119
108120 /// MCStreamer - Streaming machine code generation interface. This interface
689701 /// indicated by the hasRawTextSupport() predicate. By default this aborts.
690702 void EmitRawText(const Twine &String);
691703
704 /// EmitInlineAsmEnd - Used to perform any cleanup needed after emitting
705 /// inline assembly. Provides the start and end subtarget info values.
706 /// The end subtarget info may be NULL if it is not know, for example, when
707 /// emitting the inline assembly as raw text.
708 virtual void EmitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
709 MCSubtargetInfo *EndInfo) {
710 if (TargetStreamer)
711 TargetStreamer->emitInlineAsmEnd(StartInfo, EndInfo);
712 }
713
692714 /// Flush - Causes any cached state to be written out.
693715 virtual void Flush() {}
694716
3333 #include "llvm/Support/TargetRegistry.h"
3434 #include "llvm/Support/raw_ostream.h"
3535 #include "llvm/Target/TargetMachine.h"
36 #include "llvm/Target/TargetSubtargetInfo.h"
3637 using namespace llvm;
3738
3839 namespace {
8283 // system assembler does.
8384 if (OutStreamer.hasRawTextSupport()) {
8485 OutStreamer.EmitRawText(Str);
86 OutStreamer.EmitInlineAsmEnd(TM.getSubtarget(), 0);
8587 return;
8688 }
8789
114116 OutContext, OutStreamer,
115117 *MAI));
116118
117 // FIXME: It would be nice if we can avoid createing a new instance of
118 // MCSubtargetInfo here given TargetSubtargetInfo is available. However,
119 // we have to watch out for asm directives which can change subtarget
120 // state. e.g. .code 16, .code 32.
121 OwningPtr
122 STI(TM.getTarget().createMCSubtargetInfo(TM.getTargetTriple(),
123 TM.getTargetCPU(),
124 TM.getTargetFeatureString()));
119 // Reuse the existing Subtarget, because the AsmParser may need to
120 // modify it. For example, when switching between ARM and
121 // Thumb mode.
122 MCSubtargetInfo* STI =
123 const_cast(&TM.getSubtarget());
124
125 // Preserve a copy of the original STI because the parser may modify it.
126 // The target can restore the original state in EmitInlineAsmEnd().
127 MCSubtargetInfo STIOrig = *STI;
128
125129 OwningPtr
126130 TAP(TM.getTarget().createMCAsmParser(*STI, *Parser, *MII));
127131 if (!TAP)
133137 // Don't implicitly switch to the text section before the asm.
134138 int Res = Parser->Run(/*NoInitialTextSection*/ true,
135139 /*NoFinalize*/ true);
140 OutStreamer.EmitInlineAsmEnd(STIOrig, STI);
136141 if (Res && !HasDiagHandler)
137142 report_fatal_error("Error parsing inline asm\n");
138143 }
2424 // Pin the vtables to this file.
2525 MCTargetStreamer::~MCTargetStreamer() {}
2626 void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {}
27 void ARMTargetStreamer::anchor() {}
2827
2928 MCStreamer::MCStreamer(MCContext &Ctx, MCTargetStreamer *TargetStreamer)
3029 : Context(Ctx), TargetStreamer(TargetStreamer), EmitEHFrame(true),
103103 return 0;
104104 }
105105
106 static bool isThumb(const MCSubtargetInfo& STI) {
107 return (STI.getFeatureBits() & ARM::ModeThumb) != 0;
108 }
109
110 void ARMTargetStreamer::anchor() {}
111
112 void ARMTargetStreamer::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
113 MCSubtargetInfo *EndInfo) {
114 // If either end mode is unknown (EndInfo == NULL) or different than
115 // the start mode, then restore the start mode.
116 const bool WasThumb = isThumb(StartInfo);
117 if (EndInfo == NULL || WasThumb != isThumb(*EndInfo)) {
118 assert(Streamer);
119 Streamer->EmitAssemblerFlag(WasThumb ? MCAF_Code16 : MCAF_Code32);
120 if (EndInfo)
121 EndInfo->ToggleFeature(ARM::ModeThumb);
122 }
123 }
124
106125 namespace {
107126
108127 class ARMELFStreamer;
0 ;RUN: llc -mtriple=armv7-linux-gnueabi -filetype=obj < %s | llvm-objdump -triple=armv7 -d - | FileCheck %s
1 ;RUN: llc -mtriple=armv7-linux-gnueabi < %s | FileCheck %s -check-prefix=ASM
2 ;RUN: llc -mtriple=armv7-apple-darwin < %s | FileCheck %s -check-prefix=ASM
3
4 define hidden i32 @bah(i8* %start) #0 align 2 {
5 %1 = ptrtoint i8* %start to i32
6 %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
7 %3 = add i32 %1, 1
8 ret i32 %3
9 }
10 ; CHECK: $t
11 ; CHECK: $a
12 ; CHECK: 01 00 81 e2 add r0, r1, #1
13
14 ; .code 32 is implicit
15 ; ASM-LABEL: bah:
16 ; ASM: .code 16
17 ; ASM: .code 32
0 ;RUN: llc -mtriple=thumbv7-linux-gnueabi -filetype=obj < %s | llvm-objdump -triple=thumbv7 -d - | FileCheck %s
1 ;RUN: llc -mtriple=thumbv7-linux-gnueabi < %s | FileCheck %s -check-prefix=ASM
2 ;RUN: llc -mtriple=thumbv7-apple-darwin < %s | FileCheck %s -check-prefix=ASM
3
4 define hidden i32 @bah(i8* %start) #0 align 2 {
5 %1 = ptrtoint i8* %start to i32
6 %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
7 %3 = add i32 %1, 1
8 ret i32 %3
9 }
10 ; CHECK: $a
11 ; CHECK: $t
12 ; CHECK: 48 1c adds r0, r1, #1
13
14 ; ASM: .code 16
15 ; ASM-LABEL: bah:
16 ; ASM: .code 32
17 ; ASM: .code 16
0 ;RUN: llc -mtriple=thumbv7-linux-gnueabi -filetype=obj < %s > %t
1 ; Two pass decoding needed because llvm-objdump does not respect mapping symbols
2 ;RUN: llvm-objdump -triple=armv7 -d %t | FileCheck %s --check-prefix=ARM
3 ;RUN: llvm-objdump -triple=thumbv7 -d %t | FileCheck %s --check-prefix=THUMB
4
5 define hidden i32 @bah(i8* %start) #0 align 2 {
6 %1 = ptrtoint i8* %start to i32
7 %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
8 %3 = add i32 %1, 1
9 ret i32 %3
10 }
11
12 ; ARM: $a
13 ; ARM-NEXT: 04 70 2d e5 str r7, [sp, #-4]!
14 ; ARM: $t
15 ; ARM-NEXT: 48 1c
16
17 ; THUMB: $a
18 ; THUMB-NEXT: 04 70
19 ; THUMB-NEXT: 2d e5
20 ; THUMB: $t
21 ; THUMB-NEXT: 48 1c adds r0, r1, #1