Skip to content
ARMInstrThumb2.td 105 KiB
Newer Older
defm t2SMUL : T2I_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>;
defm t2SMLA : T2I_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>;

// Halfword multiple accumulate long: SMLAL<x><y> -- for disassembly only
def t2SMLALBB : T2I_mac<1, 0b100, 0b1000, (outs GPR:$ldst,GPR:$hdst),
           (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALBT : T2I_mac<1, 0b100, 0b1001, (outs GPR:$ldst,GPR:$hdst),
           (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALTB : T2I_mac<1, 0b100, 0b1010, (outs GPR:$ldst,GPR:$hdst),
           (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALTT : T2I_mac<1, 0b100, 0b1011, (outs GPR:$ldst,GPR:$hdst),
           (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;

// Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD
// These are for disassembly only.

def t2SMUAD   : T2I_mac<0, 0b010, 0b0000, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                        IIC_iMAC32, "smuad", "\t$dst, $a, $b", []> {
  let Inst{15-12} = 0b1111;
}
def t2SMUADX  : T2I_mac<0, 0b010, 0b0001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                        IIC_iMAC32, "smuadx", "\t$dst, $a, $b", []> {
  let Inst{15-12} = 0b1111;
}
def t2SMUSD   : T2I_mac<0, 0b100, 0b0000, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                        IIC_iMAC32, "smusd", "\t$dst, $a, $b", []> {
  let Inst{15-12} = 0b1111;
}
def t2SMUSDX  : T2I_mac<0, 0b100, 0b0001, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                        IIC_iMAC32, "smusdx", "\t$dst, $a, $b", []> {
  let Inst{15-12} = 0b1111;
}
def t2SMLAD   : T2I_mac<0, 0b010, 0b0000, (outs GPR:$dst),
                        (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlad",
                        "\t$dst, $a, $b, $acc", []>;
def t2SMLADX  : T2I_mac<0, 0b010, 0b0001, (outs GPR:$dst),
                        (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smladx",
                        "\t$dst, $a, $b, $acc", []>;
def t2SMLSD   : T2I_mac<0, 0b100, 0b0000, (outs GPR:$dst),
                        (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlsd",
                        "\t$dst, $a, $b, $acc", []>;
def t2SMLSDX  : T2I_mac<0, 0b100, 0b0001, (outs GPR:$dst),
                        (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlsdx",
                        "\t$dst, $a, $b, $acc", []>;
def t2SMLALD  : T2I_mac<1, 0b100, 0b1100, (outs GPR:$ldst,GPR:$hdst),
                        (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlald",
                        "\t$ldst, $hdst, $a, $b", []>;
def t2SMLALDX : T2I_mac<1, 0b100, 0b1101, (outs GPR:$ldst,GPR:$hdst),
                        (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaldx",
                        "\t$ldst, $hdst, $a, $b", []>;
def t2SMLSLD  : T2I_mac<1, 0b101, 0b1100, (outs GPR:$ldst,GPR:$hdst),
                        (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlsld",
                        "\t$ldst, $hdst, $a, $b", []>;
def t2SMLSLDX : T2I_mac<1, 0b101, 0b1101, (outs GPR:$ldst,GPR:$hdst),
                        (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlsldx",
                        "\t$ldst, $hdst, $a, $b", []>;

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

Jim Grosbach's avatar
Jim Grosbach committed
class T2I_misc<bits<2> op1, bits<2> op2, dag oops, dag iops,
      InstrItinClass itin, string opc, string asm, list<dag> pattern>
  : T2I<oops, iops, itin, opc, asm, pattern> {
  let Inst{31-27} = 0b11111;
  let Inst{26-22} = 0b01010;
  let Inst{21-20} = op1;
  let Inst{15-12} = 0b1111;
  let Inst{7-6} = 0b10;
  let Inst{5-4} = op2;
}

def t2CLZ : T2I_misc<0b11, 0b00, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
                    "clz", "\t$dst, $src", [(set GPR:$dst, (ctlz GPR:$src))]>;
Jim Grosbach's avatar
Jim Grosbach committed
def t2RBIT : T2I_misc<0b01, 0b10, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
                      "rbit", "\t$dst, $src",
                      [(set GPR:$dst, (ARMrbit GPR:$src))]>;
def t2REV : T2I_misc<0b01, 0b00, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
                   "rev", ".w\t$dst, $src", [(set GPR:$dst, (bswap GPR:$src))]>;
def t2REV16 : T2I_misc<0b01, 0b01, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
                       "rev16", ".w\t$dst, $src",
                [(set GPR:$dst,
                    (or (and (srl GPR:$src, (i32 8)), 0xFF),
                        (or (and (shl GPR:$src, (i32 8)), 0xFF00),
                            (or (and (srl GPR:$src, (i32 8)), 0xFF0000),
                                (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>;

def t2REVSH : T2I_misc<0b01, 0b11, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
                       "revsh", ".w\t$dst, $src",
Evan Cheng's avatar
Evan Cheng committed
                      (or (srl (and GPR:$src, 0xFF00), (i32 8)),
Evan Cheng's avatar
Evan Cheng committed
def t2PKHBT : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
                  IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2, lsl $shamt",
Evan Cheng's avatar
Evan Cheng committed
                  [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF),
                                      (and (shl GPR:$src2, (i32 imm:$shamt)),
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b01;
  let Inst{24-20} = 0b01100;
  let Inst{5} = 0; // BT form
  let Inst{4} = 0;
}
Evan Cheng's avatar
Evan Cheng committed

// Alternate cases for PKHBT where identities eliminate some nodes.
def : T2Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)),
            (t2PKHBT GPR:$src1, GPR:$src2, 0)>,
Evan Cheng's avatar
Evan Cheng committed
def : T2Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$shamt)),
            (t2PKHBT GPR:$src1, GPR:$src2, imm16_31:$shamt)>,
Evan Cheng's avatar
Evan Cheng committed

def t2PKHTB : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
                  IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2, asr $shamt",
Evan Cheng's avatar
Evan Cheng committed
                  [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000),
                                      (and (sra GPR:$src2, imm16_31:$shamt),
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b01;
  let Inst{24-20} = 0b01100;
  let Inst{5} = 1; // TB form
  let Inst{4} = 0;
}
Evan Cheng's avatar
Evan Cheng committed

// 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 : T2Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, (i32 16))),
            (t2PKHTB GPR:$src1, GPR:$src2, 16)>,
Evan Cheng's avatar
Evan Cheng committed
def : T2Pat<(or (and GPR:$src1, 0xFFFF0000),
                     (and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)),
            (t2PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>,

//===----------------------------------------------------------------------===//
//  Comparison Instructions...
//

defm t2CMP  : T2I_cmp_irs<0b1101, "cmp",
                          BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
defm t2CMPz : T2I_cmp_irs<0b1101, "cmp",
                          BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>;
//FIXME: Disable CMN, as CCodes are backwards from compare expectations
//       Compare-to-zero still works out, just not the relationals
//defm t2CMN  : T2I_cmp_irs<0b1000, "cmn",
//                          BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;
defm t2CMNz : T2I_cmp_irs<0b1000, "cmn",
                          BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>;
//def : T2Pat<(ARMcmp  GPR:$src, t2_so_imm_neg:$imm),
//            (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
def : T2Pat<(ARMcmpZ  GPR:$src, t2_so_imm_neg:$imm),
            (t2CMNzri GPR:$src, t2_so_imm_neg:$imm)>;
defm t2TST  : T2I_cmp_irs<0b0000, "tst",
                          BinOpFrag<(ARMcmpZ (and node:$LHS, node:$RHS), 0)>>;
defm t2TEQ  : T2I_cmp_irs<0b0100, "teq",
                          BinOpFrag<(ARMcmpZ (xor node:$LHS, node:$RHS), 0)>>;

// A8.6.27  CBNZ, CBZ - Compare and branch on (non)zero.
// Short range conditional branch. Looks awesome for loops. Need to figure
// out how to use this one.


// Conditional moves
// FIXME: should be able to write a pattern for ARMcmov, but can't use
Jim Grosbach's avatar
Jim Grosbach committed
// a two-value operand where a dag node expects two operands. :(
def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true), IIC_iCMOVr,
      [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst"> {
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b01;
  let Inst{24-21} = 0b0010;
  let Inst{20} = 0; // The S bit.
  let Inst{19-16} = 0b1111; // Rn
  let Inst{14-12} = 0b000;
  let Inst{7-4} = 0b0000;
}
def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true),
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
                   RegConstraint<"$false = $dst"> {
  let Inst{31-27} = 0b11110;
  let Inst{25} = 0;
  let Inst{24-21} = 0b0010;
  let Inst{20} = 0; // The S bit.
  let Inst{19-16} = 0b1111; // Rn
  let Inst{15} = 0;
}

class T2I_movcc_sh<bits<2> opcod, dag oops, dag iops, InstrItinClass itin,
                   string opc, string asm, list<dag> pattern>
  : T2I<oops, iops, itin, opc, asm, pattern> {
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b01;
  let Inst{24-21} = 0b0010;
  let Inst{20} = 0; // The S bit.
  let Inst{19-16} = 0b1111; // Rn
  let Inst{5-4} = opcod; // Shift type.
}
def t2MOVCClsl : T2I_movcc_sh<0b00, (outs GPR:$dst),
                             (ins GPR:$false, GPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "lsl", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCClsr : T2I_movcc_sh<0b01, (outs GPR:$dst),
                             (ins GPR:$false, GPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "lsr", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCCasr : T2I_movcc_sh<0b10, (outs GPR:$dst),
                             (ins GPR:$false, GPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCCror : T2I_movcc_sh<0b11, (outs GPR:$dst),
                             (ins GPR:$false, GPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "ror", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
//===----------------------------------------------------------------------===//
// Atomic operations intrinsics
//

// memory barriers protect the atomic sequences
let hasSideEffects = 1 in {
def t2Int_MemBarrierV7 : AInoP<(outs), (ins),
                        [(ARMMemBarrierV7)]>,
  let Inst{31-4} = 0xF3BF8F5;
  // FIXME: add support for options other than a full system DMB
  let Inst{3-0} = 0b1111;
}

def t2Int_SyncBarrierV7 : AInoP<(outs), (ins),
                        [(ARMSyncBarrierV7)]>,
  let Inst{31-4} = 0xF3BF8F4;
  // FIXME: add support for options other than a full system DSB
  let Inst{3-0} = 0b1111;
// Helper class for multiclass T2MemB -- for disassembly only
class T2I_memb<string opc, string asm>
  : T2I<(outs), (ins), NoItinerary, opc, asm,
        [/* For disassembly only; pattern left blank */]>,
    Requires<[IsThumb2, HasV7]> {
  let Inst{31-20} = 0xf3b;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

multiclass T2MemB<bits<4> op7_4, string opc> {

  def st : T2I_memb<opc, "\tst"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b1110;
  }

  def ish : T2I_memb<opc, "\tish"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b1011;
  }

  def ishst : T2I_memb<opc, "\tishst"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b1010;
  }

  def nsh : T2I_memb<opc, "\tnsh"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b0111;
  }

  def nshst : T2I_memb<opc, "\tnshst"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b0110;
  }

  def osh : T2I_memb<opc, "\tosh"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b0011;
  }

  def oshst : T2I_memb<opc, "\toshst"> {
    let Inst{7-4} = op7_4;
    let Inst{3-0} = 0b0010;
  }
}

// These DMB variants are for disassembly only.
defm t2DMB : T2MemB<0b0101, "dmb">;

// These DSB variants are for disassembly only.
defm t2DSB : T2MemB<0b0100, "dsb">;

// ISB has only full system option -- for disassembly only
def t2ISBsy : T2I_memb<"isb", ""> {
  let Inst{7-4} = 0b0110;
  let Inst{3-0} = 0b1111;
}

class T2I_ldrex<bits<2> opcod, dag oops, dag iops, AddrMode am, SizeFlagVal sz,
                InstrItinClass itin, string opc, string asm, string cstr,
                list<dag> pattern, bits<4> rt2 = 0b1111>
  : Thumb2I<oops, iops, am, sz, itin, opc, asm, cstr, pattern> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{11-8} = rt2;
  let Inst{7-6} = 0b01;
  let Inst{5-4} = opcod;
  let Inst{3-0} = 0b1111;
}
class T2I_strex<bits<2> opcod, dag oops, dag iops, AddrMode am, SizeFlagVal sz,
                InstrItinClass itin, string opc, string asm, string cstr,
                list<dag> pattern, bits<4> rt2 = 0b1111>
  : Thumb2I<oops, iops, am, sz, itin, opc, asm, cstr, pattern> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001100;
  let Inst{11-8} = rt2;
  let Inst{7-6} = 0b01;
  let Inst{5-4} = opcod;
}

def t2LDREXB : T2I_ldrex<0b00, (outs GPR:$dest), (ins GPR:$ptr), AddrModeNone,
                         Size4Bytes, NoItinerary, "ldrexb", "\t$dest, [$ptr]",
                         "", []>;
def t2LDREXH : T2I_ldrex<0b01, (outs GPR:$dest), (ins GPR:$ptr), AddrModeNone,
                         Size4Bytes, NoItinerary, "ldrexh", "\t$dest, [$ptr]",
                         "", []>;
def t2LDREX  : Thumb2I<(outs GPR:$dest), (ins GPR:$ptr), AddrModeNone,
                       Size4Bytes, NoItinerary,
                       "ldrex", "\t$dest, [$ptr]", "",
                      []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000101;
  let Inst{11-8} = 0b1111;
  let Inst{7-0} = 0b00000000; // imm8 = 0
}
def t2LDREXD : T2I_ldrex<0b11, (outs GPR:$dest, GPR:$dest2), (ins GPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "ldrexd", "\t$dest, $dest2, [$ptr]", "",
                         [], {?, ?, ?, ?}>;
let mayStore = 1, Constraints = "@earlyclobber $success" in {
def t2STREXB : T2I_strex<0b00, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "strexb", "\t$success, $src, [$ptr]", "", []>;
def t2STREXH : T2I_strex<0b01, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "strexh", "\t$success, $src, [$ptr]", "", []>;
def t2STREX  : Thumb2I<(outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                       AddrModeNone, Size4Bytes, NoItinerary,
                       "strex", "\t$success, $src, [$ptr]", "",
                      []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000100;
  let Inst{7-0} = 0b00000000; // imm8 = 0
}
def t2STREXD : T2I_strex<0b11, (outs GPR:$success),
                         (ins GPR:$src, GPR:$src2, GPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "strexd", "\t$success, $src, $src2, [$ptr]", "", [],
                         {?, ?, ?, ?}>;
// Clear-Exclusive is for disassembly only.
def t2CLREX : T2I<(outs), (ins), NoItinerary, "clrex", "",
                  [/* For disassembly only; pattern left blank */]>,
            Requires<[IsARM, HasV7]>  {
  let Inst{31-20} = 0xf3b;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
  let Inst{7-4} = 0b0010;
}

//===----------------------------------------------------------------------===//
// TLS Instructions
//

// __aeabi_read_tp preserves the registers r1-r3.
let isCall = 1,
  Defs = [R0, R12, LR, CPSR] in {
  def t2TPsoft : T2XI<(outs), (ins), IIC_Br,
                     [(set R0, ARMthread_pointer)]> {
    let Inst{31-27} = 0b11110;
    let Inst{15-14} = 0b11;
    let Inst{12} = 1;
  }
//===----------------------------------------------------------------------===//
// SJLJ Exception handling intrinsics
Jim Grosbach's avatar
Jim Grosbach committed
//   eh_sjlj_setjmp() is an instruction sequence to store the return
//   address and save #0 in R0 for the non-longjmp case.
//   Since by its nature we may be coming from some other function to get
//   here, and we're using the stack frame for the containing function to
//   save/restore registers, we can't keep anything live in regs across
//   the eh_sjlj_setjmp(), else it will almost certainly have been tromped upon
//   when we get here from a longjmp(). We force everthing out of registers
//   except for our own input by listing the relevant registers in Defs. By
//   doing so, we also cause the prologue/epilogue code to actively preserve
//   all of the callee-saved resgisters, which is exactly what we want.
//   $val is a scratch register for our use.
  [ R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,  R8,  R9,  R10, R11, R12, LR,  D0,
    D1,  D2,  D3,  D4,  D5,  D6,  D7,  D8,  D9,  D10, D11, D12, D13, D14, D15,
    D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30,
    D31 ], hasSideEffects = 1, isBarrier = 1 in {
  def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins GPR:$src, tGPR:$val),
                               AddrModeNone, SizeSpecial, NoItinerary,
                               "mov\t$val, pc\t${:comment} begin eh.setjmp\n\t"
                               "adds\t$val, #7\n\t"
                               "str\t$val, [$src, #4]\n\t"
                               "movs\tr0, #0\n\t"
                               "b\t1f\n\t"
                               "movs\tr0, #1\t${:comment} end eh.setjmp\n\t"
Jim Grosbach's avatar
Jim Grosbach committed
                               "1:", "",
                          [(set R0, (ARMeh_sjlj_setjmp GPR:$src, tGPR:$val))]>,
                             Requires<[IsThumb2, HasVFP2]>;
  [ R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,  R8,  R9,  R10, R11, R12, LR ],
  hasSideEffects = 1, isBarrier = 1 in {
  def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins GPR:$src, tGPR:$val),
                               AddrModeNone, SizeSpecial, NoItinerary,
                               "mov\t$val, pc\t${:comment} begin eh.setjmp\n\t"
                               "adds\t$val, #7\n\t"
                               "str\t$val, [$src, #4]\n\t"
                               "movs\tr0, #0\n\t"
                               "b\t1f\n\t"
                               "movs\tr0, #1\t${:comment} end eh.setjmp\n\t"
                               "1:", "",
                          [(set R0, (ARMeh_sjlj_setjmp GPR:$src, tGPR:$val))]>,
                                  Requires<[IsThumb2, NoVFP]>;
}
//===----------------------------------------------------------------------===//
// Control-Flow Instructions
//

// FIXME: remove when we have a way to marking a MI with these properties.
// FIXME: $dst1 should be a def. But the extra ops must be in the end of the
// operand list.
// FIXME: Should pc be an implicit operand like PICADD, etc?
let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1,
    hasExtraDefRegAllocReq = 1 in
  def t2LDM_RET : T2XIt<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p,
                                         reglist:$dsts, variable_ops), IIC_Br,
                        "ldm${addr:submode}${p}${addr:wide}\t$addr!, $dsts",
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b00;
  let Inst{24-23} = {?, ?}; // IA: '01', DB: '10'
  let Inst{22} = 0;
let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
let isPredicable = 1 in
def t2B   : T2XI<(outs), (ins brtarget:$target), IIC_Br,
                 [(br bb:$target)]> {
  let Inst{31-27} = 0b11110;
  let Inst{15-14} = 0b10;
  let Inst{12} = 1;
}
let isNotDuplicable = 1, isIndirectBranch = 1 in {
    T2JTI<(outs),
          (ins GPR:$target, GPR:$index, jt2block_operand:$jt, i32imm:$id),
          [(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt, imm:$id)]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0100100;
  let Inst{19-16} = 0b1111;
  let Inst{14-12} = 0b000;
  let Inst{11-8} = 0b1111; // Rd = pc
  let Inst{7-4} = 0b0000;
}
// FIXME: Add a non-pc based case that can be predicated.
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
         IIC_Br, "tbb\t$index\n$jt", []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction)
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0000; // B form
}
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
         IIC_Br, "tbh\t$index\n$jt", []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction)
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0001; // H form
}

// Generic versions of the above two instructions, for disassembly only

def t2TBBgen : T2I<(outs), (ins GPR:$a, GPR:$b), IIC_Br,
                    "tbb", "\t[$a, $b]", []>{
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0000; // B form
}

def t2TBHgen : T2I<(outs), (ins GPR:$a, GPR:$b), IIC_Br,
                   "tbh", "\t[$a, $b, lsl #1]", []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0001; // H form
}
} // isBranch, isTerminator, isBarrier

// FIXME: should be able to write a pattern for ARMBrcond, but can't use
// a two-value operand where a dag node expects two operands. :(
let isBranch = 1, isTerminator = 1 in
def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br,
                [/*(ARMbrcond bb:$target, imm:$cc)*/]> {
  let Inst{31-27} = 0b11110;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}
def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
                    AddrModeNone, Size2Bytes,  IIC_iALUx,
                    "it$mask\t$cc", "", []> {
  // 16-bit instruction.
  let Inst{15-8} = 0b10111111;
}
// Branch and Exchange Jazelle -- for disassembly only
// Rm = Inst{19-16}
def t2BXJ : T2I<(outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-20} = 0b111100;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// Change Processor State is a system instruction -- for disassembly only.
// The singleton $opt operand contains the following information:
// opt{4-0} = mode from Inst{4-0}
// opt{5} = changemode from Inst{17}
// opt{8-6} = AIF from Inst{8-6}
// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
def t2CPS : T2XI<(outs),(ins cps_opt:$opt), NoItinerary, "cps$opt",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-20} = 0b111010;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// A6.3.4 Branches and miscellaneous control
// Table A6-14 Change Processor State, and hint instructions
// Helper class for disassembly only.
class T2I_hint<bits<8> op7_0, string opc, string asm>
  : T2I<(outs), (ins), NoItinerary, opc, asm,
        [/* For disassembly only; pattern left blank */]> {
  let Inst{31-20} = 0xf3a;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
  let Inst{10-8} = 0b000;
  let Inst{7-0} = op7_0;
}

def t2NOP   : T2I_hint<0b00000000, "nop",   ".w">;
def t2YIELD : T2I_hint<0b00000001, "yield", ".w">;
def t2WFE   : T2I_hint<0b00000010, "wfe",   ".w">;
def t2WFI   : T2I_hint<0b00000011, "wfi",   ".w">;
def t2SEV   : T2I_hint<0b00000100, "sev",   ".w">;

def t2DBG : T2I<(outs),(ins i32imm:$opt), NoItinerary, "dbg", "\t$opt",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-20} = 0xf3a;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
  let Inst{10-8} = 0b000;
  let Inst{7-4} = 0b1111;
}

// Secure Monitor Call is a system instruction -- for disassembly only
// Option = Inst{19-16}
def t2SMC : T2I<(outs), (ins i32imm:$opt), NoItinerary, "smc", "\t$opt",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26-20} = 0b1111111;
  let Inst{15-12} = 0b1000;
}

// Store Return State is a system instruction -- for disassembly only
def t2SRSDBW : T2I<(outs),(ins i32imm:$mode),NoItinerary,"srsdb","\tsp!, $mode",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000010; // W = 1
}

