diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index d8ba0c7f2b8..5cded5cfff9 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -91,7 +91,6 @@ public: AArch64TargetStreamer(MCStreamer &S); ~AArch64TargetStreamer(); - void finish() override; /// Callback used to implement the ldr= pseudo. @@ -103,6 +102,9 @@ public: /// Emit contents of constant pool for the current section. void emitCurrentConstantPool(); + /// Callback used to implement the .inst directive. + virtual void emitInst(uint32_t Inst); + private: std::unique_ptr ConstantPools; }; diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 1c92c8c07b8..7bac8dd8dfc 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" @@ -74,6 +75,8 @@ private: bool showMatchError(SMLoc Loc, unsigned ErrCode); bool parseDirectiveWord(unsigned Size, SMLoc L); + bool parseDirectiveInst(SMLoc L); + bool parseDirectiveTLSDescCall(SMLoc L); bool parseDirectiveLOH(StringRef LOH, SMLoc L); @@ -3912,6 +3915,11 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, /// ParseDirective parses the arm specific directives bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { + const MCObjectFileInfo::Environment Format = + getContext().getObjectFileInfo()->getObjectFileType(); + bool IsMachO = Format == MCObjectFileInfo::IsMachO; + bool IsCOFF = Format == MCObjectFileInfo::IsCOFF; + StringRef IDVal = DirectiveID.getIdentifier(); SMLoc Loc = DirectiveID.getLoc(); if (IDVal == ".hword") @@ -3927,6 +3935,11 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) { if (IDVal == ".unreq") return parseDirectiveUnreq(DirectiveID.getLoc()); + if (!IsMachO && !IsCOFF) { + if (IDVal == ".inst") + return parseDirectiveInst(Loc); + } + return parseDirectiveLOH(IDVal, Loc); } @@ -3955,6 +3968,46 @@ bool AArch64AsmParser::parseDirectiveWord(unsigned Size, SMLoc L) { return false; } +/// parseDirectiveInst +/// ::= .inst opcode [, ...] +bool AArch64AsmParser::parseDirectiveInst(SMLoc Loc) { + if (getLexer().is(AsmToken::EndOfStatement)) { + Parser.eatToEndOfStatement(); + Error(Loc, "expected expression following directive"); + return false; + } + + for (;;) { + const MCExpr *Expr; + + if (getParser().parseExpression(Expr)) { + Error(Loc, "expected expression"); + return false; + } + + const MCConstantExpr *Value = dyn_cast_or_null(Expr); + if (!Value) { + Error(Loc, "expected constant expression"); + return false; + } + + getTargetStreamer().emitInst(Value->getValue()); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) { + Error(Loc, "unexpected token in directive"); + return false; + } + + Parser.Lex(); // Eat comma. + } + + Parser.Lex(); + return false; +} + // parseDirectiveTLSDescCall: // ::= .tlsdesccall symbol bool AArch64AsmParser::parseDirectiveTLSDescCall(SMLoc L) { diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp index 9cf87ea5b92..60e9c19dbc0 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp +++ b/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp @@ -15,8 +15,10 @@ #include "llvm/MC/MCELFStreamer.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" @@ -34,12 +36,42 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { +class AArch64ELFStreamer; + +class AArch64TargetAsmStreamer : public AArch64TargetStreamer { + formatted_raw_ostream &OS; + + void emitInst(uint32_t Inst) override; + +public: + AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); +}; + +AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS) + : AArch64TargetStreamer(S), OS(OS) {} + +void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) { + OS << "\t.inst\t0x" << utohexstr(Inst) << "\n"; +} + +class AArch64TargetELFStreamer : public AArch64TargetStreamer { +private: + AArch64ELFStreamer &getStreamer(); + + void emitInst(uint32_t Inst) override; + +public: + AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {} +}; + /// Extend the generic ELFStreamer class so that it can emit mapping symbols at /// the appropriate points in the object files. These symbols are defined in the /// AArch64 ELF ABI: @@ -55,6 +87,8 @@ namespace { /// by MachO. Beware! class AArch64ELFStreamer : public MCELFStreamer { public: + friend class AArch64TargetELFStreamer; + AArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) : MCELFStreamer(Context, TAB, OS, Emitter), MappingSymbolCounter(0), @@ -82,6 +116,18 @@ public: MCELFStreamer::EmitInstruction(Inst, STI); } + void emitInst(uint32_t Inst) { + char Buffer[4]; + const bool LittleEndian = getContext().getAsmInfo()->isLittleEndian(); + + EmitA64MappingSymbol(); + for (unsigned II = 0; II != 4; ++II) { + const unsigned I = LittleEndian ? (4 - II - 1) : II; + Buffer[4 - II - 1] = uint8_t(Inst >> I * CHAR_BIT); + } + MCELFStreamer::EmitBytes(StringRef(Buffer, 4)); + } + /// This is one of the functions used to emit data into an ELF section, so the /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) /// if necessary. @@ -144,13 +190,33 @@ private: /// @} }; +} // end anonymous namespace + +AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() { + return static_cast(Streamer); +} + +void AArch64TargetELFStreamer::emitInst(uint32_t Inst) { + getStreamer().emitInst(Inst); } namespace llvm { +MCStreamer * +createAArch64MCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useDwarfDirectory, + MCInstPrinter *InstPrint, MCCodeEmitter *CE, + MCAsmBackend *TAB, bool ShowInst) { + MCStreamer *S = llvm::createAsmStreamer( + Ctx, OS, isVerboseAsm, useDwarfDirectory, InstPrint, CE, TAB, ShowInst); + new AArch64TargetAsmStreamer(*S, OS); + return S; +} + MCELFStreamer *createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter, bool RelaxAll) { AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); + new AArch64TargetELFStreamer(*S); if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp index 3897339233c..0f7a6b81b41 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -198,6 +198,14 @@ extern "C" void LLVMInitializeAArch64TargetMC() { createMCStreamer); TargetRegistry::RegisterMCObjectStreamer(TheARM64Target, createMCStreamer); + // Register the asm streamer. + TargetRegistry::RegisterAsmStreamer(TheAArch64leTarget, + createAArch64MCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheAArch64beTarget, + createAArch64MCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheARM64Target, + createAArch64MCAsmStreamer); + // Register the MCInstPrinter. TargetRegistry::RegisterMCInstPrinter(TheAArch64leTarget, createAArch64MCInstPrinter); diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h index 975959b2356..1553115781c 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h +++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h @@ -18,12 +18,15 @@ #include namespace llvm { +class formatted_raw_ostream; class MCAsmBackend; class MCCodeEmitter; class MCContext; class MCInstrInfo; +class MCInstPrinter; class MCRegisterInfo; class MCObjectWriter; +class MCStreamer; class MCSubtargetInfo; class StringRef; class Target; @@ -50,6 +53,11 @@ MCObjectWriter *createAArch64ELFObjectWriter(raw_ostream &OS, uint8_t OSABI, MCObjectWriter *createAArch64MachObjectWriter(raw_ostream &OS, uint32_t CPUType, uint32_t CPUSubtype); +MCStreamer * +createAArch64MCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useDwarfDirectory, + MCInstPrinter *InstPrint, MCCodeEmitter *CE, + MCAsmBackend *TAB, bool ShowInst); } // End llvm namespace // Defines symbolic names for AArch64 registers. This defines a mapping from diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp index dcc1a3c9f05..e3112fa76d3 100644 --- a/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp +++ b/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp @@ -39,3 +39,5 @@ void AArch64TargetStreamer::emitCurrentConstantPool() { // finish() - write out any non-empty assembler constant pools. void AArch64TargetStreamer::finish() { ConstantPools->emitAll(Streamer); } + +void AArch64TargetStreamer::emitInst(uint32_t Inst) {} diff --git a/test/MC/AArch64/inst-directive-diagnostic.s b/test/MC/AArch64/inst-directive-diagnostic.s new file mode 100644 index 00000000000..8abad5ecbc9 --- /dev/null +++ b/test/MC/AArch64/inst-directive-diagnostic.s @@ -0,0 +1,19 @@ +// RUN: not llvm-mc %s -triple=aarch64-none-linux-gnu -filetype asm -o - 2>&1 \ +// RUN: | FileCheck -check-prefix CHECK-ERROR %s + + .align 2 + .global diagnostics + .type diagnostics,%function +diagnostics: +.Label: + .inst +// CHECK-ERROR: expected expression following directive + + .inst 0x5e104020, +// CHECK-ERROR: expected expression + + .inst .Label +// CHECK-ERROR: expected constant expression + + .inst 0x5e104020 0x5e104020 +// CHECK-ERROR: unexpected token in directive diff --git a/test/MC/AArch64/inst-directive.s b/test/MC/AArch64/inst-directive.s new file mode 100644 index 00000000000..6a4b64eeaaf --- /dev/null +++ b/test/MC/AArch64/inst-directive.s @@ -0,0 +1,24 @@ +// RUN: llvm-mc %s -triple=aarch64-none-linux-gnu -filetype=asm -o - \ +// RUN: | FileCheck %s --check-prefix=CHECK-ASM +// RUN: llvm-mc %s -triple=aarch64-none-linux-gnu -filetype=obj -o - \ +// RUN: | llvm-readobj -s -sd | FileCheck %s --check-prefix=CHECK-OBJ + + .section .inst.aarch64_inst + + .align 2 + .global aarch64_inst + .type aarch64_inst,%function +aarch64_inst: + .inst 0x5e104020 + +// CHECK-ASM: .align 2 +// CHECK-ASM: .globl aarch64_inst +// CHECK-ASM: .type aarch64_inst,@function +// CHECK-ASM: aarch64_inst: +// CHECK-ASM: .inst 0x5E104020 + +// CHECK-OBJ: Section { +// CHECK-OBJ: Name: .inst.aarch64_inst +// CHECK-OBJ: SectionData ( +// CHECK-OBJ-NEXT: 0000: 2040105E +// CHECK-OBJ-NEXT: )