ARM thumb assembly parsing for arithmetic flag setting instructions.
authorJim Grosbach <grosbach@apple.com>
Tue, 16 Aug 2011 20:45:50 +0000 (20:45 +0000)
committerJim Grosbach <grosbach@apple.com>
Tue, 16 Aug 2011 20:45:50 +0000 (20:45 +0000)
Thumb one requires that many arithmetic instruction forms have an 'S'
suffix. For Thumb2, the whether the suffix is required or precluded depends
on whether the instruction is in an IT block. Use target parser predicates
to check for these sorts of context-sensitive constraints.

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

lib/Target/ARM/ARMInstrFormats.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
test/MC/ARM/mode-switch.s
test/MC/ARM/nop-thumb-padding.s
test/MC/ARM/nop-thumb2-padding.s

index ba378ed5fed88c6ec8f9396a03031fa3fdd0ec85..fecc6bfdef8451a33c69559e58c844243f39f96e 100644 (file)
@@ -236,6 +236,10 @@ class InstTemplate<AddrMode am, int sz, IndexMode im,
   Domain D = d;
   bit isUnaryDataProc = 0;
   bit canXformTo16Bit = 0;
+  // The instruction is a 16-bit flag setting Thumb instruction. Used
+  // by the parser to determine whether to require the 'S' suffix on the
+  // mnemonic (when not in an IT block) or preclude it (when in an IT block).
+  bit thumbArithFlagSetting = 0;
 
   // If this is a pseudo instruction, mark it isCodeGenOnly.
   let isCodeGenOnly = !eq(!cast<string>(f), "Pseudo");
@@ -247,6 +251,7 @@ class InstTemplate<AddrMode am, int sz, IndexMode im,
   let TSFlags{13}    = isUnaryDataProc;
   let TSFlags{14}    = canXformTo16Bit;
   let TSFlags{17-15} = D.Value;
+  let TSFlags{18}    = thumbArithFlagSetting;
 
   let Constraints = cstr;
   let Itinerary = itin;
@@ -895,6 +900,7 @@ class Thumb1sI<dag oops, dag iops, AddrMode am, int sz,
   let InOperandList = !con(iops, (ins pred:$p));
   let AsmString = !strconcat(opc, "${s}${p}", asm);
   let Pattern = pattern;
+  let thumbArithFlagSetting = 1;
   list<Predicate> Predicates = [IsThumb, IsThumb1Only];
 }
 
index 1f298b3759c1b16764edfcef19b965615da86072..afc1e251c0d7c8f4b909f0ad92b57d9dec069938 100644 (file)
@@ -78,6 +78,9 @@ class ARMAsmParser : public MCTargetAsmParser {
   bool isThumbOne() const {
     return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2) == 0;
   }
+  bool isThumbTwo() const {
+    return isThumb() && (STI.getFeatureBits() & ARM::FeatureThumb2);
+  }
   void SwitchMode() {
     unsigned FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb));
     setAvailableFeatures(FB);
@@ -146,6 +149,10 @@ class ARMAsmParser : public MCTargetAsmParser {
                           const SmallVectorImpl<MCParsedAsmOperand*> &Ops);
 
 public:
+  enum ARMMatchResultTy {
+    Match_RequiresITBlock = FIRST_TARGET_MATCH_RESULT_TY
+  };
+
   ARMAsmParser(MCSubtargetInfo &_STI, MCAsmParser &_Parser)
     : MCTargetAsmParser(), STI(_STI), Parser(_Parser) {
     MCAsmParserExtension::Initialize(_Parser);
@@ -160,6 +167,8 @@ public:
                         SmallVectorImpl<MCParsedAsmOperand*> &Operands);
   bool ParseDirective(AsmToken DirectiveID);
 
+  unsigned checkTargetMatchPredicate(MCInst &Inst);
+
   bool MatchAndEmitInstruction(SMLoc IDLoc,
                                SmallVectorImpl<MCParsedAsmOperand*> &Operands,
                                MCStreamer &Out);
@@ -2975,6 +2984,44 @@ processInstruction(MCInst &Inst,
   }
 }
 
