Skip to content
ARMInstrInfo.td 58.7 KiB
Newer Older
// Zero extenders
let AddedComplexity = 16 in {
defm UXTB   : AI_unary_rrot<0x0, "uxtb"  , UnOpFrag<(and node:$Src, 0x000000FF)>>;
defm UXTH   : AI_unary_rrot<0x0, "uxth"  , UnOpFrag<(and node:$Src, 0x0000FFFF)>>;
defm UXTB16 : AI_unary_rrot<0x0, "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>;
def : ARMV6Pat<(and (shl GPR:$Src, 8), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 24)>;
def : ARMV6Pat<(and (srl GPR:$Src, 8), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 8)>;

defm UXTAB : AI_bin_rrot<0x0, "uxtab",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
defm UXTAH : AI_bin_rrot<0x0, "uxtah",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>;
// This isn't safe in general, the add is two 16-bit units, not a 32-bit add.
//defm UXTAB16 : xxx<"uxtab16", 0xff00ff>;
// TODO: UXT(A){B|H}16

//===----------------------------------------------------------------------===//
//  Arithmetic Instructions.
//

defm ADD  : AsI1_bin_irs<0x4, "add", BinOpFrag<(add  node:$LHS, node:$RHS)>>;
defm SUB  : AsI1_bin_irs<0x2, "sub", BinOpFrag<(sub  node:$LHS, node:$RHS)>>;
defm ADDS : ASI1_bin_s_irs<0x4, "add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
defm SUBS : ASI1_bin_s_irs<0x2, "sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
// FIXME: Do not allow ADC / SBC to be predicated for now.
defm ADC  : AsXI1_bin_c_irs<0x5, "adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
defm SBC  : AsXI1_bin_c_irs<0x6, "sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
// These don't define reg/reg forms, because they are handled above.
def RSBri : AsI1<0x3, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPRIm,
                  "rsb", " $dst, $a, $b",
                  [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]>;

def RSBrs : AsI1<0x3, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPRSoReg,
                  "rsb", " $dst, $a, $b",
                  [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]>;
def RSBSri : AI1<0x3, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPRIm,
                 [(set GPR:$dst, (subc so_imm:$b, GPR:$a))]>;
def RSBSrs : AI1<0x3, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPRSoReg,
                 [(set GPR:$dst, (subc so_reg:$b, GPR:$a))]>;
}
// FIXME: Do not allow RSC to be predicated for now. But they can set CPSR.
def RSCri : AXI1<0x7, (outs GPR:$dst), (ins GPR:$a, so_imm:$b, cc_out:$s),
                 DPRIm, "rsc${s} $dst, $a, $b",
                 [(set GPR:$dst, (sube so_imm:$b, GPR:$a))]>;
def RSCrs : AXI1<0x7, (outs GPR:$dst), (ins GPR:$a, so_reg:$b, cc_out:$s),
                 DPRSoReg, "rsc${s} $dst, $a, $b",
                 [(set GPR:$dst, (sube so_reg:$b, GPR:$a))]>;
}
// (sub X, imm) gets canonicalized to (add X, -imm).  Match this form.
def : ARMPat<(add    GPR:$src, so_imm_neg:$imm),
             (SUBri  GPR:$src, so_imm_neg:$imm)>;
//def : ARMPat<(addc   GPR:$src, so_imm_neg:$imm),
//             (SUBSri GPR:$src, so_imm_neg:$imm)>;
//def : ARMPat<(adde   GPR:$src, so_imm_neg:$imm),
//             (SBCri  GPR:$src, so_imm_neg:$imm)>;
Rafael Espindola's avatar
Rafael Espindola committed

