Skip to content
ARMInstrInfo.td 121 KiB
Newer Older
          D0,  D1,  D2,  D3,  D4,  D5,  D6,  D7,
          D16, D17, D18, D19, D20, D21, D22, D23,
David Goodwin's avatar
David Goodwin committed
          D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR] in {
  def BLr9  : ABXI<0b1011, (outs), (ins i32imm:$func, variable_ops),
                [(ARMcall tglobaladdr:$func)]>, Requires<[IsARM, IsDarwin]> {
    let Inst{31-28} = 0b1110;
  }

  def BLr9_pred : ABI<0b1011, (outs), (ins i32imm:$func, variable_ops),
                   [(ARMcall_pred tglobaladdr:$func)]>,
                  Requires<[IsARM, IsDarwin]>;

  // ARMv5T and above
  def BLXr9 : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm,
                [(ARMcall GPR:$func)]>, Requires<[IsARM, HasV5T, IsDarwin]> {
    let Inst{7-4}   = 0b0011;
    let Inst{19-8}  = 0b111111111111;
    let Inst{27-20} = 0b00010010;
  }

  // Note: Restrict $func to the tGPR regclass to prevent it being in LR.
  def BXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                  [(ARMcall_nolink tGPR:$func)]>,
             Requires<[IsARM, HasV4T, IsDarwin]> {
    let Inst{7-4}   = 0b0001;
    let Inst{19-8}  = 0b111111111111;
    let Inst{27-20} = 0b00010010;

  // ARMv4
  def BMOVPCRXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                 IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
                 [(ARMcall_nolink tGPR:$func)]>,
           Requires<[IsARM, NoV4T, IsDarwin]> {
    let Inst{11-4}  = 0b00000000;
    let Inst{15-12} = 0b1111;
    let Inst{19-16} = 0b0000;
    let Inst{27-20} = 0b00011010;
  }
// Tail calls.

let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
  // Darwin versions.
  let Defs = [R0, R1, R2, R3, R9, R12,
              D0, D1, D2, D3, D4, D5, D6, D7,
              D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26,
              D27, D28, D29, D30, D31, PC],
      Uses = [SP] in {
    def TCRETURNdi : AInoP<(outs), (ins i32imm:$dst, variable_ops),
                       Pseudo, IIC_Br,
                       "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>;

    def TCRETURNri : AInoP<(outs), (ins tcGPR:$dst, variable_ops),
                       Pseudo, IIC_Br,
                       "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>;

    def TAILJMPd : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
                   IIC_Br, "b\t$dst  @ TAILCALL",
                   []>, Requires<[IsDarwin]>;

    def TAILJMPdt: ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
                   IIC_Br, "b.w\t$dst  @ TAILCALL",
                   []>, Requires<[IsDarwin]>;

    def TAILJMPr : AXI<(outs), (ins tcGPR:$dst, variable_ops),
                     BrMiscFrm, IIC_Br, "bx\t$dst  @ TAILCALL",
                   []>, Requires<[IsDarwin]> {
                   let Inst{7-4}   = 0b0001;
                   let Inst{19-8}  = 0b111111111111;
                   let Inst{27-20} = 0b00010010;
                   let Inst{31-28} = 0b1110;
    }
  }

  // Non-Darwin versions (the difference is R9).
  let Defs = [R0, R1, R2, R3, R12,
              D0, D1, D2, D3, D4, D5, D6, D7,
              D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26,
              D27, D28, D29, D30, D31, PC],
      Uses = [SP] in {
    def TCRETURNdiND : AInoP<(outs), (ins i32imm:$dst, variable_ops),
                       Pseudo, IIC_Br,
                       "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>;

    def TCRETURNriND : AInoP<(outs), (ins tcGPR:$dst, variable_ops),
                       Pseudo, IIC_Br,
                       "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>;

    def TAILJMPdND : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
                   IIC_Br, "b\t$dst  @ TAILCALL",
                   []>, Requires<[IsARM, IsNotDarwin]>;

    def TAILJMPdNDt : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
                   IIC_Br, "b.w\t$dst  @ TAILCALL",
                   []>, Requires<[IsThumb, IsNotDarwin]>;

    def TAILJMPrND : AXI<(outs), (ins tcGPR:$dst, variable_ops),
                     BrMiscFrm, IIC_Br, "bx\t$dst  @ TAILCALL",
                   []>, Requires<[IsNotDarwin]> {
                   let Inst{7-4}   = 0b0001;
                   let Inst{19-8}  = 0b111111111111;
                   let Inst{27-20} = 0b00010010;
                   let Inst{31-28} = 0b1110;
    }
  // B is "predicable" since it can be xformed into a Bcc.
  let isBarrier = 1 in {
    def B : ABXI<0b1010, (outs), (ins brtarget:$target), IIC_Br,
  let isNotDuplicable = 1, isIndirectBranch = 1 in {
  def BR_JTr : JTI<(outs), (ins GPR:$target, jtblock_operand:$jt, i32imm:$id),
                    [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]> {
    let Inst{20}    = 0; // S Bit
    let Inst{24-21} = 0b1101;
    let Inst{27-25} = 0b000;
  def BR_JTm : JTI<(outs),
                   (ins addrmode2:$target, jtblock_operand:$jt, i32imm:$id),
                   [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt,
                     imm:$id)]> {
    let Inst{20}    = 1; // L bit
    let Inst{21}    = 0; // W bit
    let Inst{22}    = 0; // B bit
    let Inst{24}    = 1; // P bit
    let Inst{27-25} = 0b011;
  def BR_JTadd : JTI<(outs),
                   (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, i32imm:$id),
                    IIC_Br, "add\tpc, $target, $idx$jt",
                    [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt,
                      imm:$id)]> {
    let Inst{20}    = 0; // S bit
    let Inst{24-21} = 0b0100;
    let Inst{27-25} = 0b000;
  }
  } // isNotDuplicable = 1, isIndirectBranch = 1
  } // isBarrier = 1
  // FIXME: should be able to write a pattern for ARMBrcond, but can't use
Jim Grosbach's avatar
Jim Grosbach committed
  // a two-value operand where a dag node expects two operands. :(
  def Bcc : ABI<0b1010, (outs), (ins brtarget:$target),
               [/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]>;
// Branch and Exchange Jazelle -- for disassembly only
def BXJ : ABI<0b0001, (outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0010;
  //let Inst{19-8} = 0xfff;
  let Inst{7-4} = 0b0010;
}

// Secure Monitor Call is a system instruction -- for disassembly only
def SMC : ABI<0b0001, (outs), (ins i32imm:$opt), NoItinerary, "smc", "\t$opt",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0110;
  let Inst{7-4} = 0b0111;
}

// Supervisor Call (Software Interrupt) -- for disassembly only
let isCall = 1 in {
def SVC : ABI<0b1111, (outs), (ins i32imm:$svc), IIC_Br, "svc", "\t$svc",
              [/* For disassembly only; pattern left blank */]>;
}

// Store Return State is a system instruction -- for disassembly only
def SRSW : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, i32imm:$mode),
                NoItinerary, "srs${addr:submode}\tsp!, $mode",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b110; // W = 1
}

