Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -95,6 +95,7 @@ virtual void emitFPU(unsigned FPU) = 0; virtual void emitArch(unsigned Arch) = 0; virtual void finishAttributeSection() = 0; + virtual void emitInst(uint32_t Inst, char Suffix = '\0') = 0; }; /// MCStreamer - Streaming machine code generation interface. This interface Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" @@ -150,6 +151,7 @@ bool parseDirectiveSetFP(SMLoc L); bool parseDirectivePad(SMLoc L); bool parseDirectiveRegSave(SMLoc L, bool IsVector); + bool parseDirectiveInst(SMLoc L, char Suffix = '\0'); StringRef splitMnemonic(StringRef Mnemonic, unsigned &PredicationCode, bool &CarrySetting, unsigned &ProcessorIMod, @@ -7809,6 +7811,12 @@ return parseDirectiveRegSave(DirectiveID.getLoc(), false); else if (IDVal == ".vsave") return parseDirectiveRegSave(DirectiveID.getLoc(), true); + else if (IDVal == ".inst") + return parseDirectiveInst(DirectiveID.getLoc()); + else if (IDVal == ".inst.n") + return parseDirectiveInst(DirectiveID.getLoc(), 'n'); + else if (IDVal == ".inst.w") + return parseDirectiveInst(DirectiveID.getLoc(), 'w'); return true; } @@ -8288,6 +8296,77 @@ return false; } +/// parseDirectiveInst +/// ::= .inst opcode [, ...] +/// ::= .inst.n opcode [, ...] +/// ::= .inst.w opcode [, ...] +bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) { + int Width; + + if (isThumb()) { + switch (Suffix) { + case 'n': + Width = 2; + break; + case 'w': + Width = 4; + break; + default: + Parser.eatToEndOfStatement(); + return Error(Loc, "cannot determine Thumb instruction size, " + "use inst.n/inst.w instead"); + } + } else { + if (Suffix) { + Parser.eatToEndOfStatement(); + return Error(Loc, "width suffixes are invalid in ARM mode"); + } + Width = 4; + } + + if (getLexer().is(AsmToken::EndOfStatement)) { + Parser.eatToEndOfStatement(); + return Error(Loc, "expected expression following directive"); + } + + for (;;) { + const MCExpr *Expr; + + if (getParser().parseExpression(Expr)) + return Error(Loc, "expected expression"); + + if (const MCConstantExpr *Value = dyn_cast_or_null(Expr)) { + switch (Width) { + case 2: + if (Value->getValue() > 0xffff) + return Error(Loc, "inst.n operand is too big, use inst.w instead"); + break; + case 4: + if (Value->getValue() > 0xffffffff) + return Error(Loc, "inst.w operand is too big"); + break; + default: + llvm_unreachable("only supported widths are 2 and 4"); + } + + getTargetStreamer().emitInst(Value->getValue(), Suffix); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return Error(Loc, "unexpected token in directive"); + + Parser.Lex(); + } else { + return Error(Loc, "expected constant expression"); + } + } + + Parser.Lex(); + return false; +} + /// Force static initialization. extern "C" void LLVMInitializeARMAsmParser() { RegisterMCAsmParser X(TheARMTarget); Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -20,8 +20,10 @@ #include "ARMUnwindOp.h" #include "ARMUnwindOpAsm.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -121,6 +123,7 @@ virtual void emitTextAttribute(unsigned Attribute, StringRef String); virtual void emitArch(unsigned Arch); virtual void emitFPU(unsigned FPU); + virtual void emitInst(uint32_t Inst, char Suffix = '\0'); virtual void finishAttributeSection(); public: @@ -190,6 +193,13 @@ void ARMTargetAsmStreamer::finishAttributeSection() { } +void ARMTargetAsmStreamer::emitInst(uint32_t Inst, char Suffix) { + OS << "\t.inst"; + if (Suffix) + OS << "." << Suffix; + OS << "\t0x" << utohexstr(Inst) << "\n"; +} + class ARMTargetELFStreamer : public ARMTargetStreamer { private: // This structure holds all attributes, accounting for @@ -295,6 +305,7 @@ virtual void emitTextAttribute(unsigned Attribute, StringRef String); virtual void emitArch(unsigned Arch); virtual void emitFPU(unsigned FPU); + virtual void emitInst(uint32_t Inst, char Suffix = '\0'); virtual void finishAttributeSection(); size_t calculateContentSize() const; @@ -367,6 +378,42 @@ MCELFStreamer::EmitInstruction(Inst); } + virtual void emitInst(uint32_t Inst, char Suffix) { + unsigned Size; + char Buffer[4]; + const bool LittleEndian = getContext().getAsmInfo()->isLittleEndian(); + + switch (Suffix) { + case '\0': + Size = 4; + + EmitARMMappingSymbol(); + for (unsigned II = 0, IE = Size; II != IE; II++) { + const unsigned I = LittleEndian ? (Size - II - 1) : II; + Buffer[Size - II - 1] = uint8_t(Inst >> I * CHAR_BIT); + } + + break; + case 'n': + case 'w': + Size = (Suffix == 'n' ? 2 : 4); + + EmitThumbMappingSymbol(); + for (unsigned II = 0, IE = Size; II != IE; II = II + 2) { + const unsigned I0 = LittleEndian ? II + 0 : (Size - II - 1); + const unsigned I1 = LittleEndian ? II + 1 : (Size - II - 2); + Buffer[Size - II - 2] = uint8_t(Inst >> I0 * CHAR_BIT); + Buffer[Size - II - 1] = uint8_t(Inst >> I1 * CHAR_BIT); + } + + break; + default: + llvm_unreachable("Invalid Suffix"); + } + + MCELFStreamer::EmitBytes(StringRef(Buffer, Size)); + } + /// This is one of the functions used to emit data into an ELF section, so the /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if /// necessary. @@ -791,6 +838,9 @@ Contents.clear(); FPU = ARM::INVALID_FPU; } +void ARMTargetELFStreamer::emitInst(uint32_t Inst, char Suffix) { + getStreamer().emitInst(Inst, Suffix); +} void ARMELFStreamer::FinishImpl() { MCTargetStreamer &TS = getTargetStreamer(); Index: test/MC/ARM/inst-arm-suffixes.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-arm-suffixes.s @@ -0,0 +1,15 @@ +@ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2> %t \ +@ RUN: | FileCheck --check-prefix CHECK-ERRORS %s %t + + .syntax unified + .arm + + .align 2 + .global suffixes_invalid_in_arm + .type suffixes_invalid_in_arm,%function +suffixes_invalid_in_arm: + .inst.n 2 +@ CHECK-ERRORS: width suffixes are invalid in ARM mode + .inst.w 4 +@ CHECK-ERRORS: width suffixes are invalid in ARM mode + Index: test/MC/ARM/inst-constant-required.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-constant-required.s @@ -0,0 +1,15 @@ +@ RUN: llvm-mc %s -triple=armv7-linux-gnueabi -filetype asm -o - 2> %t \ +@ RUN: | FileCheck --check-prefix CHECK-ERRORS %s %t + + .syntax unified + .arm + + .align 2 + .global constant_expression_required + .type constant_expression_required,%function +constant_expression_required: +.Label: + movs r0, r0 + .inst .Label +@ CHECK-ERRORS: expected constant expression + Index: test/MC/ARM/inst-directive-emit.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-directive-emit.s @@ -0,0 +1,20 @@ +@ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - | FileCheck %s + + .syntax unified + .thumb + + .align 2 + .global emit_asm + .type emit_asm,%function +emit_asm: + .inst.w 0xf2400000, 0xf2c00000 + +@ CHECK: .text +@ CHECK: .code 16 +@ CHECK: .align 2 +@ CHECK: .globl emit_asm +@ CHECK: .type emit_asm,%function +@ CHECK: emit_asm: +@ CHECK: inst.w 0xF2400000 +@ CHECK: inst.w 0xF2C00000 + Index: test/MC/ARM/inst-directive.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-directive.s @@ -0,0 +1,81 @@ +@ RUN: llvm-mc %s -triple=armv7-linux-gnueabi -filetype=obj -o - \ +@ RUN: | llvm-readobj -s -sd | FileCheck %s + + .syntax unified + +@------------------------------------------------------------------------------- +@ arm_inst +@------------------------------------------------------------------------------- + .arm + + .section .inst.arm_inst + + .align 2 + .global arm_inst + .type arm_inst,%function +arm_inst: + .inst 0xdefe + +@ CHECK: Section { +@ CHECK: Name: .inst.arm_inst +@ CHECK: SectionData ( +@ CHECK-NEXT: 0000: FEDE0000 +@ CHECK-NEXT: ) + +@------------------------------------------------------------------------------- +@ thumb_inst_n +@------------------------------------------------------------------------------- + .thumb + + .section .inst.thumb_inst_n + + .align 2 + .global thumb_inst_n + .type thumb_inst_n,%function +thumb_inst_n: + .inst.n 0xdefe + +@ CHECK: Section { +@ CHECK: Name: .inst.thumb_inst_n +@ CHECK: SectionData ( +@ CHECK-NEXT: 0000: FEDE +@ CHECK-NEXT: ) + +@------------------------------------------------------------------------------- +@ thumb_inst_w +@------------------------------------------------------------------------------- + .thumb + + .section .inst.thumb_inst_w + + .align 2 + .global thumb_inst_w + .type thumb_inst_w,%function +thumb_inst_w: + .inst.w 0x00000000 + +@ CHECK: Section { +@ CHECK: Name: .inst.thumb_inst_w +@ CHECK: SectionData ( +@ CHECK-NEXT: 0000: 00000000 +@ CHECK-NEXT: ) + +@------------------------------------------------------------------------------- +@ thumb_inst_w +@------------------------------------------------------------------------------- + .thumb + + .section .inst.thumb_inst_inst + + .align 2 + .global thumb_inst_inst + .type thumb_inst_inst,%function +thumb_inst_inst: + .inst.w 0xf2400000, 0xf2c00000 + +@ CHECK: Section { +@ CHECK: Name: .inst.thumb_inst_inst +@ CHECK: SectionData ( +@ CHECK-NEXT: 0000: 40F20000 C0F20000 +@ CHECK-NEXT: ) + Index: test/MC/ARM/inst-thumb-overflow-2.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-thumb-overflow-2.s @@ -0,0 +1,13 @@ +@ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2> %t \ +@ RUN: | FileCheck --check-prefix CHECK-ERRORS %s %t + + .syntax unified + .thumb + + .align 2 + .global constant_overflow + .type constant_overflow,%function +constant_overflow: + .inst.w 1 << 32 +@ CHECK-ERRORS: inst.w operand is too big + Index: test/MC/ARM/inst-thumb-overflow.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-thumb-overflow.s @@ -0,0 +1,13 @@ +@ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2> %t \ +@ RUN: | FileCheck --check-prefix CHECK-ERRORS %s %t + + .syntax unified + .thumb + + .align 2 + .global constant_overflow + .type constant_overflow,%function +constant_overflow: + .inst.n 1 << 31 +@ CHECK-ERRORS: inst.n operand is too big, use inst.w instead + Index: test/MC/ARM/inst-thumb-suffixes.s =================================================================== --- /dev/null +++ test/MC/ARM/inst-thumb-suffixes.s @@ -0,0 +1,13 @@ +@ RUN: llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2> %t \ +@ RUN: | FileCheck --check-prefix CHECK-ERRORS %s %t + + .syntax unified + .thumb + + .align 2 + .global suffixes_required_in_thumb + .type suffixes_required_in_thumb,%function +suffixes_required_in_thumb: + .inst 0x0000 +@ CHECK-ERRORS: cannot determine Thumb instruction size, use inst.n/inst.w instead +