[llvm-commits] [llvm] r125489 - in /llvm/trunk: lib/Target/ARM/ lib/Target/ARM/AsmParser/ lib/Target/ARM/Disassembler/ lib/Target/ARM/InstPrinter/ test/MC/ARM/ test/MC/Disassembler/ARM/ utils/TableGen/

Bruno Cardoso Lopes bruno.cardoso at gmail.com
Mon Feb 14 05:09:44 PST 2011


Author: bruno
Date: Mon Feb 14 07:09:44 2011
New Revision: 125489

URL: http://llvm.org/viewvc/llvm-project?rev=125489&view=rev
Log:
Fix encoding and add parsing support for the arm/thumb CPS instruction:
- Add custom operand matching for imod and iflags.
- Rename SplitMnemonicAndCC to SplitMnemonic since it splits more than CC
  from mnemonic.
- While adding ".w" as an operand, don't change "Head" to avoid passing the
  wrong mnemonic to ParseOperand.
- Add asm parser tests.
- Add disassembler tests just to make sure it can catch all cps versions.


Modified:
    llvm/trunk/lib/Target/ARM/ARMBaseInfo.h
    llvm/trunk/lib/Target/ARM/ARMInstrFormats.td
    llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
    llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
    llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
    llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
    llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
    llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
    llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
    llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
    llvm/trunk/test/MC/ARM/arm_instructions.s
    llvm/trunk/test/MC/ARM/thumb.s
    llvm/trunk/test/MC/ARM/thumb2.s
    llvm/trunk/test/MC/Disassembler/ARM/arm-tests.txt
    llvm/trunk/test/MC/Disassembler/ARM/thumb-tests.txt
    llvm/trunk/utils/TableGen/EDEmitter.cpp

Modified: llvm/trunk/lib/Target/ARM/ARMBaseInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInfo.h?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMBaseInfo.h (original)
+++ llvm/trunk/lib/Target/ARM/ARMBaseInfo.h Mon Feb 14 07:09:44 2011
@@ -97,6 +97,36 @@
   }
 }
 
+namespace ARM_PROC {
+  enum IMod {
+    IE = 2,
+    ID = 3
+  };
+
+  enum IFlags {
+    F = 1,
+    I = 2,
+    A = 4
+  };
+
+  inline static const char *IFlagsToString(unsigned val) {
+    switch (val) {
+    default: llvm_unreachable("Unknown iflags operand");
+    case F: return "f";
+    case I: return "i";
+    case A: return "a";
+    }
+  }
+
+  inline static const char *IModToString(unsigned val) {
+    switch (val) {
+    default: llvm_unreachable("Unknown imod operand");
+    case IE: return "ie";
+    case ID: return "id";
+    }
+  }
+}
+
 namespace ARM_MB {
   // The Memory Barrier Option constants map directly to the 4-bit encoding of
   // the option field for memory barrier operations.

Modified: llvm/trunk/lib/Target/ARM/ARMInstrFormats.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrFormats.td?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrFormats.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrFormats.td Mon Feb 14 07:09:44 2011
@@ -155,6 +155,22 @@
   let ParserMethod = "tryParseMemBarrierOptOperand";
 }
 
+def ProcIFlagsOperand : AsmOperandClass {
+  let Name = "ProcIFlags";
+  let SuperClasses = [];
+  let ParserMethod = "tryParseProcIFlagsOperand";
+}
+
+// ARM imod and iflag operands, used only by the CPS instruction.
+def imod_op : Operand<i32> {
+  let PrintMethod = "printCPSIMod";
+}
+
+def iflags_op : Operand<i32> {
+  let PrintMethod = "printCPSIFlag";
+  let ParserMatchClass = ProcIFlagsOperand;
+}
+
 // ARM Predicate operand. Default to 14 = always (AL). Second part is CC
 // register whose default is 0 (no register).
 def pred : PredicateOperand<OtherVT, (ops i32imm, CCR),

Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Mon Feb 14 07:09:44 2011
@@ -1102,21 +1102,37 @@
   let Inst{7-4} = 0b0111;
 }
 
