diff options
author | Bill Wendling <isanbard@gmail.com> | 2010-11-30 07:44:32 +0000 |
---|---|---|
committer | Bill Wendling <isanbard@gmail.com> | 2010-11-30 07:44:32 +0000 |
commit | ef4a68badbde372faac9ca47efb9001def57a43d (patch) | |
tree | 2365abf528a38f22d1d78168fd89899a6034ae6a /lib/Target/ARM/AsmParser/ARMAsmParser.cpp | |
parent | 3f8e61789100ee411d0bfe00fb90df60eaed65f5 (diff) |
Add parsing for the Thumb t_addrmode_s4 addressing mode. This can almost
certainly be made more generic. But it does allow us to parse something like:
ldr r3, [r2, r4]
correctly in Thumb mode.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120408 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM/AsmParser/ARMAsmParser.cpp')
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 41 |
1 files changed, 35 insertions, 6 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index f9a792e8dd..31742e3624 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -222,16 +222,30 @@ public: if (!isMemory() || Mem.OffsetIsReg || Mem.OffsetRegShifted || Mem.Writeback || Mem.Negative) return false; + // If there is an offset expression, make sure it's valid. - if (!Mem.Offset) - return true; + if (!Mem.Offset) return true; + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset); - if (!CE) - return false; + if (!CE) return false; + // The offset must be a multiple of 4 in the range 0-1020. int64_t Value = CE->getValue(); return ((Value & 0x3) == 0 && Value <= 1020 && Value >= -1020); } + bool isMemModeThumb() const { + if (!isMemory() || (!Mem.OffsetIsReg && !Mem.Offset) || Mem.Writeback) + return false; + + if (!Mem.Offset) return true; + + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset); + if (!CE) return false; + + // The offset must be a multiple of 4 in the range 0-124. + uint64_t Value = CE->getValue(); + return ((Value & 0x3) == 0 && Value <= 124); + } void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. @@ -302,6 +316,21 @@ public: } } + void addMemModeThumbOperands(MCInst &Inst, unsigned N) const { + assert(N == 3 && isMemModeThumb() && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateReg(Mem.BaseRegNum)); + + if (Mem.Offset) { + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Mem.Offset); + assert(CE && "Non-constant mode offset operand!"); + Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4)); + Inst.addOperand(MCOperand::CreateReg(0)); + } else { + Inst.addOperand(MCOperand::CreateImm(0)); + Inst.addOperand(MCOperand::CreateReg(Mem.OffsetRegNum)); + } + } + virtual void dump(raw_ostream &OS) const; static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) { @@ -592,8 +621,8 @@ ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &Operands) { int OffsetRegNum; bool OffsetRegShifted; enum ShiftType ShiftType; - const MCExpr *ShiftAmount; - const MCExpr *Offset; + const MCExpr *ShiftAmount = 0; + const MCExpr *Offset = 0; if (ParseMemoryOffsetReg(Negative, OffsetRegShifted, ShiftType, ShiftAmount, Offset, OffsetIsReg, OffsetRegNum, E)) return true; |