[llvm-commits] [llvm] r138773 - in /llvm/trunk: include/llvm/MC/MCInstrDesc.h lib/CodeGen/MachineInstr.cpp lib/Target/ARM/AsmParser/ARMAsmParser.cpp test/MC/ARM/basic-thumb2-instructions.s test/MC/ARM/thumb2-diagnostics.s

Jim Grosbach grosbach at apple.com
Mon Aug 29 15:24:09 PDT 2011


Author: grosbach
Date: Mon Aug 29 17:24:09 2011
New Revision: 138773

URL: http://llvm.org/viewvc/llvm-project?rev=138773&view=rev
Log:
Thumb2 parsing and encoding for IT blocks.

Added:
    llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s
    llvm/trunk/test/MC/ARM/thumb2-diagnostics.s
Modified:
    llvm/trunk/include/llvm/MC/MCInstrDesc.h
    llvm/trunk/lib/CodeGen/MachineInstr.cpp
    llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Modified: llvm/trunk/include/llvm/MC/MCInstrDesc.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCInstrDesc.h?rev=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCInstrDesc.h (original)
+++ llvm/trunk/include/llvm/MC/MCInstrDesc.h Mon Aug 29 17:24:09 2011
@@ -289,6 +289,18 @@
     return Flags & (1 << MCID::Barrier);
   }
 
+  /// findFirstPredOperandIdx() - Find the index of the first operand in the
+  /// operand list that is used to represent the predicate. It returns -1 if
+  /// none is found.
+  int findFirstPredOperandIdx() const {
+    if (isPredicable()) {
+      for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
+        if (OpInfo[i].isPredicate())
+          return i;
+    }
+    return -1;
+  }
+
   /// isTerminator - Returns true if this instruction part of the terminator for
   /// a basic block.  Typically this is things like return and branch
   /// instructions.

Modified: llvm/trunk/lib/CodeGen/MachineInstr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineInstr.cpp?rev=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/MachineInstr.cpp (original)
+++ llvm/trunk/lib/CodeGen/MachineInstr.cpp Mon Aug 29 17:24:09 2011
@@ -942,6 +942,10 @@
 /// operand list that is used to represent the predicate. It returns -1 if
 /// none is found.
 int MachineInstr::findFirstPredOperandIdx() const {
+  // Don't call MCID.findFirstPredOperandIdx() because this variant
+  // is sometimes called on an instruction that's not yet complete, and
+  // so the number of operands is less than the MCID indicates. In
+  // particular, the PTX target does this.
   const MCInstrDesc &MCID = getDesc();
   if (MCID.isPredicable()) {
     for (unsigned i = 0, e = getNumOperands(); i != e; ++i)

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=138773&r1=138772&r2=138773&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Mon Aug 29 17:24:09 2011
@@ -44,6 +44,28 @@
   MCSubtargetInfo &STI;
   MCAsmParser &Parser;
 
+  struct {
+    ARMCC::CondCodes Cond;    // Condition for IT block.
+    unsigned Mask:4;          // Condition mask for instructions.
+                              // Starting at first 1 (from lsb).
+                              //   '1'  condition as indicated in IT.
+                              //   '0'  inverse of condition (else).
+                              // Count of instructions in IT block is
+                              // 4 - trailingzeroes(mask)
+
+    bool FirstCond;           // Explicit flag for when we're parsing the
+                              // First instruction in the IT block. It's
+                              // implied in the mask, so needs special
+                              // handling.
+
+    unsigned CurPosition;     // Current position in parsing of IT
+                              // block. In range [0,3]. Initialized
+                              // according to count of instructions in block.
+                              // ~0U if no active IT block.
+  } ITState;
+  bool inITBlock() { return ITState.CurPosition != ~0U;}
+
+
   MCAsmParser &getParser() const { return Parser; }
   MCAsmLexer &getLexer() const { return Parser.getLexer(); }
 
@@ -165,6 +187,7 @@
 public:
   enum ARMMatchResultTy {
     Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY,
+    Match_RequiresNotITBlock,
     Match_RequiresV6,
     Match_RequiresThumb2
   };
@@ -175,6 +198,9 @@
 
     // Initialize the set of available features.
     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+
+    // Not in an ITBlock to start with.
+    ITState.CurPosition = ~0U;
   }
 
   // Implementation of the MCTargetAsmParser interface:
@@ -3085,18 +3111,23 @@
   // where the conditional bit0 is zero, the instruction post-processing
   // will adjust the mask accordingly.
   if (Mnemonic == "it") {
+    SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + 2);
+    if (ITMask.size() > 3) {
+      Parser.EatToEndOfStatement();
+      return Error(Loc, "too many conditions on IT instruction");
+    }
     unsigned Mask = 8;
     for (unsigned i = ITMask.size(); i != 0; --i) {
       char pos = ITMask[i - 1];
       if (pos != 't' && pos != 'e') {
         Parser.EatToEndOfStatement();
-        return Error(NameLoc, "illegal IT instruction mask '" + ITMask + "'");
+        return Error(Loc, "illegal IT block condition mask '" + ITMask + "'");
       }
       Mask >>= 1;
       if (ITMask[i - 1] == 't')
         Mask |= 8;
     }
-    Operands.push_back(ARMOperand::CreateITMask(Mask, NameLoc));
+    Operands.push_back(ARMOperand::CreateITMask(Mask, Loc));
   }
 
   // FIXME: This is all a pretty gross hack. We should automatically handle