// Note: These are implemented in C++ code, because they have to generate
// ADD/SUBrs instructions, which use a complex pattern that a xform function
// cannot produce.
// (mul X, 2^n+1) -> (add (X << n), X)
// (mul X, 2^n-1) -> (rsb X, (X << n))
//===----------------------------------------------------------------------===//
//  Bitwise Instructions.
//
defm AND   : AsI1_bin_irs<0x0, "and", BinOpFrag<(and node:$LHS, node:$RHS)>>;
defm ORR   : AsI1_bin_irs<0xC, "orr", BinOpFrag<(or  node:$LHS, node:$RHS)>>;
defm EOR   : AsI1_bin_irs<0x1, "eor", BinOpFrag<(xor node:$LHS, node:$RHS)>>;
defm BIC   : AsI1_bin_irs<0xE, "bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
def  MVNr  : AsI<0xE, (outs GPR:$dst), (ins GPR:$src), DPRdReg,
                 "mvn", " $dst, $src", [(set GPR:$dst, (not GPR:$src))]>;
def  MVNs  : AsI<0xE, (outs GPR:$dst), (ins so_reg:$src), DPRdSoReg,
                 "mvn", " $dst, $src", [(set GPR:$dst, (not so_reg:$src))]>;
def  MVNi  : AsI<0xE, (outs GPR:$dst), (ins so_imm:$imm), DPRdIm,
                 "mvn", " $dst, $imm", [(set GPR:$dst, so_imm_not:$imm)]>;
def : ARMPat<(and   GPR:$src, so_imm_not:$imm),
             (BICri GPR:$src, so_imm_not:$imm)>;
//===----------------------------------------------------------------------===//
//  Multiply Instructions.
//
def MUL  : AsI<0x0, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulFrm,
               "mul", " $dst, $a, $b",
               [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
def MLA  : AsI<0x2, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               MulFrm, "mla", " $dst, $a, $b, $c",
               [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>;

// Extra precision multiplies with low / high results
def SMULL : AsI<0xC, (outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b),
                MulFrm, "smull", " $ldst, $hdst, $a, $b", []>;
def UMULL : AsI<0x8, (outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b),
                MulFrm, "umull", " $ldst, $hdst, $a, $b", []>;

// Multiply + accumulate
def SMLAL : AsI<0xE, (outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b),
                MulFrm, "smlal", " $ldst, $hdst, $a, $b", []>;
def UMLAL : AsI<0xA, (outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b),
                MulFrm, "umlal", " $ldst, $hdst, $a, $b", []>;
def UMAAL : AI<0x0, (outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), MulFrm,
               "umaal", " $ldst, $hdst, $a, $b", []>,
            Requires<[IsARM, HasV6]>;

// Most significant word multiply
def SMMUL : AI<0x0, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulFrm,
               "smmul", " $dst, $a, $b",
               [(set GPR:$dst, (mulhs GPR:$a, GPR:$b))]>,
            Requires<[IsARM, HasV6]>;

def SMMLA : AI<0x0, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), MulFrm,
               "smmla", " $dst, $a, $b, $c",
               [(set GPR:$dst, (add (mulhs GPR:$a, GPR:$b), GPR:$c))]>,
            Requires<[IsARM, HasV6]>;
def SMMLS : AI<0x0, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), MulFrm,
               [(set GPR:$dst, (sub GPR:$c, (mulhs GPR:$a, GPR:$b)))]>,
               Requires<[IsARM, HasV6]>;

multiclass AI_smul<string opc, PatFrag opnode> {
  def BB : AI<0x8, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMUL,
              !strconcat(opc, "bb"), " $dst, $a, $b",
              [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),
                                      (sext_inreg GPR:$b, i16)))]>,
           Requires<[IsARM, HasV5TE]>;

  def BT : AI<0xC, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMUL,
              !strconcat(opc, "bt"), " $dst, $a, $b",
              [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),
                                      (sra GPR:$b, 16)))]>,
           Requires<[IsARM, HasV5TE]>;

  def TB : AI<0xA, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMUL,
              !strconcat(opc, "tb"), " $dst, $a, $b",
              [(set GPR:$dst, (opnode (sra GPR:$a, 16),
                                      (sext_inreg GPR:$b, i16)))]>,
           Requires<[IsARM, HasV5TE]>;

  def TT : AI<0xE, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMUL,
              !strconcat(opc, "tt"), " $dst, $a, $b",
              [(set GPR:$dst, (opnode (sra GPR:$a, 16),
                                      (sra GPR:$b, 16)))]>,
            Requires<[IsARM, HasV5TE]>;

  def WB : AI<0xA, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMULW,
              !strconcat(opc, "wb"), " $dst, $a, $b",
              [(set GPR:$dst, (sra (opnode GPR:$a,
                                    (sext_inreg GPR:$b, i16)), 16))]>,
           Requires<[IsARM, HasV5TE]>;

  def WT : AI<0xE, (outs GPR:$dst), (ins GPR:$a, GPR:$b), MulSMULW,
              !strconcat(opc, "wt"), " $dst, $a, $b",
              [(set GPR:$dst, (sra (opnode GPR:$a,
                                    (sra GPR:$b, 16)), 16))]>,
            Requires<[IsARM, HasV5TE]>;
}

