/* Pointer to a linked list of literal pools.  */
 literal_pool * list_of_pools = NULL;
+
+/* State variables for IT block handling.  */
+static bfd_boolean current_it_mask = 0;
+static int current_cc;
+
 \f
 /* Pure syntax.         */
 
     {
       if (!inst.operands[2].isreg)
        {
+         /* ??? Convert large immediates to addw/subw.  */
+         /* ??? 16-bit adds with small immediates.  */
          /* For an immediate, we always generate a 32-bit opcode;
             section relaxation will shrink it later if possible.  */
          inst.instruction = THUMB_OP32 (inst.instruction);
          /* See if we can do this with a 16-bit instruction.  */
          if (!inst.operands[2].shifted && inst.size_req != 4)
            {
-             if (Rd <= 7 && Rn <= 7 && Rn <= 7
-                 && (inst.instruction == T_MNEM_adds
-                     || inst.instruction == T_MNEM_subs))
+             bfd_boolean narrow;
+
+             if (inst.instruction == T_MNEM_adds
+                 || inst.instruction == T_MNEM_subs)
+               narrow = (current_it_mask == 0);
+             else
+               narrow = (current_it_mask != 0);
+             if (Rd > 7 || Rs > 7 || Rn > 7)
+               narrow = FALSE;
+
+             if (narrow)
                {
-                 inst.instruction = (inst.instruction == T_MNEM_adds
+                 inst.instruction = ((inst.instruction == T_MNEM_adds
+                                      || inst.instruction == T_MNEM_add)
                                      ? T_OPCODE_ADD_R3
                                      : T_OPCODE_SUB_R3);
                  inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
        }
       else
        {
+         bfd_boolean narrow;
+
          /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction)
-             && !inst.operands[2].shifted
-             && inst.size_req != 4
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = current_it_mask == 0;
+         else
+           narrow = current_it_mask != 0;
+
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (narrow
              && Rd == Rs)
            {
              inst.instruction = THUMB_OP16 (inst.instruction);
        }
       else
        {
+         bfd_boolean narrow;
+
          /* See if we can do this with a 16-bit instruction.  */
-         if (THUMB_SETS_FLAGS (inst.instruction)
-             && !inst.operands[2].shifted
-             && inst.size_req != 4)
+         if (THUMB_SETS_FLAGS (inst.instruction))
+           narrow = current_it_mask == 0;
+         else
+           narrow = current_it_mask != 0;
+
+         if (Rd > 7 || Rn > 7 || Rs > 7)
+           narrow = FALSE;
+         if (inst.operands[2].shifted)
+           narrow = FALSE;
+         if (inst.size_req == 4)
+           narrow = FALSE;
+
+         if (narrow)
            {
              if (Rd == Rs)
                {
 do_t_it (void)
 {
   unsigned int cond = inst.operands[0].imm;
+
+  current_it_mask = (inst.instruction & 0xf) | 0x10;
+  current_cc = cond;
+
+  /* If the condition is a negative condition, invert the mask.  */
   if ((cond & 0x1) == 0x0)
     {
       unsigned int mask = inst.instruction & 0x000f;
-      inst.instruction &= 0xfff0;
 
       if ((mask & 0x7) == 0)
        /* no conversion needed */;
       else if ((mask & 0x3) == 0)
-       mask = (~(mask & 0x8) & 0x8) | 0x4;
-      else if ((mask & 1) == 0)
-       mask = (~(mask & 0xC) & 0xC) | 0x2;
+       mask ^= 0x8;
+      else if ((mask & 0x1) == 0)
+       mask ^= 0xC;
       else
-       mask = (~(mask & 0xE) & 0xE) | 0x1;
+       mask ^= 0xE;
 
-      inst.instruction |= (mask & 0xF);
+      inst.instruction &= 0xfff0;
+      inst.instruction |= mask;
     }
 
   inst.instruction |= cond << 4;
          return;
        }
 
+      /* Check conditional suffixes.  */
+      if (current_it_mask)
+       {
+         int cond;
+         cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
+         if (cond != inst.cond)
+           {
+             as_bad (_("incorrect condition in IT block"));
+             return;
+           }
+         current_it_mask <<= 1;
+         current_it_mask &= 0x1f;
+       }
+      else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
+       {
+         as_bad (_("thumb conditional instrunction not in IT block"));
+         return;
+       }
+
       mapping_state (MAP_THUMB);
       inst.instruction = opcode->tvalue;
 
       if (!parse_operands (p, opcode->operands))
        opcode->tencode ();
 
+      /* Clear current_it_mask at the end of an IT block.  */
+      if (current_it_mask == 0x10)
+       current_it_mask = 0;
+
       if (!inst.error)
        {
          assert (inst.instruction < 0xe800 || inst.instruction > 0xffff);