Skip to content
ARMInstrInfo.td 114 KiB
Newer Older
// Halfword multiply accumulate long: SMLAL<x><y> -- for disassembly only
def SMLALBB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 0;
  let Inst{6} = 0;
}

def SMLALBT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 0;
  let Inst{6} = 1;
}

def SMLALTB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 1;
  let Inst{6} = 0;
}

def SMLALTT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                      IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b",
                      [/* For disassembly only; pattern left blank */]>,
              Requires<[IsARM, HasV5TE]> {
  let Inst{5} = 1;
  let Inst{6} = 1;
}

// Helper class for AI_smld -- for disassembly only
class AMulDualI<bit long, bit sub, bit swap, dag oops, dag iops,
                InstrItinClass itin, string opc, string asm>
  : AI<oops, iops, MulFrm, itin, opc, asm, []>, Requires<[IsARM, HasV6]> {
  let Inst{4}     = 1;
  let Inst{5}     = swap;
  let Inst{6}     = sub;
  let Inst{7}     = 0;
  let Inst{21-20} = 0b00;
  let Inst{22}    = long;
  let Inst{27-23} = 0b01110;
}

multiclass AI_smld<bit sub, string opc> {

  def D : AMulDualI<0, sub, 0, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                  NoItinerary, !strconcat(opc, "d"), "\t$dst, $a, $b, $acc">;

  def DX : AMulDualI<0, sub, 1, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc),
                  NoItinerary, !strconcat(opc, "dx"), "\t$dst, $a, $b, $acc">;

  def LD : AMulDualI<1, sub, 0, (outs GPR:$ldst,GPR:$hdst), (ins GPR:$a,GPR:$b),
                  NoItinerary, !strconcat(opc, "ld"), "\t$ldst, $hdst, $a, $b">;

  def LDX : AMulDualI<1, sub, 1, (outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b),
                  NoItinerary, !strconcat(opc, "ldx"),"\t$ldst, $hdst, $a, $b">;

}

defm SMLA : AI_smld<0, "smla">;
defm SMLS : AI_smld<1, "smls">;

multiclass AI_sdml<bit sub, string opc> {

  def D : AMulDualI<0, sub, 0, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                    NoItinerary, !strconcat(opc, "d"), "\t$dst, $a, $b"> {
    let Inst{15-12} = 0b1111;
  }

  def DX : AMulDualI<0, sub, 1, (outs GPR:$dst), (ins GPR:$a, GPR:$b),
                    NoItinerary, !strconcat(opc, "dx"), "\t$dst, $a, $b"> {
    let Inst{15-12} = 0b1111;
  }

}

defm SMUA : AI_sdml<0, "smua">;
defm SMUS : AI_sdml<1, "smus">;
//===----------------------------------------------------------------------===//
//  Misc. Arithmetic Instructions.
//
def CLZ  : AMiscA1I<0b000010110, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              [(set GPR:$dst, (ctlz GPR:$src))]>, Requires<[IsARM, HasV5T]> {
  let Inst{7-4}   = 0b0001;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
Jim Grosbach's avatar
Jim Grosbach committed
def RBIT : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              "rbit", "\t$dst, $src",
              [(set GPR:$dst, (ARMrbit GPR:$src))]>,
           Requires<[IsARM, HasV6T2]> {
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{7-4}   = 0b0011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}

def REV  : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
              [(set GPR:$dst, (bswap GPR:$src))]>, Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b0011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def REV16 : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
               [(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)))))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b1011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def REVSH : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr,
               [(set GPR:$dst,
                  (sext_inreg
                    (or (srl (and GPR:$src, 0xFF00), (i32 8)),
                        (shl GPR:$src, (i32 8))), i16))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{7-4}   = 0b1011;
  let Inst{11-8}  = 0b1111;
  let Inst{19-16} = 0b1111;
}
def PKHBT : AMiscA1I<0b01101000, (outs GPR:$dst),
                                 (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2, lsl $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF),
                                   (and (shl GPR:$src2, (i32 imm:$shamt)),
                                        0xFFFF0000)))]>,
               Requires<[IsARM, HasV6]> {
  let Inst{6-4} = 0b001;
}

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