-// Change Processor State is a system instruction -- for disassembly only.
-// The singleton $opt operand contains the following information:
-// opt{4-0} = mode from Inst{4-0}
-// opt{5} = changemode from Inst{17}
-// opt{8-6} = AIF from Inst{8-6}
-// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
-// FIXME: Integrated assembler will need these split out.
-def CPS : AXI<(outs), (ins cps_opt:$opt), MiscFrm, NoItinerary, "cps$opt",
-              [/* For disassembly only; pattern left blank */]>,
-          Requires<[IsARM]> {
+// Change Processor State is a system instruction -- for disassembly and
+// parsing only.
+// FIXME: Since the asm parser has currently no clean way to handle optional
+// operands, create 3 versions of the same instruction. Once there's a clean
+// framework to represent optional operands, change this behavior.
+class CPS<dag iops, string asm_ops>
+  : AXI<(outs), iops, MiscFrm, NoItinerary, !strconcat("cps", asm_ops),
+        [/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> {
+  bits<2> imod;
+  bits<3> iflags;
+  bits<5> mode;
+  bit M;
+
   let Inst{31-28} = 0b1111;
   let Inst{27-20} = 0b00010000;
-  let Inst{16} = 0;
-  let Inst{5} = 0;
-}
+  let Inst{19-18} = imod;
+  let Inst{17}    = M; // Enabled if mode is set;
+  let Inst{16}    = 0;
+  let Inst{8-6}   = iflags;
+  let Inst{5}     = 0;
+  let Inst{4-0}   = mode;
+}
+
+let M = 1 in
+  def CPS3p : CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode),
+                  "$imod\t$iflags, $mode">;
+let mode = 0, M = 0 in
+  def CPS2p : CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod\t$iflags">;
+
+let imod = 0, iflags = 0, M = 1 in
+  def CPS1p : CPS<(ins i32imm:$mode), "\t$mode">;
 
 // Preload signals the memory system of possible future data/instruction access.
 // These are for disassembly only.

Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb.td?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb.td Mon Feb 14 07:09:44 2011
@@ -266,21 +266,17 @@
 }
 
 // Change Processor State is a system instruction -- for disassembly only.
-// The singleton $opt operand contains the following information:
-// 
-//   opt{4-0} = mode ==> don't care
-//   opt{5} = changemode ==> 0 (false for 16-bit Thumb instr)
-//   opt{8-6} = AIF from Inst{2-0}
-//   opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable
-//
-// The opt{4-0} and opt{5} sub-fields are to accommodate 32-bit Thumb and ARM
-// CPS which has more options.
-def tCPS : T1I<(outs), (ins cps_opt:$opt), NoItinerary, "cps$opt",
-              [/* For disassembly only; pattern left blank */]>,
+def tCPS : T1I<(outs), (ins imod_op:$imod, iflags_op:$iflags),
+                NoItinerary, "cps$imod $iflags",
+                [/* For disassembly only; pattern left blank */]>,
            T1Misc<0b0110011> {
   // A8.6.38 & B6.1.1
-  let Inst{3} = 0;
-  // FIXME: Finish encoding.
+  bit imod;
+  bits<3> iflags;
+
+  let Inst{4}   = imod;
+  let Inst{3}   = 0;
+  let Inst{2-0} = iflags;
 }
 
 // For both thumb1 and thumb2.

Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Mon Feb 14 07:09:44 2011
@@ -3127,41 +3127,40 @@
   let Inst{19-16} = func;
 }
 
