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
#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"
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,
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;
}
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");
+
+ const MCConstantExpr *Value = dyn_cast_or_null<MCConstantExpr>(Expr);
+ if (!Value)
+ return Error(Loc, "expected constant expression");
+
+ 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,
+ StringRef(Suffix ? "inst.w" : "inst") + " 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();
+ }
+
+ Parser.Lex();
+ return false;
+}
+
/// Force static initialization.
extern "C" void LLVMInitializeARMAsmParser() {
RegisterMCAsmParser<ARMAsmParser> X(TheARMTarget);
#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"
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:
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
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;
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;
+
+ assert(!IsThumb);
+ 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);
+
+ assert(IsThumb);
+ 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.
Contents.clear();
FPU = ARM::INVALID_FPU;
}
+void ARMTargetELFStreamer::emitInst(uint32_t Inst, char Suffix) {
+ getStreamer().emitInst(Inst, Suffix);
+}
void ARMELFStreamer::FinishImpl() {
MCTargetStreamer &TS = getTargetStreamer();
--- /dev/null
+@ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERROR %s
+
+ .syntax unified
+ .arm
+
+ .align 2
+ .global suffixes_invalid_in_arm
+ .type suffixes_invalid_in_arm,%function
+suffixes_invalid_in_arm:
+ .inst.n 2
+@ CHECK-ERROR: width suffixes are invalid in ARM mode
+ .inst.w 4
+@ CHECK-ERROR: width suffixes are invalid in ARM mode
+
--- /dev/null
+@ RUN: not llvm-mc %s -triple=armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERROR %s
+
+ .syntax unified
+ .arm
+
+ .align 2
+ .global constant_expression_required
+ .type constant_expression_required,%function
+constant_expression_required:
+.Label:
+ movs r0, r0
+ .inst .Label
+@ CHECK-ERROR: expected constant expression
+
--- /dev/null
+@ 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
+
--- /dev/null
+@ 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: )
+
--- /dev/null
+@ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERROR %s
+
+ .syntax unified
+ .arm
+
+ .align 2
+ .global constant_overflow
+ .type constant_overflow,%function
+constant_overflow:
+ .inst 1 << 32
+@ CHECK-ERROR: inst operand is too big
+
+
--- /dev/null
+@ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERRORS %s
+
+ .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
+
--- /dev/null
+@ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERROR %s
+
+ .syntax unified
+ .thumb
+
+ .align 2
+ .global constant_overflow
+ .type constant_overflow,%function
+constant_overflow:
+ .inst.n 1 << 31
+@ CHECK-ERROR: inst.n operand is too big, use inst.w instead
+
--- /dev/null
+@ RUN: not llvm-mc %s -triple armv7-linux-gnueabi -filetype asm -o - 2>&1 \
+@ RUN: | FileCheck -check-prefix CHECK-ERROR %s
+
+ .syntax unified
+ .thumb
+
+ .align 2
+ .global suffixes_required_in_thumb
+ .type suffixes_required_in_thumb,%function
+suffixes_required_in_thumb:
+ .inst 0x0000
+@ CHECK-ERROR: cannot determine Thumb instruction size, use inst.n/inst.w instead
+