Skip to content
ARMInstrInfo.td 122 KiB
Newer Older
  // ARMv5T and above
  def BLX : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm,
                [(ARMcall GPR:$func)]>,
            Requires<[IsARM, HasV5T, IsNotDarwin]> {
    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 BX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
           Requires<[IsARM, HasV4T, IsNotDarwin]> {
    let Inst{7-4}   = 0b0001;
    let Inst{19-8}  = 0b111111111111;
    let Inst{27-20} = 0b00010010;

  // ARMv4
  def BMOVPCRX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                 IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
                 [(ARMcall_nolink tGPR:$func)]>,
           Requires<[IsARM, NoV4T, IsNotDarwin]> {
    let Inst{11-4}  = 0b00000000;
    let Inst{15-12} = 0b1111;
    let Inst{19-16} = 0b0000;
    let Inst{27-20} = 0b00011010;
  }
  Defs = [R0,  R1,  R2,  R3,  R9,  R12, LR,
          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_iLoad_r,
               [(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_iLoad_r,
// Loads with zero extension
def LDRH  : AI3ldh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                  IIC_iLoad_bh_r, "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_iLoad_bh_r, "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_iLoad_bh_r, "ldrsh", "\t$dst, $addr",
                   [(set GPR:$dst, (sextloadi16 addrmode3:$addr))]>;
def LDRSB : AI3ldsb<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                   IIC_iLoad_bh_r, "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_iLoad_d_r, "ldrd", "\t$dst1, $addr",
                 []>, Requires<[IsARM, HasV5TE]>;

// Indexed loads
def LDR_PRE  : AI2ldwpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoad_ru,
                     "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_iLoad_ru,
                     "ldr", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRH_PRE  : AI3ldhpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                     "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_iLoad_bh_ru,
                    "ldrh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRB_PRE  : AI2ldbpr<(outs GPR:$dst, GPR:$base_wb),
                     (ins addrmode2:$addr), LdFrm, IIC_iLoad_bh_ru,
                     "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_iLoad_bh_ru,
                    "ldrb", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSH_PRE : AI3ldshpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                      "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_iLoad_bh_ru,
                   "ldrsh", "\t$dst, [$base], $offset", "$base = $base_wb", []>;
def LDRSB_PRE : AI3ldsbpr<(outs GPR:$dst, GPR:$base_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                      "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_iLoad_ru,
                   "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_iLoad_d_ru,
                 "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_iLoad_d_ru,
            "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_iLoad_ru,
                   "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_iLoad_bh_ru,
                  "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_iLoad_bh_ru,
                 "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_iLoad_bh_ru,
                  "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_iLoad_bh_ru,
                 "ldrsht", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

def STR  : AI2stw<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStore_r,
               [(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_iStore_bh_r, "strh", "\t$src, $addr",
               [(truncstorei16 GPR:$src, addrmode3:$addr)]>;

def STRB : AI2stb<(outs), (ins GPR:$src, addrmode2:$addr), StFrm,
               IIC_iStore_bh_r, "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),
               StMiscFrm, IIC_iStore_d_r,
               "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),
                     StFrm, IIC_iStore_ru,
                    "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),
                     StFrm, IIC_iStore_ru,
                    "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),
                     StMiscFrm, IIC_iStore_ru,
                     "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),
                     StMiscFrm, IIC_iStore_bh_ru,
                     "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),
                     StFrm, IIC_iStore_bh_ru,
                     "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),
                     StFrm, IIC_iStore_bh_ru,
                     "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_iStore_d_ru,
                     "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_iStore_d_ru,
                     "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_iStore_ru,
                    "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_iStore_bh_ru,
                     "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_iStore_bh_ru,
                    "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,
                 IndexModeNone, LdStMulFrm, IIC_iLoad_m,
                 "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_iLoad_mu,
                     "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,
                 IndexModeNone, LdStMulFrm, IIC_iStore_m,
                 "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_iStore_mu,
                     "stm${addr:submode}${p}\t$addr!, $srcs",
} // mayStore, neverHasSideEffects, hasExtraSrcRegAllocReq
//===----------------------------------------------------------------------===//
//  Move Instructions.
//
let neverHasSideEffects = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr,
                "mov", "\t$Rd, $Rm", []>, UnaryDP {
  bits<4> Rd;
  bits<4> Rm;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{3-0} = Rm;
  let Inst{15-12} = Rd;
// A version for the smaller set of tail call registers.
let neverHasSideEffects = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVr_TC : AsI1<0b1101, (outs tcGPR:$Rd), (ins tcGPR:$Rm), DPFrm, 
                IIC_iMOVr, "mov", "\t$Rd, $Rm", []>, UnaryDP {
  bits<4> Rd;
  bits<4> Rm;
  let Inst{11-4} = 0b00000000;
  let Inst{25} = 0;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{3-0} = Rm;
  let Inst{15-12} = Rd;
Jim Grosbach's avatar
Jim Grosbach committed
def MOVs : AsI1<0b1101, (outs GPR:$Rd), (ins so_reg:$src),
Jim Grosbach's avatar
Jim Grosbach committed
                "mov", "\t$Rd, $src", [(set GPR:$Rd, so_reg:$src)]>, UnaryDP {
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMOVi,
                "mov", "\t$Rd, $imm", [(set GPR:$Rd, so_imm:$imm)]>, UnaryDP {
Jim Grosbach's avatar
Jim Grosbach committed
  bits<4> Rd;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{15-12} = Rd;
  let Inst{19-16} = 0b0000;
}

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_ext_rrot<0b01101010,
                         "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>;
defm SXTH  : AI_ext_rrot<0b01101011,
                         "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>;
defm SXTAB : AI_exta_rrot<0b01101010,
               "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>;
defm SXTAH : AI_exta_rrot<0b01101011,
               "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>;
defm SXTB16  : AI_ext_rrot_np<0b01101000, "sxtb16">;
defm SXTAB16 : AI_exta_rrot_np<0b01101000, "sxtab16">;
// Zero extenders
let AddedComplexity = 16 in {
defm UXTB   : AI_ext_rrot<0b01101110,
                          "uxtb"  , UnOpFrag<(and node:$Src, 0x000000FF)>>;
defm UXTH   : AI_ext_rrot<0b01101111,
                          "uxth"  , UnOpFrag<(and node:$Src, 0x0000FFFF)>>;
defm UXTB16 : AI_ext_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_exta_rrot<0b01101110, "uxtab",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
defm UXTAH : AI_exta_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.
defm UXTAB16 : AI_exta_rrot_np<0b01101100, "uxtab16">;
def SBFX  : I<(outs GPR:$dst),
              (ins GPR:$src, imm0_31:$lsb, imm0_31:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
               "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_iUNAsi,
               "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>;
defm ANDS  : AI1_bin_s_irs<0b0000, "and",
                           BinOpFrag<(ARMand 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_iMVNr,
                  [(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,