llvm.org GIT mirror llvm / 304512c
ARM IAS: support .inst directive This adds support for the .inst directive. This is an ARM specific directive to indicate an instruction encoded as a constant expression. The major difference between .word, .short, or .byte and .inst is that the latter will be disassembled as an instruction since it does not get flagged as data. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197657 91177308-0d34-0410-b5e6-96231b3b80d8 Saleem Abdulrasool 6 years ago
11 changed file(s) with 317 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
9494 virtual void emitFPU(unsigned FPU) = 0;
9595 virtual void emitArch(unsigned Arch) = 0;
9696 virtual void finishAttributeSection() = 0;
97 virtual void emitInst(uint32_t Inst, char Suffix = '\0') = 0;
9798 };
9899
99100 /// MCStreamer - Streaming machine code generation interface. This interface
1818 #include "llvm/ADT/OwningPtr.h"
1919 #include "llvm/ADT/STLExtras.h"
2020 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringExtras.h"
2122 #include "llvm/ADT/StringSwitch.h"
2223 #include "llvm/ADT/Twine.h"
2324 #include "llvm/MC/MCAsmInfo.h"
149150 bool parseDirectiveSetFP(SMLoc L);
150151 bool parseDirectivePad(SMLoc L);
151152 bool parseDirectiveRegSave(SMLoc L, bool IsVector);
153 bool parseDirectiveInst(SMLoc L, char Suffix = '\0');
152154
153155 StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode,
154156 bool &CarrySetting, unsigned &ProcessorIMod,
78087810 return parseDirectiveRegSave(DirectiveID.getLoc(), false);
78097811 else if (IDVal == ".vsave")
78107812 return parseDirectiveRegSave(DirectiveID.getLoc(), true);
7813 else if (IDVal == ".inst")
7814 return parseDirectiveInst(DirectiveID.getLoc());
7815 else if (IDVal == ".inst.n")
7816 return parseDirectiveInst(DirectiveID.getLoc(), 'n');
7817 else if (IDVal == ".inst.w")
7818 return parseDirectiveInst(DirectiveID.getLoc(), 'w');
78117819 return true;
78127820 }
78137821
82848292 return Error(L, ".vsave expects DPR registers");
82858293
82868294 getTargetStreamer().emitRegSave(Op->getRegList(), IsVector);
8295 return false;
8296 }
8297
8298 /// parseDirectiveInst
8299 /// ::= .inst opcode [, ...]
8300 /// ::= .inst.n opcode [, ...]
8301 /// ::= .inst.w opcode [, ...]
8302 bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) {
8303 int Width;
8304
8305 if (isThumb()) {
8306 switch (Suffix) {
8307 case 'n':
8308 Width = 2;
8309 break;
8310 case 'w':
8311 Width = 4;
8312 break;
8313 default:
8314 Parser.eatToEndOfStatement();
8315 return Error(Loc, "cannot determine Thumb instruction size, "
8316 "use inst.n/inst.w instead");
8317 }
8318 } else {
8319 if (Suffix) {
8320 Parser.eatToEndOfStatement();
8321 return Error(Loc, "width suffixes are invalid in ARM mode");
8322 }
8323 Width = 4;
8324 }
8325
8326 if (getLexer().is(AsmToken::EndOfStatement)) {
8327 Parser.eatToEndOfStatement();
8328 return Error(Loc, "expected expression following directive");
8329 }
8330
8331 for (;;) {
8332 const MCExpr *Expr;
8333
8334 if (getParser().parseExpression(Expr))
8335 return Error(Loc, "expected expression");
8336
8337 const MCConstantExpr *Value = dyn_cast_or_null(Expr);
8338 if (!Value)
8339 return Error(Loc, "expected constant expression");
8340
8341 switch (Width) {
8342 case 2:
8343 if (Value->getValue() > 0xffff)
8344 return Error(Loc, "inst.n operand is too big, use inst.w instead");
8345 break;
8346 case 4:
8347 if (Value->getValue() > 0xffffffff)
8348 return Error(Loc,
8349 StringRef(Suffix ? "inst.w" : "inst") + " operand is too big");
8350 break;
8351 default:
8352 llvm_unreachable("only supported widths are 2 and 4");
8353 }
8354
8355 getTargetStreamer().emitInst(Value->getValue(), Suffix);
8356
8357 if (getLexer().is(AsmToken::EndOfStatement))
8358 break;
8359
8360 if (getLexer().isNot(AsmToken::Comma))
8361 return Error(Loc, "unexpected token in directive");
8362
8363 Parser.Lex();
8364 }
8365
8366 Parser.Lex();
82878367 return false;
82888368 }
82898369
1919 #include "ARMUnwindOp.h"
2020 #include "ARMUnwindOpAsm.h"
2121 #include "llvm/ADT/SmallPtrSet.h"
22 #include "llvm/ADT/StringExtras.h"
2223 #include "llvm/ADT/Twine.h"
2324 #include "llvm/MC/MCAsmBackend.h"
25 #include "llvm/MC/MCAsmInfo.h"
2426 #include "llvm/MC/MCAssembler.h"
2527 #include "llvm/MC/MCCodeEmitter.h"
2628 #include "llvm/MC/MCContext.h"
120122 virtual void emitTextAttribute(unsigned Attribute, StringRef String);
121123 virtual void emitArch(unsigned Arch);
122124 virtual void emitFPU(unsigned FPU);
125 virtual void emitInst(uint32_t Inst, char Suffix = '\0');
123126 virtual void finishAttributeSection();
124127
125128 public:
187190 OS << "\t.fpu\t" << GetFPUName(FPU) << "\n";
188191 }
189192 void ARMTargetAsmStreamer::finishAttributeSection() {
193 }
194
195 void ARMTargetAsmStreamer::emitInst(uint32_t Inst, char Suffix) {
196 OS << "\t.inst";
197 if (Suffix)
198 OS << "." << Suffix;
199 OS << "\t0x" << utohexstr(Inst) << "\n";
190200 }
191201
192202 class ARMTargetELFStreamer : public ARMTargetStreamer {
294304 virtual void emitTextAttribute(unsigned Attribute, StringRef String);
295305 virtual void emitArch(unsigned Arch);
296306 virtual void emitFPU(unsigned FPU);
307 virtual void emitInst(uint32_t Inst, char Suffix = '\0');
297308 virtual void finishAttributeSection();
298309
299310 size_t calculateContentSize() const;
364375 EmitARMMappingSymbol();
365376
366377 MCELFStreamer::EmitInstruction(Inst);
378 }
379
380 virtual void emitInst(uint32_t Inst, char Suffix) {
381 unsigned Size;
382 char Buffer[4];
383 const bool LittleEndian = getContext().getAsmInfo()->isLittleEndian();
384
385 switch (Suffix) {
386 case '\0':
387 Size = 4;
388
389 assert(!IsThumb);
390 EmitARMMappingSymbol();
391 for (unsigned II = 0, IE = Size; II != IE; II++) {
392 const unsigned I = LittleEndian ? (Size - II - 1) : II;
393 Buffer[Size - II - 1] = uint8_t(Inst >> I * CHAR_BIT);
394 }
395
396 break;
397 case 'n':
398 case 'w':
399 Size = (Suffix == 'n' ? 2 : 4);
400
401 assert(IsThumb);
402 EmitThumbMappingSymbol();
403 for (unsigned II = 0, IE = Size; II != IE; II = II + 2) {
404 const unsigned I0 = LittleEndian ? II + 0 : (Size - II - 1);
405 const unsigned I1 = LittleEndian ? II + 1 : (Size - II - 2);
406 Buffer[Size - II - 2] = uint8_t(Inst >> I0 * CHAR_BIT);
407 Buffer[Size - II - 1] = uint8_t(Inst >> I1 * CHAR_BIT);
408 }
409
410 break;
411 default:
412 llvm_unreachable("Invalid Suffix");
413 }
414
415 MCELFStreamer::EmitBytes(StringRef(Buffer, Size));
367416 }
368417
369418 /// This is one of the functions used to emit data into an ELF section, so the
789838
790839 Contents.clear();
791840 FPU = ARM::INVALID_FPU;
841 }
842 void ARMTargetELFStreamer::emitInst(uint32_t Inst, char Suffix) {
843 getStreamer().emitInst(Inst, Suffix);
792844 }
793845
794846 void ARMELFStreamer::FinishImpl() {
0 @ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERROR %s
2
3 .syntax unified
4 .arm
5
6 .align 2
7 .global suffixes_invalid_in_arm
8 .type suffixes_invalid_in_arm,%function
9 suffixes_invalid_in_arm:
10 .inst.n 2
11 @ CHECK-ERROR: width suffixes are invalid in ARM mode
12 .inst.w 4
13 @ CHECK-ERROR: width suffixes are invalid in ARM mode
14
0 @ RUN: not llvm-mc %s -triple=armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERROR %s
2
3 .syntax unified
4 .arm
5
6 .align 2
7 .global constant_expression_required
8 .type constant_expression_required,%function
9 constant_expression_required:
10 .Label:
11 movs r0, r0
12 .inst .Label
13 @ CHECK-ERROR: expected constant expression
14
0 @ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - | FileCheck %s
1
2 .syntax unified
3 .thumb
4
5 .align 2
6 .global emit_asm
7 .type emit_asm,%function
8 emit_asm:
9 .inst.w 0xf2400000, 0xf2c00000
10
11 @ CHECK: .text
12 @ CHECK: .code 16
13 @ CHECK: .align 2
14 @ CHECK: .globl emit_asm
15 @ CHECK: .type emit_asm,%function
16 @ CHECK: emit_asm:
17 @ CHECK: inst.w 0xF2400000
18 @ CHECK: inst.w 0xF2C00000
19
0 @ RUN: llvm-mc %s -triple=armv7-linux-gnueabi -filetype=obj -o - \
1 @ RUN: | llvm-readobj -s -sd | FileCheck %s
2
3 .syntax unified
4
5 @-------------------------------------------------------------------------------
6 @ arm_inst
7 @-------------------------------------------------------------------------------
8 .arm
9
10 .section .inst.arm_inst
11
12 .align 2
13 .global arm_inst
14 .type arm_inst,%function
15 arm_inst:
16 .inst 0xdefe
17
18 @ CHECK: Section {
19 @ CHECK: Name: .inst.arm_inst
20 @ CHECK: SectionData (
21 @ CHECK-NEXT: 0000: FEDE0000
22 @ CHECK-NEXT: )
23
24 @-------------------------------------------------------------------------------
25 @ thumb_inst_n
26 @-------------------------------------------------------------------------------
27 .thumb
28
29 .section .inst.thumb_inst_n
30
31 .align 2
32 .global thumb_inst_n
33 .type thumb_inst_n,%function
34 thumb_inst_n:
35 .inst.n 0xdefe
36
37 @ CHECK: Section {
38 @ CHECK: Name: .inst.thumb_inst_n
39 @ CHECK: SectionData (
40 @ CHECK-NEXT: 0000: FEDE
41 @ CHECK-NEXT: )
42
43 @-------------------------------------------------------------------------------
44 @ thumb_inst_w
45 @-------------------------------------------------------------------------------
46 .thumb
47
48 .section .inst.thumb_inst_w
49
50 .align 2
51 .global thumb_inst_w
52 .type thumb_inst_w,%function
53 thumb_inst_w:
54 .inst.w 0x00000000
55
56 @ CHECK: Section {
57 @ CHECK: Name: .inst.thumb_inst_w
58 @ CHECK: SectionData (
59 @ CHECK-NEXT: 0000: 00000000
60 @ CHECK-NEXT: )
61
62 @-------------------------------------------------------------------------------
63 @ thumb_inst_w
64 @-------------------------------------------------------------------------------
65 .thumb
66
67 .section .inst.thumb_inst_inst
68
69 .align 2
70 .global thumb_inst_inst
71 .type thumb_inst_inst,%function
72 thumb_inst_inst:
73 .inst.w 0xf2400000, 0xf2c00000
74
75 @ CHECK: Section {
76 @ CHECK: Name: .inst.thumb_inst_inst
77 @ CHECK: SectionData (
78 @ CHECK-NEXT: 0000: 40F20000 C0F20000
79 @ CHECK-NEXT: )
80
0 @ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERROR %s
2
3 .syntax unified
4 .arm
5
6 .align 2
7 .global constant_overflow
8 .type constant_overflow,%function
9 constant_overflow:
10 .inst 1 << 32
11 @ CHECK-ERROR: inst operand is too big
12
13
0 @ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERRORS %s
2
3 .syntax unified
4 .thumb
5
6 .align 2
7 .global constant_overflow
8 .type constant_overflow,%function
9 constant_overflow:
10 .inst.w 1 << 32
11 @ CHECK-ERRORS: inst.w operand is too big
12
0 @ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERROR %s
2
3 .syntax unified
4 .thumb
5
6 .align 2
7 .global constant_overflow
8 .type constant_overflow,%function
9 constant_overflow:
10 .inst.n 1 << 31
11 @ CHECK-ERROR: inst.n operand is too big, use inst.w instead
12
0 @ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
1 @ RUN: | FileCheck -check-prefix CHECK-ERROR %s
2
3 .syntax unified
4 .thumb
5
6 .align 2
7 .global suffixes_required_in_thumb
8 .type suffixes_required_in_thumb,%function
9 suffixes_required_in_thumb:
10 .inst 0x0000
11 @ CHECK-ERROR: cannot determine Thumb instruction size, use inst.n/inst.w instead
12