Skip to content
ARMInstrThumb2.td 110 KiB
Newer Older
  def BT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16,
              !strconcat(opc, "bt"), "\t$dst, $a, $b",
              [(set rGPR:$dst, (opnode (sext_inreg rGPR:$a, i16),
                                      (sra rGPR:$b, (i32 16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b01;
  }
  def TB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16,
              !strconcat(opc, "tb"), "\t$dst, $a, $b",
              [(set rGPR:$dst, (opnode (sra rGPR:$a, (i32 16)),
                                      (sext_inreg rGPR:$b, i16)))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b10;
  }
  def TT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16,
              !strconcat(opc, "tt"), "\t$dst, $a, $b",
              [(set rGPR:$dst, (opnode (sra rGPR:$a, (i32 16)),
                                      (sra rGPR:$b, (i32 16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b11;
  }
  def WB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16,
              !strconcat(opc, "wb"), "\t$dst, $a, $b",
              [(set rGPR:$dst, (sra (opnode rGPR:$a,
                                    (sext_inreg rGPR:$b, i16)), (i32 16)))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b011;
    let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b00;
  }
  def WT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16,
              !strconcat(opc, "wt"), "\t$dst, $a, $b",
              [(set rGPR:$dst, (sra (opnode rGPR:$a,
                                    (sra rGPR:$b, (i32 16))), (i32 16)))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b011;
    let Inst{15-12} = 0b1111; // Ra = 0b1111 (no accumulate)
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b01;
  }
}


multiclass T2I_smla<string opc, PatFrag opnode> {
  def BB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
              !strconcat(opc, "bb"), "\t$dst, $a, $b, $acc",
              [(set rGPR:$dst, (add rGPR:$acc,
                               (opnode (sext_inreg rGPR:$a, i16),
                                       (sext_inreg rGPR:$b, i16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b00;
  }
  def BT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
             !strconcat(opc, "bt"), "\t$dst, $a, $b, $acc",
             [(set rGPR:$dst, (add rGPR:$acc, (opnode (sext_inreg rGPR:$a, i16),
Jim Grosbach's avatar
Jim Grosbach committed
                                                  (sra rGPR:$b, (i32 16)))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b01;
  }
  def TB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
              !strconcat(opc, "tb"), "\t$dst, $a, $b, $acc",
              [(set rGPR:$dst, (add rGPR:$acc, (opnode (sra rGPR:$a, (i32 16)),
Jim Grosbach's avatar
Jim Grosbach committed
                                                (sext_inreg rGPR:$b, i16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b10;
  }
  def TT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
              !strconcat(opc, "tt"), "\t$dst, $a, $b, $acc",
             [(set rGPR:$dst, (add rGPR:$acc, (opnode (sra rGPR:$a, (i32 16)),
Jim Grosbach's avatar
Jim Grosbach committed
                                                  (sra rGPR:$b, (i32 16)))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b001;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b11;
  }
  def WB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
              !strconcat(opc, "wb"), "\t$dst, $a, $b, $acc",
              [(set rGPR:$dst, (add rGPR:$acc, (sra (opnode rGPR:$a,
Jim Grosbach's avatar
Jim Grosbach committed
                                     (sext_inreg rGPR:$b, i16)), (i32 16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b011;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b00;
  }
  def WT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16,
              !strconcat(opc, "wt"), "\t$dst, $a, $b, $acc",
              [(set rGPR:$dst, (add rGPR:$acc, (sra (opnode rGPR:$a,
Jim Grosbach's avatar
Jim Grosbach committed
                                       (sra rGPR:$b, (i32 16))), (i32 16))))]> {
    let Inst{31-27} = 0b11111;
    let Inst{26-23} = 0b0110;
    let Inst{22-20} = 0b011;
    let Inst{15-12} = {?, ?, ?, ?}; // Ra
    let Inst{7-6} = 0b00;
    let Inst{5-4} = 0b01;
  }
}

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 rGPR:$ldst,rGPR:$hdst),
Jim Grosbach's avatar
Jim Grosbach committed
         (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALBT : T2I_mac<1, 0b100, 0b1001, (outs rGPR:$ldst,rGPR:$hdst),
Jim Grosbach's avatar
Jim Grosbach committed
         (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALTB : T2I_mac<1, 0b100, 0b1010, (outs rGPR:$ldst,rGPR:$hdst),
Jim Grosbach's avatar
Jim Grosbach committed
         (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b",
           [/* For disassembly only; pattern left blank */]>;
def t2SMLALTT : T2I_mac<1, 0b100, 0b1011, (outs rGPR:$ldst,rGPR:$hdst),
Jim Grosbach's avatar
Jim Grosbach committed
         (ins rGPR:$a,rGPR:$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.

Jim Grosbach's avatar
Jim Grosbach committed
def t2SMUAD: T2I_mac<0, 0b010, 0b0000, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b),
                     IIC_iMAC32, "smuad", "\t$dst, $a, $b", []> {
Jim Grosbach's avatar
Jim Grosbach committed
def t2SMUADX:T2I_mac<0, 0b010, 0b0001, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b),
                     IIC_iMAC32, "smuadx", "\t$dst, $a, $b", []> {
Jim Grosbach's avatar
Jim Grosbach committed
def t2SMUSD: T2I_mac<0, 0b100, 0b0000, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b),
                     IIC_iMAC32, "smusd", "\t$dst, $a, $b", []> {
Jim Grosbach's avatar
Jim Grosbach committed
def t2SMUSDX:T2I_mac<0, 0b100, 0b0001, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b),
                     IIC_iMAC32, "smusdx", "\t$dst, $a, $b", []> {
def t2SMLAD   : T2I_mac<0, 0b010, 0b0000, (outs rGPR:$dst),
                        (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlad",
def t2SMLADX  : T2I_mac<0, 0b010, 0b0001, (outs rGPR:$dst),
                        (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smladx",
def t2SMLSD   : T2I_mac<0, 0b100, 0b0000, (outs rGPR:$dst),
                        (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlsd",
def t2SMLSDX  : T2I_mac<0, 0b100, 0b0001, (outs rGPR:$dst),
                        (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlsdx",
def t2SMLALD  : T2I_mac<1, 0b100, 0b1100, (outs rGPR:$ldst,rGPR:$hdst),
                        (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlald",
def t2SMLALDX : T2I_mac<1, 0b100, 0b1101, (outs rGPR:$ldst,rGPR:$hdst),
                        (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlaldx",
def t2SMLSLD  : T2I_mac<1, 0b101, 0b1100, (outs rGPR:$ldst,rGPR:$hdst),
                        (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlsld",
def t2SMLSLDX : T2I_mac<1, 0b101, 0b1101, (outs rGPR:$ldst,rGPR:$hdst),
                        (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlsldx",

//===----------------------------------------------------------------------===//
//  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 rGPR:$dst), (ins rGPR:$src), IIC_iUNAr,
                    "clz", "\t$dst, $src", [(set rGPR:$dst, (ctlz rGPR:$src))]>;
def t2RBIT : T2I_misc<0b01, 0b10, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr,
                      [(set rGPR:$dst, (ARMrbit rGPR:$src))]>;
def t2REV : T2I_misc<0b01, 0b00, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr,
Jim Grosbach's avatar
Jim Grosbach committed
                 "rev", ".w\t$dst, $src", [(set rGPR:$dst, (bswap rGPR:$src))]>;
def t2REV16 : T2I_misc<0b01, 0b01, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr,
                       "rev16", ".w\t$dst, $src",
                [(set rGPR:$dst,
                    (or (and (srl rGPR:$src, (i32 8)), 0xFF),
                        (or (and (shl rGPR:$src, (i32 8)), 0xFF00),
                            (or (and (srl rGPR:$src, (i32 8)), 0xFF0000),
Jim Grosbach's avatar
Jim Grosbach committed
                               (and (shl rGPR:$src, (i32 8)), 0xFF000000)))))]>;
def t2REVSH : T2I_misc<0b01, 0b11, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr,
                       "revsh", ".w\t$dst, $src",
                      (or (srl (and rGPR:$src, 0xFF00), (i32 8)),
                          (shl rGPR:$src, (i32 8))), i16))]>;
def t2PKHBT : T2I<(outs rGPR:$dst), (ins rGPR:$src1, rGPR:$src2, shift_imm:$sh),
                  IIC_iBITsi, "pkhbt", "\t$dst, $src1, $src2$sh",
                  [(set rGPR:$dst, (or (and rGPR:$src1, 0xFFFF),
                                      (and (shl rGPR:$src2, lsl_amt:$sh),
                  Requires<[HasT2ExtractPack, IsThumb2]> {
  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 rGPR:$src1, 0xFFFF), (and rGPR:$src2, 0xFFFF0000)),
            (t2PKHBT rGPR:$src1, rGPR:$src2, 0)>,
            Requires<[HasT2ExtractPack, IsThumb2]>;
def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (shl rGPR:$src2, imm16_31:$sh)),
            (t2PKHBT rGPR:$src1, rGPR:$src2, (lsl_shift_imm imm16_31:$sh))>,
            Requires<[HasT2ExtractPack, IsThumb2]>;
// Note: Shifts of 1-15 bits will be transformed to srl instead of sra and
// will match the pattern below.
def t2PKHTB : T2I<(outs rGPR:$dst), (ins rGPR:$src1, rGPR:$src2, shift_imm:$sh),
                  IIC_iBITsi, "pkhtb", "\t$dst, $src1, $src2$sh",
                  [(set rGPR:$dst, (or (and rGPR:$src1, 0xFFFF0000),
                                       (and (sra rGPR:$src2, asr_amt:$sh),
                                            0xFFFF)))]>,
                  Requires<[HasT2ExtractPack, IsThumb2]> {
  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 rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16_31:$sh)),
            (t2PKHTB rGPR:$src1, rGPR:$src2, (asr_shift_imm imm16_31:$sh))>,
            Requires<[HasT2ExtractPack, IsThumb2]>;
def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000),
                (and (srl rGPR:$src2, imm1_15:$sh), 0xFFFF)),
            (t2PKHTB rGPR:$src1, rGPR:$src2, (asr_shift_imm imm1_15:$sh))>,
            Requires<[HasT2ExtractPack, IsThumb2]>;

//===----------------------------------------------------------------------===//
//  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)>>;
// 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. :(
let neverHasSideEffects = 1 in {
def t2MOVCCr : T2I<(outs rGPR:$dst), (ins rGPR:$false, rGPR:$true), IIC_iCMOVr,
   [/*(set rGPR:$dst, (ARMcmov rGPR:$false, rGPR:$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 rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true),
[/*(set rGPR:$dst,(ARMcmov rGPR:$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;
}

def t2MOVCCi16 : T2I<(outs rGPR:$dst), (ins rGPR:$false, i32imm:$src),
                      IIC_iCMOVi,
                      "movw", "\t$dst, $src", []>,
                      RegConstraint<"$false = $dst"> {
  let Inst{31-27} = 0b11110;
  let Inst{25} = 1;
  let Inst{24-21} = 0b0010;
  let Inst{20} = 0; // The S bit.
  let Inst{15} = 0;
}

def t2MOVCCi32imm : PseudoInst<(outs rGPR:$dst),
                               (ins rGPR:$false, i32imm:$src, pred:$p),
                    IIC_iCMOVix2, "", []>, RegConstraint<"$false = $dst">;
def t2MVNCCi : T2I<(outs rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true),
                   IIC_iCMOVi, "mvn", ".w\t$dst, $true",
[/*(set rGPR:$dst,(ARMcmov rGPR:$false,t2_so_imm_not:$true,
                   imm:$cc, CCR:$ccr))*/]>,
                   RegConstraint<"$false = $dst"> {
  let Inst{31-27} = 0b11110;
  let Inst{25} = 0;
  let Inst{24-21} = 0b0011;
  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 rGPR:$dst),
                             (ins rGPR:$false, rGPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "lsl", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCClsr : T2I_movcc_sh<0b01, (outs rGPR:$dst),
                             (ins rGPR:$false, rGPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "lsr", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCCasr : T2I_movcc_sh<0b10, (outs rGPR:$dst),
                             (ins rGPR:$false, rGPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCCror : T2I_movcc_sh<0b11, (outs rGPR:$dst),
                             (ins rGPR:$false, rGPR:$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 t2DMB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary,
                  "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>,
                  Requires<[IsThumb, HasDB]> {
  bits<4> opt;
  let Inst{31-4} = 0xf3bf8f5;
  let Inst{3-0} = opt;
def t2DSB : AInoP<(outs), (ins memb_opt:$opt), ThumbFrm, NoItinerary,
                  "dsb", "\t$opt",
                  [/* For disassembly only; pattern left blank */]>,
                  Requires<[IsThumb, HasDB]> {
  bits<4> opt;
  let Inst{31-4} = 0xf3bf8f4;
  let Inst{3-0} = opt;
}

// ISB has only full system option -- for disassembly only
def t2ISB : T2I<(outs), (ins), NoItinerary, "isb", "",
                  [/* For disassembly only; pattern left blank */]>,
                  Requires<[IsThumb2, HasV7]> {
  let Inst{31-4} = 0xf3bf8f6;
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 rGPR:$dest), (ins rGPR:$ptr), AddrModeNone,
                         Size4Bytes, NoItinerary, "ldrexb", "\t$dest, [$ptr]",
                         "", []>;
def t2LDREXH : T2I_ldrex<0b01, (outs rGPR:$dest), (ins rGPR:$ptr), AddrModeNone,
                         Size4Bytes, NoItinerary, "ldrexh", "\t$dest, [$ptr]",
                         "", []>;
def t2LDREX  : Thumb2I<(outs rGPR:$dest), (ins rGPR:$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 rGPR:$dest, rGPR:$dest2), (ins rGPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "ldrexd", "\t$dest, $dest2, [$ptr]", "",
                         [], {?, ?, ?, ?}>;
let mayStore = 1, Constraints = "@earlyclobber $success" in {
def t2STREXB : T2I_strex<0b00, (outs rGPR:$success), (ins rGPR:$src, rGPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "strexb", "\t$success, $src, [$ptr]", "", []>;
def t2STREXH : T2I_strex<0b01, (outs rGPR:$success), (ins rGPR:$src, rGPR:$ptr),
                         AddrModeNone, Size4Bytes, NoItinerary,
                         "strexh", "\t$success, $src, [$ptr]", "", []>;
def t2STREX  : Thumb2I<(outs rGPR:$success), (ins rGPR:$src, rGPR:$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 rGPR:$success),
                         (ins rGPR:$src, rGPR:$src2, rGPR:$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, isCodeGenOnly = 1 in {
  def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val),
                               AddrModeNone, SizeSpecial, NoItinerary, "", "",
                          [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>,
  [ R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,  R8,  R9,  R10, R11, R12, LR ],
  hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1 in {
  def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val),
                               AddrModeNone, SizeSpecial, NoItinerary, "", "",
                          [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>,
//===----------------------------------------------------------------------===//
// 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, isCodeGenOnly = 1 in
  def t2LDM_RET: T2XIt<(outs GPR:$wb), (ins GPR:$Rn, ldstm_mode:$amode, pred:$p,
                                        reglist:$dsts, variable_ops),
                        "ldm${amode}${p}.w\t$Rn!, $dsts",
                        "$Rn = $wb", []> {
  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,
    isCodeGenOnly = 1 in { // $id doesn't exist in asmstring, should be lowered.
    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.
let isCodeGenOnly = 1 in  // $id doesn't exist in asm string, should be lowered.
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
  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
}
let isCodeGenOnly = 1 in  // $id doesn't exist in asm string, should be lowered.
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
  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 rGPR:$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 rGPR:$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 rGPR:$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 rGPR:$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 rGPR:$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
//

def : T2Pat<(or rGPR:$LHS, t2_so_imm2part:$RHS),
             (t2ORRri (t2ORRri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
def : T2Pat<(xor rGPR:$LHS, t2_so_imm2part:$RHS),
             (t2EORri (t2EORri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
def : T2Pat<(add rGPR:$LHS, t2_so_imm2part:$RHS),
             (t2ADDri (t2ADDri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
def : T2Pat<(add rGPR:$LHS, t2_so_neg_imm2part:$RHS),
             (t2SUBri (t2SUBri rGPR:$LHS, (t2_so_neg_imm2part_1 imm:$RHS)),
// This is a single pseudo instruction to make it re-materializable.
// FIXME: Remove this when we can do generalized remat.
def t2MOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVix2,
                            "", [(set rGPR:$dst, (i32 imm:$src))]>,
                            Requires<[IsThumb, HasV6T2]>;
// 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),
                   IIC_iLoadiALU, "",
               [(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 rGPR:$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 rGPR:$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 rGPR:$src, msr_mask:$mask), NoItinerary, "msr",
                [/* 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 rGPR:$src, msr_mask:$mask), NoItinerary, "msr",
                   [/* 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;
}