diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td
index ba378ed5fed8..fecc6bfdef84 100644
--- a/llvm/lib/Target/ARM/ARMInstrFormats.td
+++ b/llvm/lib/Target/ARM/ARMInstrFormats.td
@@ -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];
 }
 
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 1f298b3759c1..afc1e251c0d7 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -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!");
diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
index 5fede1588b4f..0a8fb6a03b6c 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
@@ -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,
diff --git a/llvm/test/MC/ARM/mode-switch.s b/llvm/test/MC/ARM/mode-switch.s
index 4cc986a3e173..54e23f1b5c74 100644
--- a/llvm/test/MC/ARM/mode-switch.s
+++ b/llvm/test/MC/ARM/mode-switch.s
@@ -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
diff --git a/llvm/test/MC/ARM/nop-thumb-padding.s b/llvm/test/MC/ARM/nop-thumb-padding.s
index c7ef1fd59b5f..1e173f1a42d9 100644
--- a/llvm/test/MC/ARM/nop-thumb-padding.s
+++ b/llvm/test/MC/ARM/nop-thumb-padding.s
@@ -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')
diff --git a/llvm/test/MC/ARM/nop-thumb2-padding.s b/llvm/test/MC/ARM/nop-thumb2-padding.s
index e1570c987fdf..a8aa3a1168ef 100644
--- a/llvm/test/MC/ARM/nop-thumb2-padding.s
+++ b/llvm/test/MC/ARM/nop-thumb2-padding.s
@@ -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')