-// Change Processor State is a system instruction -- for disassembly only.
-// The singleton $opt operand contains the following information:
-// opt{4-0} = mode from Inst{4-0}
-// opt{5} = changemode from Inst{17}
-// opt{8-6} = AIF from Inst{8-6}
-// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
-def t2CPS : T2XI<(outs),(ins cps_opt:$opt), NoItinerary, "cps$opt",
-                 [/* For disassembly only; pattern left blank */]> {
+// Change Processor State is a system instruction -- for disassembly and
+// parsing only.
+// FIXME: Since the asm parser has currently no clean way to handle optional
+// operands, create 3 versions of the same instruction. Once there's a clean
+// framework to represent optional operands, change this behavior.
+class t2CPS<dag iops, string asm_op> : T2XI<(outs), iops, NoItinerary,
+            !strconcat("cps", asm_op),
+            [/* For disassembly only; pattern left blank */]> {
+  bits<2> imod;
+  bits<3> iflags;
+  bits<5> mode;
+  bit M;
+
   let Inst{31-27} = 0b11110;
-  let Inst{26} = 0;
+  let Inst{26}    = 0;
   let Inst{25-20} = 0b111010;
+  let Inst{19-16} = 0b1111;
   let Inst{15-14} = 0b10;
-  let Inst{12} = 0;
-
-  bits<11> opt;
-
-  // mode number
-  let Inst{4-0} = opt{4-0};
-
-  // M flag
-  let Inst{8} = opt{5};
-
-  // F flag
-  let Inst{5} = opt{6};
-
-  // I flag
-  let Inst{6} = opt{7};
-
-  // A flag
-  let Inst{7} = opt{8};
-
-  // imod flag
-  let Inst{10-9} = opt{10-9};
+  let Inst{12}    = 0;
+  let Inst{10-9}  = imod;
+  let Inst{8}     = M;
+  let Inst{7-5}   = iflags;
+  let Inst{4-0}   = mode;
 }
 
+let M = 1 in
+  def t2CPS3p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode),
+                      "$imod.w\t$iflags, $mode">;
+let mode = 0, M = 0 in
+  def t2CPS2p : t2CPS<(ins imod_op:$imod, iflags_op:$iflags),
+                      "$imod.w\t$iflags">;
+let imod = 0, iflags = 0, M = 1 in
+  def t2CPS1p : t2CPS<(ins i32imm:$mode), "\t$mode">;
+
 // A6.3.4 Branches and miscellaneous control
 // Table A6-14 Change Processor State, and hint instructions
 // Helper class for disassembly only.

Modified: llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Mon Feb 14 07:09:44 2011
@@ -98,6 +98,8 @@
     SmallVectorImpl<MCParsedAsmOperand*>&);
   OperandMatchResultTy tryParseMemBarrierOptOperand(
     SmallVectorImpl<MCParsedAsmOperand*> &);
+  OperandMatchResultTy tryParseProcIFlagsOperand(
+    SmallVectorImpl<MCParsedAsmOperand*> &);
 
 public:
   ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM)
@@ -126,6 +128,7 @@
     Immediate,
     MemBarrierOpt,
     Memory,
+    ProcIFlags,
     Register,
     RegisterList,
     DPRRegisterList,
@@ -150,6 +153,10 @@
     } Cop;
 
     struct {
+      ARM_PROC::IFlags Val;
+    } IFlags;
+
+    struct {
       const char *Data;
       unsigned Length;
     } Tok;
@@ -215,6 +222,8 @@
     case Memory:
       Mem = o.Mem;
       break;
+    case ProcIFlags:
+      IFlags = o.IFlags;
     }
   }
 
@@ -259,6 +268,11 @@
     return MBOpt.Val;
   }
 
+  ARM_PROC::IFlags getProcIFlags() const {
+    assert(Kind == ProcIFlags && "Invalid access!");
+    return IFlags.Val;
+  }
+
   /// @name Memory Operand Accessors
   /// @{
 
@@ -333,6 +347,7 @@
     uint64_t Value = CE->getValue();
     return ((Value & 0x3) == 0 && Value <= 124);
   }
+  bool isProcIFlags() const { return Kind == ProcIFlags; }
 
   void addExpr(MCInst &Inst, const MCExpr *Expr) const {
     // Add as immediates when possible.  Null MCExpr = 0.
@@ -433,6 +448,11 @@
     Inst.addOperand(MCOperand::CreateImm(CE->getValue()));
   }
 
