ARM LDRD(register) assembly parsing and encoding.
authorJim Grosbach <grosbach@apple.com>
Wed, 10 Aug 2011 21:56:18 +0000 (21:56 +0000)
committerJim Grosbach <grosbach@apple.com>
Wed, 10 Aug 2011 21:56:18 +0000 (21:56 +0000)
Add support for literal encoding of #-0 along the way.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137254 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/arm-memory-instructions.s

index 0aaf67692a93e5e85b6e1dcd9b1f7ee4986cd6b0..3b77cdbdff160c13c76196297805e24fd62c58de 100644 (file)
@@ -722,7 +722,10 @@ def addrmode3 : Operand<i32>,
 
 // FIXME: split into imm vs. reg versions.
 // FIXME: parser method to handle +/- register.
-def AM3OffsetAsmOperand : AsmOperandClass { let Name = "AM3Offset"; }
+def AM3OffsetAsmOperand : AsmOperandClass {
+  let Name = "AM3Offset";
+  let ParserMethod = "parseAM3Offset";
+}
 def am3offset : Operand<i32>,
                 ComplexPattern<i32, 2, "SelectAddrMode3Offset",
                                [], [SDNPWantRoot]> {
index fcc8a6a7fd655df336eb5585fdd73bf887176bcb..72ab7ea595df5dbe0e227f40d15a4261ad35b47e 100644 (file)
@@ -114,6 +114,7 @@ class ARMAsmParser : public MCTargetAsmParser {
   OperandMatchResultTy parseRotImm(SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy parseBitfield(SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy parsePostIdxReg(SmallVectorImpl<MCParsedAsmOperand*>&);
+  OperandMatchResultTy parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*>&);
 
   // Asm Match Converter Methods
   bool cvtLdWriteBackRegAddrMode2(MCInst &Inst, unsigned Opcode,
@@ -557,7 +558,8 @@ public:
     const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
     if (!CE) return false;
     int64_t Val = CE->getValue();
-    return Val > -256 && Val < 256;
+    // Special case, #-0 is INT32_MIN.
+    return (Val > -256 && Val < 256) || Val == INT32_MIN;
   }
   bool isAddrMode5() const {
     if (Kind != Memory)
@@ -865,6 +867,7 @@ public:
         ARM_AM::getAM3Opc(PostIdxReg.isAdd ? ARM_AM::add : ARM_AM::sub, 0);
       Inst.addOperand(MCOperand::CreateReg(PostIdxReg.RegNum));
       Inst.addOperand(MCOperand::CreateImm(Val));
+      return;
     }
 
     // Constant offset.
@@ -874,7 +877,7 @@ public:
     // Special case for #-0
     if (Val == INT32_MIN) Val = 0;
     if (Val < 0) Val = -Val;
-    Val = ARM_AM::getAM2Opc(AddSub, Val, ARM_AM::no_shift);
+    Val = ARM_AM::getAM3Opc(AddSub, Val);
     Inst.addOperand(MCOperand::CreateReg(0));
     Inst.addOperand(MCOperand::CreateImm(Val));
   }
@@ -2007,6 +2010,76 @@ parsePostIdxReg(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
   return MatchOperand_Success;
 }
 
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+parseAM3Offset(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+  // Check for a post-index addressing register operand. Specifically:
+  // am3offset := '+' register
+  //              | '-' register
+  //              | register
+  //              | # imm
+  //              | # + imm
+  //              | # - imm
+
+  // This method must return MatchOperand_NoMatch without consuming any tokens
+  // in the case where there is no match, as other alternatives take other
+  // parse methods.
+  AsmToken Tok = Parser.getTok();
+  SMLoc S = Tok.getLoc();
+
+  // Do immediates first, as we always parse those if we have a '#'.
+  if (Parser.getTok().is(AsmToken::Hash)) {
+    Parser.Lex(); // Eat the '#'.
+    // Explicitly look for a '-', as we need to encode negative zero
+    // differently.
+    bool isNegative = Parser.getTok().is(AsmToken::Minus);
+    const MCExpr *Offset;
+    if (getParser().ParseExpression(Offset))
+      return MatchOperand_ParseFail;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Offset);
+    if (!CE) {
+      Error(S, "constant expression expected");
+      return MatchOperand_ParseFail;
+    }
+    SMLoc E = Tok.getLoc();
+    // Negative zero is encoded as the flag value INT32_MIN.
+    int32_t Val = CE->getValue();
+    if (isNegative && Val == 0)
+      Val = INT32_MIN;
+
+    Operands.push_back(
+      ARMOperand::CreateImm(MCConstantExpr::Create(Val, getContext()), S, E));
+
+    return MatchOperand_Success;
+  }
+
+
+  bool haveEaten = false;
+  bool isAdd = true;
+  int Reg = -1;
+  if (Tok.is(AsmToken::Plus)) {
+    Parser.Lex(); // Eat the '+' token.
+    haveEaten = true;
+  } else if (Tok.is(AsmToken::Minus)) {
+    Parser.Lex(); // Eat the '-' token.
+    isAdd = false;
+    haveEaten = true;
+  }
+  if (Parser.getTok().is(AsmToken::Identifier))
+    Reg = tryParseRegister();
+  if (Reg == -1) {
+    if (!haveEaten)
+      return MatchOperand_NoMatch;
+    Error(Parser.getTok().getLoc(), "register expected");
+    return MatchOperand_ParseFail;
+  }
+  SMLoc E = Parser.getTok().getLoc();
+
+  Operands.push_back(ARMOperand::CreatePostIdxReg(Reg, isAdd, ARM_AM::no_shift,
+                                                  0, S, E));
+
+  return MatchOperand_Success;
+}
+
 /// cvtLdWriteBackRegAddrMode2 - Convert parsed operands to MCInst.
 /// Needed here because the Asm Gen Matcher can't handle properly tied operands
 /// when they refer multiple MIOperands inside a single one.
index a216a1178063e778e321f82324dff72feecd50dd..6a1c566c231d0b95894f783783484cbb476ea619 100644 (file)
@@ -114,8 +114,28 @@ _func:
         ldrd r7, r8, [r2, #15]
         ldrd r1, r2, [r9, #32]!
         ldrd r6, r7, [r1], #8
+        ldrd r1, r2, [r8], #0
+        ldrd r1, r2, [r8], #+0
+        ldrd r1, r2, [r8], #-0
 
 @ CHECK: ldrd  r3, r4, [r5]            @ encoding: [0xd0,0x30,0xc5,0xe1]
 @ CHECK: ldrd  r7, r8, [r2, #15]       @ encoding: [0xdf,0x70,0xc2,0xe1]
 @ CHECK: ldrd  r1, r2, [r9, #32]!      @ encoding: [0xd0,0x12,0xe9,0xe1]
 @ CHECK: ldrd  r6, r7, [r1], #8        @ encoding: [0xd8,0x60,0xc1,0xe0]
+@ CHECK: ldrd  r1, r2, [r8], #0        @ encoding: [0xd0,0x10,0xc8,0xe0]
+@ CHECK: ldrd  r1, r2, [r8], #0        @ encoding: [0xd0,0x10,0xc8,0xe0]
+@ CHECK: ldrd  r1, r2, [r8], #-0       @ encoding: [0xd0,0x10,0x48,0xe0]
+
+
+@------------------------------------------------------------------------------
+@ LDRD (register)
+@------------------------------------------------------------------------------
+        ldrd r3, r4, [r1, r3]
+        ldrd r4, r5, [r7, r2]!
+        ldrd r1, r2, [r8], r12
+        ldrd r1, r2, [r8], -r12
+
+       ldrd    r3, r4, [r1, r3]        @ encoding: [0xd3,0x30,0x81,0xe1]
+       ldrd    r4, r5, [r7, r2]!       @ encoding: [0xd2,0x40,0xa7,0xe1]
+       ldrd    r1, r2, [r8], r12       @ encoding: [0xdc,0x10,0x88,0xe0]
+       ldrd    r1, r2, [r8], -r12      @ encoding: [0xdc,0x10,0x08,0xe0]