[llvm] r276747 - [ARM] Implement -mimplicit-it assembler option

Oliver Stannard via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 26 07:19:47 PDT 2016


Author: olista01
Date: Tue Jul 26 09:19:47 2016
New Revision: 276747

URL: http://llvm.org/viewvc/llvm-project?rev=276747&view=rev
Log:
[ARM] Implement -mimplicit-it assembler option

This option, compatible with gas's -mimplicit-it, controls the
generation/checking of implicit IT blocks in ARM/Thumb assembly.

This option allows two behaviours that were not possible before:
- When in ARM mode, emit a warning when assembling a conditional
  instruction that is not in an IT block. This is enabled with
  -mimplicit-it=never and -mimplicit-it=thumb.
- When in Thumb mode, automatically generate IT instructions when an
  instruction with a condition code appears outside of an IT block. This
  is enabled with -mimplicit-it=thumb and -mimplicit-it=always.

The default option is -mimplicit-it=arm, which matches the existing
behaviour (allow conditional ARM instructions outside IT blocks without
warning, and error if a conditional Thumb instruction is outside an IT
block).

The general strategy for generating IT blocks in Thumb mode is to keep a
small list of instructions which should be in the IT block, and only
emit them when we encounter something in the input which means we cannot
continue the block.  This could be caused by:
- A non-predicable instruction
- An instruction with a condition not compatible with the IT block
- The IT block already contains 4 instructions
- A branch-like instruction (including ALU instructions with the PC as
  the destination), which cannot appear in the middle of an IT block
- A label (branching into an IT block is not legal)
- A change of section, architecture, ISA, etc
- The end of the assembly file.

Some of these, such as change of section and end of file, are parsed
outside of the ARM asm parser, so I've added a new virtual function to
AsmParser to ensure any previously-parsed instructions have been
emitted. The ARM implementation of this flushes the currently pending IT
block.

We now have to try instruction matching up to 3 times, because we cannot
know if the current IT block is valid before matching, and instruction
matching changes depending on the IT block state (due to the 16-bit ALU
instructions, which set the flags iff not in an IT block). In the common
case of not having an open implicit IT block and the instruction being
matched not needing one, we still only have to run the matcher once.

I've removed the ITState.FirstCond variable, because it does not store
any information that isn't already represented by CurPosition. I've also
updated the comment on CurPosition to accurately describe it's meaning
(which this patch doesn't change).

Differential Revision: https://reviews.llvm.org/D22760


Added:
    llvm/trunk/test/MC/ARM/implicit-it-generation.s
    llvm/trunk/test/MC/ARM/implicit-it.s
Modified:
    llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h
    llvm/trunk/lib/MC/MCParser/AsmParser.cpp
    llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
    llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Modified: llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h?rev=276747&r1=276746&r2=276747&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h (original)
+++ llvm/trunk/include/llvm/MC/MCParser/MCTargetAsmParser.h Tue Jul 26 09:19:47 2016
@@ -217,6 +217,10 @@ public:
   }
 
   virtual void onLabelParsed(MCSymbol *Symbol) { }
+
+  /// Ensure that all previously parsed instructions have been emitted to the
+  /// output streamer, if the target does not emit them immediately.
+  virtual void flushPendingInstructions(MCStreamer &Out) { }
 };
 
 } // End llvm namespace

Modified: llvm/trunk/lib/MC/MCParser/AsmParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCParser/AsmParser.cpp?rev=276747&r1=276746&r2=276747&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCParser/AsmParser.cpp (original)
+++ llvm/trunk/lib/MC/MCParser/AsmParser.cpp Tue Jul 26 09:19:47 2016
@@ -737,6 +737,8 @@ bool AsmParser::Run(bool NoInitialTextSe
     eatToEndOfStatement();
   }
 
+  getTargetParser().flushPendingInstructions(getStreamer());
+
   if (TheCondState.TheCond != StartingCondState.TheCond ||
       TheCondState.Ignore != StartingCondState.Ignore)
     return TokError("unmatched .ifs or .elses");
