Index: include/llvm/MC/MCStreamer.h =================================================================== --- include/llvm/MC/MCStreamer.h +++ include/llvm/MC/MCStreamer.h @@ -91,7 +91,6 @@ AArch64TargetStreamer(MCStreamer &S); ~AArch64TargetStreamer(); - void finish() override; /// Callback used to implement the ldr= pseudo. @@ -103,6 +102,9 @@ /// 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; }; Index: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -74,6 +74,8 @@ 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); @@ -3920,6 +3922,8 @@ return parseDirectiveWord(4, Loc); if (IDVal == ".xword") return parseDirectiveWord(8, Loc); + if (IDVal == ".inst") + return parseDirectiveInst(Loc); if (IDVal == ".tlsdesccall") return parseDirectiveTLSDescCall(Loc); if (IDVal == ".ltorg" || IDVal == ".pool") @@ -3955,6 +3959,46 @@ 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) { Index: lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp +++ 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,48 @@ #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; + MCInstPrinter &InstPrinter; + bool IsVerboseAsm; + + void emitInst(uint32_t Inst) override; + +public: + AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter &InstPrinter, bool VerboseAsm); +}; + +AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter &InstPrinter, + bool VerboseAsm) + : AArch64TargetStreamer(S), OS(OS), InstPrinter(InstPrinter), + IsVerboseAsm(VerboseAsm) {} + +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 +93,8 @@ /// 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 +122,18 @@ 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 +196,33 @@ /// @} }; +} // 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, *InstPrint, isVerboseAsm); + 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; Index: lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h +++ 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 *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 Index: lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp @@ -198,6 +198,14 @@ 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); Index: lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp @@ -39,3 +39,5 @@ // finish() - write out any non-empty assembler constant pools. void AArch64TargetStreamer::finish() { ConstantPools->emitAll(Streamer); } + +void AArch64TargetStreamer::emitInst(uint32_t Inst) {} Index: test/MC/AArch64/inst-directive-diagnostic.s =================================================================== --- /dev/null +++ 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 Index: test/MC/AArch64/inst-directive.s =================================================================== --- /dev/null +++ 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: )