def PKHTB : AMiscA1I<0b01101000, (outs GPR:$dst),
                                 (ins GPR:$src1, GPR:$src2, i32imm:$shamt),
               IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2, asr $shamt",
               [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000),
                                   (and (sra GPR:$src2, imm16_31:$shamt),
                                        0xFFFF)))]>, Requires<[IsARM, HasV6]> {
  let Inst{6-4} = 0b101;
}

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

                        BinOpFrag<(ARMcmp 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 CMN  : AI1_cmp_irs<0b1011, "cmn",
//                        BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;

// Note that TST/TEQ don't set all the same flags that CMP does!
                        BinOpFrag<(ARMcmpZ (and node:$LHS, node:$RHS), 0)>, 1>;
                        BinOpFrag<(ARMcmpZ (xor node:$LHS, node:$RHS), 0)>, 1>;
defm CMPz  : AI1_cmp_irs<0b1010, "cmp",
                         BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>;
defm CMNz  : AI1_cmp_irs<0b1011, "cmn",
                         BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>;
//def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm),
//             (CMNri  GPR:$src, so_imm_neg:$imm)>;
def : ARMPat<(ARMcmpZ GPR:$src, so_imm_neg:$imm),

// 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 MOVCCr : AI1<0b1101, (outs GPR:$dst), (ins GPR:$false, GPR:$true), DPFrm,
      [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">, UnaryDP {
                        (ins GPR:$false, so_reg:$true), DPSoRegFrm, IIC_iCMOVsr,
   [/*(set GPR:$dst, (ARMcmov GPR:$false, so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">, UnaryDP {
  let Inst{25} = 0;
}
                        (ins GPR:$false, so_imm:$true), DPFrm, IIC_iCMOVi,
   [/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
//===----------------------------------------------------------------------===//
// Atomic operations intrinsics
//

// memory barriers protect the atomic sequences
let hasSideEffects = 1 in {
def Int_MemBarrierV7 : AInoP<(outs), (ins),
                        [(ARMMemBarrierV7)]>,
  let Inst{31-4} = 0xf57ff05;
  // FIXME: add support for options other than a full system DMB
  // See DMB disassembly-only variants below.
  let Inst{3-0} = 0b1111;
}
def Int_SyncBarrierV7 : AInoP<(outs), (ins),
                        [(ARMSyncBarrierV7)]>,
  let Inst{31-4} = 0xf57ff04;
  // FIXME: add support for options other than a full system DSB
  // See DSB disassembly-only variants below.
  let Inst{3-0} = 0b1111;
}

def Int_MemBarrierV6 : AInoP<(outs), (ins GPR:$zero),
                       Pseudo, NoItinerary,
                       "mcr", "\tp15, 0, $zero, c7, c10, 5",
                       [(ARMMemBarrierV6 GPR:$zero)]>,
                       Requires<[IsARM, HasV6]> {
  // FIXME: add support for options other than a full system DMB
  // FIXME: add encoding
}

def Int_SyncBarrierV6 : AInoP<(outs), (ins GPR:$zero),
                        Pseudo, NoItinerary,
                        "mcr", "\tp15, 0, $zero, c7, c10, 4",
                        [(ARMSyncBarrierV6 GPR:$zero)]>,
                        Requires<[IsARM, HasV6]> {
  // FIXME: add support for options other than a full system DSB
  // FIXME: add encoding
}
// Helper class for multiclass MemB -- for disassembly only
class AMBI<string opc, string asm>
  : AInoP<(outs), (ins), MiscFrm, NoItinerary, opc, asm,
          [/* For disassembly only; pattern left blank */]>,
    Requires<[IsARM, HasV7]> {
  let Inst{31-20} = 0xf57;
}

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

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

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

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

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

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

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

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

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

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

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

Jim Grosbach's avatar
Jim Grosbach committed
let usesCustomInserter = 1 in {
  let Uses = [CPSR] in {
    def ATOMIC_LOAD_ADD_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_ADD_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_add_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_SUB_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_SUB_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_sub_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_AND_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_AND_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_and_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_OR_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_OR_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_or_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_XOR_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_XOR_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_xor_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_NAND_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_NAND_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_load_nand_8 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_ADD_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_ADD_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_add_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_SUB_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_SUB_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_sub_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_AND_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_AND_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_and_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_OR_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_OR_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_or_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_XOR_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_XOR_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_xor_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_NAND_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_NAND_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_load_nand_16 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_ADD_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_ADD_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_add_32 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_SUB_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_SUB_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_sub_32 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_AND_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_AND_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_and_32 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_OR_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_OR_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_or_32 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_XOR_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_XOR_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_xor_32 GPR:$ptr, GPR:$incr))]>;
    def ATOMIC_LOAD_NAND_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
      "${:comment} ATOMIC_LOAD_NAND_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_load_nand_32 GPR:$ptr, GPR:$incr))]>;

    def ATOMIC_SWAP_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_SWAP_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_swap_8 GPR:$ptr, GPR:$new))]>;
    def ATOMIC_SWAP_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_SWAP_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_swap_16 GPR:$ptr, GPR:$new))]>;
    def ATOMIC_SWAP_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_SWAP_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_swap_32 GPR:$ptr, GPR:$new))]>;

    def ATOMIC_CMP_SWAP_I8 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_CMP_SWAP_I8 PSEUDO!",
      [(set GPR:$dst, (atomic_cmp_swap_8 GPR:$ptr, GPR:$old, GPR:$new))]>;
    def ATOMIC_CMP_SWAP_I16 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_CMP_SWAP_I16 PSEUDO!",
      [(set GPR:$dst, (atomic_cmp_swap_16 GPR:$ptr, GPR:$old, GPR:$new))]>;
    def ATOMIC_CMP_SWAP_I32 : PseudoInst<
      (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
      "${:comment} ATOMIC_CMP_SWAP_I32 PSEUDO!",
      [(set GPR:$dst, (atomic_cmp_swap_32 GPR:$ptr, GPR:$old, GPR:$new))]>;
}
}