+  void addProcIFlagsOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    Inst.addOperand(MCOperand::CreateImm(unsigned(getProcIFlags())));
+  }
+
   virtual void dump(raw_ostream &OS) const;
 
   static ARMOperand *CreateCondCode(ARMCC::CondCodes CC, SMLoc S) {
@@ -556,6 +576,14 @@
     Op->EndLoc = S;
     return Op;
   }
+
+  static ARMOperand *CreateProcIFlags(ARM_PROC::IFlags IFlags, SMLoc S) {
+    ARMOperand *Op = new ARMOperand(ProcIFlags);
+    Op->IFlags.Val = IFlags;
+    Op->StartLoc = S;
+    Op->EndLoc = S;
+    return Op;
+  }
 };
 
 } // end anonymous namespace.
@@ -604,6 +632,15 @@
       OS << " (writeback)";
     OS << ">";
     break;
+  case ProcIFlags: {
+    OS << "<ARM_PROC::";
+    unsigned IFlags = getProcIFlags();
+    for (int i=2; i >= 0; --i)
+      if (IFlags & (1 << i))
+        OS << ARM_PROC::IFlagsToString(1 << i);
+    OS << ">";
+    break;
+  }
   case Register:
     OS << "<register " << getReg() << ">";
     break;
@@ -885,6 +922,35 @@
   return MatchOperand_Success;
 }
 
+/// ParseProcIFlagsOperand - Try to parse iflags from CPS instruction.
+ARMAsmParser::OperandMatchResultTy ARMAsmParser::
+tryParseProcIFlagsOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+  SMLoc S = Parser.getTok().getLoc();
+  const AsmToken &Tok = Parser.getTok();
+  assert(Tok.is(AsmToken::Identifier) && "Token is not an Identifier");
+  StringRef IFlagsStr = Tok.getString();
+
+  unsigned IFlags = 0;
+  for (int i = 0, e = IFlagsStr.size(); i != e; ++i) {
+    unsigned Flag = StringSwitch<unsigned>(IFlagsStr.substr(i, 1))
+    .Case("a", ARM_PROC::A)
+    .Case("i", ARM_PROC::I)
+    .Case("f", ARM_PROC::F)
+    .Default(~0U);
+
+    // If some specific iflag is already set, it means that some letter is
+    // present more than once, this is not acceptable.
+    if (Flag == ~0U || (IFlags & Flag))
+      return MatchOperand_NoMatch;
+
+    IFlags |= Flag;
+  }
+
+  Parser.Lex(); // Eat identifier token.
+  Operands.push_back(ARMOperand::CreateProcIFlags((ARM_PROC::IFlags)IFlags, S));
+  return MatchOperand_Success;
+}
+
 /// Parse an ARM memory expression, return false if successful else return true
 /// or an error.  The first token must be a '[' when called.
 ///
@@ -1254,11 +1320,13 @@
 /// setting letters to form a canonical mnemonic and flags.
 //
 // FIXME: Would be nice to autogen this.
-static StringRef SplitMnemonicAndCC(StringRef Mnemonic,
-                                    unsigned &PredicationCode,
-                                    bool &CarrySetting) {
+static StringRef SplitMnemonic(StringRef Mnemonic,
+                               unsigned &PredicationCode,
+                               bool &CarrySetting,
+                               unsigned &ProcessorIMod) {
   PredicationCode = ARMCC::AL;
   CarrySetting = false;
+  ProcessorIMod = 0;
 
   // Ignore some mnemonics we know aren't predicated forms.
   //
@@ -1312,6 +1380,21 @@
     CarrySetting = true;
   }
 
+  // The "cps" instruction can have a interrupt mode operand which is glued into
+  // the mnemonic. Check if this is the case, split it and parse the imod op
+  if (Mnemonic.startswith("cps")) {
+    // Split out any imod code.
+    unsigned IMod =
+      StringSwitch<unsigned>(Mnemonic.substr(Mnemonic.size()-2, 2))
+      .Case("ie", ARM_PROC::IE)
+      .Case("id", ARM_PROC::ID)
+      .Default(~0U);
+    if (IMod != ~0U) {
+      Mnemonic = Mnemonic.slice(0, Mnemonic.size()-2);
+      ProcessorIMod = IMod;
+    }
+  }
+
   return Mnemonic;
 }
 
