[ARM64] Fixup ADR/ADRP parsing such that they accept immediates and all labels types

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205888 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bradley Smith 2014-04-09 14:44:12 +00:00
parent 9a9fa81c1a
commit 250f973d7f
3 changed files with 99 additions and 41 deletions

View File

@ -156,6 +156,7 @@ def SIMDImmType10Operand : AsmOperandClass { let Name = "SIMDImmType10"; }
def AdrpOperand : AsmOperandClass { def AdrpOperand : AsmOperandClass {
let Name = "AdrpLabel"; let Name = "AdrpLabel";
let ParserMethod = "tryParseAdrpLabel"; let ParserMethod = "tryParseAdrpLabel";
let DiagnosticType = "InvalidLabel";
} }
def adrplabel : Operand<i64> { def adrplabel : Operand<i64> {
let EncoderMethod = "getAdrLabelOpValue"; let EncoderMethod = "getAdrLabelOpValue";
@ -166,6 +167,7 @@ def adrplabel : Operand<i64> {
def AdrOperand : AsmOperandClass { def AdrOperand : AsmOperandClass {
let Name = "AdrLabel"; let Name = "AdrLabel";
let ParserMethod = "tryParseAdrLabel"; let ParserMethod = "tryParseAdrLabel";
let DiagnosticType = "InvalidLabel";
} }
def adrlabel : Operand<i64> { def adrlabel : Operand<i64> {
let EncoderMethod = "getAdrLabelOpValue"; let EncoderMethod = "getAdrLabelOpValue";

View File

@ -999,13 +999,33 @@ public:
bool isAdrpLabel() const { bool isAdrpLabel() const {
// Validation was handled during parsing, so we just sanity check that // Validation was handled during parsing, so we just sanity check that
// something didn't go haywire. // something didn't go haywire.
return isImm(); if (!isImm())
return false;
if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
int64_t Val = CE->getValue();
int64_t Min = - (4096 * (1LL << (21 - 1)));
int64_t Max = 4096 * ((1LL << (21 - 1)) - 1);
return (Val % 4096) == 0 && Val >= Min && Val <= Max;
}
return true;
} }
bool isAdrLabel() const { bool isAdrLabel() const {
// Validation was handled during parsing, so we just sanity check that // Validation was handled during parsing, so we just sanity check that
// something didn't go haywire. // something didn't go haywire.
return isImm(); if (!isImm())
return false;
if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Imm.Val)) {
int64_t Val = CE->getValue();
int64_t Min = - (1LL << (21 - 1));
int64_t Max = ((1LL << (21 - 1)) - 1);
return Val >= Min && Val <= Max;
}
return true;
} }
void addExpr(MCInst &Inst, const MCExpr *Expr) const { void addExpr(MCInst &Inst, const MCExpr *Expr) const {
@ -1079,7 +1099,12 @@ public:
} }
void addAdrpLabelOperands(MCInst &Inst, unsigned N) const { void addAdrpLabelOperands(MCInst &Inst, unsigned N) const {
addImmOperands(Inst, N); assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(getImm());
if (!MCE)
addExpr(Inst, getImm());
else
Inst.addOperand(MCOperand::CreateImm(MCE->getValue() >> 12));
} }
void addAdrLabelOperands(MCInst &Inst, unsigned N) const { void addAdrLabelOperands(MCInst &Inst, unsigned N) const {
@ -2042,40 +2067,43 @@ ARM64AsmParser::OperandMatchResultTy
ARM64AsmParser::tryParseAdrpLabel(OperandVector &Operands) { ARM64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
SMLoc S = getLoc(); SMLoc S = getLoc();
const MCExpr *Expr; const MCExpr *Expr;
if (Parser.getTok().is(AsmToken::Hash)) {
Parser.Lex(); // Eat hash token.
}
if (parseSymbolicImmVal(Expr)) if (parseSymbolicImmVal(Expr))
return MatchOperand_ParseFail; return MatchOperand_ParseFail;
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; const MCConstantExpr *Addend;
if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
Error(S, "modified label reference + constant expected"); if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
return MatchOperand_ParseFail; ELFRefKind == ARM64MCExpr::VK_INVALID) {
// No modifier was specified at all; this is the syntax for an ELF basic
// ADRP relocation (unfortunately).
Expr = ARM64MCExpr::Create(Expr, ARM64MCExpr::VK_ABS_PAGE, getContext());
} else if ((DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGE ||
DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGE) &&
Addend != 0) {
Error(S, "gotpage label reference not allowed an addend");
return MatchOperand_ParseFail;
} else if (DarwinRefKind != MCSymbolRefExpr::VK_PAGE &&
DarwinRefKind != MCSymbolRefExpr::VK_GOTPAGE &&
DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE &&
ELFRefKind != ARM64MCExpr::VK_GOT_PAGE &&
ELFRefKind != ARM64MCExpr::VK_GOTTPREL_PAGE &&
ELFRefKind != ARM64MCExpr::VK_TLSDESC_PAGE) {
// The operand must be an @page or @gotpage qualified symbolref.
Error(S, "page or gotpage label reference expected");
return MatchOperand_ParseFail;
}
} }
if (DarwinRefKind == MCSymbolRefExpr::VK_None && // We have either a label reference possibly with addend or an immediate. The
ELFRefKind == ARM64MCExpr::VK_INVALID) { // addend is a raw value here. The linker will adjust it to only reference the
// No modifier was specified at all; this is the syntax for an ELF basic // page.
// ADRP relocation (unfortunately).
Expr = ARM64MCExpr::Create(Expr, ARM64MCExpr::VK_ABS_PAGE, getContext());
} else if ((DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGE ||
DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGE) &&
Addend != 0) {
Error(S, "gotpage label reference not allowed an addend");
return MatchOperand_ParseFail;
} else if (DarwinRefKind != MCSymbolRefExpr::VK_PAGE &&
DarwinRefKind != MCSymbolRefExpr::VK_GOTPAGE &&
DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE &&
ELFRefKind != ARM64MCExpr::VK_GOT_PAGE &&
ELFRefKind != ARM64MCExpr::VK_GOTTPREL_PAGE &&
ELFRefKind != ARM64MCExpr::VK_TLSDESC_PAGE) {
// The operand must be an @page or @gotpage qualified symbolref.
Error(S, "page or gotpage label reference expected");
return MatchOperand_ParseFail;
}
// We have a label reference possibly with addend. The addend is a raw value
// here. The linker will adjust it to only reference the page.
SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
Operands.push_back(ARM64Operand::CreateImm(Expr, S, E, getContext())); Operands.push_back(ARM64Operand::CreateImm(Expr, S, E, getContext()));
@ -2088,20 +2116,14 @@ ARM64AsmParser::OperandMatchResultTy
ARM64AsmParser::tryParseAdrLabel(OperandVector &Operands) { ARM64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
SMLoc S = getLoc(); SMLoc S = getLoc();
const MCExpr *Expr; const MCExpr *Expr;
if (Parser.getTok().is(AsmToken::Hash)) {
Parser.Lex(); // Eat hash token.
}
if (getParser().parseExpression(Expr)) if (getParser().parseExpression(Expr))
return MatchOperand_ParseFail; return MatchOperand_ParseFail;
// The operand must be an un-qualified assembler local symbolref.
// FIXME: wrong for ELF.
if (const MCSymbolRefExpr *SRE = dyn_cast<const MCSymbolRefExpr>(Expr)) {
// FIXME: Should reference the MachineAsmInfo to get the private prefix.
bool isTemporary = SRE->getSymbol().getName().startswith("L");
if (!isTemporary || SRE->getKind() != MCSymbolRefExpr::VK_None) {
Error(S, "unqualified, assembler-local label name expected");
return MatchOperand_ParseFail;
}
}
SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1); SMLoc E = SMLoc::getFromPointer(getLoc().getPointer() - 1);
Operands.push_back(ARM64Operand::CreateImm(Expr, S, E, getContext())); Operands.push_back(ARM64Operand::CreateImm(Expr, S, E, getContext()));
@ -3763,6 +3785,8 @@ bool ARM64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode) {
return Error(Loc, "immediate must be an integer in range [1,32]."); return Error(Loc, "immediate must be an integer in range [1,32].");
case Match_InvalidImm1_64: case Match_InvalidImm1_64:
return Error(Loc, "immediate must be an integer in range [1,64]."); return Error(Loc, "immediate must be an integer in range [1,64].");
case Match_InvalidLabel:
return Error(Loc, "expected label or encodable integer pc offset");
case Match_MnemonicFail: case Match_MnemonicFail:
return Error(Loc, "unrecognized instruction mnemonic"); return Error(Loc, "unrecognized instruction mnemonic");
default: default:
@ -4238,7 +4262,8 @@ bool ARM64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidImm1_8: case Match_InvalidImm1_8:
case Match_InvalidImm1_16: case Match_InvalidImm1_16:
case Match_InvalidImm1_32: case Match_InvalidImm1_32:
case Match_InvalidImm1_64: { case Match_InvalidImm1_64:
case Match_InvalidLabel: {
// Any time we get here, there's nothing fancy to do. Just get the // Any time we get here, there's nothing fancy to do. Just get the
// operand SMLoc and display the diagnostic. // operand SMLoc and display the diagnostic.
SMLoc ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc(); SMLoc ErrorLoc = ((ARM64Operand *)Operands[ErrorInfo])->getStartLoc();

31
test/MC/ARM64/adr.s Normal file
View File

@ -0,0 +1,31 @@
// RUN: not llvm-mc -triple arm64 -show-encoding < %s 2>%t | FileCheck %s
// RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
adr x0, #0
adr x0, #1
adr x0, 1f
adr x0, foo
// CHECK: adr x0, #0 // encoding: [0x00,0x00,0x00,0x10]
// CHECK: adr x0, #1 // encoding: [0x00,0x00,0x00,0x30]
// CHECK: adr x0, .Ltmp0 // encoding: [A,A,A,0x10'A']
// CHECK-NEXT: // fixup A - offset: 0, value: .Ltmp0, kind: fixup_arm64_pcrel_adr_imm21
// CHECK: adr x0, foo // encoding: [A,A,A,0x10'A']
// CHECK-NEXT: // fixup A - offset: 0, value: foo, kind: fixup_arm64_pcrel_adr_imm21
adrp x0, #0
adrp x0, #4096
adrp x0, 1f
adrp x0, foo
// CHECK: adrp x0, #0 // encoding: [0x00,0x00,0x00,0x90]
// CHECK: adrp x0, #4096 // encoding: [0x00,0x00,0x00,0xb0]
// CHECK: adrp x0, .Ltmp0 // encoding: [A,A,A,0x90'A']
// CHECK-NEXT: // fixup A - offset: 0, value: .Ltmp0, kind: fixup_arm64_pcrel_adrp_imm21
// CHECK: adrp x0, foo // encoding: [A,A,A,0x90'A']
// CHECK-NEXT: // fixup A - offset: 0, value: foo, kind: fixup_arm64_pcrel_adrp_imm21
adr x0, #0xffffffff
adrp x0, #0xffffffff
adrp x0, #1
// CHECK-ERRORS: error: expected label or encodable integer pc offset
// CHECK-ERRORS: error: expected label or encodable integer pc offset
// CHECK-ERRORS: error: expected label or encodable integer pc offset