@@ -1590,6 +1592,8 @@ bool AsmParser::parseStatement(ParseStat
     //    manner, or at least have a default behavior that's shared between
     //    all targets and platforms.
 
+    getTargetParser().flushPendingInstructions(getStreamer());
+
     // First query the target-specific parser. It will return 'true' if it
     // isn't interested in this directive.
     if (!getTargetParser().ParseDirective(ID))

Modified: llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td?rev=276747&r1=276746&r2=276747&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrThumb2.td Tue Jul 26 09:19:47 2016
@@ -3456,6 +3456,7 @@ def t2IT : Thumb2XI<(outs), (ins it_pred
 
 // Branch and Exchange Jazelle -- for disassembly only
 // Rm = Inst{19-16}
+let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in
 def t2BXJ : T2I<(outs), (ins GPRnopc:$func), NoItinerary, "bxj", "\t$func", []>,
     Sched<[WriteBr]>, Requires<[IsThumb2, IsNotMClass]> {
   bits<4> func;
@@ -3564,6 +3565,7 @@ def t2DBG : T2I<(outs), (ins imm0_15:$op
 
 // Secure Monitor Call is a system instruction.
 // Option = Inst{19-16}
+let isCall = 1, Uses = [SP] in
 def t2SMC : T2I<(outs), (ins imm0_15:$opt), NoItinerary, "smc", "\t$opt",
                 []>, Requires<[IsThumb2, HasTrustZone]> {
   let Inst{31-27} = 0b11110;
@@ -3620,6 +3622,7 @@ def : t2InstAlias<"srsia${p} $mode", (t2
 def : t2InstAlias<"srsia${p} $mode!", (t2SRSIA_UPD imm0_31:$mode, pred:$p)>;
 
 // Return From Exception is a system instruction.
+let isReturn = 1, isBarrier = 1, isTerminator = 1, Defs = [PC] in
 class T2RFE<bits<12> op31_20, dag oops, dag iops, InstrItinClass itin,
           string opc, string asm, list<dag> pattern>
   : T2I<oops, iops, itin, opc, asm, pattern>,

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=276747&r1=276746&r2=276747&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp (original)
+++ llvm/trunk/lib/Target/ARM/AsmParser/ARMAsmParser.cpp Tue Jul 26 09:19:47 2016
@@ -40,6 +40,7 @@
 #include "llvm/Support/ARMBuildAttributes.h"
 #include "llvm/Support/ARMEHABI.h"
 #include "llvm/Support/COFF.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ELF.h"
 #include "llvm/Support/MathExtras.h"
@@ -52,6 +53,21 @@ using namespace llvm;
 
 namespace {
 
+enum class ImplicitItModeTy { Always, Never, ARMOnly, ThumbOnly };
+
+static cl::opt<ImplicitItModeTy> ImplicitItMode(
+    "arm-implicit-it", cl::init(ImplicitItModeTy::ARMOnly),
+    cl::desc("Allow conditional instructions outdside of an IT block"),
+    cl::values(clEnumValN(ImplicitItModeTy::Always, "always",
+                          "Accept in both ISAs, emit implicit ITs in Thumb"),
+               clEnumValN(ImplicitItModeTy::Never, "never",
+                          "Warn in ARM, reject in Thumb"),
+               clEnumValN(ImplicitItModeTy::ARMOnly, "arm",
+                          "Accept in ARM, reject in Thumb"),
+               clEnumValN(ImplicitItModeTy::ThumbOnly, "thumb",
+                          "Warn in ARM, emit implicit ITs in Thumb"),
+               clEnumValEnd));
+
 class ARMOperand;
 
 enum VectorLaneTy { NoLanes, AllLanes, IndexedLane };
@@ -145,6 +161,16 @@ class ARMAsmParser : public MCTargetAsmP
 
   bool NextSymbolIsThumb;
 
+  bool useImplicitITThumb() const {
+    return ImplicitItMode == ImplicitItModeTy::Always ||
+           ImplicitItMode == ImplicitItModeTy::ThumbOnly;
+  }
+
+  bool useImplicitITARM() const {
+    return ImplicitItMode == ImplicitItModeTy::Always ||
+           ImplicitItMode == ImplicitItModeTy::ARMOnly;
+  }
+
   struct {
     ARMCC::CondCodes Cond;    // Condition for IT block.
     unsigned Mask:4;          // Condition mask for instructions.
@@ -153,30 +179,166 @@ class ARMAsmParser : public MCTargetAsmP
                               //   '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.
+                              // Note that this does not have the same encoding
+                              // as in the IT instruction, which also depends
+                              // on the low bit of the condition code.
 
     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.
+                              // block. In range [0,4], with 0 being the IT
+                              // instruction itself. Initialized according to
+                              // count of instructions in block.  ~0U if no
+                              // active IT block.
+
+    bool IsExplicit;          // true  - The IT instruction was present in the
+                              //         input, we should not modify it.
+                              // false - The IT instruction was added
+                              //         implicitly, we can extend it if that
+                              //         would be legal.
   } ITState;
+
+  llvm::SmallVector<MCInst, 4> PendingConditionalInsts;
+
+  void flushPendingInstructions(MCStreamer &Out) override {
+    if (!inImplicitITBlock()) {
+      assert(PendingConditionalInsts.size() == 0);
+      return;
+    }
+
+    // Emit the IT instruction
+    unsigned Mask = getITMaskEncoding();
+    MCInst ITInst;
+    ITInst.setOpcode(ARM::t2IT);
+    ITInst.addOperand(MCOperand::createImm(ITState.Cond));
+    ITInst.addOperand(MCOperand::createImm(Mask));
+    Out.EmitInstruction(ITInst, getSTI());
+
+    // Emit the conditonal instructions
+    assert(PendingConditionalInsts.size() <= 4);
+    for (MCInst Inst : PendingConditionalInsts) {
+      Out.EmitInstruction(Inst, getSTI());
+    }
+    PendingConditionalInsts.clear();
+
+    // Clear the IT state
+    ITState.Mask = 0;
+    ITState.CurPosition = ~0U;
+  }
+
   bool inITBlock() { return ITState.CurPosition != ~0U; }
+  bool inExplicitITBlock() { return inITBlock() && ITState.IsExplicit; }
+  bool inImplicitITBlock() { return inITBlock() && !ITState.IsExplicit; }
   bool lastInITBlock() {
     return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask);
   }
   void forwardITPosition() {
     if (!inITBlock()) return;
     // Move to the next instruction in the IT block, if there is one. If not,
-    // mark the block as done.
+    // mark the block as done, except for implicit IT blocks, which we leave
+    // open until we find an instruction that can't be added to it.
     unsigned TZ = countTrailingZeros(ITState.Mask);
-    if (++ITState.CurPosition == 5 - TZ)
+    if (++ITState.CurPosition == 5 - TZ && ITState.IsExplicit)
       ITState.CurPosition = ~0U; // Done with the IT block after this.
   }
 
+  // Rewind the state of the current IT block, removing the last slot from it.
+  void rewindImplicitITPosition() {
+    assert(inImplicitITBlock());
+    assert(ITState.CurPosition > 1);
+    ITState.CurPosition--;
+    unsigned TZ = countTrailingZeros(ITState.Mask);
+    unsigned NewMask = 0;
+    NewMask |= ITState.Mask & (0xC << TZ);
+    NewMask |= 0x2 << TZ;
+    ITState.Mask = NewMask;
+  }
+
+  // Rewind the state of the current IT block, removing the last slot from it.
+  // If we were at the first slot, this closes the IT block.
+  void discardImplicitITBlock() {
+    assert(inImplicitITBlock());
+    assert(ITState.CurPosition == 1);
+    ITState.CurPosition = ~0U;
+    return;
+  }
+
+  // Get the encoding of the IT mask, as it will appear in an IT instruction.
+  unsigned getITMaskEncoding() {
+    assert(inITBlock());
+    unsigned Mask = ITState.Mask;
+    unsigned TZ = countTrailingZeros(Mask);
+    if ((ITState.Cond & 1) == 0) {
+      assert(Mask && TZ <= 3 && "illegal IT mask value!");
+      Mask ^= (0xE << TZ) & 0xF;
+    }
+    return Mask;
+  }
+
+  // Get the condition code corresponding to the current IT block slot.
+  ARMCC::CondCodes currentITCond() {
+    unsigned MaskBit;
+    if (ITState.CurPosition == 1)
+      MaskBit = 1;
+    else
+      MaskBit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
+
+    return MaskBit ? ITState.Cond : ARMCC::getOppositeCondition(ITState.Cond);
+  }
+
+  // Invert the condition of the current IT block slot without changing any
+  // other slots in the same block.
+  void invertCurrentITCondition() {
+    if (ITState.CurPosition == 1) {
+      ITState.Cond = ARMCC::getOppositeCondition(ITState.Cond);
+    } else {
+      ITState.Mask ^= 1 << (5 - ITState.CurPosition);
+    }
+  }
+
+  // Returns true if the current IT block is full (all 4 slots used).
+  bool isITBlockFull() {
+    return inITBlock() && (ITState.Mask & 1);
+  }
+
+  // Extend the current implicit IT block to have one more slot with the given
+  // condition code.
+  void extendImplicitITBlock(ARMCC::CondCodes Cond) {
+    assert(inImplicitITBlock());
+    assert(!isITBlockFull());
+    assert(Cond == ITState.Cond ||
+           Cond == ARMCC::getOppositeCondition(ITState.Cond));
+    unsigned TZ = countTrailingZeros(ITState.Mask);
+    unsigned NewMask = 0;
+    // Keep any existing condition bits.
+    NewMask |= ITState.Mask & (0xE << TZ);
+    // Insert the new condition bit.
+    NewMask |= (Cond == ITState.Cond) << TZ;
+    // Move the trailing 1 down one bit.
+    NewMask |= 1 << (TZ - 1);
+    ITState.Mask = NewMask;
+  }
+
+  // Create a new implicit IT block with a dummy condition code.
+  void startImplicitITBlock() {
+    assert(!inITBlock());
+    ITState.Cond = ARMCC::AL;
+    ITState.Mask = 8;
+    ITState.CurPosition = 1;
+    ITState.IsExplicit = false;
+    return;
+  }
+
+  // Create a new explicit IT block with the given condition and mask. The mask
+  // should be in the parsed format, with a 1 implying 't', regardless of the
+  // low bit of the condition.
+  void startExplicitITBlock(ARMCC::CondCodes Cond, unsigned Mask) {
+    assert(!inITBlock());
+    ITState.Cond = Cond;
+    ITState.Mask = Mask;
+    ITState.CurPosition = 0;
+    ITState.IsExplicit = true;
+    return;
+  }
+
   void Note(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges = None) {
     return getParser().Note(L, Msg, Ranges);
   }
@@ -355,6 +517,7 @@ class ARMAsmParser : public MCTargetAsmP
   bool processInstruction(MCInst &Inst, const OperandVector &Ops, MCStreamer &Out);
   bool shouldOmitCCOutOperand(StringRef Mnemonic, OperandVector &Operands);
   bool shouldOmitPredicateOperand(StringRef Mnemonic, OperandVector &Operands);
+  bool isITBlockTerminator(MCInst &Inst) const;
 
 public:
   enum ARMMatchResultTy {
@@ -399,6 +562,9 @@ public:
                                OperandVector &Operands, MCStreamer &Out,
                                uint64_t &ErrorInfo,
                                bool MatchingInlineAsm) override;
+  unsigned MatchInstruction(OperandVector &Operands, MCInst &Inst,
+                            uint64_t &ErrorInfo, bool MatchingInlineAsm,
+                            bool &EmitInITBlock, MCStreamer &Out);
   void onLabelParsed(MCSymbol *Symbol) override;
 };
 } // end anonymous namespace
@@ -6188,18 +6354,11 @@ bool ARMAsmParser::validateInstruction(M
   // NOTE: BKPT and HLT instructions have the interesting property of being
   // allowed in IT blocks, but not being predicable. They just always execute.
   if (inITBlock() && !instIsBreakpoint(Inst)) {
-    unsigned Bit = 1;
-    if (ITState.FirstCond)
-      ITState.FirstCond = false;
-    else
-      Bit = (ITState.Mask >> (5 - ITState.CurPosition)) & 1;
     // 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) {
+    if (Cond != currentITCond()) {
       // Find the condition code Operand to get its SMLoc information.
       SMLoc CondLoc;
       for (unsigned I = 1; I < Operands.size(); ++I)
@@ -6208,14 +6367,19 @@ bool ARMAsmParser::validateInstruction(M
       return Error(CondLoc, "incorrect condition in IT block; got '" +
                    StringRef(ARMCondCodeToString(ARMCC::CondCodes(Cond))) +
                    "', but expected '" +
-                   ARMCondCodeToString(ARMCC::CondCodes(ITCond)) + "'");
+                   ARMCondCodeToString(ARMCC::CondCodes(currentITCond())) + "'");
     }
   // Check for non-'al' condition codes outside of the IT block.
   } else if (isThumbTwo() && MCID.isPredicable() &&
              Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
              ARMCC::AL && Inst.getOpcode() != ARM::tBcc &&
-             Inst.getOpcode() != ARM::t2Bcc)
+             Inst.getOpcode() != ARM::t2Bcc) {
     return Error(Loc, "predicated instructions must be in IT block");
+  } else if (!isThumb() && !useImplicitITARM() && MCID.isPredicable() &&
+             Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() !=
+                 ARMCC::AL) {
+    return Warning(Loc, "predicated instructions should be in IT block");
+  }
 
   const unsigned Opcode = Inst.getOpcode();
   switch (Opcode) {
@@ -8636,27 +8800,15 @@ bool ARMAsmParser::processInstruction(MC
   }
   case ARM::ITasm:
   case ARM::t2IT: {
-    // The mask bits for all but the first condition are represented as
-    // the low bit of the condition code value implies 't'. We currently
-    // always have 1 implies 't', so XOR toggle the bits if the low bit
-    // of the condition code is zero. 
     MCOperand &MO = Inst.getOperand(1);
     unsigned Mask = MO.getImm();
-    unsigned OrigMask = Mask;
-    unsigned TZ = countTrailingZeros(Mask);
-    if ((Inst.getOperand(0).getImm() & 1) == 0) {
-      assert(Mask && TZ <= 3 && "illegal IT mask value!");
-      Mask ^= (0xE << TZ) & 0xF;
-    }
-    MO.setImm(Mask);
+    ARMCC::CondCodes Cond = ARMCC::CondCodes(Inst.getOperand(0).getImm());
 
     // 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;
+    startExplicitITBlock(Cond, Mask);
+    MO.setImm(getITMaskEncoding());
     break;
   }
   case ARM::t2LSLrr:
@@ -8804,6 +8956,132 @@ template <> inline bool IsCPSRDead<MCIns
 }
 }
 
+// Returns true if Inst is unpredictable if it is in and IT block, but is not
+// the last instruction in the block.
+bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const {
+  const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+
+  // All branch & call instructions terminate IT blocks.
+  if (MCID.isTerminator() || MCID.isCall() || MCID.isReturn() ||
+      MCID.isBranch() || MCID.isIndirectBranch())
+    return true;
+
+  // Any arithmetic instruction which writes to the PC also terminates the IT
+  // block.
+  for (unsigned OpIdx = 0; OpIdx < MCID.getNumDefs(); ++OpIdx) {
+    MCOperand &Op = Inst.getOperand(OpIdx);
+    if (Op.isReg() && Op.getReg() == ARM::PC)
+      return true;
+  }
+
+  if (MCID.hasImplicitDefOfPhysReg(ARM::PC, MRI))
+    return true;
+
+  // Instructions with variable operand lists, which write to the variable
+  // operands. We only care about Thumb instructions here, as ARM instructions
+  // obviously can't be in an IT block.
+  switch (Inst.getOpcode()) {
+  case ARM::t2LDMIA:
+  case ARM::t2LDMIA_UPD:
+  case ARM::t2LDMDB:
+  case ARM::t2LDMDB_UPD:
+    if (listContainsReg(Inst, 3, ARM::PC))
+      return true;
+    break;
+  case ARM::tPOP:
+    if (listContainsReg(Inst, 2, ARM::PC))
+      return true;
+    break;
+  }
+
+  return false;
+}
+
+unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst,
+                                          uint64_t &ErrorInfo,
+                                          bool MatchingInlineAsm,
+                                          bool &EmitInITBlock,
+                                          MCStreamer &Out) {
+  // If we can't use an implicit IT block here, just match as normal.
+  if (inExplicitITBlock() || !isThumbTwo() || !useImplicitITThumb())
+    return MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+
+  // Try to match the instruction in an extension of the current IT block (if
+  // there is one).
+  if (inImplicitITBlock()) {
+    extendImplicitITBlock(ITState.Cond);
+    if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+            Match_Success) {
+      // The match succeded, but we still have to check that the instruction is
+      // valid in this implicit IT block.
+      const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+      if (MCID.isPredicable()) {
+        ARMCC::CondCodes InstCond =
+            (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+                .getImm();
+        ARMCC::CondCodes ITCond = currentITCond();
+        if (InstCond == ITCond) {
+          EmitInITBlock = true;
+          return Match_Success;
+        } else if (InstCond == ARMCC::getOppositeCondition(ITCond)) {
+          invertCurrentITCondition();
+          EmitInITBlock = true;
+          return Match_Success;
+        }
+      }
+    }
+    rewindImplicitITPosition();
+  }
+
+  // Finish the current IT block, and try to match outside any IT block.
+  flushPendingInstructions(Out);
+  unsigned PlainMatchResult =
+      MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
+  if (PlainMatchResult == Match_Success) {
+    const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+    if (MCID.isPredicable()) {
+      ARMCC::CondCodes InstCond =
+          (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+              .getImm();
+      // Some forms of the branch instruction have their own condition code
+      // fields, so can be conditionally executed without an IT block.
+      if (Inst.getOpcode() == ARM::tBcc || Inst.getOpcode() == ARM::t2Bcc) {
+        EmitInITBlock = false;
+        return Match_Success;
+      }
+      if (InstCond == ARMCC::AL) {
+        EmitInITBlock = false;
+        return Match_Success;
+      }
+    } else {
+      EmitInITBlock = false;
+      return Match_Success;
+    }
+  }
+
+  // Try to match in a new IT block. The matcher doesn't check the actual
+  // condition, so we create an IT block with a dummy condition, and fix it up
+  // once we know the actual condition.
+  startImplicitITBlock();
+  if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) ==
+      Match_Success) {
+    const MCInstrDesc &MCID = MII.get(Inst.getOpcode());
+    if (MCID.isPredicable()) {
+      ITState.Cond =
+          (ARMCC::CondCodes)Inst.getOperand(MCID.findFirstPredOperandIdx())
+              .getImm();
+      EmitInITBlock = true;
+      return Match_Success;
+    }
+  }
+  discardImplicitITBlock();
+
+  // If none of these succeed, return the error we got when trying to match
+  // outside any IT blocks.
+  EmitInITBlock = false;
+  return PlainMatchResult;
+}
+
 static const char *getSubtargetFeatureName(uint64_t Val);
 bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
                                            OperandVector &Operands,
@@ -8811,9 +9089,11 @@ bool ARMAsmParser::MatchAndEmitInstructi
                                            bool MatchingInlineAsm) {
   MCInst Inst;
   unsigned MatchResult;
+  bool PendConditionalInstruction = false;
+
+  MatchResult = MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm,
+                                 PendConditionalInstruction, Out);
 