@@ -1342,7 +1425,7 @@
       Mnemonic == "mcrr2" || Mnemonic == "cbz" || Mnemonic == "cdp2" ||
       Mnemonic == "trap" || Mnemonic == "mrc2" || Mnemonic == "mrrc2" ||
       Mnemonic == "dsb" || Mnemonic == "movs" || Mnemonic == "isb" ||
-      Mnemonic == "clrex") {
+      Mnemonic == "clrex" || Mnemonic.startswith("cps")) {
     CanAcceptPredicationCode = false;
   } else {
     CanAcceptPredicationCode = true;
@@ -1363,8 +1446,10 @@
 
   // Split out the predication code and carry setting flag from the mnemonic.
   unsigned PredicationCode;
+  unsigned ProcessorIMod;
   bool CarrySetting;
-  Head = SplitMnemonicAndCC(Head, PredicationCode, CarrySetting);
+  Head = SplitMnemonic(Head, PredicationCode, CarrySetting,
+                       ProcessorIMod);
 
   Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
 
@@ -1404,13 +1489,25 @@
     // FIXME: Issue a nice error.
   }
 
+  // Add the processor imod operand, if necessary.
+  if (ProcessorIMod) {
+    Operands.push_back(ARMOperand::CreateImm(
+          MCConstantExpr::Create(ProcessorIMod, getContext()),
+                                 NameLoc, NameLoc));
+  } else {
+    // This mnemonic can't ever accept a imod, but the user wrote
+    // one (or misspelled another mnemonic).
+
+    // FIXME: Issue a nice error.
+  }
+
   // Add the remaining tokens in the mnemonic.
   while (Next != StringRef::npos) {
     Start = Next;
     Next = Name.find('.', Start + 1);
-    Head = Name.slice(Start, Next);
+    StringRef ExtraToken = Name.slice(Start, Next);
 
-    Operands.push_back(ARMOperand::CreateToken(Head, NameLoc));
+    Operands.push_back(ARMOperand::CreateToken(ExtraToken, NameLoc));
   }
 
   // Read the remaining operands.

Modified: llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp (original)
+++ llvm/trunk/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp Mon Feb 14 07:09:44 2011
@@ -2942,15 +2942,25 @@
     return true;
   }
 
-  // CPS has a singleton $opt operand that contains the following information:
-  // opt{4-0} = mode from Inst{4-0}
-  // opt{5} = changemode from Inst{17}
-  // opt{8-6} = AIF from Inst{8-6}
-  // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
-  if (Opcode == ARM::CPS) {
-    unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 |
-      slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9;
-    MI.addOperand(MCOperand::CreateImm(Option));
+  // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
+  // opcodes which match the same real instruction. This is needed since there's
+  // no current handling of optional arguments. Fix here when a better handling
+  // of optional arguments is implemented.
+  if (Opcode == ARM::CPS3p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6)));   // iflags
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));   // mode
+    NumOpsAdded = 3;
+    return true;
+  }
+  if (Opcode == ARM::CPS2p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6)));   // iflags
+    NumOpsAdded = 2;
+    return true;
+  }
+  if (Opcode == ARM::CPS1p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
     NumOpsAdded = 1;
     return true;
   }

Modified: llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h (original)
+++ llvm/trunk/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h Mon Feb 14 07:09:44 2011
@@ -828,14 +828,13 @@
   }
 
   // CPS has a singleton $opt operand that contains the following information:
-  // opt{4-0} = don't care
-  // opt{5} = 0 (false)
-  // opt{8-6} = AIF from Inst{2-0}
-  // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable
+  // The first op would be 0b10 as enable and 0b11 as disable in regular ARM,
+  // but in Thumb it's is 0 as enable and 1 as disable. So map it to ARM's
+  // default one. The second get the AIF flags from Inst{2-0}.
   if (Opcode == ARM::tCPS) {
-    unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10;
-    MI.addOperand(MCOperand::CreateImm(Option));
-    NumOpsAdded = 1;
+    MI.addOperand(MCOperand::CreateImm(2 + slice(insn, 4, 4)));
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 2, 0)));
+    NumOpsAdded = 2;
     return true;
   }
 
@@ -1659,15 +1658,25 @@
     break;
   }
 
-  // CPS has a singleton $opt operand that contains the following information:
-  // opt{4-0} = mode from Inst{4-0}
-  // opt{5} = changemode from Inst{8}
-  // opt{8-6} = AIF from Inst{7-5}
-  // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable
-  if (Opcode == ARM::t2CPS) {
-    unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 |
-      slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9;
-    MI.addOperand(MCOperand::CreateImm(Option));
+  // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different
+  // opcodes which match the same real instruction. This is needed since there's
+  // no current handling of optional arguments. Fix here when a better handling
+  // of optional arguments is implemented.
+  if (Opcode == ARM::t2CPS3p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5)));  // iflags
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0)));  // mode
+    NumOpsAdded = 3;
+    return true;
+  }
+  if (Opcode == ARM::t2CPS2p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5)));  // iflags
+    NumOpsAdded = 2;
+    return true;
+  }
+  if (Opcode == ARM::t2CPS1p) {
+    MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode
     NumOpsAdded = 1;
     return true;
   }

Modified: llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp (original)
+++ llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp Mon Feb 14 07:09:44 2011
@@ -379,27 +379,19 @@
     O << "le";
 }
 
-void ARMInstPrinter::printCPSOptionOperand(const MCInst *MI, unsigned OpNum,
-                                           raw_ostream &O) {
+void ARMInstPrinter::printCPSIMod(const MCInst *MI, unsigned OpNum,
+                                  raw_ostream &O) {
   const MCOperand &Op = MI->getOperand(OpNum);
-  unsigned option = Op.getImm();
-  unsigned mode = option & 31;
-  bool changemode = option >> 5 & 1;
-  unsigned AIF = option >> 6 & 7;
-  unsigned imod = option >> 9 & 3;
-  if (imod == 2)
-    O << "ie";
-  else if (imod == 3)
-    O << "id";
-  O << '\t';
-  if (imod > 1) {
-    if (AIF & 4) O << 'a';
-    if (AIF & 2) O << 'i';
-    if (AIF & 1) O << 'f';
-    if (AIF > 0 && changemode) O << ", ";
-  }
-  if (changemode)
-    O << '#' << mode;
+  O << ARM_PROC::IModToString(Op.getImm());
+}
+
+void ARMInstPrinter::printCPSIFlag(const MCInst *MI, unsigned OpNum,
+                                   raw_ostream &O) {
+  const MCOperand &Op = MI->getOperand(OpNum);
+  unsigned IFlags = Op.getImm();
+  for (int i=2; i >= 0; --i)
+    if (IFlags & (1 << i))
+      O << ARM_PROC::IFlagsToString(1 << i);
 }
 
 void ARMInstPrinter::printMSRMaskOperand(const MCInst *MI, unsigned OpNum,

Modified: llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.h?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.h (original)
+++ llvm/trunk/lib/Target/ARM/InstPrinter/ARMInstPrinter.h Mon Feb 14 07:09:44 2011
@@ -85,6 +85,8 @@
                                    raw_ostream &O);
 
   void printSetendOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
+  void printCPSIMod(const MCInst *MI, unsigned OpNum, raw_ostream &O);
+  void printCPSIFlag(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printCPSOptionOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printMSRMaskOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);
   void printNegZeroOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O);

Modified: llvm/trunk/test/MC/ARM/arm_instructions.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/arm_instructions.s?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/arm_instructions.s (original)
+++ llvm/trunk/test/MC/ARM/arm_instructions.s Mon Feb 14 07:09:44 2011
@@ -237,3 +237,12 @@
 @ CHECK: dsb  oshst @ encoding: [0x42,0xf0,0x7f,0xf5]
         dsb  oshst
 