multiclass AI_smla<string opc, PatFrag opnode> {
  def BB : AI<0x8, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLA,
              !strconcat(opc, "bb"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc,
                               (opnode (sext_inreg GPR:$a, i16),
                                       (sext_inreg GPR:$b, i16))))]>,
           Requires<[IsARM, HasV5TE]>;

  def BT : AI<0xC, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLA,
              !strconcat(opc, "bt"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (opnode (sext_inreg GPR:$a, i16),
                                                     (sra GPR:$b, 16))))]>,

  def TB : AI<0xA, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLA,
              !strconcat(opc, "tb"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, 16),
                                                 (sext_inreg GPR:$b, i16))))]>,
           Requires<[IsARM, HasV5TE]>;

  def TT : AI<0xE, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLA,
              !strconcat(opc, "tt"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, 16),
                                                     (sra GPR:$b, 16))))]>,
            Requires<[IsARM, HasV5TE]>;

  def WB : AI<0xA, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLAW,
              !strconcat(opc, "wb"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
                                            (sext_inreg GPR:$b, i16)), 16)))]>,
           Requires<[IsARM, HasV5TE]>;

  def WT : AI<0xE, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), MulSMLAW,
              !strconcat(opc, "wt"), " $dst, $a, $b, $acc",
              [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a,
                                                   (sra GPR:$b, 16)), 16)))]>,
            Requires<[IsARM, HasV5TE]>;
}
defm SMUL : AI_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
defm SMLA : AI_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
// TODO: Halfword multiple accumulate long: SMLAL<x><y>
// TODO: Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
//===----------------------------------------------------------------------===//
//  Misc. Arithmetic Instructions.
//
def CLZ  : AI<0x0, (outs GPR:$dst), (ins GPR:$src), ArithMisc,
              [(set GPR:$dst, (ctlz GPR:$src))]>, Requires<[IsARM, HasV5T]>;

def REV  : AI<0x0, (outs GPR:$dst), (ins GPR:$src), ArithMisc,
              [(set GPR:$dst, (bswap GPR:$src))]>, Requires<[IsARM, HasV6]>;

def REV16 : AI<0x0, (outs GPR:$dst), (ins GPR:$src), ArithMisc,
               [(set GPR:$dst,
                   (or (and (srl GPR:$src, 8), 0xFF),
                       (or (and (shl GPR:$src, 8), 0xFF00),
                           (or (and (srl GPR:$src, 8), 0xFF0000),
                               (and (shl GPR:$src, 8), 0xFF000000)))))]>,
               Requires<[IsARM, HasV6]>;

def REVSH : AI<0x0, (outs GPR:$dst), (ins GPR:$src), ArithMisc,
               [(set GPR:$dst,
                  (sext_inreg
                        (shl GPR:$src, 8)), i16))]>,
               Requires<[IsARM, HasV6]>;

def PKHBT : AI<0x0, (outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               Pseudo, "pkhbt", " $dst, $src1, $src2, LSL $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF),
                                   (and (shl GPR:$src2, (i32 imm:$shamt)),
                                        0xFFFF0000)))]>,
               Requires<[IsARM, HasV6]>;

