Thumb parsing and encoding support for ADD SP instructions.
authorJim Grosbach <grosbach@apple.com>
Wed, 24 Aug 2011 21:22:15 +0000 (21:22 +0000)
committerJim Grosbach <grosbach@apple.com>
Wed, 24 Aug 2011 21:22:15 +0000 (21:22 +0000)
Fix the test FIXME and add parsing support for the ADD (SP plus immediate)
and ADD (SP plus register) instruction forms.

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

lib/Target/ARM/ARMInstrThumb.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/basic-thumb-instructions.s
test/MC/ARM/thumb-diagnostics.s
utils/TableGen/EDEmitter.cpp

index 61b94ccef7ee12aecb1518cc429d5795dd8bca45..a5ddec3d23ed8c584dd2b00449269b4df8fa85e9 100644 (file)
@@ -78,8 +78,17 @@ def t_adrlabel : Operand<i32> {
 }
 
 // Scaled 4 immediate.
-def t_imm_s4 : Operand<i32> {
+def t_imm0_1020s4_asmoperand: AsmOperandClass { let Name = "Imm0_1020s4"; }
+def t_imm0_1020s4 : Operand<i32> {
   let PrintMethod = "printThumbS4ImmOperand";
+  let ParserMatchClass = t_imm0_1020s4_asmoperand;
+  let OperandType = "OPERAND_IMMEDIATE";
+}
+
+def t_imm0_508s4_asmoperand: AsmOperandClass { let Name = "Imm0_508s4"; }
+def t_imm0_508s4 : Operand<i32> {
+  let PrintMethod = "printThumbS4ImmOperand";
+  let ParserMatchClass = t_imm0_508s4_asmoperand;
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
@@ -305,35 +314,39 @@ def tPICADD : TIt<(outs GPR:$dst), (ins GPR:$lhs, pclabel:$cp), IIC_iALUr, "",
 // This is rematerializable, which is particularly useful for taking the
 // address of locals.
 let isReMaterializable = 1 in
-def tADDrSPi : T1pI<(outs tGPR:$dst), (ins GPRsp:$sp, t_imm_s4:$rhs), IIC_iALUi,
-                   "add", "\t$dst, $sp, $rhs", []>,
+def tADDrSPi : T1pI<(outs tGPR:$dst), (ins GPRsp:$sp, t_imm0_1020s4:$imm),
+                    IIC_iALUi, "add", "\t$dst, $sp, $imm", []>,
                T1Encoding<{1,0,1,0,1,?}> {
   // A6.2 & A8.6.8
   bits<3> dst;
-  bits<8> rhs;
+  bits<8> imm;
   let Inst{10-8} = dst;
-  let Inst{7-0}  = rhs;
+  let Inst{7-0}  = imm;
   let DecoderMethod = "DecodeThumbAddSpecialReg";
 }
 
 // ADD sp, sp, #<imm7>
-def tADDspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm_s4:$rhs),
-                     IIC_iALUi, "add", "\t$Rdn, $rhs", []>,
+def tADDspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm0_508s4:$imm),
+                     IIC_iALUi, "add", "\t$Rdn, $imm", []>,
               T1Misc<{0,0,0,0,0,?,?}> {
   // A6.2.5 & A8.6.8
-  bits<7> rhs;
-  let Inst{6-0} = rhs;
+  bits<7> imm;
+  let Inst{6-0} = imm;
   let DecoderMethod = "DecodeThumbAddSPImm";
 }
 
+// Can optionally specify SP as a three operand instruction.
+def : tInstAlias<"add${p} sp, sp, $imm",
+                 (tADDspi SP, t_imm0_508s4:$imm, pred:$p)>;
+
 // SUB sp, sp, #<imm7>
 // FIXME: The encoding and the ASM string don't match up.
-def tSUBspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm_s4:$rhs),
-                    IIC_iALUi, "sub", "\t$Rdn, $rhs", []>,
+def tSUBspi : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, t_imm0_508s4:$imm),
+                    IIC_iALUi, "sub", "\t$Rdn, $imm", []>,
               T1Misc<{0,0,0,0,1,?,?}> {
   // A6.2.5 & A8.6.214
-  bits<7> rhs;
-  let Inst{6-0} = rhs;
+  bits<7> imm;
+  let Inst{6-0} = imm;
   let DecoderMethod = "DecodeThumbAddSPImm";
 }
 
@@ -350,13 +363,13 @@ def tADDrSP : T1pIt<(outs GPR:$Rdn), (ins GPR:$Rn, GPRsp:$sp), IIC_iALUr,
 }
 
 // ADD sp, <Rm>
-def tADDspr : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, GPR:$rhs), IIC_iALUr,
-                  "add", "\t$Rdn, $rhs", []>,
+def tADDspr : T1pIt<(outs GPRsp:$Rdn), (ins GPRsp:$Rn, GPR:$Rm), IIC_iALUr,
+                  "add", "\t$Rdn, $Rm", []>,
               T1Special<{0,0,?,?}> {
   // A8.6.9 Encoding T2
-  bits<4> Rdn;
+  bits<4> Rm;
   let Inst{7} = 1;
-  let Inst{6-3} = Rdn;
+  let Inst{6-3} = Rm;
   let Inst{2-0} = 0b101;
   let DecoderMethod = "DecodeThumbAddSPReg";
 }
