1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

[AArch64] Support expression results as immediate values in mov

Summary:
This patch adds support of using the result of an expression as an
immediate value. For example,

0:
.skip 4
 1:
mov x0, 1b - 0b

is assembled to

mov x0, #4

Currently it does not support expressions requiring relocation unless
explicitly specified. This fixes PR#45781.

Reviewers: peter.smith, ostannard, efriedma

Reviewed By: efriedma

Subscribers: nickdesaulniers, llozano, manojgupta, efriedma, ostannard, kristof.beyls, hiraditya, danielkiss, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D80028
This commit is contained in:
Jian Cai 2020-06-08 17:56:46 -07:00
parent ea1b197077
commit 688a507b32
7 changed files with 94 additions and 31 deletions

View File

@ -970,12 +970,16 @@ public:
bool isMOVZMovAlias() const { bool isMOVZMovAlias() const {
if (!isImm()) return false; if (!isImm()) return false;
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm()); const MCExpr *E = getImm();
if (!CE) return false; if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(E)) {
uint64_t Value = CE->getValue(); uint64_t Value = CE->getValue();
return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth); return AArch64_AM::isMOVZMovAlias(Value, Shift, RegWidth);
} }
// Only supports the case of Shift being 0 if an expression is used as an
// operand
return !Shift && E;
}
template<int RegWidth, int Shift> template<int RegWidth, int Shift>
bool isMOVNMovAlias() const { bool isMOVNMovAlias() const {
@ -1774,9 +1778,13 @@ public:
void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const { void addMOVZMovAliasOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!"); assert(N == 1 && "Invalid number of operands!");
const MCConstantExpr *CE = cast<MCConstantExpr>(getImm()); const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
if (CE) {
uint64_t Value = CE->getValue(); uint64_t Value = CE->getValue();
Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff)); Inst.addOperand(MCOperand::createImm((Value >> Shift) & 0xffff));
} else {
addExpr(Inst, getImm());
}
} }
template<int Shift> template<int Shift>

View File

@ -243,6 +243,17 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, const MCValue &Target,
static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS && if (AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_ABS &&
AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) { AArch64MCExpr::getSymbolLoc(RefKind) != AArch64MCExpr::VK_SABS) {
if (!RefKind) {
// The fixup is an expression
if (SignedValue > 0xFFFF || SignedValue < -0xFFFF)
Ctx.reportError(Fixup.getLoc(),
"fixup value out of range [-0xFFFF, 0xFFFF]");
// Invert the negative immediate because it will feed into a MOVN.
if (SignedValue < 0)
SignedValue = ~SignedValue;
Value = static_cast<uint64_t>(SignedValue);
} else
// VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't // VK_GOTTPREL, VK_TPREL, VK_DTPREL are movw fixups, but they can't
// ever be resolved in the assembler. // ever be resolved in the assembler.
Ctx.reportError(Fixup.getLoc(), Ctx.reportError(Fixup.getLoc(),
@ -441,7 +452,8 @@ void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
// handle this more cleanly. This may affect the output of -show-mc-encoding. // handle this more cleanly. This may affect the output of -show-mc-encoding.
AArch64MCExpr::VariantKind RefKind = AArch64MCExpr::VariantKind RefKind =
static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind()); static_cast<AArch64MCExpr::VariantKind>(Target.getRefKind());
if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS) { if (AArch64MCExpr::getSymbolLoc(RefKind) == AArch64MCExpr::VK_SABS ||
(!RefKind && Fixup.getTargetKind() == AArch64::fixup_aarch64_movw)) {
// If the immediate is negative, generate MOVN else MOVZ. // If the immediate is negative, generate MOVN else MOVZ.
// (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ. // (Bit 30 = 0) ==> MOVN, (Bit 30 = 1) ==> MOVZ.
if (SignedValue < 0) if (SignedValue < 0)

View File

@ -569,7 +569,8 @@ unsigned AArch64MCCodeEmitter::fixMOVZ(const MCInst &MI, unsigned EncodedValue,
if (UImm16MO.isImm()) if (UImm16MO.isImm())
return EncodedValue; return EncodedValue;
const AArch64MCExpr *A64E = cast<AArch64MCExpr>(UImm16MO.getExpr()); const MCExpr *E = UImm16MO.getExpr();
if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(E)) {
switch (A64E->getKind()) { switch (A64E->getKind()) {
case AArch64MCExpr::VK_DTPREL_G2: case AArch64MCExpr::VK_DTPREL_G2:
case AArch64MCExpr::VK_DTPREL_G1: case AArch64MCExpr::VK_DTPREL_G1:
@ -583,9 +584,9 @@ unsigned AArch64MCCodeEmitter::fixMOVZ(const MCInst &MI, unsigned EncodedValue,
// Nothing to do for an unsigned fixup. // Nothing to do for an unsigned fixup.
return EncodedValue; return EncodedValue;
} }
}
return EncodedValue;
return EncodedValue & ~(1u << 30);
} }
void AArch64MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, void AArch64MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,

View File

@ -167,7 +167,7 @@
// MOV alias should not accept any fiddling // MOV alias should not accept any fiddling
mov x2, xsp, #123 mov x2, xsp, #123
mov wsp, w27, #0xfff, lsl #12 mov wsp, w27, #0xfff, lsl #12
// CHECK-ERROR: error: expected compatible register or logical immediate // CHECK-ERROR: error: invalid operand for instruction
// CHECK-ERROR-NEXT: mov x2, xsp, #123 // CHECK-ERROR-NEXT: mov x2, xsp, #123
// CHECK-ERROR-NEXT: ^ // CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: invalid operand for instruction // CHECK-ERROR-NEXT: error: invalid operand for instruction

View File

@ -0,0 +1,16 @@
// RUN: llvm-mc -triple aarch64-none-linux-gnu %s -filetype=obj -o %t | llvm-objdump --triple aarch64-none-linux-gnu -Dr %t | FileCheck %s
0:
.skip 4
1:
mov x0, 1b - 0b
// CHECK: mov x0, #4
mov x0, 0b - 1b
// CHECK: mov x0, #-4
mov x0, 0b - 0b
// CHECK: mov x0, #0
mov x0, 1b - 2 - 0b + 6
// CHECK: mov x0, #8
mov x0, #:abs_g0_s:1b
// CHECK: mov x0, #0
// CHECK-NEXT: R_AARCH64_MOVW_SABS_G0 .text+0x4

View File

@ -0,0 +1,9 @@
// RUN: llvm-mc -triple aarch64-none-linux-gnu %s -filetype=obj -o %t | llvm-objdump -d %t | FileCheck %s
0:
.skip 4
1:
mov x0, 1b - 0b
// CHECK: mov x0, #4
mov x0, 0b - 1b
// CHECK: mov x0, #-4

View File

@ -0,0 +1,17 @@
// RUN: not llvm-mc -triple aarch64-none-linux-gnu %s -filetype=obj -o /dev/null 2>&1 | FileCheck %s
0:
.skip 0x10000
1:
mov x0, 1b - 0b
// CHECK: error: fixup value out of range
// CHECK: mov x0, 1b - 0b
// CHECK: ^
mov x0, 0b - 1b
// CHECK: error: fixup value out of range
// CHECK: mov x0, 0b - 1b
// CHECK: ^
mov x0, 1b
// CHECK: error: invalid fixup for movz/movk instruction
// CHECK: mov x0, 1b
// CHECK: ^