ARM parsing and encoding for the <option> form of LDC/STC instructions.
authorJim Grosbach <grosbach@apple.com>
Wed, 12 Oct 2011 17:34:41 +0000 (17:34 +0000)
committerJim Grosbach <grosbach@apple.com>
Wed, 12 Oct 2011 17:34:41 +0000 (17:34 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@141786 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrInfo.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
lib/Target/ARM/InstPrinter/ARMInstPrinter.h
test/MC/ARM/basic-arm-instructions.s
test/MC/ARM/diagnostics.s
utils/TableGen/EDEmitter.cpp

index d43da911e228b6451d4b23183a768d664a99956c..2cf0f09ffc64e91ccee3e344abbe5e5fe1e4ab7a 100644 (file)
@@ -842,6 +842,14 @@ def c_imm : Operand<i32> {
   let PrintMethod = "printCImmediate";
   let ParserMatchClass = CoprocRegAsmOperand;
 }
+def CoprocOptionAsmOperand : AsmOperandClass {
+  let Name = "CoprocOption";
+  let ParserMethod = "parseCoprocOptionOperand";
+}
+def coproc_option_imm : Operand<i32> {
+  let PrintMethod = "printCoprocOptionImm";
+  let ParserMatchClass = CoprocOptionAsmOperand;
+}
 
 //===----------------------------------------------------------------------===//
 
@@ -4312,8 +4320,8 @@ multiclass LdStCop<bit load, bit Dbit, string asm> {
   }
   def _OPTION : ACI<(outs),
                     (ins p_imm:$cop, c_imm:$CRd, addr_offset_none:$addr,
-                         nohash_imm:$option),
-      asm, "\t$cop, $CRd, $addr, \\{$option\\}"> {
+                         coproc_option_imm:$option),
+      asm, "\t$cop, $CRd, $addr, $option"> {
     bits<8> option;
     bits<4> addr;
     bits<4> cop;
@@ -4383,8 +4391,8 @@ multiclass LdSt2Cop<bit load, bit Dbit, string asm> {
   }
   def _OPTION : ACInoP<(outs),
                        (ins p_imm:$cop, c_imm:$CRd, addr_offset_none:$addr,
-                            nohash_imm:$option),
-      asm, "\t$cop, $CRd, $addr, \\{$option\\}"> {
+                            coproc_option_imm:$option),
+      asm, "\t$cop, $CRd, $addr, $option"> {
     bits<8> option;
     bits<4> addr;
     bits<4> cop;
index afb6e5684dd796e2f648497c8c057ec413754ee2..3ce086a04919acf12672f633f9998c7cc27afc1d 100644 (file)
@@ -138,6 +138,8 @@ class ARMAsmParser : public MCTargetAsmParser {
     SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy parseCoprocRegOperand(
     SmallVectorImpl<MCParsedAsmOperand*>&);
+  OperandMatchResultTy parseCoprocOptionOperand(
+    SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy parseMemBarrierOptOperand(
     SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy parseProcIFlagsOperand(
@@ -247,6 +249,7 @@ class ARMOperand : public MCParsedAsmOperand {
     k_ITCondMask,
     k_CoprocNum,
     k_CoprocReg,
+    k_CoprocOption,
     k_Immediate,
     k_FPImmediate,
     k_MemBarrierOpt,
@@ -279,6 +282,10 @@ class ARMOperand : public MCParsedAsmOperand {
       unsigned Val;
     } Cop;
 
+    struct {
+      unsigned Val;
+    } CoprocOption;
+
     struct {
       unsigned Mask:4;
     } ITMask;
@@ -390,6 +397,9 @@ public:
     case k_CoprocReg:
       Cop = o.Cop;
       break;
+    case k_CoprocOption:
+      CoprocOption = o.CoprocOption;
+      break;
     case k_Immediate:
       Imm = o.Imm;
       break;
@@ -495,6 +505,7 @@ public:
 
   bool isCoprocNum() const { return Kind == k_CoprocNum; }
   bool isCoprocReg() const { return Kind == k_CoprocReg; }
+  bool isCoprocOption() const { return Kind == k_CoprocOption; }
   bool isCondCode() const { return Kind == k_CondCode; }
   bool isCCOut() const { return Kind == k_CCOut; }
   bool isITMask() const { return Kind == k_ITCondMask; }
@@ -924,6 +935,16 @@ public:
     Inst.addOperand(MCOperand::CreateImm(getCoproc()));
   }
 
+  void addCoprocRegOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::CreateImm(getCoproc()));
+  }
+
+  void addCoprocOptionOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::CreateImm(CoprocOption.Val));
+  }
+
   void addITMaskOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::CreateImm(ITMask.Mask));
@@ -934,11 +955,6 @@ public:
     Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode())));
   }
 
-  void addCoprocRegOperands(MCInst &Inst, unsigned N) const {
-    assert(N == 1 && "Invalid number of operands!");
-    Inst.addOperand(MCOperand::CreateImm(getCoproc()));
-  }
-
   void addCCOutOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::CreateReg(getReg()));
@@ -1453,6 +1469,14 @@ public:
     return Op;
   }
 