+@ CHECK: cpsie  aif @ encoding: [0xc0,0x01,0x08,0xf1]
+        cpsie  aif
+
+@ CHECK: cps  #15 @ encoding: [0x0f,0x00,0x02,0xf1]
+        cps  #15
+
+@ CHECK: cpsie  if, #10 @ encoding: [0xca,0x00,0x0a,0xf1]
+        cpsie  if, #10
+

Modified: llvm/trunk/test/MC/ARM/thumb.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/thumb.s?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/thumb.s (original)
+++ llvm/trunk/test/MC/ARM/thumb.s Mon Feb 14 07:09:44 2011
@@ -65,3 +65,6 @@
 
 @ CHECK: wfi @ encoding: [0x30,0xbf]
         wfi
+
+@ CHECK: cpsie aif @ encoding: [0x67,0xb6]
+        cpsie aif

Modified: llvm/trunk/test/MC/ARM/thumb2.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/thumb2.s?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/test/MC/ARM/thumb2.s (original)
+++ llvm/trunk/test/MC/ARM/thumb2.s Mon Feb 14 07:09:44 2011
@@ -252,3 +252,10 @@
 @ CHECK: dsb  oshst @ encoding: [0xbf,0xf3,0x42,0x8f]
   dsb  oshst
 
+@ CHECK: cpsie.w  aif @ encoding: [0xaf,0xf3,0xe0,0x84]
+  cpsie.w  aif
+@ CHECK: cps  #15 @ encoding: [0xaf,0xf3,0x0f,0x81]
+  cps  #15
+@ CHECK: cpsie.w  if, #10 @ encoding: [0xaf,0xf3,0x6a,0x85]
+  cpsie.w  if, #10
+

Modified: llvm/trunk/test/MC/Disassembler/ARM/arm-tests.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Disassembler/ARM/arm-tests.txt?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/test/MC/Disassembler/ARM/arm-tests.txt (original)
+++ llvm/trunk/test/MC/Disassembler/ARM/arm-tests.txt Mon Feb 14 07:09:44 2011
@@ -118,3 +118,12 @@
 
 # CHECK:        setend le
 0x00 0x00 0x01 0xf1
+
+# CHECK: cpsie  aif
+0xc0 0x01 0x08 0xf1
+
+# CHECK: cps  #15
+0x0f 0x00 0x02 0xf1
+
+# CHECK: cpsie if, #10
+0xca 0x00 0x0a 0xf1

Modified: llvm/trunk/test/MC/Disassembler/ARM/thumb-tests.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Disassembler/ARM/thumb-tests.txt?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/test/MC/Disassembler/ARM/thumb-tests.txt (original)
+++ llvm/trunk/test/MC/Disassembler/ARM/thumb-tests.txt Mon Feb 14 07:09:44 2011
@@ -103,3 +103,15 @@
 # IT block end
 # CHECK:	rsbs	r1, r2, #0
 0x51 0x42
+
+# CHECK: cpsid.w  f
+0xaf 0xf3 0x20 0x86
+
+# CHECK: cps  #15
+0xaf 0xf3 0x0f 0x81
+
+# CHECK: cpsie.w  if, #10
+0xaf 0xf3 0x6a 0x85
+
+# CHECK: cpsie aif
+0x67 0xb6

Modified: llvm/trunk/utils/TableGen/EDEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/EDEmitter.cpp?rev=125489&r1=125488&r2=125489&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/EDEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/EDEmitter.cpp Mon Feb 14 07:09:44 2011
@@ -576,6 +576,8 @@
   IMM("nohash_imm");
   IMM("p_imm");
   IMM("c_imm");
+  IMM("imod_op");
+  IMM("iflags_op");
   IMM("cpinst_operand");
   IMM("setend_op");
   IMM("cps_opt");





More information about the llvm-commits mailing list