let mayLoad = 1 in {
def LDREXB : AIldrex<0b10, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
                    "ldrexb", "\t$dest, [$ptr]",
                    []>;
def LDREXH : AIldrex<0b11, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
                    "ldrexh", "\t$dest, [$ptr]",
                    []>;
def LDREX  : AIldrex<0b00, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary,
                    "ldrex", "\t$dest, [$ptr]",
                    []>;
def LDREXD : AIldrex<0b01, (outs GPR:$dest, GPR:$dest2), (ins GPR:$ptr),
                    NoItinerary,
                    "ldrexd", "\t$dest, $dest2, [$ptr]",
                    []>;
let mayStore = 1, Constraints = "@earlyclobber $success" in {
def STREXB : AIstrex<0b10, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                    NoItinerary,
                    "strexb", "\t$success, $src, [$ptr]",
                    []>;
def STREXH : AIstrex<0b11, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                    NoItinerary,
                    "strexh", "\t$success, $src, [$ptr]",
                    []>;
def STREX  : AIstrex<0b00, (outs GPR:$success), (ins GPR:$src, GPR:$ptr),
                    NoItinerary,
def STREXD : AIstrex<0b01, (outs GPR:$success),
                    (ins GPR:$src, GPR:$src2, GPR:$ptr),
                    NoItinerary,
                    "strexd", "\t$success, $src, $src2, [$ptr]",
                    []>;
// Clear-Exclusive is for disassembly only.
def CLREX : AXI<(outs), (ins), MiscFrm, NoItinerary, "clrex",
                [/* For disassembly only; pattern left blank */]>,
            Requires<[IsARM, HasV7]>  {
  let Inst{31-20} = 0xf57;
  let Inst{7-4} = 0b0001;
}

// SWP/SWPB are deprecated in V6/V7 and for disassembly only.
let mayLoad = 1 in {
def SWP : AI<(outs GPR:$dst), (ins GPR:$src, GPR:$ptr), LdStExFrm, NoItinerary,
             "swp", "\t$dst, $src, [$ptr]",
             [/* For disassembly only; pattern left blank */]> {
  let Inst{27-23} = 0b00010;
  let Inst{22} = 0; // B = 0
  let Inst{21-20} = 0b00;
  let Inst{7-4} = 0b1001;
}

def SWPB : AI<(outs GPR:$dst), (ins GPR:$src, GPR:$ptr), LdStExFrm, NoItinerary,
             "swpb", "\t$dst, $src, [$ptr]",
             [/* For disassembly only; pattern left blank */]> {
  let Inst{27-23} = 0b00010;
  let Inst{22} = 1; // B = 1
  let Inst{21-20} = 0b00;
  let Inst{7-4} = 0b1001;
}
}

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

// __aeabi_read_tp preserves the registers r1-r3.
  def TPsoft : ABXI<0b1011, (outs), (ins), IIC_Br,
//===----------------------------------------------------------------------===//
// 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.
//   A constant value is passed in $val, and we use the location as a scratch.
let Defs =
  [ 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,
  def Int_eh_sjlj_setjmp : XI<(outs), (ins GPR:$src, GPR:$val),
                               AddrModeNone, SizeSpecial, IndexModeNone,
                               Pseudo, NoItinerary,
                               "str\tsp, [$src, #+8] ${:comment} eh_setjmp begin\n\t"
                               "add\t$val, pc, #8\n\t"
                               "str\t$val, [$src, #+4]\n\t"
                         [(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>,
                           Requires<[IsARM, HasVFP2]>;
}

let Defs =
  [ R0,  R1,  R2,  R3,  R4,  R5,  R6,  R7,  R8,  R9,  R10, R11, R12, LR ] in {
  def Int_eh_sjlj_setjmp_nofp : XI<(outs), (ins GPR:$src, GPR:$val),
                                   AddrModeNone, SizeSpecial, IndexModeNone,
                                   Pseudo, NoItinerary,
                                   "str\tsp, [$src, #+8] ${:comment} eh_setjmp begin\n\t"
                                   "add\t$val, pc, #8\n\t"
                                   "str\t$val, [$src, #+4]\n\t"
                                   "mov\tr0, #0\n\t"
                                   "add\tpc, pc, #0\n\t"
                         [(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>,
                                Requires<[IsARM, NoVFP]>;
// FIXME: Non-Darwin version(s)
let isBarrier = 1, hasSideEffects = 1, isTerminator = 1,
    Defs = [ R7, LR, SP ] in {
def Int_eh_sjlj_longjmp : XI<(outs), (ins GPR:$src, GPR:$scratch),
                             AddrModeNone, SizeSpecial, IndexModeNone,
                             Pseudo, NoItinerary,
                             "ldr\tsp, [$src, #8]\n\t"
                             "ldr\t$scratch, [$src, #4]\n\t"
                             "ldr\tr7, [$src]\n\t"
                             "bx\t$scratch", "",
                         [(ARMeh_sjlj_longjmp GPR:$src, GPR:$scratch)]>,
                                Requires<[IsARM, IsDarwin]>;
}

//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//
// Large immediate handling.
Rafael Espindola's avatar
Rafael Espindola committed

// Two piece so_imms.
Jim Grosbach's avatar
Jim Grosbach committed
def MOVi2pieces : AI1x2<(outs GPR:$dst), (ins so_imm2part:$src),
                         [(set GPR:$dst, so_imm2part:$src)]>,
                  Requires<[IsARM, NoV6T2]>;
def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS),
             (ORRri (ORRri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
                    (so_imm2part_2 imm:$RHS))>;
def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS),
             (EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
                    (so_imm2part_2 imm:$RHS))>;
def : ARMPat<(add GPR:$LHS, so_imm2part:$RHS),
             (ADDri (ADDri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
                    (so_imm2part_2 imm:$RHS))>;
def : ARMPat<(add GPR:$LHS, so_neg_imm2part:$RHS),
             (SUBri (SUBri GPR:$LHS, (so_neg_imm2part_1 imm:$RHS)),
                    (so_neg_imm2part_2 imm:$RHS))>;
Rafael Espindola's avatar
Rafael Espindola committed

// This is a single pseudo instruction, the benefit is that it can be remat'd
// as a single unit instead of having to handle reg inputs.
// FIXME: Remove this when we can do generalized remat.
let isReMaterializable = 1 in
def MOVi32imm : AI1x2<(outs GPR:$dst), (ins i32imm:$src), Pseudo, IIC_iMOVi,
Jim Grosbach's avatar
Jim Grosbach committed
                   "movw", "\t$dst, ${src:lo16}\n\tmovt${p}\t$dst, ${src:hi16}",
                     [(set GPR:$dst, (i32 imm:$src))]>,
               Requires<[IsARM, HasV6T2]>;
// ConstantPool, GlobalAddress, and JumpTable
def : ARMPat<(ARMWrapper  tglobaladdr :$dst), (LEApcrel tglobaladdr :$dst)>,
            Requires<[IsARM, DontUseMovt]>;
def : ARMPat<(ARMWrapper  tconstpool  :$dst), (LEApcrel tconstpool  :$dst)>;
def : ARMPat<(ARMWrapper  tglobaladdr :$dst), (MOVi32imm tglobaladdr :$dst)>,
            Requires<[IsARM, UseMovt]>;
def : ARMPat<(ARMWrapperJT tjumptable:$dst, imm:$id),
             (LEApcrelJT tjumptable:$dst, imm:$id)>;

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

// Direct calls
def : ARMPat<(ARMcall texternalsym:$func), (BL texternalsym:$func)>,
      Requires<[IsARM, IsNotDarwin]>;
def : ARMPat<(ARMcall texternalsym:$func), (BLr9 texternalsym:$func)>,
      Requires<[IsARM, IsDarwin]>;
// zextload i1 -> zextload i8
def : ARMPat<(zextloadi1 addrmode2:$addr),  (LDRB addrmode2:$addr)>;
// extload -> zextload
def : ARMPat<(extloadi1  addrmode2:$addr),  (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi8  addrmode2:$addr),  (LDRB addrmode2:$addr)>;
def : ARMPat<(extloadi16 addrmode3:$addr),  (LDRH addrmode3:$addr)>;
def : ARMPat<(extloadi8  addrmodepc:$addr), (PICLDRB addrmodepc:$addr)>;
def : ARMPat<(extloadi16 addrmodepc:$addr), (PICLDRH addrmodepc:$addr)>;

def : ARMV5TEPat<(mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
                      (sra (shl GPR:$b, (i32 16)), (i32 16))),
                 (SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul sext_16_node:$a, sext_16_node:$b),
                 (SMULBB GPR:$a, GPR:$b)>;
def : ARMV5TEPat<(mul (sra (shl GPR:$a, (i32 16)), (i32 16)),
                      (sra GPR:$b, (i32 16))),
def : ARMV5TEPat<(mul sext_16_node:$a, (sra GPR:$b, (i32 16))),
def : ARMV5TEPat<(mul (sra GPR:$a, (i32 16)),
                      (sra (shl GPR:$b, (i32 16)), (i32 16))),
def : ARMV5TEPat<(mul (sra GPR:$a, (i32 16)), sext_16_node:$b),
def : ARMV5TEPat<(sra (mul GPR:$a, (sra (shl GPR:$b, (i32 16)), (i32 16))),
                      (i32 16)),
def : ARMV5TEPat<(sra (mul GPR:$a, sext_16_node:$b), (i32 16)),
                 (SMULWB GPR:$a, GPR:$b)>;

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

//===----------------------------------------------------------------------===//
// Thumb Support
//
include "ARMInstrThumb.td"
//===----------------------------------------------------------------------===//
// Thumb2 Support
//

include "ARMInstrThumb2.td"

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

//===----------------------------------------------------------------------===//
// Advanced SIMD (NEON) Support
//

include "ARMInstrNEON.td"

//===----------------------------------------------------------------------===//
// Coprocessor Instructions.  For disassembly only.
//

def CDP : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
            nohash_imm:$CRd, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
            NoItinerary, "cdp", "\tp$cop, $opc1, cr$CRd, cr$CRn, cr$CRm, $opc2",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{4} = 0;
}

def CDP2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
               nohash_imm:$CRd, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
               NoItinerary, "cdp2\tp$cop, $opc1, cr$CRd, cr$CRn, cr$CRm, $opc2",
               [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{4} = 0;
}

class ACI<dag oops, dag iops, string opc, string asm>
  : I<oops, iops, AddrModeNone, Size4Bytes, IndexModeNone, BrFrm, NoItinerary,
      opc, asm, "", [/* For disassembly only; pattern left blank */]> {
  let Inst{27-25} = 0b110;
}

multiclass LdStCop<bits<4> op31_28, bit load, string opc> {

  def _OFFSET : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
      opc, "\tp$cop, cr$CRd, $addr"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 1; // P = 1
    let Inst{21} = 0; // W = 0
    let Inst{22} = 0; // D = 0
    let Inst{20} = load;
  }

  def _PRE : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
      opc, "\tp$cop, cr$CRd, $addr!"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 1; // P = 1
    let Inst{21} = 1; // W = 1
    let Inst{22} = 0; // D = 0
    let Inst{20} = load;
  }

  def _POST : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, GPR:$base, am2offset:$offset),
      opc, "\tp$cop, cr$CRd, [$base], $offset"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 0; // P = 0
    let Inst{21} = 1; // W = 1
    let Inst{22} = 0; // D = 0
    let Inst{20} = load;
  }

  def _OPTION : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, GPR:$base, i32imm:$option),
      opc, "\tp$cop, cr$CRd, [$base], $option"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 0; // P = 0
    let Inst{23} = 1; // U = 1
    let Inst{21} = 0; // W = 0
    let Inst{22} = 0; // D = 0
    let Inst{20} = load;
  }

  def L_OFFSET : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
      !strconcat(opc, "l"), "\tp$cop, cr$CRd, $addr"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 1; // P = 1
    let Inst{21} = 0; // W = 0
    let Inst{22} = 1; // D = 1
    let Inst{20} = load;
  }

  def L_PRE : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, addrmode2:$addr),
      !strconcat(opc, "l"), "\tp$cop, cr$CRd, $addr!"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 1; // P = 1
    let Inst{21} = 1; // W = 1
    let Inst{22} = 1; // D = 1
    let Inst{20} = load;
  }

  def L_POST : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, GPR:$base, am2offset:$offset),
      !strconcat(opc, "l"), "\tp$cop, cr$CRd, [$base], $offset"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 0; // P = 0
    let Inst{21} = 1; // W = 1
    let Inst{22} = 1; // D = 1
    let Inst{20} = load;
  }

  def L_OPTION : ACI<(outs),
      (ins nohash_imm:$cop, nohash_imm:$CRd, GPR:$base, nohash_imm:$option),
      !strconcat(opc, "l"), "\tp$cop, cr$CRd, [$base], $option"> {
    let Inst{31-28} = op31_28;
    let Inst{24} = 0; // P = 0
    let Inst{23} = 1; // U = 1
    let Inst{21} = 0; // W = 0
    let Inst{22} = 1; // D = 1
    let Inst{20} = load;
  }
}