-  MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
-                                     MatchingInlineAsm);
   switch (MatchResult) {
   case Match_Success:
     // Context sensitive operand constraints aren't handled by the matcher,
@@ -8853,7 +9133,13 @@ bool ARMAsmParser::MatchAndEmitInstructi
       return false;
 
     Inst.setLoc(IDLoc);
-    Out.EmitInstruction(Inst, getSTI());
+    if (PendConditionalInstruction) {
+      PendingConditionalInsts.push_back(Inst);
+      if (isITBlockFull() || isITBlockTerminator(Inst))
+        flushPendingInstructions(Out);
+    } else {
+      Out.EmitInstruction(Inst, getSTI());
+    }
     return false;
   case Match_MissingFeature: {
     assert(ErrorInfo && "Unknown missing feature!");
@@ -9106,6 +9392,9 @@ bool ARMAsmParser::parseDirectiveARM(SML
 }
 
 void ARMAsmParser::onLabelParsed(MCSymbol *Symbol) {
+  // We need to flush the current implicit IT block on a label, because it is
+  // not legal to branch into an IT block.
+  flushPendingInstructions(getStreamer());
   if (NextSymbolIsThumb) {
     getParser().getStreamer().EmitThumbFunc(Symbol);
     NextSymbolIsThumb = false;

Added: llvm/trunk/test/MC/ARM/implicit-it-generation.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/implicit-it-generation.s?rev=276747&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/implicit-it-generation.s (added)
+++ llvm/trunk/test/MC/ARM/implicit-it-generation.s Tue Jul 26 09:19:47 2016
@@ -0,0 +1,409 @@
+@ RUN: llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=always < %s -show-encoding | FileCheck %s
+
+@ Single instruction
+  .section test1
+@ CHECK-LABEL: test1
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Multiple instructions, same condition
+  .section test2
+@ CHECK-LABEL: test2
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+@ CHECK: itttt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ Multiple instructions, equal but opposite conditions
+  .section test3
+@ CHECK-LABEL: test3
+  addeq r0, #1
+  addne r0, #1
+  addeq r0, #1
+  addne r0, #1
+@ CHECK: itete eq
+@ CHECK: addeq
+@ CHECK: addne
+@ CHECK: addeq
+@ CHECK: addne
+
+@ Multiple instructions, unrelated conditions
+  .section test4
+@ CHECK-LABEL: test4
+  addeq r0, #1
+  addlt r0, #1
+  addeq r0, #1
+  addge r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it lt
+@ CHECK: addlt
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it ge
+@ CHECK: addge
+
+@ More than 4 instructions eligible for a block
+  .section test5
+@ CHECK-LABEL: test5
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+  addeq r0, #1
+@ CHECK: itttt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: itt eq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ Flush on a label
+  .section test6
+@ CHECK-LABEL: test6
+  addeq r0, #1
+label:
+  addeq r0, #1
+5:
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on a section-change directive
+  .section test7a
+@ CHECK-LABEL: test7a
+  addeq r0, #1
+  .section test7b
+  addeq r0, #1
+  .previous
+  addeq r0, #1
+  .pushsection test7c
+  addeq r0, #1
+  .popsection
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an ISA change (even to the same ISA)
+  .section test8
+@ CHECK-LABEL: test8
+  addeq r0, #1
+  .thumb
+  addeq r0, #1
+  .arm
+  addeq r0, #1
+  .thumb
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an arch, cpu or fpu change
+  .section test9
+@ CHECK-LABEL: test9
+  addeq r0, #1
+  .arch armv7-a
+  addeq r0, #1
+  .cpu cortex-a15
+  addeq r0, #1
+  .fpu vfpv3
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush on an unpredicable instruction
+  .section test10
+@ CHECK-LABEL: test10
+  addeq r0, #1
+  setend le
+  addeq r0, #1
+  hvc #0
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: setend le
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: hvc.w #0
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Flush when reaching an explicit IT instruction
+  .section test11
+@ CHECK-LABEL: test11
+  addeq r0, #1
+  it eq
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Don't extend an explicit IT instruction
+  .section test12
+@ CHECK-LABEL: test12
+  it eq
+  addeq r0, #1
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ Branch-like instructions can only be used at the end of an IT block, so
+@ terminate it.
+  .section test13
+@ CHECK-LABEL: test13
+  .cpu cortex-a15
+  addeq pc, r0
+  addeq pc, sp, pc
+  ldreq pc, [r0, #4]
+  ldreq pc, [r0, #-4]
+  ldreq pc, [r0, r1]
+  ldreq pc, [pc, #-0]
+  moveq pc, r0
+  bleq #4
+  blxeq #4
+  blxeq r0
+  bxeq r0
+  bxjeq r0
+  tbbeq [r0, r1]
+  tbheq [r0, r1, lsl #1]
+  ereteq
+  rfeiaeq r0
+  rfeiaeq r0!
+  rfedbeq r0
+  rfedbeq r0!
+  smceq #0
+  ldmiaeq r0, {pc}
+  ldmiaeq r0!, {r1, pc}
+  ldmdbeq r0, {pc}
+  ldmdbeq r0!, {r1, pc}
+  popeq {pc}
+  .arch armv8-m.main
+  bxnseq r0
+  blxnseq r0
+@ CHECK: it eq
+@ CHECK: addeq pc, r0
+@ CHECK: it eq
+@ CHECK: addeq pc, sp, pc
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [r0, #4]
+@ CHECK: it eq
+@ CHECK: ldreq pc, [r0, #-4]
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [r0, r1]
+@ CHECK: it eq
+@ CHECK: ldreq.w pc, [pc, #-0]
+@ CHECK: it eq
+@ CHECK: moveq pc, r0
+@ CHECK: it eq
+@ CHECK: bleq #4
+@ CHECK: it eq
+@ CHECK: blxeq #4
+@ CHECK: it eq
+@ CHECK: blxeq r0
+@ CHECK: it eq
+@ CHECK: bxeq r0
+@ CHECK: it eq
+@ CHECK: bxjeq r0
+@ CHECK: it eq
+@ CHECK: tbbeq [r0, r1]
+@ CHECK: it eq
+@ CHECK: tbheq [r0, r1, lsl #1]
+@ CHECK: it eq
+@ CHECK: ereteq
+@ CHECK: it eq
+@ CHECK: rfeiaeq r0
+@ CHECK: it eq
+@ CHECK: rfeiaeq r0!
+@ CHECK: it eq
+@ CHECK: rfedbeq r0
+@ CHECK: it eq
+@ CHECK: rfedbeq r0!
+@ CHECK: it eq
+@ CHECK: smceq #0
+@ CHECK: it eq
+@ CHECK: ldmeq.w r0, {pc}
+@ CHECK: it eq
+@ CHECK: ldmeq.w r0!, {r1, pc}
+@ CHECK: it eq
+@ CHECK: ldmdbeq r0, {pc}
+@ CHECK: it eq
+@ CHECK: ldmdbeq r0!, {r1, pc}
+@ CHECK: it eq
+@ CHECK: popeq {pc}
+@ CHECK: it eq
+@ CHECK: bxnseq r0
+@ CHECK: it eq
+@ CHECK: blxnseq r0
+
+@ Thumb 16-bit ALU instructions set the flags iff they are not in an IT block,
+@ so instruction matching must change when generating an implicit IT block.
+  .section test14
+@ CHECK-LABEL: test14
+@ Outside an IT block, the 16-bit encoding must set flags
+  add r0, #1
+@ CHECK:add.w   r0, r0, #1              @ encoding: [0x00,0xf1,0x01,0x00] 
+  adds r0, #1
+@ CHECK: adds    r0, #1                  @ encoding: [0x01,0x30]
+@ Inside an IT block, the 16-bit encoding can not set flags
+  addeq r0, #1
+@ CHECK: itt eq
+@ CHECK: addeq   r0, #1                  @ encoding: [0x01,0x30]
+  addseq r0, #1
+@ CHECK: addseq.w        r0, r0, #1      @ encoding: [0x10,0xf1,0x01,0x00]
+
+@ Some variants of the B instruction have their own condition code field, and
+@ are not valid in IT blocks.
+  .section test15
+@ CHECK-LABEL: test15
+@ Outside of an IT block, the 4 variants (narrow/wide,
+@ predicated/non-predicated) are selected as normal, and the predicated
+@ encodings are used instead of opening a new IT block:
+  b #0x100
+@ CHECK: b       #256                    @ encoding: [0x80,0xe0] 
+  b #0x800
+@ CHECK: b.w     #2048                   @ encoding: [0x00,0xf0,0x00,0xbc]
+  beq #0x4
+@ CHECK-NOT: it
+@ CHECK: beq     #4                      @ encoding: [0x02,0xd0]
+  beq #0x100
+@ CHECK-NOT: it
+@ CHECK: beq.w   #256                    @ encoding: [0x00,0xf0,0x80,0x80]
+
+@ We could support "beq #0x100000" to "beq #0x1fffffc" by using t2Bcc in
+@ an IT block (these currently fail as the target is out of range). However, long
+@ ranges like this are rarely assembly-time constants, so this probably isn't
+@ worth doing.
+
+@ If we already have an open IT block, we can use the non-predicated encodings,
+@ which have a greater range:
+  addeq r0, r1
+  beq #0x4
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq     #4                      @ encoding: [0x02,0xe0]
+  addeq r0, r1
+  beq #0x100
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq     #256                    @ encoding: [0x80,0xe0]
+  addeq r0, r1
+  beq #0x800
+@ CHECK: itt eq
+@ CHECK: addeq r0, r1
+@ CHECK: beq.w   #2048                   @ encoding: [0x00,0xf0,0x00,0xbc]
+
+@ If we have an open but incompatible IT block, we close it and use the
+@ self-predicated encodings, without an IT block:
+  addeq r0, r1
+  bgt #0x4
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bgt     #4                      @ encoding: [0x02,0xdc]
+  addeq r0, r1
+  bgt #0x100
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bgt.w   #256                    @ encoding: [0x00,0xf3,0x80,0x80]
+
+@ Breakpoint instructions are allowed in IT blocks, but are always executed
+@ regardless of the condition flags. We could continue an IT block through
+@ them, but currently do not.
+  .section test16
+@ CHECK-LABEL: test16
+  addeq r0, r1
+  bkpt #0
+  addeq r0, r1
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+@ CHECK: bkpt #0
+@ CHECK: it eq
+@ CHECK: addeq r0, r1
+
+@ The .if directive causes entire assembly statments to be dropped before they
+@ reach the IT block generation code. This happens to be exactly what we want,
+@ and allows IT blocks to extend into and out of .if blocks. Only one arm of the
+@ .if will be seen by the IT state tracking code, so the subeq shouldn't have
+@ any effect here.
+  .section test17
+@ CHECK-LABEL: test17
+  addeq r0, r1
+  .if 1
+  addeq r0, r1
+  .else
+  subeq r0, r1
+  .endif
+  addeq r0, r1
+@ CHECK: ittt eq
+@ CHECK: addeq
+@ CHECK: addeq
+@ CHECK: addeq
+
+@ TODO: There are some other directives which we could continue through, such
+@ as .set and .global, but we currently conservatively flush the IT block before
+@ every directive (except for .if and friends, which are handled separately).
+  .section test18
+@ CHECK-LABEL: test18
+  addeq r0, r1
+  .set s, 1
+  addeq r0, r1
+@ CHECK: it eq
+@ CHECK: addeq
+@ CHECK: it eq
+@ CHECK: addeq
+
+@ The .rept directive can be used to create long IT blocks.
+  .section test19
+@ CHECK-LABEL: test19
+  .rept 3
+  addeq r0, r1
+  subne r0, r1
+  .endr
+@ CHECK: itete eq
+@ CHECK:  addeq r0, r1
+@ CHECK:  subne.w r0, r0, r1
+@ CHECK:  addeq r0, r1
+@ CHECK:  subne.w r0, r0, r1
+@ CHECK: ite eq
+@ CHECK:  addeq r0, r1
+@ CHECK:  subne.w r0, r0, r1
+
+@ Flush at end of file
+  .section test99
+@ CHECK-LABEL: test99
+  addeq r0, #1
+@ CHECK: it eq
+@ CHECK: addeq

Added: llvm/trunk/test/MC/ARM/implicit-it.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/ARM/implicit-it.s?rev=276747&view=auto
==============================================================================
--- llvm/trunk/test/MC/ARM/implicit-it.s (added)
+++ llvm/trunk/test/MC/ARM/implicit-it.s Tue Jul 26 09:19:47 2016
@@ -0,0 +1,73 @@
+@ RUN: not llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=never  < %s 2>%t | FileCheck %s --check-prefix=CHECK
+@ RUN:     FileCheck %s < %t --check-prefix=THUMB-STDERR
+@ RUN: not llvm-mc -triple   armv7a--none-eabi -arm-implicit-it=never  < %s 2>%t | FileCheck %s --check-prefix=CHECK --check-prefix=ARM
+@ RUN:     FileCheck %s < %t --check-prefix=ARM-STDERR
+
+@ RUN: not llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=always < %s      | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB
+@ RUN: not llvm-mc -triple   armv7a--none-eabi -arm-implicit-it=always < %s      | FileCheck %s --check-prefix=CHECK --check-prefix=ARM
+
+@ RUN: not llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=arm    < %s 2>%t | FileCheck %s --check-prefix=CHECK
+@ RUN:     FileCheck %s < %t --check-prefix=THUMB-STDERR
+@ RUN: not llvm-mc -triple   armv7a--none-eabi -arm-implicit-it=arm    < %s      | FileCheck %s --check-prefix=CHECK --check-prefix=ARM
+
+@ RUN: not llvm-mc -triple thumbv7a--none-eabi                     < %s 2>%t | FileCheck %s --check-prefix=CHECK
+@ RUN:     FileCheck %s < %t --check-prefix=THUMB-STDERR
+@ RUN: not llvm-mc -triple   armv7a--none-eabi                     < %s      | FileCheck %s --check-prefix=CHECK --check-prefix=ARM
+
+@ RUN: not llvm-mc -triple thumbv7a--none-eabi -arm-implicit-it=thumb  < %s      | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB
+@ RUN: not llvm-mc -triple   armv7a--none-eabi -arm-implicit-it=thumb  < %s 2>%t | FileCheck %s --check-prefix=CHECK --check-prefix=ARM
+@ RUN:     FileCheck %s < %t --check-prefix=ARM-STDERR
+
+@ A single conditional instruction without IT block
+  .section test1
+@ CHECK-LABEL: test1
+  addeq r0, r0, #1
+@ THUMB: it eq
+@ THUMB: addeq r0, r0, #1
+@ ARM:   addeq r0, r0, #1
+@ THUMB-STDERR: error: predicated instructions must be in IT block
+@ ARM-STDERR: warning: predicated instructions should be in IT block
+
+@ A single conditional instruction with IT block
+  .section test2
+@ CHECK-LABEL: test2
+  it eq
+  addeq r0, r0, #1
+@ THUMB: it eq
+@ THUMB: addeq r0, r0, #1
+@ ARM:   addeq r0, r0, #1
+@ THUMB-STDERR-NOT: error:
+@ ARM-STDERR-NOT: warning:
+
+@ A single conditional instruction with IT block, but incorrect condition
+  .section test3
+@ CHECK-LABEL: test3
+  it eq
+  addgt r0, r0, #1
+@ THUMB-STDERR: error: incorrect condition in IT block
+@ ARM-STDERR:   error: incorrect condition in IT block
+
+@ Multiple conditional instructions in an IT block, inverted and non-inverted conditions
+  .section test4
+@ CHECK-LABEL: test4
+  itete gt
+  addgt r0, r0, #1
+  addle r0, r0, #1
+  addgt r0, r0, #1
+  addle r0, r0, #1
+@ THUMB: itete gt
+@ CHECK: addgt r0, r0, #1
+@ CHECK: addle r0, r0, #1
+@ CHECK: addgt r0, r0, #1
+@ CHECK: addle r0, r0, #1
+@ THUMB-STDERR-NOT: error:
+@ ARM-STDERR-NOT: warning:
+
+@ Incorrectly inverted condition on the second slot of an IT block
+  .section test5
+@ CHECK-LABEL: test5
+  itt eq
+  addeq r0, r0, #1
+  addne r0, r0, #1
+@ THUMB-STDERR: error: incorrect condition in IT block
+@ ARM-STDERR:   error: incorrect condition in IT block




More information about the llvm-commits mailing list