// Alternate cases for PKHBT where identities eliminate some nodes.
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)),
               (PKHBT GPR:$src1, GPR:$src2, 0)>;
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$shamt)),
               (PKHBT GPR:$src1, GPR:$src2, imm16_31:$shamt)>;


def PKHTB : AI<0x0, (outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               Pseudo, "pkhtb", " $dst, $src1, $src2, ASR $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000),
                                   (and (sra GPR:$src2, imm16_31:$shamt),
                                        0xFFFF)))]>, Requires<[IsARM, HasV6]>;

// Alternate cases for PKHTB where identities eliminate some nodes.  Note that
// a shift amount of 0 is *not legal* here, it is PKHBT instead.
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, 16)),
               (PKHTB GPR:$src1, GPR:$src2, 16)>;
def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000),
                   (and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)),
               (PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>;
//===----------------------------------------------------------------------===//
//  Comparison Instructions...
//

defm CMP  : AI1_cmp_irs<0xA, "cmp",
                        BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
defm CMN  : AI1_cmp_irs<0xB, "cmn",
                        BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;

// Note that TST/TEQ don't set all the same flags that CMP does!
defm TST  : AI1_cmp_irs<0x8, "tst",
                        BinOpFrag<(ARMcmpNZ (and node:$LHS, node:$RHS), 0)>>;
defm TEQ  : AI1_cmp_irs<0x9, "teq",
                        BinOpFrag<(ARMcmpNZ (xor node:$LHS, node:$RHS), 0)>>;
defm CMPnz : AI1_cmp_irs<0xA, "cmp",
                         BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>;
defm CMNnz : AI1_cmp_irs<0xA, "cmn",
                         BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>;

def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm),
             (CMNri  GPR:$src, so_imm_neg:$imm)>;

def : ARMPat<(ARMcmpNZ GPR:$src, so_imm_neg:$imm),
             (CMNri  GPR:$src, so_imm_neg:$imm)>;