def SRS  : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, i32imm:$mode),
                NoItinerary, "srs${addr:submode}\tsp, $mode",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b100; // W = 0
}

// Return From Exception is a system instruction -- for disassembly only
def RFEW : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base),
                NoItinerary, "rfe${addr:submode}\t$base!",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b011; // W = 1
}

def RFE  : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base),
                NoItinerary, "rfe${addr:submode}\t$base",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b001; // W = 0
}

//===----------------------------------------------------------------------===//
//  Load / store Instructions.
//
Rafael Espindola's avatar
Rafael Espindola committed

let canFoldAsLoad = 1, isReMaterializable = 1 in
def LDR  : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr,
               [(set GPR:$dst, (load addrmode2:$addr))]>;

// Special LDR for loads from non-pc-relative constpools.
let canFoldAsLoad = 1, mayLoad = 1, neverHasSideEffects = 1,
    isReMaterializable = 1 in
def LDRcp : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr,
// Loads with zero extension
def LDRH  : AI3ldh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                  IIC_iLoadr, "ldrh", "\t$dst, $addr",
                  [(set GPR:$dst, (zextloadi16 addrmode3:$addr))]>;
Jim Grosbach's avatar
Jim Grosbach committed
def LDRB  : AI2ldb<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm,
                  IIC_iLoadr, "ldrb", "\t$dst, $addr",
                  [(set GPR:$dst, (zextloadi8 addrmode2:$addr))]>;