defm LDC  : LdStCop<{?,?,?,?}, 1, "ldc">;
defm LDC2 : LdStCop<0b1111,    1, "ldc2">;
defm STC  : LdStCop<{?,?,?,?}, 0, "stc">;
defm STC2 : LdStCop<0b1111,    0, "stc2">;

def MCR : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
              GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
              NoItinerary, "mcr", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{20} = 0;
  let Inst{4} = 1;
}

def MCR2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
                GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
                NoItinerary, "mcr2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{20} = 0;
  let Inst{4} = 1;
}

def MRC : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
              GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
              NoItinerary, "mrc", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{20} = 1;
  let Inst{4} = 1;
}

def MRC2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1,
                GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2),
                NoItinerary, "mrc2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{20} = 1;
  let Inst{4} = 1;
}

def MCRR : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc,
               GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm),
               NoItinerary, "mcrr", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm",
               [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0100;
}

def MCRR2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc,
                 GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm),
                 NoItinerary, "mcrr2\tp$cop, $opc, $Rt, $Rt2, cr$CRm",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{23-20} = 0b0100;
}

def MRRC : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc,
               GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm),
               NoItinerary, "mrrc", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm",
               [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0101;
}

def MRRC2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc,
                 GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm),
                 NoItinerary, "mrrc2\tp$cop, $opc, $Rt, $Rt2, cr$CRm",
                 [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{23-20} = 0b0101;
}

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

def MRS : ABI<0b0001,(outs GPR:$dst),(ins), NoItinerary, "mrs", "\t$dst, cpsr",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0000;
  let Inst{7-4} = 0b0000;
}

def MRSsys : ABI<0b0001,(outs GPR:$dst),(ins), NoItinerary,"mrs","\t$dst, spsr",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0100;
  let Inst{7-4} = 0b0000;
}

def MSR : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary,
              "msr", "\tcpsr$mask, $src",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0010;
  let Inst{7-4} = 0b0000;
}

def MSRi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary,
              "msr", "\tcpsr$mask, $a",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0010;
  let Inst{7-4} = 0b0000;
}

def MSRsys : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary,
              "msr", "\tspsr$mask, $src",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0110;
  let Inst{7-4} = 0b0000;
}

def MSRsysi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary,
              "msr", "\tspsr$mask, $a",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{23-20} = 0b0110;
  let Inst{7-4} = 0b0000;
}