+  static ARMOperand *CreateCoprocOption(unsigned Val, SMLoc S, SMLoc E) {
+    ARMOperand *Op = new ARMOperand(k_CoprocOption);
+    Op->Cop.Val = Val;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
   static ARMOperand *CreateCCOut(unsigned RegNum, SMLoc S) {
     ARMOperand *Op = new ARMOperand(k_CCOut);
     Op->Reg.RegNum = RegNum;
@@ -1668,6 +1692,9 @@ void ARMOperand::print(raw_ostream &OS) const {
   case k_CoprocReg:
     OS << "<coprocessor register: " << getCoproc() << ">";
     break;
+  case k_CoprocOption:
+    OS << "<coprocessor option: " << CoprocOption.Val << ">";
+    break;
   case k_MSRMask:
     OS << "<mask: " << getMSRMask() << ">";
     break;
@@ -2088,6 +2115,40 @@ parseCoprocRegOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
   return MatchOperand_Success;
 }
 
+/// parseCoprocOptionOperand - Try to parse an coprocessor option operand.
+/// coproc_option : '{' imm0_255 '}'
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+parseCoprocOptionOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+  SMLoc S = Parser.getTok().getLoc();
+
+  // If this isn't a '{', this isn't a coprocessor immediate operand.
+  if (Parser.getTok().isNot(AsmToken::LCurly))
+    return MatchOperand_NoMatch;
+  Parser.Lex(); // Eat the '{'
+
+  const MCExpr *Expr;
+  SMLoc Loc = Parser.getTok().getLoc();
+  if (getParser().ParseExpression(Expr)) {
+    Error(Loc, "illegal expression");
+    return MatchOperand_ParseFail;
+  }
+  const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr);
+  if (!CE || CE->getValue() < 0 || CE->getValue() > 255) {
+    Error(Loc, "coprocessor option must be an immediate in range [0, 255]");
+    return MatchOperand_ParseFail;
+  }
+  int Val = CE->getValue();
+
+  // Check for and consume the closing '}'
+  if (Parser.getTok().isNot(AsmToken::RCurly))
+    return MatchOperand_ParseFail;
+  SMLoc E = Parser.getTok().getLoc();
+  Parser.Lex(); // Eat the '}'
+
+  Operands.push_back(ARMOperand::CreateCoprocOption(Val, S, E));
+  return MatchOperand_Success;
+}
+
 // For register list parsing, we need to map from raw GPR register numbering
 // to the enumeration values. The enumeration values aren't sorted by
 // register number due to our using "sp", "lr" and "pc" as canonical names.
index 81608922842f757811612ec9923b9640be83593b..ccdac3ebeb471f553e8d5173b45827abf638dbc5 100644 (file)
@@ -719,6 +719,11 @@ void ARMInstPrinter::printCImmediate(const MCInst *MI, unsigned OpNum,
   O << "c" << MI->getOperand(OpNum).getImm();
 }
 
+void ARMInstPrinter::printCoprocOptionImm(const MCInst *MI, unsigned OpNum,
+                                          raw_ostream &O) {
+  O << "{" << MI->getOperand(OpNum).getImm() << "}";
+}
+
 void ARMInstPrinter::printPCLabel(const MCInst *MI, unsigned OpNum,
                                   raw_ostream &O) {
   llvm_unreachable("Unhandled PC-relative pseudo-instruction!");
index 61b26e67924c95afdc4ae8042016f215ed4dd4f0..5c2173fcde6265485a1e6cc15e7b615c8d8d741a 100644 (file)
@@ -120,6 +120,7 @@ public:
   void printNoHashImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printPImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printCImmediate(const MCInst *MI, unsigned OpNum, raw_ostream &O);
+  void printCoprocOptionImm(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printFPImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printNEONModImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printImmPlusOneOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
index 04054e95c0ef589d93ed38b22c609e14aa2ac365..8b4c0536c9518c33effc0caab02fc04a9d9afc1f 100644 (file)
@@ -684,6 +684,8 @@ Lforward:
         ldcleq p6, c14, [r10], #16
         ldclhi p7, c15, [r11], #-72
 
+        ldc2 p2, c8, [r1], { 25 }
+
 @ CHECK: ldc2  p0, c8, [r1, #4]        @ encoding: [0x01,0x80,0x91,0xfd]
 @ CHECK: ldc2  p1, c7, [r2]            @ encoding: [0x00,0x71,0x92,0xfd]
 @ CHECK: ldc2  p2, c6, [r3, #-224]     @ encoding: [0x38,0x62,0x13,0xfd]
@@ -723,6 +725,8 @@ Lforward:
 @ CHECK: ldcleq        p6, c14, [r10], #16     @ encoding: [0x04,0xe6,0xfa,0x0c]
 @ CHECK: ldclhi        p7, c15, [r11], #-72    @ encoding: [0x12,0xf7,0x7b,0x8c]
 
+@ CHECK: ldc2  p2, c8, [r1], {25}      @ encoding: [0x19,0x82,0x91,0xfc]
+
 
 @------------------------------------------------------------------------------
 @ LDM*
index 41dde080522d7a73400ff07c22ff3b30ff5e8554..f722dd7c070ebf281298e3f6c7c6ef8f3d3fa3a7 100644 (file)
 @ CHECK-ERRORS:         vpush {s0, s3}
 @ CHECK-ERRORS:                    ^
 
+        @ Out of range coprocessor option immediate.
+        ldc2 p2, c8, [r1], { 256 }
+        ldc2 p2, c8, [r1], { -1 }
+
+@ CHECK-ERRORS: error: coprocessor option must be an immediate in range [0, 255]
+@ CHECK-ERRORS:         ldc2 p2, c8, [r1], { 256 }
+@ CHECK-ERRORS:                              ^
+@ CHECK-ERRORS: error: coprocessor option must be an immediate in range [0, 255]
+@ CHECK-ERRORS:         ldc2 p2, c8, [r1], { -1 }
+@ CHECK-ERRORS:                              ^
index a38f0066d989dd610243901073d077b0bf096ecd..abef70e31897b2aba2d9e9e5fe84b6a2b3387bc3 100644 (file)
@@ -581,6 +581,7 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type,
   IMM("nohash_imm");
   IMM("p_imm");
   IMM("c_imm");
+  IMM("coproc_option_imm");
   IMM("imod_op");
   IMM("iflags_op");
   IMM("cpinst_operand");