// Loads with sign extension
def LDRSH : AI3ldsh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                   IIC_iLoadr, "ldrsh", "\t$dst, $addr",
                   [(set GPR:$dst, (sextloadi16 addrmode3:$addr))]>;
def LDRSB : AI3ldsb<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                   IIC_iLoadr, "ldrsb", "\t$dst, $addr",
                   [(set GPR:$dst, (sextloadi8 addrmode3:$addr))]>;
let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in {
// Load doubleword
Evan Cheng's avatar
Evan Cheng committed
def LDRD : AI3ldd<(outs GPR:$dst1, GPR:$dst2), (ins addrmode3:$addr), LdMiscFrm,
                 IIC_iLoadr, "ldrd", "\t$dst1, $addr",
                 []>, Requires<[IsARM, HasV5TE]>;

// Indexed loads
def LDR_PRE  : AI2ldwpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoadru,
                     "ldr", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDR_POST : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru,
                     "ldr", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRH_PRE  : AI3ldhpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                     "ldrh", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRH_POST : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                    "ldrh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRB_PRE  : AI2ldbpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoadru,
                     "ldrb", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRB_POST : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb),
                     (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru,
                    "ldrb", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSH_PRE : AI3ldshpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                      "ldrsh", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRSH_POST: AI3ldshpo<(outs GPR:$dst, GPR:$base_wb),
                      (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                   "ldrsh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSB_PRE : AI3ldsbpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru,
                      "ldrsb", "\t$dst, $addr!", "$addr.base = $base_wb", []>;
def LDRSB_POST: AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb),
                      (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                   "ldrsb", "\t$dst, [$base], $offset", "$base = $base_wb", []>;

// For disassembly only
def LDRD_PRE : AI3lddpr<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb),
                        (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadr,
                 "ldrd", "\t$dst1, $dst2, $addr!", "$addr.base = $base_wb", []>,
                Requires<[IsARM, HasV5TE]>;

// For disassembly only
def LDRD_POST : AI3lddpo<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb),
                       (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadr,
            "ldrd", "\t$dst1, $dst2, [$base], $offset", "$base = $base_wb", []>,
                Requires<[IsARM, HasV5TE]>;

} // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1
// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.

def LDRT : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb),
                   (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru,
                   "ldrt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRBT : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb),
                  (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru,
                  "ldrbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRSBT : AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb),
                 (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                 "ldrsbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRHT : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb),
                  (ins GPR:$base, am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                  "ldrht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def LDRSHT : AI3ldshpo<(outs GPR:$dst, GPR:$base_wb),
                 (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru,
                 "ldrsht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def STR  : AI2stw<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer,
               [(store GPR:$src, addrmode2:$addr)]>;

// Stores with truncate
Jim Grosbach's avatar
Jim Grosbach committed
def STRH : AI3sth<(outs), (ins GPR:$src, addrmode3:$addr), StMiscFrm,
               IIC_iStorer, "strh", "\t$src, $addr",
               [(truncstorei16 GPR:$src, addrmode3:$addr)]>;

def STRB : AI2stb<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer,
               "strb", "\t$src, $addr",
               [(truncstorei8 GPR:$src, addrmode2:$addr)]>;

// Store doubleword
let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in
def STRD : AI3std<(outs), (ins GPR:$src1, GPR:$src2, addrmode3:$addr),
               "strd", "\t$src1, $addr", []>, Requires<[IsARM, HasV5TE]>;

// Indexed stores
def STR_PRE  : AI2stwpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base, am2offset:$offset),
                    "str", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (pre_store GPR:$src, GPR:$base, am2offset:$offset))]>;

def STR_POST : AI2stwpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                    "str", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (post_store GPR:$src, GPR:$base, am2offset:$offset))]>;