index 32a4fbbb01f02536f488ffb374ea7029e906fa5e..965b39412c8f80abc8c9583e9ce880709f9543c9 100644 (file)
@@ -412,6 +412,22 @@ public:
   bool isCondCode() const { return Kind == CondCode; }
   bool isCCOut() const { return Kind == CCOut; }
   bool isImm() const { return Kind == Immediate; }
+  bool isImm0_1020s4() const {
+    if (Kind != Immediate)
+      return false;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    if (!CE) return false;
+    int64_t Value = CE->getValue();
+    return ((Value & 3) == 0) && Value >= 0 && Value <= 1020;
+  }
+  bool isImm0_508s4() const {
+    if (Kind != Immediate)
+      return false;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    if (!CE) return false;
+    int64_t Value = CE->getValue();
+    return ((Value & 3) == 0) && Value >= 0 && Value <= 508;
+  }
   bool isImm0_255() const {
     if (Kind != Immediate)
       return false;
@@ -791,6 +807,22 @@ public:
     addExpr(Inst, getImm());
   }
 
+  void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    // The immediate is scaled by four in the encoding and is stored
+    // in the MCInst as such. Lop off the low two bits here.
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
+  }
+
+  void addImm0_508s4Operands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    // The immediate is scaled by four in the encoding and is stored
+    // in the MCInst as such. Lop off the low two bits here.
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm());
+    Inst.addOperand(MCOperand::CreateImm(CE->getValue() / 4));
+  }
+
   void addImm0_255Operands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     addExpr(Inst, getImm());
@@ -2883,6 +2915,21 @@ bool ARMAsmParser::shouldOmitCCOutOperand(StringRef Mnemonic,
       static_cast<ARMOperand*>(Operands[4])->isReg() &&
       static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
     return true;
+  // Register-register 'add' for thumb does not have a cc_out operand
+  // when it's an ADD Rdm, SP, {Rdm|#imm} instruction.
+  if (isThumb() && Mnemonic == "add" && Operands.size() == 6 &&
+      static_cast<ARMOperand*>(Operands[3])->isReg() &&
+      static_cast<ARMOperand*>(Operands[4])->isReg() &&
+      static_cast<ARMOperand*>(Operands[4])->getReg() == ARM::SP &&
+      static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
+    return true;
+  // Register-register 'add' for thumb does not have a cc_out operand
+  // when it's an ADD SP, #imm.
+  if (isThumb() && Mnemonic == "add" && Operands.size() == 5 &&
+      static_cast<ARMOperand*>(Operands[3])->isReg() &&
+      static_cast<ARMOperand*>(Operands[3])->getReg() == ARM::SP &&
+      static_cast<ARMOperand*>(Operands[1])->getReg() == 0)
+    return true;
 
   return false;
 }
index 88500d3dc499661f438225765792a5a69d496235..ba02ec2902d1a9b9d0d5809a260b9713cbdc61b6 100644 (file)
@@ -45,11 +45,29 @@ _func:
 
 
 @------------------------------------------------------------------------------
-@ FIXME: ADD (SP plus immediate)
+@ ADD (SP plus immediate)
 @------------------------------------------------------------------------------
+        add sp, #4
+        add sp, #508
+        add sp, sp, #4
+        add r2, sp, #8
+        add r2, sp, #1020
+
+@ CHECK: add   sp, #4                  @ encoding: [0x01,0xb0]
+@ CHECK: add   sp, #508                @ encoding: [0x7f,0xb0]
+@ CHECK: add   sp, #4                  @ encoding: [0x01,0xb0]
+@ CHECK: add   r2, sp, #8              @ encoding: [0x02,0xaa]
+@ CHECK: add   r2, sp, #1020           @ encoding: [0xff,0xaa]
+
+
 @------------------------------------------------------------------------------
-@ FIXME: ADD (SP plus register)
+@ ADD (SP plus register)
 @------------------------------------------------------------------------------
+        add sp, r3
+        add r2, sp, r2
+
+@ CHECK: add   sp, r3                  @ encoding: [0x9d,0x44]
+@ CHECK: add   r2, sp, r2              @ encoding: [0x6a,0x44]
 
 
 @------------------------------------------------------------------------------
index 650e8cecf3096cab6c170d26a682bebf490aa5d1..ea5d115be94dd1dfa87f12deac160cfa7eafda20 100644 (file)
@@ -118,3 +118,22 @@ error: invalid operand for instruction
 @ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled
 @ CHECK-ERRORS:         svc #256
 @ CHECK-ERRORS:         ^
+
+
+@ Out of range immediate for ADD SP instructions
+        add sp, #-1
+        add sp, #3
+        add sp, sp, #512
+        add r2, sp, #1024
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS:         add sp, #-1
+@ CHECK-ERRORS:                 ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS:         add sp, #3
+@ CHECK-ERRORS:                 ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS:         add sp, sp, #512
+@ CHECK-ERRORS:                     ^
+@ CHECK-ERRORS: error: invalid operand for instruction
+@ CHECK-ERRORS:         add r2, sp, #1024
+@ CHECK-ERRORS:                     ^
index 852b9bf125bc5db9bf1926a20bd1e2c35e7c7c82..ce59ff730e98150169c139b9fd59234da6ffffa6 100644 (file)
@@ -603,7 +603,8 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
   IMM("pkh_lsl_amt");
   IMM("pkh_asr_amt");
   IMM("jt2block_operand");
-  IMM("t_imm_s4");
+  IMM("t_imm0_1020s4");
+  IMM("t_imm0_508s4");
   IMM("pclabel");
   IMM("adrlabel");
   IMM("t_adrlabel");