@@ -3128,18 +3159,18 @@
   }
 
   // Add the carry setting operand, if necessary.
-  //
-  // FIXME: It would be awesome if we could somehow invent a location such that
-  // match errors on this operand would print a nice diagnostic about how the
-  // 's' character in the mnemonic resulted in a CCOut operand.
-  if (CanAcceptCarrySet)
+  if (CanAcceptCarrySet) {
+    SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size());
     Operands.push_back(ARMOperand::CreateCCOut(CarrySetting ? ARM::CPSR : 0,
-                                               NameLoc));
+                                               Loc));
+  }
 
   // Add the predication code operand, if necessary.
   if (CanAcceptPredicationCode) {
+    SMLoc Loc = SMLoc::getFromPointer(NameLoc.getPointer() + Mnemonic.size() +
+                                      CarrySetting);
     Operands.push_back(ARMOperand::CreateCondCode(
-                         ARMCC::CondCodes(PredicationCode), NameLoc));
+                         ARMCC::CondCodes(PredicationCode), Loc));
   }
 
   // Add the processor imod operand, if necessary.
@@ -3261,10 +3292,57 @@
   return false;
 }
 
+// FIXME: We would really prefer to have MCInstrInfo (the wrapper around
+// the ARMInsts array) instead. Getting that here requires awkward
+// API changes, though. Better way?
+namespace llvm {
+extern MCInstrDesc ARMInsts[];
+}
+static MCInstrDesc &getInstDesc(unsigned Opcode) {
+  return ARMInsts[Opcode];
+}
+
 // FIXME: We would really like to be able to tablegen'erate this.
 bool ARMAsmParser::
 validateInstruction(MCInst &Inst,
                     const SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
+  MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+  SMLoc Loc = Operands[0]->getStartLoc();
+  // Check the IT block state first.
+  if (inITBlock()) {
+    unsigned bit = 1;
+    if (ITState.FirstCond)
+      ITState.FirstCond = false;
+    else
+      bit = (ITState.Mask >> (4 - ITState.CurPosition)) & 1;
+    // Increment our position in the IT block first thing, as we want to
+    // move forward even if we find an error in the IT block.
+    unsigned TZ = CountTrailingZeros_32(ITState.Mask);
+    if (++ITState.CurPosition == 4 - TZ)
+      ITState.CurPosition = ~0U; // Done with the IT block after this.
+    // The instruction must be predicable.
+    if (!MCID.isPredicable())
+      return Error(Loc, "instructions in IT block must be predicable");
+    unsigned Cond = Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm();
+    unsigned ITCond = bit ? ITState.Cond :
+      ARMCC::getOppositeCondition(ITState.Cond);
+    if (Cond != ITCond) {
+      // Find the condition code Operand to get its SMLoc information.
+      SMLoc CondLoc;
+      for (unsigned i = 1; i < Operands.size(); ++i)
+        if (static_cast<ARMOperand*>(Operands[i])->isCondCode())
+          CondLoc = Operands[i]->getStartLoc();
+      return Error(CondLoc, "incorrect condition in IT block; got '" +
+                   StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
+                   "', but expected '" +
+                   ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
+    }
+    // Check for non-'al' condition codes outside of the IT block.
+  } else if (isThumbTwo() && MCID.isPredicable() &&
+             Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
+             ARMCC::AL)
+    return Error(Loc, "predicated instructions must be in IT block");
+
   switch (Inst.getOpcode()) {
   case ARM::LDRD:
   case ARM::LDRD_PRE:
@@ -3413,29 +3491,28 @@
     // so mask that in if needed
     MCOperand &MO = Inst.getOperand(1);
     unsigned Mask = MO.getImm();
+    unsigned OrigMask = Mask;
+    unsigned TZ = CountTrailingZeros_32(Mask);
     if ((Inst.getOperand(0).getImm() & 1) == 0) {
-      unsigned TZ = CountTrailingZeros_32(Mask);
       assert(Mask && TZ <= 3 && "illegal IT mask value!");
       for (unsigned i = 3; i != TZ; --i)
         Mask ^= 1 << i;
     } else
       Mask |= 0x10;
     MO.setImm(Mask);
+
+    // Set up the IT block state according to the IT instruction we just
+    // matched.
+    assert(!inITBlock() && "nested IT blocks?!");
+    ITState.Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
+    ITState.Mask = OrigMask; // Use the original mask, not the updated one.
+    ITState.CurPosition = 0;
+    ITState.FirstCond = true;
     break;
   }
   }
 }
 