def STRH_PRE : AI3sthpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am3offset:$offset),
                     "strh", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb,
                      (pre_truncsti16 GPR:$src, GPR:$base,am3offset:$offset))]>;

def STRH_POST: AI3sthpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am3offset:$offset),
                     "strh", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb, (post_truncsti16 GPR:$src,
                                         GPR:$base, am3offset:$offset))]>;

def STRB_PRE : AI2stbpr<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     "strb", "\t$src, [$base, $offset]!", "$base = $base_wb",
                    [(set GPR:$base_wb, (pre_truncsti8 GPR:$src,
                                         GPR:$base, am2offset:$offset))]>;

def STRB_POST: AI2stbpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     "strb", "\t$src, [$base], $offset", "$base = $base_wb",
                    [(set GPR:$base_wb, (post_truncsti8 GPR:$src,
                                         GPR:$base, am2offset:$offset))]>;
// For disassembly only
def STRD_PRE : AI3stdpr<(outs GPR:$base_wb),
                     (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset),
                     StMiscFrm, IIC_iStoreru,
                     "strd", "\t$src1, $src2, [$base, $offset]!",
                     "$base = $base_wb", []>;

// For disassembly only
def STRD_POST: AI3stdpo<(outs GPR:$base_wb),
                     (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset),
                     StMiscFrm, IIC_iStoreru,
                     "strd", "\t$src1, $src2, [$base], $offset",
                     "$base = $base_wb", []>;

// STRT, STRBT, and STRHT are for disassembly only.