+// 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.
+  MCInstrDesc &MCID = getInstDesc(Inst.getOpcode());
+  if (MCID.TSFlags & ARMII::ThumbArithFlagSetting) {
+    assert(MCID.hasOptionalDef() &&
+           "optionally flag setting instruction missing optional def operand");
+    assert(MCID.NumOperands == Inst.getNumOperands() &&
+           "operand count mismatch!");
+    // Find the optional-def operand (cc_out).
+    unsigned OpNo;
+    for (OpNo = 0;
+         !MCID.OpInfo[OpNo].isOptionalDef() && OpNo < MCID.NumOperands;
+         ++OpNo)
+      ;
+    // If we're parsing Thumb1, reject it completely.
+    if (isThumbOne() && Inst.getOperand(OpNo).getReg() != ARM::CPSR)
+      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)
+      return Match_RequiresITBlock;
+  }
+  return Match_Success;
+}
+
 bool ARMAsmParser::
 MatchAndEmitInstruction(SMLoc IDLoc,
                         SmallVectorImpl<MCParsedAsmOperand*> &Operands,
@@ -3013,9 +3060,11 @@ MatchAndEmitInstruction(SMLoc IDLoc,
     return Error(ErrorLoc, "invalid operand for instruction");
   }
   case Match_MnemonicFail:
-    return Error(IDLoc, "unrecognized instruction mnemonic");
+    return Error(IDLoc, "invalid instruction");
   case Match_ConversionFail:
     return Error(IDLoc, "unable to convert operands to instruction");
+  case Match_RequiresITBlock:
+    return Error(IDLoc, "instruction only valid inside IT block");
   }
 
   llvm_unreachable("Implement any new match types added!");
index 5fede1588b4f2bebb4c317426cba67430d1efc87..0a8fb6a03b6c18de927db0aeeaa2a247c6aaad00 100644 (file)
@@ -384,6 +384,12 @@ namespace ARMII {
     // a 16-bit Thumb instruction if certain conditions are met.
     Xform16Bit    = 1 << 14,
 
+    // ThumbArithFlagSetting - The instruction is a 16-bit flag setting Thumb
+    // instruction. Used by the parser to determine whether to require the 'S'
+    // suffix on the mnemonic (when not in an IT block) or preclude it (when
+    // in an IT block).
+    ThumbArithFlagSetting = 1 << 18,
+
     //===------------------------------------------------------------------===//
     // Code domain.
     DomainShift   = 15,
index 4cc986a3e173442c8d5a91680df70fd233dee810..54e23f1b5c74650c9ae4f8ed1f2c7b51e15b91c2 100644 (file)
@@ -4,14 +4,14 @@
 
 .code 16
 
-@ CHECK:       add.w   r0, r0, r1              @ encoding: [0x00,0xeb,0x01,0x00]
+@ CHECK: add.w r0, r0, r1              @ encoding: [0x00,0xeb,0x01,0x00]
        add.w   r0, r0, r1
 
 .code 32
-@ CHECK:       add     r0, r0, r1              @ encoding: [0x01,0x00,0x80,0xe0]
+@ CHECK: add   r0, r0, r1              @ encoding: [0x01,0x00,0x80,0xe0]
        add     r0, r0, r1
 
 .code 16
-@ CHECK:       add     r0, r0, r1              @ encoding: [0x40,0x18]
-        
-        add     r0, r0, r1
+@ CHECK: adds  r0, r0, r1              @ encoding: [0x40,0x18]
+
+        adds    r0, r0, r1
index c7ef1fd59b5f595220eae3eae3884ee552e47b94..1e173f1a42d9b08024813a6d12f17bab2cde5406 100644 (file)
@@ -5,8 +5,8 @@
 .thumb_func x
 .code 16
 x:
-      add r0, r1, r2
+      adds r0, r1, r2
       .align 4
-      add r0, r1, r2
+      adds r0, r1, r2
 
 @ CHECK: ('_section_data', '8818c046 c046c046 c046c046 c046c046 8818')
index e1570c987fdf195c2a1a6b91471ed8d2fec02b6e..a8aa3a1168efe94f7201ce07665c7742f5fdff90 100644 (file)
@@ -5,8 +5,8 @@
 .thumb_func x
 .code 16
 x:
-      add r0, r1, r2
+      adds r0, r1, r2
       .align 4
-      add r0, r1, r2
+      adds r0, r1, r2
 
 @ CHECK: ('_section_data', '881800bf 00bf00bf 00bf00bf 00bf00bf 8818')