diff options
author | Bill Wendling <isanbard@gmail.com> | 2010-11-03 01:49:29 +0000 |
---|---|---|
committer | Bill Wendling <isanbard@gmail.com> | 2010-11-03 01:49:29 +0000 |
commit | 92b5a2eb1646b3c1173a5ff3c0073f24ed5ee6a4 (patch) | |
tree | 534c8e3e743a503fd2abdb4a63599fb3e4b979dc /lib/Target/ARM/AsmParser/ARMAsmParser.cpp | |
parent | 394d6298bcf89a75b51c8314a6705f6984e46b49 (diff) |
The MC code couldn't handle ARM LDR instructions with negative offsets:
vldr.64 d1, [r0, #-32]
The problem was with how the addressing mode 5 encodes the offsets. This change
makes sure that the way offsets are handled in addressing mode 5 is consistent
throughout the MC code. It involves re-refactoring the "getAddrModeImmOpValue"
method into an "Imm12" and "addressing mode 5" version. But not to worry! The
majority of the duplicated code has been unified.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118144 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM/AsmParser/ARMAsmParser.cpp')
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 4552374bcc..f5dc38bcfe 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMAddressingModes.h" #include "ARMSubtarget.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" @@ -260,16 +261,25 @@ public: Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); assert(!Mem.OffsetIsReg && "invalid mode 5 operand"); + // FIXME: #-0 is encoded differently than #0. Does the parser preserve // the difference? if (Mem.Offset) { const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset); - assert(CE && "non-constant mode 5 offset operand!"); + assert(CE && "Non-constant mode 5 offset operand!"); + // The MCInst offset operand doesn't include the low two bits (like // the instruction encoding). - Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4)); - } else + int64_t Offset = CE->getValue() / 4; + if (Offset >= 0) + Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::add, + Offset))); + else + Inst.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(ARM_AM::sub, + -Offset))); + } else { Inst.addOperand(MCOperand::CreateImm(0)); + } } virtual void dump(raw_ostream &OS) const; |