def STRT : AI2stwpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                    (ins GPR:$src, GPR:$base,am2offset:$offset),
                    StFrm, IIC_iStoreru,
                    "strt", "\t$src, [$base], $offset", "$base = $base_wb",
                    [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

def STRBT : AI2stbpo<(outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                     (ins GPR:$src, GPR:$base,am2offset:$offset),
                     StFrm, IIC_iStoreru,
                     "strbt", "\t$src, [$base], $offset", "$base = $base_wb",
                     [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

def STRHT: AI3sthpo<(outs GPR:$base_wb),
                    (ins GPR:$src, GPR:$base,am3offset:$offset),
                    StMiscFrm, IIC_iStoreru,
                    "strht", "\t$src, [$base], $offset", "$base = $base_wb",
                    [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

//===----------------------------------------------------------------------===//
//  Load / store multiple Instructions.
//
let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in {
def LDM : AXI4ld<(outs), (ins addrmode4:$addr, pred:$p,
                          reglist:$dsts, variable_ops),
                 IndexModeNone, LdStMulFrm, IIC_iLoadm,
                 "ldm${addr:submode}${p}\t$addr, $dsts", "", []>;

def LDM_UPD : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p,
                                      reglist:$dsts, variable_ops),
                     IndexModeUpd, LdStMulFrm, IIC_iLoadm,
                     "ldm${addr:submode}${p}\t$addr!, $dsts",
} // mayLoad, neverHasSideEffects, hasExtraDefRegAllocReq
let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in {
def STM : AXI4st<(outs), (ins addrmode4:$addr, pred:$p,
                          reglist:$srcs, variable_ops),
                 IndexModeNone, LdStMulFrm, IIC_iStorem,
                 "stm${addr:submode}${p}\t$addr, $srcs", "", []>;

def STM_UPD : AXI4st<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p,
                                      reglist:$srcs, variable_ops),
                     IndexModeUpd, LdStMulFrm, IIC_iStorem,
                     "stm${addr:submode}${p}\t$addr!, $srcs",
} // mayStore, neverHasSideEffects, hasExtraSrcRegAllocReq
//===----------------------------------------------------------------------===//
//  Move Instructions.
//
let neverHasSideEffects = 1 in
def MOVr : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
// A version for the smaller set of tail call registers.
let neverHasSideEffects = 1 in
def MOVr_TC : AsI1<0b1101, (outs tcGPR:$dst), (ins tcGPR:$src), DPFrm, 
                IIC_iMOVr, "mov", "\t$dst, $src", []>, UnaryDP {
  let Inst{11-4} = 0b00000000;
  let Inst{25} = 0;
}

Jim Grosbach's avatar
Jim Grosbach committed
def MOVs : AsI1<0b1101, (outs GPR:$dst), (ins so_reg:$src),
                "mov", "\t$dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP {
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$dst), (ins so_imm:$src), DPFrm, IIC_iMOVi,
                "mov", "\t$dst, $src", [(set GPR:$dst, so_imm:$src)]>, UnaryDP {
  let Inst{25} = 1;
}

let isReMaterializable = 1, isAsCheapAsAMove = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVi16 : AI1<0b1000, (outs GPR:$dst), (ins i32imm:$src),
                 [(set GPR:$dst, imm0_65535:$src)]>,
  let Inst{20} = 0;
def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
                  DPFrm, IIC_iMOVi,
Jim Grosbach's avatar
Jim Grosbach committed
                        (or (and GPR:$src, 0xffff),
                            lo16AllZero:$imm))]>, UnaryDP,
                  Requires<[IsARM, HasV6T2]> {
  let Inst{20} = 0;
Evan Cheng's avatar
Evan Cheng committed
def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>,
      Requires<[IsARM, HasV6T2]>;

David Goodwin's avatar
David Goodwin committed
let Uses = [CPSR] in
def MOVrx : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, IIC_iMOVsi,
                 [(set GPR:$dst, (ARMrrx GPR:$src))]>, UnaryDP;
// These aren't really mov instructions, but we have to define them this way
// due to flag operands.
Jim Grosbach's avatar
Jim Grosbach committed
def MOVsrl_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo,
                      IIC_iMOVsi, "movs", "\t$dst, $src, lsr #1",
                      [(set GPR:$dst, (ARMsrl_flag GPR:$src))]>, UnaryDP;
def MOVsra_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo,
                      IIC_iMOVsi, "movs", "\t$dst, $src, asr #1",
                      [(set GPR:$dst, (ARMsra_flag GPR:$src))]>, UnaryDP;
//===----------------------------------------------------------------------===//
//  Extend Instructions.
//
// Sign extenders
Rafael Espindola's avatar
Rafael Espindola committed

defm SXTB  : AI_unary_rrot<0b01101010,
                           "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>;
defm SXTH  : AI_unary_rrot<0b01101011,
                           "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>;
defm SXTAB : AI_bin_rrot<0b01101010,
               "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>;
defm SXTAH : AI_bin_rrot<0b01101011,
               "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>;
// For disassembly only
defm SXTB16  : AI_unary_rrot_np<0b01101000, "sxtb16">;

// For disassembly only
defm SXTAB16 : AI_bin_rrot_np<0b01101000, "sxtab16">;
// Zero extenders
let AddedComplexity = 16 in {
defm UXTB   : AI_unary_rrot<0b01101110,
                            "uxtb"  , UnOpFrag<(and node:$Src, 0x000000FF)>>;
defm UXTH   : AI_unary_rrot<0b01101111,
                            "uxth"  , UnOpFrag<(and node:$Src, 0x0000FFFF)>>;
defm UXTB16 : AI_unary_rrot<0b01101100,
                            "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>;
// FIXME: This pattern incorrectly assumes the shl operator is a rotate.
//        The transformation should probably be done as a combiner action
//        instead so we can include a check for masking back in the upper
//        eight bits of the source into the lower eight bits of the result.
//def : ARMV6Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF),
//               (UXTB16r_rot GPR:$Src, 24)>;
def : ARMV6Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 8)>;

defm UXTAB : AI_bin_rrot<0b01101110, "uxtab",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
defm UXTAH : AI_bin_rrot<0b01101111, "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.
// For disassembly only
defm UXTAB16 : AI_bin_rrot_np<0b01101100, "uxtab16">;
def SBFX  : I<(outs GPR:$dst),
              (ins GPR:$src, imm0_31:$lsb, imm0_31:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi,
               "sbfx", "\t$dst, $src, $lsb, $width", "", []>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111101;
  let Inst{6-4}   = 0b101;
}

def UBFX  : I<(outs GPR:$dst),
              (ins GPR:$src, imm0_31:$lsb, imm0_31:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi,
               "ubfx", "\t$dst, $src, $lsb, $width", "", []>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111111;
  let Inst{6-4}   = 0b101;
}

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

                         BinOpFrag<(add  node:$LHS, node:$RHS)>, 1>;
                         BinOpFrag<(sub  node:$LHS, node:$RHS)>>;
defm ADDS : AI1_bin_s_irs<0b0100, "adds",
                          BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
defm SUBS : AI1_bin_s_irs<0b0010, "subs",
                          BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>>;
defm ADCS : AI1_adde_sube_s_irs<0b0101, "adcs",
                          BinOpFrag<(adde_live_carry node:$LHS, node:$RHS)>, 1>;
defm SBCS : AI1_adde_sube_s_irs<0b0110, "sbcs",
                          BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>;
def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
Bob Wilson's avatar
Bob Wilson committed
                 IIC_iALUi, "rsb", "\t$dst, $a, $b",
                 [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]> {
// The reg/reg form is only defined for the disassembler; for codegen it is
// equivalent to SUBrr.
def RSBrr : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm,
Bob Wilson's avatar
Bob Wilson committed
                 IIC_iALUr, "rsb", "\t$dst, $a, $b",
                 [/* For disassembly only; pattern left blank */]> {
    let Inst{25} = 0;
    let Inst{11-4} = 0b00000000;
}

def RSBrs : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
Bob Wilson's avatar
Bob Wilson committed
                 IIC_iALUsr, "rsb", "\t$dst, $a, $b",
                 [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]> {
def RSBSri : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm,
                 IIC_iALUi, "rsbs", "\t$dst, $a, $b",
def RSBSrs : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm,
                 IIC_iALUsr, "rsbs", "\t$dst, $a, $b",
                 [(set GPR:$dst, (subc so_reg:$b, GPR:$a))]> {
    let Inst{20} = 1;
    let Inst{25} = 0;
}
let Uses = [CPSR] in {
def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
                 [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>,
                 Requires<[IsARM]> {
// The reg/reg form is only defined for the disassembler; for codegen it is
// equivalent to SUBrr.
def RSCrr : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                 DPFrm, IIC_iALUr, "rsc", "\t$dst, $a, $b",
                 [/* For disassembly only; pattern left blank */]> {
    let Inst{25} = 0;
    let Inst{11-4} = 0b00000000;
}
def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
                 DPSoRegFrm, IIC_iALUsr, "rsc", "\t$dst, $a, $b",
                 [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>,
                 Requires<[IsARM]> {
let Defs = [CPSR], Uses = [CPSR] in {
def RSCSri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b),
                  [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>,
                  Requires<[IsARM]> {
def RSCSrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b),
                  DPSoRegFrm, IIC_iALUsr, "rscs\t$dst, $a, $b",
                  [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>,
                  Requires<[IsARM]> {
// (sub X, imm) gets canonicalized to (add X, -imm).  Match this form.
// The assume-no-carry-in form uses the negation of the input since add/sub
// assume opposite meanings of the carry flag (i.e., carry == !borrow).
// See the definition of AddWithCarry() in the ARM ARM A2.2.1 for the gory
// details.
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)>;
// The with-carry-in form matches bitwise not instead of the negation.
// Effectively, the inverse interpretation of the carry flag already accounts
// for part of the negation.
def : ARMPat<(adde   GPR:$src, so_imm_not:$imm),
             (SBCri  GPR:$src, so_imm_not:$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))
// ARM Arithmetic Instruction -- for disassembly only
class AAI<bits<8> op27_20, bits<4> op7_4, string opc,
          list<dag> pattern = [/* For disassembly only; pattern left blank */]>
  : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, IIC_iALUr,
  let Inst{27-20} = op27_20;
  let Inst{7-4} = op7_4;
}

// Saturating add/subtract -- for disassembly only

def QADD    : AAI<0b00010000, 0b0101, "qadd",
                  [(set GPR:$dst, (int_arm_qadd GPR:$a, GPR:$b))]>;
def QADD16  : AAI<0b01100010, 0b0001, "qadd16">;
def QADD8   : AAI<0b01100010, 0b1001, "qadd8">;
def QASX    : AAI<0b01100010, 0b0011, "qasx">;
def QDADD   : AAI<0b00010100, 0b0101, "qdadd">;
def QDSUB   : AAI<0b00010110, 0b0101, "qdsub">;
def QSAX    : AAI<0b01100010, 0b0101, "qsax">;
def QSUB    : AAI<0b00010010, 0b0101, "qsub",
                  [(set GPR:$dst, (int_arm_qsub GPR:$a, GPR:$b))]>;
def QSUB16  : AAI<0b01100010, 0b0111, "qsub16">;
def QSUB8   : AAI<0b01100010, 0b1111, "qsub8">;
def UQADD16 : AAI<0b01100110, 0b0001, "uqadd16">;
def UQADD8  : AAI<0b01100110, 0b1001, "uqadd8">;
def UQASX   : AAI<0b01100110, 0b0011, "uqasx">;
def UQSAX   : AAI<0b01100110, 0b0101, "uqsax">;
def UQSUB16 : AAI<0b01100110, 0b0111, "uqsub16">;
def UQSUB8  : AAI<0b01100110, 0b1111, "uqsub8">;

// Signed/Unsigned add/subtract -- for disassembly only

def SASX   : AAI<0b01100001, 0b0011, "sasx">;
def SADD16 : AAI<0b01100001, 0b0001, "sadd16">;
def SADD8  : AAI<0b01100001, 0b1001, "sadd8">;
def SSAX   : AAI<0b01100001, 0b0101, "ssax">;
def SSUB16 : AAI<0b01100001, 0b0111, "ssub16">;
def SSUB8  : AAI<0b01100001, 0b1111, "ssub8">;
def UASX   : AAI<0b01100101, 0b0011, "uasx">;
def UADD16 : AAI<0b01100101, 0b0001, "uadd16">;
def UADD8  : AAI<0b01100101, 0b1001, "uadd8">;
def USAX   : AAI<0b01100101, 0b0101, "usax">;
def USUB16 : AAI<0b01100101, 0b0111, "usub16">;
def USUB8  : AAI<0b01100101, 0b1111, "usub8">;

// Signed/Unsigned halving add/subtract -- for disassembly only

def SHASX   : AAI<0b01100011, 0b0011, "shasx">;
def SHADD16 : AAI<0b01100011, 0b0001, "shadd16">;
def SHADD8  : AAI<0b01100011, 0b1001, "shadd8">;
def SHSAX   : AAI<0b01100011, 0b0101, "shsax">;
def SHSUB16 : AAI<0b01100011, 0b0111, "shsub16">;
def SHSUB8  : AAI<0b01100011, 0b1111, "shsub8">;
def UHASX   : AAI<0b01100111, 0b0011, "uhasx">;
def UHADD16 : AAI<0b01100111, 0b0001, "uhadd16">;
def UHADD8  : AAI<0b01100111, 0b1001, "uhadd8">;
def UHSAX   : AAI<0b01100111, 0b0101, "uhsax">;
def UHSUB16 : AAI<0b01100111, 0b0111, "uhsub16">;
def UHSUB8  : AAI<0b01100111, 0b1111, "uhsub8">;

// Unsigned Sum of Absolute Differences [and Accumulate] -- for disassembly only
def USAD8  : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b),
                MulFrm /* for convenience */, NoItinerary, "usad8",
                "\t$dst, $a, $b", []>,
             Requires<[IsARM, HasV6]> {
  let Inst{27-20} = 0b01111000;
  let Inst{15-12} = 0b1111;
  let Inst{7-4} = 0b0001;
}
def USADA8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                MulFrm /* for convenience */, NoItinerary, "usada8",
                "\t$dst, $a, $b, $acc", []>,
             Requires<[IsARM, HasV6]> {
  let Inst{27-20} = 0b01111000;
  let Inst{7-4} = 0b0001;
}

// Signed/Unsigned saturate -- for disassembly only

def SSAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh),
              SatFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a$sh",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110101;
def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm,
                NoItinerary, "ssat16", "\t$dst, $bit_pos, $a",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{27-20} = 0b01101010;
  let Inst{7-4} = 0b0011;
}

def USAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh),
              SatFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a$sh",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{27-21} = 0b0110111;
def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm,
                NoItinerary, "usat16", "\t$dst, $bit_pos, $a",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{27-20} = 0b01101110;
  let Inst{7-4} = 0b0011;
}
def : ARMV6Pat<(int_arm_ssat GPR:$a, imm:$pos), (SSAT imm:$pos, GPR:$a, 0)>;
def : ARMV6Pat<(int_arm_usat GPR:$a, imm:$pos), (USAT imm:$pos, GPR:$a, 0)>;
//===----------------------------------------------------------------------===//
//  Bitwise Instructions.
//
                          BinOpFrag<(and node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(or  node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(xor node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
Evan Cheng's avatar
Evan Cheng committed
def BFC    : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
Evan Cheng's avatar
Evan Cheng committed
               [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111110;
  let Inst{6-0}   = 0b0011111;
}

// A8.6.18  BFI - Bitfield insert (Encoding A1)
def BFI    : I<(outs GPR:$dst), (ins GPR:$src, GPR:$val, bf_inv_mask_imm:$imm),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
               "bfi", "\t$dst, $val, $imm", "$src = $dst",
               [(set GPR:$dst, (ARMbfi GPR:$src, GPR:$val,
                                bf_inv_mask_imm:$imm))]>,
               Requires<[IsARM, HasV6T2]> {
  let Inst{27-21} = 0b0111110;
  let Inst{6-4}   = 0b001; // Rn: Inst{3-0} != 15
}

def  MVNr  : AsI1<0b1111, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
                  [(set GPR:$dst, (not GPR:$src))]>, UnaryDP {
def  MVNs  : AsI1<0b1111, (outs GPR:$dst), (ins so_reg:$src), DPSoRegFrm,
                  [(set GPR:$dst, (not so_reg:$src))]>, UnaryDP {
  let Inst{25} = 0;
}
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def  MVNi  : AsI1<0b1111, (outs GPR:$dst), (ins so_imm:$imm), DPFrm,
                  [(set GPR:$dst, so_imm_not:$imm)]>,UnaryDP {
    let Inst{25} = 1;
}
def : ARMPat<(and   GPR:$src, so_imm_not:$imm),
             (BICri GPR:$src, so_imm_not:$imm)>;
//===----------------------------------------------------------------------===//
//  Multiply Instructions.
//
let isCommutable = 1 in
def MUL   : AsMul1I<0b0000000, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                   [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
def MLA   : AsMul1I<0b0000001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
                   [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>;
def MLS   : AMul1I<0b0000011, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
Evan Cheng's avatar
Evan Cheng committed
                   [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>,
                   Requires<[IsARM, HasV6T2]>;

// Extra precision multiplies with low / high results
let neverHasSideEffects = 1 in {
let isCommutable = 1 in {
def SMULL : AsMul1I<0b0000110, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMUL64,
def UMULL : AsMul1I<0b0000100, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMUL64,

// Multiply + accumulate
def SMLAL : AsMul1I<0b0000111, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,
def UMLAL : AsMul1I<0b0000101, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,
def UMAAL : AMul1I <0b0000010, (outs GPR:$ldst, GPR:$hdst),
                               (ins GPR:$a, GPR:$b), IIC_iMAC64,

// Most significant word multiply
def SMMUL : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
            Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0001;
  let Inst{15-12} = 0b1111;
}
def SMMULR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
               IIC_iMUL32, "smmulr", "\t$dst, $a, $b",
               [/* For disassembly only; pattern left blank */]>,
            Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0011; // R = 1
  let Inst{15-12} = 0b1111;
}

def SMMLA : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               [(set GPR:$dst, (add (mulhs GPR:$a, GPR:$b), GPR:$c))]>,
def SMMLAR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               IIC_iMAC32, "smmlar", "\t$dst, $a, $b, $c",
               [/* For disassembly only; pattern left blank */]>,
            Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0011; // R = 1
}
def SMMLS : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               [(set GPR:$dst, (sub GPR:$c, (mulhs GPR:$a, GPR:$b)))]>,
def SMMLSR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
               IIC_iMAC32, "smmlsr", "\t$dst, $a, $b, $c",
               [/* For disassembly only; pattern left blank */]>,
            Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b1111; // R = 1
}

  def BB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
              IIC_iMUL32, !strconcat(opc, "bb"), "\t$dst, $a, $b",
              [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16),