-// FIXME: We would really prefer to have MCInstrInfo (the wrapper around
-// the ARMInsts array) instead. Getting that here requires awkward
-// API changes, though. Better way?
-namespace llvm {
-extern MCInstrDesc ARMInsts[];
-}
-static MCInstrDesc &getInstDesc(unsigned Opcode) {
-  return ARMInsts[Opcode];
-}
-
 unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
   // 16-bit thumb arithmetic instructions either require or preclude the 'S'
   // suffix depending on whether they're in an IT block or not.
@@ -3457,10 +3534,12 @@
       return Match_MnemonicFail;
     // If we're parsing Thumb2, which form is legal depends on whether we're
     // in an IT block.
-    // FIXME: We don't yet do IT blocks, so just always consider it to be
-    // that we aren't in one until we do.
-    if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR)
+    if (isThumbTwo() && Inst.getOperand(OpNo).getReg() != ARM::CPSR &&
+        !inITBlock())
       return Match_RequiresITBlock;
+    if (isThumbTwo() && Inst.getOperand(OpNo).getReg() == ARM::CPSR &&
+        inITBlock())
+      return Match_RequiresNotITBlock;
   }
   // Some high-register supporting Thumb1 encodings only allow both registers
   // to be from r0-r7 when in Thumb2.
@@ -3518,6 +3597,8 @@
   case Match_ConversionFail:
     // The converter function will have already emited a diagnostic.
     return true;
+  case Match_RequiresNotITBlock:
+    return Error(IDLoc, "flag setting instruction only valid outside IT block");
   case Match_RequiresITBlock:
     return Error(IDLoc, "instruction only valid inside IT block");
   case Match_RequiresV6:

Added: llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s?rev=138773&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s (added)
+++ llvm/trunk/test/MC/ARM/basic-thumb2-instructions.s Mon Aug 29 17:24:09 2011
@@ -0,0 +1,32 @@
+@ RUN: llvm-mc -triple=thumbv7-apple-darwin -show-encoding < %s | FileCheck %s
+  .syntax unified
+  .globl _func
+
+@ Check that the assembler can handle the documented syntax from the ARM ARM.
+@ For complex constructs like shifter operands, check more thoroughly for them
+@ once then spot check that following instructions accept the form generally.
+@ This gives us good coverage while keeping the overall size of the test
+@ more reasonable.
+
+
+@ FIXME: Some 3-operand instructions have a 2-operand assembly syntax.
+
+_func:
+@ CHECK: _func
+
+ at ------------------------------------------------------------------------------
+@ IT
+ at ------------------------------------------------------------------------------
+@ Test encodings of a few full IT blocks, not just the IT instruction
+
+        iteet eq
+        addeq r0, r1, r2
+        nopne
+        subne r5, r6, r7
+        addeq r1, r2, #4
+
+@ CHECK: iteet	eq                      @ encoding: [0x0d,0xbf]
+@ CHECK: addeq	r0, r1, r2              @ encoding: [0x88,0x18]
+@ CHECK: nopne                          @ encoding: [0x00,0xbf]
+@ CHECK: subne	r5, r6, r7              @ encoding: [0xf5,0x1b]
+@ CHECK: addeq	r1, r2, #4              @ encoding: [0x11,0x1d]

Added: llvm/trunk/test/MC/ARM/thumb2-diagnostics.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/thumb2-diagnostics.s?rev=138773&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/thumb2-diagnostics.s (added)
+++ llvm/trunk/test/MC/ARM/thumb2-diagnostics.s Mon Aug 29 17:24:09 2011
@@ -0,0 +1,30 @@
+@ RUN: not llvm-mc -triple=thumbv7-apple-darwin < %s 2> %t
+@ RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
+
+@ Ill-formed IT block instructions.
+        itet eq
+        addle r0, r1, r2
+        nop
+        it le
+        iteeee gt
+        ittfe le
+        nopeq
+
+@ CHECK-ERRORS: error: incorrect condition in IT block; got 'le', but expected 'eq'
+@ CHECK-ERRORS:         addle r0, r1, r2
+@ CHECK-ERRORS:            ^
+@ CHECK-ERRORS: error: incorrect condition in IT block; got 'al', but expected 'ne'
+@ CHECK-ERRORS:         nop
+@ CHECK-ERRORS:            ^
+@ CHECK-ERRORS: error: instructions in IT block must be predicable
+@ CHECK-ERRORS:         it le
+@ CHECK-ERRORS:         ^
+@ CHECK-ERRORS: error: too many conditions on IT instruction
+@ CHECK-ERRORS:         iteeee gt
+@ CHECK-ERRORS:           ^
+@ CHECK-ERRORS: error: illegal IT block condition mask 'tfe'
+@ CHECK-ERRORS:         ittfe le
+@ CHECK-ERRORS:           ^
+@ CHECK-ERRORS: error: predicated instructions must be in IT block
+@ CHECK-ERRORS:         nopeq
+@ CHECK-ERRORS:         ^





More information about the llvm-commits mailing list