aarch64: support target-specific .req assembler directive

Based on the support for .req on ARM. The aarch64 variant has to keep track if
the alias register was a vector register (v0-31) or a general purpose or
VFP/Advanced SIMD ([bhsdq]0-31) register.

Patch by Janne Grunau!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212161 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Saleem Abdulrasool 2014-07-02 04:50:23 +00:00
parent b80dce061b
commit 8f9108459e
4 changed files with 188 additions and 3 deletions

View File

@ -43,6 +43,9 @@ private:
MCSubtargetInfo &STI; MCSubtargetInfo &STI;
MCAsmParser &Parser; MCAsmParser &Parser;
// Map of register aliases registers via the .req directive.
StringMap<std::pair<bool, unsigned> > RegisterReqs;
AArch64TargetStreamer &getTargetStreamer() { AArch64TargetStreamer &getTargetStreamer() {
MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
return static_cast<AArch64TargetStreamer &>(TS); return static_cast<AArch64TargetStreamer &>(TS);
@ -56,6 +59,7 @@ private:
bool parseSysAlias(StringRef Name, SMLoc NameLoc, OperandVector &Operands); bool parseSysAlias(StringRef Name, SMLoc NameLoc, OperandVector &Operands);
AArch64CC::CondCode parseCondCodeString(StringRef Cond); AArch64CC::CondCode parseCondCodeString(StringRef Cond);
bool parseCondCode(OperandVector &Operands, bool invertCondCode); bool parseCondCode(OperandVector &Operands, bool invertCondCode);
unsigned matchRegisterNameAlias(StringRef Name, bool isVector);
int tryParseRegister(); int tryParseRegister();
int tryMatchVectorRegister(StringRef &Kind, bool expected); int tryMatchVectorRegister(StringRef &Kind, bool expected);
bool parseRegister(OperandVector &Operands); bool parseRegister(OperandVector &Operands);
@ -74,6 +78,9 @@ private:
bool parseDirectiveLOH(StringRef LOH, SMLoc L); bool parseDirectiveLOH(StringRef LOH, SMLoc L);
bool parseDirectiveLtorg(SMLoc L); bool parseDirectiveLtorg(SMLoc L);
bool parseDirectiveReq(StringRef Name, SMLoc L);
bool parseDirectiveUnreq(SMLoc L);
bool validateInstruction(MCInst &Inst, SmallVectorImpl<SMLoc> &Loc); bool validateInstruction(MCInst &Inst, SmallVectorImpl<SMLoc> &Loc);
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
OperandVector &Operands, MCStreamer &Out, OperandVector &Operands, MCStreamer &Out,
@ -1825,6 +1832,26 @@ bool AArch64AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
return (RegNo == (unsigned)-1); return (RegNo == (unsigned)-1);
} }
// Matches a register name or register alias previously defined by '.req'
unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name,
bool isVector) {
unsigned RegNum = isVector ? matchVectorRegName(Name)
: MatchRegisterName(Name);
if (RegNum == 0) {
// Check for aliases registered via .req. Canonicalize to lower case.
// That's more consistent since register names are case insensitive, and
// it's how the original entry was passed in from MC/MCParser/AsmParser.
auto Entry = RegisterReqs.find(Name.lower());
if (Entry == RegisterReqs.end())
return 0;
// set RegNum if the match is the right kind of register
if (isVector == Entry->getValue().first)
RegNum = Entry->getValue().second;
}
return RegNum;
}
/// tryParseRegister - Try to parse a register name. The token must be an /// tryParseRegister - Try to parse a register name. The token must be an
/// Identifier when called, and if it is a register name the token is eaten and /// Identifier when called, and if it is a register name the token is eaten and
/// the register is added to the operand list. /// the register is added to the operand list.
@ -1833,7 +1860,7 @@ int AArch64AsmParser::tryParseRegister() {
assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier"); assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
std::string lowerCase = Tok.getString().lower(); std::string lowerCase = Tok.getString().lower();
unsigned RegNum = MatchRegisterName(lowerCase); unsigned RegNum = matchRegisterNameAlias(lowerCase, false);
// Also handle a few aliases of registers. // Also handle a few aliases of registers.
if (RegNum == 0) if (RegNum == 0)
RegNum = StringSwitch<unsigned>(lowerCase) RegNum = StringSwitch<unsigned>(lowerCase)
@ -1863,7 +1890,8 @@ int AArch64AsmParser::tryMatchVectorRegister(StringRef &Kind, bool expected) {
// a '.'. // a '.'.
size_t Start = 0, Next = Name.find('.'); size_t Start = 0, Next = Name.find('.');
StringRef Head = Name.slice(Start, Next); StringRef Head = Name.slice(Start, Next);
unsigned RegNum = matchVectorRegName(Head); unsigned RegNum = matchRegisterNameAlias(Head, true);
if (RegNum) { if (RegNum) {
if (Next != StringRef::npos) { if (Next != StringRef::npos) {
Kind = Name.slice(Next, StringRef::npos); Kind = Name.slice(Next, StringRef::npos);
@ -2861,7 +2889,7 @@ AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
if (!Tok.is(AsmToken::Identifier)) if (!Tok.is(AsmToken::Identifier))
return MatchOperand_NoMatch; return MatchOperand_NoMatch;
unsigned RegNum = MatchRegisterName(Tok.getString().lower()); unsigned RegNum = matchRegisterNameAlias(Tok.getString().lower(), false);
MCContext &Ctx = getContext(); MCContext &Ctx = getContext();
const MCRegisterInfo *RI = Ctx.getRegisterInfo(); const MCRegisterInfo *RI = Ctx.getRegisterInfo();
@ -3078,6 +3106,15 @@ bool AArch64AsmParser::ParseInstruction(ParseInstructionInfo &Info,
.Case("bnv", "b.nv") .Case("bnv", "b.nv")
.Default(Name); .Default(Name);
// First check for the AArch64-specific .req directive.
if (Parser.getTok().is(AsmToken::Identifier) &&
Parser.getTok().getIdentifier() == ".req") {
parseDirectiveReq(Name, NameLoc);
// We always return 'error' for this, as we're done with this
// statement and don't need to match the 'instruction."
return true;
}
// Create the leading tokens for the mnemonic, split by '.' characters. // Create the leading tokens for the mnemonic, split by '.' characters.
size_t Start = 0, Next = Name.find('.'); size_t Start = 0, Next = Name.find('.');
StringRef Head = Name.slice(Start, Next); StringRef Head = Name.slice(Start, Next);
@ -3857,6 +3894,9 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
return parseDirectiveTLSDescCall(Loc); return parseDirectiveTLSDescCall(Loc);
if (IDVal == ".ltorg" || IDVal == ".pool") if (IDVal == ".ltorg" || IDVal == ".pool")
return parseDirectiveLtorg(Loc); return parseDirectiveLtorg(Loc);
if (IDVal == ".unreq")
return parseDirectiveUnreq(DirectiveID.getLoc());
return parseDirectiveLOH(IDVal, Loc); return parseDirectiveLOH(IDVal, Loc);
} }
@ -3964,6 +4004,59 @@ bool AArch64AsmParser::parseDirectiveLtorg(SMLoc L) {
return false; return false;
} }
/// parseDirectiveReq
/// ::= name .req registername
bool AArch64AsmParser::parseDirectiveReq(StringRef Name, SMLoc L) {
Parser.Lex(); // Eat the '.req' token.
SMLoc SRegLoc = getLoc();
unsigned RegNum = tryParseRegister();
bool IsVector = false;
if (RegNum == static_cast<unsigned>(-1)) {
StringRef Kind;
RegNum = tryMatchVectorRegister(Kind, false);
if (!Kind.empty()) {
Error(SRegLoc, "vector register without type specifier expected");
return false;
}
IsVector = true;
}
if (RegNum == static_cast<unsigned>(-1)) {
Parser.eatToEndOfStatement();
Error(SRegLoc, "register name or alias expected");
return false;
}
// Shouldn't be anything else.
if (Parser.getTok().isNot(AsmToken::EndOfStatement)) {
Error(Parser.getTok().getLoc(), "unexpected input in .req directive");
Parser.eatToEndOfStatement();
return false;
}
Parser.Lex(); // Consume the EndOfStatement
auto pair = std::make_pair(IsVector, RegNum);
if (RegisterReqs.GetOrCreateValue(Name, pair).getValue() != pair)
Warning(L, "ignoring redefinition of register alias '" + Name + "'");
return true;
}
/// parseDirectiveUneq
/// ::= .unreq registername
bool AArch64AsmParser::parseDirectiveUnreq(SMLoc L) {
if (Parser.getTok().isNot(AsmToken::Identifier)) {
Error(Parser.getTok().getLoc(), "unexpected input in .unreq directive.");
Parser.eatToEndOfStatement();
return false;
}
RegisterReqs.erase(Parser.getTok().getIdentifier().lower());
Parser.Lex(); // Eat the identifier.
return false;
}
bool bool
AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
AArch64MCExpr::VariantKind &ELFRefKind, AArch64MCExpr::VariantKind &ELFRefKind,

View File

@ -0,0 +1,18 @@
// RUN: llvm-mc -triple=arm64-eabi < %s | FileCheck %s
_foo:
OBJECT .req x2
mov x4, OBJECT
mov x4, oBjEcT
.unreq oBJECT
_foo2:
OBJECT .req w5
mov w4, OBJECT
.unreq OBJECT
// CHECK-LABEL: _foo:
// CHECK: mov x4, x2
// CHECK: mov x4, x2
// CHECK-LABEL: _foo2:
// CHECK: mov w4, w5

View File

@ -0,0 +1,37 @@
// RUN: not llvm-mc -triple aarch64-none-linux-gnu < %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ERROR %s
bar:
fred .req x5
fred .req x6
// CHECK-ERROR: warning: ignoring redefinition of register alias 'fred'
// CHECK-ERROR: fred .req x6
// CHECK-ERROR: ^
ada .req v2.8b
// CHECK-ERROR: error: vector register without type specifier expected
// CHECK-ERROR: ada .req v2.8b
// CHECK-ERROR: ^
bob .req lisa
// CHECK-ERROR: error: register name or alias expected
// CHECK-ERROR: bob .req lisa
// CHECK-ERROR: ^
lisa .req x1, 23
// CHECK-ERROR: error: unexpected input in .req directive
// CHECK-ERROR: lisa .req x1, 23
// CHECK-ERROR: ^
mov bob, fred
// CHECK-ERROR: error: invalid operand for instruction
// CHECK-ERROR: mov bob, fred
// CHECK-ERROR: ^
.unreq 1
// CHECK-ERROR: error: unexpected input in .unreq directive.
// CHECK-ERROR: .unreq 1
// CHECK-ERROR: ^
mov x1, fred
// CHECK: mov x1, x5
// CHECK-NOT: mov x1, x6

37
test/MC/AArch64/dot-req.s Normal file
View File

@ -0,0 +1,37 @@
// RUN: llvm-mc -triple=aarch64-none-linux-gnu -show-encoding < %s | FileCheck %s
bar:
fred .req x5
mov fred, x11
.unreq fred
fred .req w6
mov w1, fred
bob .req fred
ada .req w1
mov ada, bob
.unreq bob
.unreq fred
.unreq ada
// CHECK: mov x5, x11 // encoding: [0xe5,0x03,0x0b,0xaa]
// CHECK: mov w1, w6 // encoding: [0xe1,0x03,0x06,0x2a]
// CHECK: mov w1, w6 // encoding: [0xe1,0x03,0x06,0x2a]
bob .req b6
hanah .req h5
sam .req s4
dora .req d3
quentin .req q2
vesna .req v1
addv bob, v0.8b
mov hanah, v4.h[3]
fadd s0, sam, sam
fmov d2, dora
ldr quentin, [sp]
mov v0.8b, vesna.8b
// CHECK: addv b6, v0.8b // encoding: [0x06,0xb8,0x31,0x0e]
// CHECK: mov h5, v4.h[3] // encoding: [0x85,0x04,0x0e,0x5e]
// CHECK: fadd s0, s4, s4 // encoding: [0x80,0x28,0x24,0x1e]
// CHECK: fmov d2, d3 // encoding: [0x62,0x40,0x60,0x1e]
// CHECK: ldr q2, [sp] // encoding: [0xe2,0x03,0xc0,0x3d]
// CHECK: mov v0.8b, v1.8b // encoding: [0x20,0x1c,0xa1,0x0e]