[AArch64] Add support for the .inst directive.

This has been implement using the MCTargetStreamer interface as is done in the
ARM, Mips and PPC backends.

Phabricator: http://reviews.llvm.org/D5891
PR20964

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220422 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chad Rosier 2014-10-22 20:35:57 +00:00
parent 596e63d001
commit fa16693864
8 changed files with 183 additions and 1 deletions

View File

@ -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<AssemblerConstantPools> ConstantPools;
};

View File

@ -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<MCConstantExpr>(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) {

View File

@ -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<AArch64ELFStreamer &>(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;

View File

@ -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);

View File

@ -18,12 +18,15 @@
#include <string>
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

View File

@ -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) {}

View File

@ -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

View File

@ -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: )