def t2SRSDB  : T2I<(outs),(ins i32imm:$mode),NoItinerary,"srsdb","\tsp, $mode",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000000; // W = 0
}

def t2SRSIAW : T2I<(outs),(ins i32imm:$mode),NoItinerary,"srsia","\tsp!, $mode",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0011010; // W = 1
}

def t2SRSIA  : T2I<(outs), (ins i32imm:$mode),NoItinerary,"srsia","\tsp, $mode",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0011000; // W = 0
}

// Return From Exception is a system instruction -- for disassembly only
def t2RFEDBW : T2I<(outs), (ins GPR:$base), NoItinerary, "rfedb", "\t$base!",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000011; // W = 1
}

def t2RFEDB  : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeab", "\t$base",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0000001; // W = 0
}

def t2RFEIAW : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeia", "\t$base!",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0011011; // W = 1
}

def t2RFEIA  : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeia", "\t$base",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0011001; // W = 0
}

//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//

// Two piece so_imms.
def : T2Pat<(or GPR:$LHS, t2_so_imm2part:$RHS),
             (t2ORRri (t2ORRri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
                    (t2_so_imm2part_2 imm:$RHS))>;
def : T2Pat<(xor GPR:$LHS, t2_so_imm2part:$RHS),
             (t2EORri (t2EORri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
                    (t2_so_imm2part_2 imm:$RHS))>;
def : T2Pat<(add GPR:$LHS, t2_so_imm2part:$RHS),
             (t2ADDri (t2ADDri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
                    (t2_so_imm2part_2 imm:$RHS))>;
def : T2Pat<(add GPR:$LHS, t2_so_neg_imm2part:$RHS),
             (t2SUBri (t2SUBri GPR:$LHS, (t2_so_neg_imm2part_1 imm:$RHS)),
                    (t2_so_neg_imm2part_2 imm:$RHS))>;
// 32-bit immediate using movw + movt.
// This is a single pseudo instruction to make it re-materializable. Remove
// when we can do generalized remat.
let isReMaterializable = 1 in
def t2MOVi32imm : T2Ix2<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVi,
                   "movw", "\t$dst, ${src:lo16}\n\tmovt${p}\t$dst, ${src:hi16}",
// ConstantPool, GlobalAddress, and JumpTable
def : T2Pat<(ARMWrapper  tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>,
           Requires<[IsThumb2, DontUseMovt]>;
def : T2Pat<(ARMWrapper  tconstpool  :$dst), (t2LEApcrel tconstpool  :$dst)>;
def : T2Pat<(ARMWrapper  tglobaladdr :$dst), (t2MOVi32imm tglobaladdr :$dst)>,
           Requires<[IsThumb2, UseMovt]>;

def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id),
            (t2LEApcrelJT tjumptable:$dst, imm:$id)>;

// Pseudo instruction that combines ldr from constpool and add pc. This should
// be expanded into two instructions late to allow if-conversion and
// scheduling.
let canFoldAsLoad = 1, isReMaterializable = 1 in
def t2LDRpci_pic : PseudoInst<(outs GPR:$dst), (ins i32imm:$addr, pclabel:$cp),
                   NoItinerary,
                   "${:comment} ldr.w\t$dst, $addr\n$cp:\n\tadd\t$dst, pc",
               [(set GPR:$dst, (ARMpic_add (load (ARMWrapper tconstpool:$addr)),
                                           imm:$cp))]>,
               Requires<[IsThumb2]>;

//===----------------------------------------------------------------------===//
// Move between special register and ARM core register -- for disassembly only
//

// Rd = Instr{11-8}
def t2MRS : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, cpsr",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-21} = 0b11111;
  let Inst{20} = 0; // The R bit.
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// Rd = Instr{11-8}
def t2MRSsys : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, spsr",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-21} = 0b11111;
  let Inst{20} = 1; // The R bit.
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// Rn = Inst{19-16}
def t2MSR : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr",
                "\tcpsr$mask, $src",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-21} = 0b11100;
  let Inst{20} = 0; // The R bit.
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// Rn = Inst{19-16}
def t2MSRsys : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr",
                   "\tspsr$mask, $src",
                   [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-21} = 0b11100;
  let Inst{20} = 1; // The R bit.
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}