From 97dd28fb89dc4c4caa3c60890335dc99489981a6 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Tue, 30 Nov 2010 22:40:36 +0000 Subject: [PATCH] Fix handling of ARM negative pc-relative fixups for loads and stores. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120480 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/ARMAsmBackend.cpp | 32 ++++++++++++++++++++++++----- lib/Target/ARM/ARMMCCodeEmitter.cpp | 13 ++++++++---- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/lib/Target/ARM/ARMAsmBackend.cpp b/lib/Target/ARM/ARMAsmBackend.cpp index e7ff8bd1fab..6267a5af990 100644 --- a/lib/Target/ARM/ARMAsmBackend.cpp +++ b/lib/Target/ARM/ARMAsmBackend.cpp @@ -131,8 +131,8 @@ static unsigned getFixupKindNumBytes(unsigned Kind) { switch (Kind) { default: llvm_unreachable("Unknown fixup kind!"); case FK_Data_4: return 4; - case ARM::fixup_arm_pcrel_12: return 2; - case ARM::fixup_arm_vfp_pcrel_12: return 1; + case ARM::fixup_arm_pcrel_12: return 3; + case ARM::fixup_arm_vfp_pcrel_12: return 3; case ARM::fixup_arm_branch: return 3; } } @@ -143,14 +143,36 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { llvm_unreachable("Unknown fixup kind!"); case FK_Data_4: return Value; - case ARM::fixup_arm_pcrel_12: + case ARM::fixup_arm_pcrel_12: { + bool isAdd = true; // ARM PC-relative values are offset by 8. - return Value - 8; + Value -= 8; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + assert ((Value < 4096) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + return Value; + } case ARM::fixup_arm_branch: - case ARM::fixup_arm_vfp_pcrel_12: // These values don't encode the low two bits since they're always zero. // Offset by 8 just as above. return (Value - 8) >> 2; + case ARM::fixup_arm_vfp_pcrel_12: { + // Offset by 8 just as above. + Value = Value - 8; + bool isAdd = true; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + // These values don't encode the low two bits since they're always zero. + Value >>= 2; + assert ((Value < 256) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + return Value; + } } } diff --git a/lib/Target/ARM/ARMMCCodeEmitter.cpp b/lib/Target/ARM/ARMMCCodeEmitter.cpp index 742afa5d03e..fd595fd8ffb 100644 --- a/lib/Target/ARM/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/ARMMCCodeEmitter.cpp @@ -46,8 +46,8 @@ public: const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { const static MCFixupKindInfo Infos[] = { // name offset bits flags - { "fixup_arm_pcrel_12", 2, 12, MCFixupKindInfo::FKF_IsPCRel }, - { "fixup_arm_vfp_pcrel_12", 3, 8, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_arm_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_arm_vfp_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_arm_branch", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, }; @@ -395,6 +395,7 @@ getAddrModeImm12OpValue(const MCInst &MI, unsigned OpIdx, if (!MO.isReg()) { Reg = getARMRegisterNumbering(ARM::PC); // Rn is PC. Imm12 = 0; + isAdd = false ; // 'U' bit is set as part of the fixup. assert(MO.isExpr() && "Unexpected machine operand type!"); const MCExpr *Expr = MO.getExpr(); @@ -574,11 +575,13 @@ getAddrMode5OpValue(const MCInst &MI, unsigned OpIdx, // {8} = (U)nsigned (add == '1', sub == '0') // {7-0} = imm8 unsigned Reg, Imm8; + bool isAdd; // If The first operand isn't a register, we have a label reference. const MCOperand &MO = MI.getOperand(OpIdx); if (!MO.isReg()) { Reg = getARMRegisterNumbering(ARM::PC); // Rn is PC. Imm8 = 0; + isAdd = false; // 'U' bit is handled as part of the fixup. assert(MO.isExpr() && "Unexpected machine operand type!"); const MCExpr *Expr = MO.getExpr(); @@ -586,12 +589,14 @@ getAddrMode5OpValue(const MCInst &MI, unsigned OpIdx, Fixups.push_back(MCFixup::Create(0, Expr, Kind)); ++MCNumCPRelocations; - } else + } else { EncodeAddrModeOpValues(MI, OpIdx, Reg, Imm8, Fixups); + isAdd = ARM_AM::getAM5Op(Imm8) == ARM_AM::add; + } uint32_t Binary = ARM_AM::getAM5Offset(Imm8); // Immediate is always encoded as positive. The 'U' bit controls add vs sub. - if (ARM_AM::getAM5Op(Imm8) == ARM_AM::add) + if (isAdd) Binary |= (1 << 8); Binary |= (Reg << 9); return Binary; -- 2.34.1