AArch64/ARM64: allow negative addends, at least on ELF.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207111 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tim Northover 2014-04-24 12:56:38 +00:00
parent 421c65b9b4
commit d4daf1762d
2 changed files with 20 additions and 14 deletions

View File

@ -122,7 +122,7 @@ public:
static bool classifySymbolRef(const MCExpr *Expr, static bool classifySymbolRef(const MCExpr *Expr,
ARM64MCExpr::VariantKind &ELFRefKind, ARM64MCExpr::VariantKind &ELFRefKind,
MCSymbolRefExpr::VariantKind &DarwinRefKind, MCSymbolRefExpr::VariantKind &DarwinRefKind,
const MCConstantExpr *&Addend); int64_t &Addend);
}; };
} // end anonymous namespace } // end anonymous namespace
@ -587,7 +587,7 @@ public:
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (!ARM64AsmParser::classifySymbolRef(getImm(), ELFRefKind, DarwinRefKind, if (!ARM64AsmParser::classifySymbolRef(getImm(), ELFRefKind, DarwinRefKind,
Addend)) { Addend)) {
return false; return false;
@ -911,7 +911,7 @@ public:
const MCExpr *Expr = Mem.OffsetImm; const MCExpr *Expr = Mem.OffsetImm;
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (!ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, if (!ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind,
Addend)) { Addend)) {
// If we don't understand the expression, assume the best and // If we don't understand the expression, assume the best and
@ -931,8 +931,7 @@ public:
// Note that we don't range-check the addend. It's adjusted modulo page // Note that we don't range-check the addend. It's adjusted modulo page
// size when converted, so there is no "out of range" condition when using // size when converted, so there is no "out of range" condition when using
// @pageoff. // @pageoff.
int64_t Value = Addend ? Addend->getValue() : 0; return Addend >= 0 && (Addend % Scale) == 0;
return Value >= 0 && (Value % Scale) == 0;
} else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF || } else if (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF ||
DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) { DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF) {
// @gotpageoff/@tlvppageoff can only be used directly, not with an addend. // @gotpageoff/@tlvppageoff can only be used directly, not with an addend.
@ -1482,7 +1481,7 @@ public:
const MCExpr *Expr = Mem.OffsetImm; const MCExpr *Expr = Mem.OffsetImm;
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (Scale > 1 && if (Scale > 1 &&
(!ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, (!ARM64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind,
Addend) || Addend) ||
@ -2091,7 +2090,7 @@ ARM64AsmParser::tryParseAdrpLabel(OperandVector &Operands) {
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { if (classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
if (DarwinRefKind == MCSymbolRefExpr::VK_None && if (DarwinRefKind == MCSymbolRefExpr::VK_None &&
ELFRefKind == ARM64MCExpr::VK_INVALID) { ELFRefKind == ARM64MCExpr::VK_INVALID) {
@ -2925,7 +2924,7 @@ bool ARM64AsmParser::parseMemory(OperandVector &Operands) {
// assume it's OK and let the relocation stuff puke if it's not. // assume it's OK and let the relocation stuff puke if it's not.
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (classifySymbolRef(OffsetExpr, ELFRefKind, DarwinRefKind, Addend) && if (classifySymbolRef(OffsetExpr, ELFRefKind, DarwinRefKind, Addend) &&
Addend == 0) { Addend == 0) {
assert(ELFRefKind == ARM64MCExpr::VK_INVALID && assert(ELFRefKind == ARM64MCExpr::VK_INVALID &&
@ -3491,7 +3490,7 @@ bool ARM64AsmParser::validateInstruction(MCInst &Inst,
const MCExpr *Expr = Inst.getOperand(2).getExpr(); const MCExpr *Expr = Inst.getOperand(2).getExpr();
ARM64MCExpr::VariantKind ELFRefKind; ARM64MCExpr::VariantKind ELFRefKind;
MCSymbolRefExpr::VariantKind DarwinRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind;
const MCConstantExpr *Addend; int64_t Addend;
if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { if (!classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) {
return Error(Loc[2], "invalid immediate expression"); return Error(Loc[2], "invalid immediate expression");
} }
@ -4478,9 +4477,10 @@ bool
ARM64AsmParser::classifySymbolRef(const MCExpr *Expr, ARM64AsmParser::classifySymbolRef(const MCExpr *Expr,
ARM64MCExpr::VariantKind &ELFRefKind, ARM64MCExpr::VariantKind &ELFRefKind,
MCSymbolRefExpr::VariantKind &DarwinRefKind, MCSymbolRefExpr::VariantKind &DarwinRefKind,
const MCConstantExpr *&Addend) { int64_t &Addend) {
ELFRefKind = ARM64MCExpr::VK_INVALID; ELFRefKind = ARM64MCExpr::VK_INVALID;
DarwinRefKind = MCSymbolRefExpr::VK_None; DarwinRefKind = MCSymbolRefExpr::VK_None;
Addend = 0;
if (const ARM64MCExpr *AE = dyn_cast<ARM64MCExpr>(Expr)) { if (const ARM64MCExpr *AE = dyn_cast<ARM64MCExpr>(Expr)) {
ELFRefKind = AE->getKind(); ELFRefKind = AE->getKind();
@ -4491,7 +4491,6 @@ ARM64AsmParser::classifySymbolRef(const MCExpr *Expr,
if (SE) { if (SE) {
// It's a simple symbol reference with no addend. // It's a simple symbol reference with no addend.
DarwinRefKind = SE->getKind(); DarwinRefKind = SE->getKind();
Addend = 0;
return true; return true;
} }
@ -4504,15 +4503,20 @@ ARM64AsmParser::classifySymbolRef(const MCExpr *Expr,
return false; return false;
DarwinRefKind = SE->getKind(); DarwinRefKind = SE->getKind();
if (BE->getOpcode() != MCBinaryExpr::Add) if (BE->getOpcode() != MCBinaryExpr::Add &&
BE->getOpcode() != MCBinaryExpr::Sub)
return false; return false;
// See if the addend is is a constant, otherwise there's more going // See if the addend is is a constant, otherwise there's more going
// on here than we can deal with. // on here than we can deal with.
Addend = dyn_cast<MCConstantExpr>(BE->getRHS()); auto AddendExpr = dyn_cast<MCConstantExpr>(BE->getRHS());
if (!Addend) if (!AddendExpr)
return false; return false;
Addend = AddendExpr->getValue();
if (BE->getOpcode() == MCBinaryExpr::Sub)
Addend = -Addend;
// It's some symbol reference + a constant addend, but really // It's some symbol reference + a constant addend, but really
// shouldn't use both Darwin and ELF syntax. // shouldn't use both Darwin and ELF syntax.
return ELFRefKind == ARM64MCExpr::VK_INVALID || return ELFRefKind == ARM64MCExpr::VK_INVALID ||

View File

@ -1,5 +1,7 @@
// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj -o - %s | llvm-objdump -triple=aarch64-linux-gnu -r - | FileCheck %s // RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj -o - %s | llvm-objdump -triple=aarch64-linux-gnu -r - | FileCheck %s
// RUN: llvm-mc -triple=arm64-linux-gnu -filetype=obj -o - %s | llvm-objdump -triple=aarch64-linux-gnu -r - | FileCheck %s
add x0, x4, #:lo12:sym add x0, x4, #:lo12:sym
// CHECK: 0 R_AARCH64_ADD_ABS_LO12_NC sym // CHECK: 0 R_AARCH64_ADD_ABS_LO12_NC sym
add x3, x5, #:lo12:sym+1 add x3, x5, #:lo12:sym+1