// Conditional moves
// FIXME: should be able to write a pattern for ARMcmov, but can't use
// a two-value operand where a dag node expects two operands. :( 
def MOVCCr : AI<0xD, (outs GPR:$dst), (ins GPR:$false, GPR:$true),
                DPRdReg, "mov", " $dst, $true",
      [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">;
def MOVCCs : AI<0xD, (outs GPR:$dst), (ins GPR:$false, so_reg:$true),
                DPRdSoReg, "mov", " $dst, $true",
   [/*(set GPR:$dst, (ARMcmov GPR:$false, so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">;
def MOVCCi : AI<0xD, (outs GPR:$dst), (ins GPR:$false, so_imm:$true),
                DPRdIm, "mov", " $dst, $true",
   [/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">;


// LEApcrel - Load a pc-relative address into a register without offending the
// assembler.
def LEApcrel : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, pred:$p), Pseudo,
                   !strconcat(!strconcat(".set PCRELV${:uid}, ($label-(",
                                         "${:private}PCRELL${:uid}+8))\n"),
                              !strconcat("${:private}PCRELL${:uid}:\n\t",
                                         "add$p $dst, pc, #PCRELV${:uid}")),
def LEApcrelJT : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, i32imm:$id, pred:$p),
          Pseudo,
          !strconcat(!strconcat(".set PCRELV${:uid}, (${label}_${id:no_hash}-(",
                                         "${:private}PCRELL${:uid}+8))\n"),
                              !strconcat("${:private}PCRELL${:uid}:\n\t",
                                         "add$p $dst, pc, #PCRELV${:uid}")),
//===----------------------------------------------------------------------===//
// TLS Instructions
//

// __aeabi_read_tp preserves the registers r1-r3.
  def TPsoft : AXI<0x0, (outs), (ins), BranchMisc,
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//
// ConstantPool, GlobalAddress, and JumpTable
def : ARMPat<(ARMWrapper  tglobaladdr :$dst), (LEApcrel tglobaladdr :$dst)>;
def : ARMPat<(ARMWrapper  tconstpool  :$dst), (LEApcrel tconstpool  :$dst)>;
def : ARMPat<(ARMWrapperJT tjumptable:$dst, imm:$id),
             (LEApcrelJT tjumptable:$dst, imm:$id)>;
// Large immediate handling.
Rafael Espindola's avatar
Rafael Espindola committed

// Two piece so_imms.
def MOVi2pieces : AI1x2<0x0, (outs GPR:$dst), (ins so_imm2part:$src), DPRdMisc,
                         [(set GPR:$dst, so_imm2part:$src)]>;
def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS),
              (ORRri (ORRri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
                     (so_imm2part_2 imm:$RHS))>;
def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS),
              (EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
                     (so_imm2part_2 imm:$RHS))>;
Rafael Espindola's avatar
Rafael Espindola committed

// TODO: add,sub,and, 3-instr forms?
Rafael Espindola's avatar
Rafael Espindola committed

// Direct calls
def : ARMPat<(ARMcall texternalsym:$func), (BL texternalsym:$func)>;
// zextload i1 -> zextload i8
def : ARMPat<(zextloadi1 addrmode2:$addr),  (LDRB addrmode2:$addr)>;
// extload -> zextload
def : ARMPat<(extloadi1  addrmode2:$addr),  (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi8  addrmode2:$addr),  (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi16 addrmode3:$addr),  (LDRH addrmode3:$addr)>;
// truncstore i1 -> truncstore i8
def : ARMPat<(truncstorei1 GPR:$src, addrmode2:$dst), 
Dale Johannesen's avatar
Dale Johannesen committed
             (STRB GPR:$src, addrmode2:$dst)>;
def : ARMPat<(pre_truncsti1 GPR:$src, GPR:$base, am2offset:$offset), 
Dale Johannesen's avatar
Dale Johannesen committed
             (STRB_PRE GPR:$src, GPR:$base, am2offset:$offset)>;
def : ARMPat<(post_truncsti1 GPR:$src, GPR:$base, am2offset:$offset), 
Dale Johannesen's avatar
Dale Johannesen committed
             (STRB_POST GPR:$src, GPR:$base, am2offset:$offset)>;
// smul* and smla*
def : ARMV5TEPat<(mul (sra (shl GPR:$a, 16), 16), (sra (shl GPR:$b, 16), 16)),
                 (SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, sext_16_node:$b),
                 (SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra (shl GPR:$a, 16), 16), (sra GPR:$b, 16)),
                 (SMULBT GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, (sra GPR:$b, 16)),
                 (SMULBT GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra GPR:$a, 16), (sra (shl GPR:$b, 16), 16)),
                 (SMULTB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra GPR:$a, 16), sext_16_node:$b),
                (SMULTB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(sra (mul GPR:$a, (sra (shl GPR:$b, 16), 16)), 16),
                 (SMULWB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(sra (mul GPR:$a, sext_16_node:$b), 16),
                 (SMULWB GPR:$a, GPR:$b)>;

def : ARMV5TEPat<(add GPR:$acc,
                      (mul (sra (shl GPR:$a, 16), 16),
                           (sra (shl GPR:$b, 16), 16))),
                 (SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (mul sext_16_node:$a, sext_16_node:$b)),
                 (SMLABB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (mul (sra (shl GPR:$a, 16), 16), (sra GPR:$b, 16))),
                 (SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (mul sext_16_node:$a, (sra GPR:$b, 16))),
                 (SMLABT GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (mul (sra GPR:$a, 16), (sra (shl GPR:$b, 16), 16))),
                 (SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (mul (sra GPR:$a, 16), sext_16_node:$b)),
                 (SMLATB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (sra (mul GPR:$a, (sra (shl GPR:$b, 16), 16)), 16)),
                 (SMLAWB GPR:$a, GPR:$b, GPR:$acc)>;
def : ARMV5TEPat<(add GPR:$acc,
                      (sra (mul GPR:$a, sext_16_node:$b), 16)),
                 (SMLAWB GPR:$a, GPR:$b, GPR:$acc)>;

//===----------------------------------------------------------------------===//
// Thumb Support
//
include "ARMInstrThumb.td"
//===----------------------------------------------------------------------===//
// Floating Point Support
//
include "ARMInstrVFP.td"