Skip to content
ARMInstrInfo.td 134 KiB
Newer Older
// 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
Jim Grosbach's avatar
Jim Grosbach committed
// FIXME: Integrated assembler will need these split out.
def CPS : AXI<(outs), (ins cps_opt:$opt), MiscFrm, NoItinerary, "cps$opt",
              [/* For disassembly only; pattern left blank */]>,
          Requires<[IsARM]> {
  let Inst{31-28} = 0b1111;
  let Inst{27-20} = 0b00010000;
  let Inst{16} = 0;
  let Inst{5} = 0;
}

// Preload signals the memory system of possible future data/instruction access.
// These are for disassembly only.
multiclass APreLoad<bits<1> read, bits<1> data, string opc> {
  def i12 : AXI<(outs), (ins addrmode_imm12:$addr), MiscFrm, IIC_Preload,
                [(ARMPreload addrmode_imm12:$addr, (i32 read), (i32 data))]> {
    let Inst{31-26} = 0b111101;
    let Inst{25} = 0; // 0 for immediate form
    let Inst{23} = addr{12};        // U (add = ('U' == 1))
    let Inst{19-16} = addr{16-13};  // Rn
    let Inst{15-12} = Rt;
    let Inst{11-0}  = addr{11-0};   // imm12
  def rs : AXI<(outs), (ins ldst_so_reg:$shift), MiscFrm, IIC_Preload,
               [(ARMPreload ldst_so_reg:$shift, (i32 read), (i32 data))]> {
    let Inst{31-26} = 0b111101;
    let Inst{25} = 1; // 1 for register form
    let Inst{23} = shift{12};    // U (add = ('U' == 1))
    let Inst{19-16} = shift{16-13}; // Rn
    let Inst{11-0}  = shift{11-0};
defm PLD  : APreLoad<1, 1, "pld">,  Requires<[IsARM]>;
defm PLDW : APreLoad<0, 1, "pldw">, Requires<[IsARM,HasV7,HasMP]>;
defm PLI  : APreLoad<1, 0, "pli">,  Requires<[IsARM,HasV7]>;
def SETEND : AXI<(outs),(ins setend_op:$end), MiscFrm, NoItinerary,
                 "setend\t$end",
                 [/* For disassembly only; pattern left blank */]>,
  bits<1> end;
  let Inst{31-10} = 0b1111000100000001000000;
  let Inst{9} = end;
  let Inst{8-0} = 0;
def DBG : AI<(outs), (ins i32imm:$opt), MiscFrm, NoItinerary, "dbg", "\t$opt",
             [/* For disassembly only; pattern left blank */]>,
          Requires<[IsARM, HasV7]> {
  bits<4> opt;
  let Inst{27-4} = 0b001100100000111100001111;
  let Inst{3-0} = opt;
// A5.4 Permanently UNDEFINED instructions.
let isBarrier = 1, isTerminator = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def TRAP : AXI<(outs), (ins), MiscFrm, NoItinerary,
           Requires<[IsARM]> {
  let Inst{27-25} = 0b011;
  let Inst{24-20} = 0b11111;
  let Inst{7-5} = 0b111;
  let Inst{4} = 0b1;
}

// Address computation and loads and stores in PIC mode.
Jim Grosbach's avatar
Jim Grosbach committed
// FIXME: These PIC insn patterns are pseudos, but derive from the normal insn
//        classes (AXI1, et.al.) and so have encoding information and such,
//        which is suboptimal. Once the rest of the code emitter (including
//        JIT) is MC-ized we should look at refactoring these into true
//        pseudos. As is, the encoding information ends up being ignored,
//        as these instructions are lowered to individual MC-insts.
Evan Cheng's avatar
Evan Cheng committed
def PICADD : AXI1<0b0100, (outs GPR:$dst), (ins GPR:$a, pclabel:$cp, pred:$p),
                  Pseudo, IIC_iALUr, "",
                   [(set GPR:$dst, (ARMpic_add GPR:$a, imm:$cp))]>;
def PICLDR  : AXI2ldw<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p),
                  Pseudo, IIC_iLoad_r, "",
                  [(set GPR:$dst, (load addrmodepc:$addr))]>;
def PICLDRH : AXI3ldh<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p),
            Pseudo, IIC_iLoad_bh_r, "",
                  [(set GPR:$dst, (zextloadi16 addrmodepc:$addr))]>;

def PICLDRB : AXI2ldb<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p),
            Pseudo, IIC_iLoad_bh_r, "",
                  [(set GPR:$dst, (zextloadi8 addrmodepc:$addr))]>;

def PICLDRSH : AXI3ldsh<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p),
           Pseudo, IIC_iLoad_bh_r, "",
                  [(set GPR:$dst, (sextloadi16 addrmodepc:$addr))]>;

def PICLDRSB : AXI3ldsb<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p),
           Pseudo, IIC_iLoad_bh_r, "",
                  [(set GPR:$dst, (sextloadi8 addrmodepc:$addr))]>;
}
let AddedComplexity = 10 in {
def PICSTR  : AXI2stw<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p),
               Pseudo, IIC_iStore_r, "",
               [(store GPR:$src, addrmodepc:$addr)]>;

def PICSTRH : AXI3sth<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p),
           Pseudo, IIC_iStore_bh_r, "",
               [(truncstorei16 GPR:$src, addrmodepc:$addr)]>;

def PICSTRB : AXI2stb<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p),
           Pseudo, IIC_iStore_bh_r, "",
               [(truncstorei8 GPR:$src, addrmodepc:$addr)]>;
}
Evan Cheng's avatar
Evan Cheng committed

// LEApcrel - Load a pc-relative address into a register without offending the
// assembler.
// FIXME: These are marked as pseudos, but they're really not(?). They're just
// the ADR instruction. Is this the right way to handle that? They need
// encoding information regardless.
def LEApcrel : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, pred:$p),
Evan Cheng's avatar
Evan Cheng committed

Evan Cheng's avatar
Evan Cheng committed
def LEApcrelJT : AXI1<0x0, (outs GPR:$dst),
                           (ins i32imm:$label, nohash_imm:$id, pred:$p),
                      Pseudo, IIC_iALUi,
                      "adr$p\t$dst, #${label}_${id}", []> {
Evan Cheng's avatar
Evan Cheng committed

//===----------------------------------------------------------------------===//
//  Control Flow Instructions.
//
let isReturn = 1, isTerminator = 1, isBarrier = 1 in {
  // ARMV4T and above
Jim Grosbach's avatar
Jim Grosbach committed
  def BX_RET : AI<(outs), (ins), BrMiscFrm, IIC_Br,
                  "bx", "\tlr", [(ARMretflag)]>,
               Requires<[IsARM, HasV4T]> {
    let Inst{27-0}  = 0b0001001011111111111100011110;
Jim Grosbach's avatar
Jim Grosbach committed
  def MOVPCLR : AI<(outs), (ins), BrMiscFrm, IIC_Br,
                  "mov", "\tpc, lr", [(ARMretflag)]>,
               Requires<[IsARM, NoV4T]> {
    let Inst{27-0} = 0b0001101000001111000000001110;
// Indirect branches
let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
  // ARMV4T and above
  def BRIND : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "bx\t$dst",
                  [(brind GPR:$dst)]>,
              Requires<[IsARM, HasV4T]> {
    let Inst{31-4} = 0b1110000100101111111111110001;

  // ARMV4 only
  def MOVPCRX : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "mov\tpc, $dst",
                  [(brind GPR:$dst)]>,
              Requires<[IsARM, NoV4T]> {
    let Inst{31-4} = 0b1110000110100000111100000000;
// FIXME: remove when we have a way to marking a MI with these properties.
// 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 LDM_RET : AXI4ld<(outs GPR:$wb), (ins GPR:$Rn, ldstm_mode:$mode, pred:$p,
                       IndexModeUpd, LdStMulFrm, IIC_iLoad_mBr,
                       "$Rn = $wb", []> {
  let Inst{21}    = 1;
}
// On non-Darwin platforms R9 is callee-saved.
  Defs = [R0,  R1,  R2,  R3,  R12, LR,
          D0,  D1,  D2,  D3,  D4,  D5,  D6,  D7,
          D16, D17, D18, D19, D20, D21, D22, D23,
David Goodwin's avatar
David Goodwin committed
          D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR] in {
  def BL  : ABXI<0b1011, (outs), (ins bltarget:$func, variable_ops),
                [(ARMcall tglobaladdr:$func)]>,
            Requires<[IsARM, IsNotDarwin]> {
    let Inst{31-28} = 0b1110;
    bits<24> func;
    let Inst{23-0} = func;
  def BL_pred : ABI<0b1011, (outs), (ins bltarget:$func, variable_ops),
                   [(ARMcall_pred tglobaladdr:$func)]>,
                Requires<[IsARM, IsNotDarwin]> {
    bits<24> func;
    let Inst{23-0} = func;
  }
  // ARMv5T and above
  def BLX : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm,
                [(ARMcall GPR:$func)]>,
            Requires<[IsARM, HasV5T, IsNotDarwin]> {
    let Inst{27-4} = 0b000100101111111111110011;
  // Note: Restrict $func to the tGPR regclass to prevent it being in LR.
  def BX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
           Requires<[IsARM, HasV4T, IsNotDarwin]> {
    bits<4> func;
    let Inst{27-4} = 0b000100101111111111110001;
    let Inst{3-0}   = func;

  // ARMv4
  def BMOVPCRX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                 IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
                 [(ARMcall_nolink tGPR:$func)]>,
           Requires<[IsARM, NoV4T, IsNotDarwin]> {
    bits<4> func;
    let Inst{27-4} = 0b000110100000111100000000;
    let Inst{3-0}   = func;
  Defs = [R0,  R1,  R2,  R3,  R9,  R12, LR,
          D0,  D1,  D2,  D3,  D4,  D5,  D6,  D7,
          D16, D17, D18, D19, D20, D21, D22, D23,
David Goodwin's avatar
David Goodwin committed
          D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR] in {
  def BLr9  : ABXI<0b1011, (outs), (ins bltarget:$func, variable_ops),
                [(ARMcall tglobaladdr:$func)]>, Requires<[IsARM, IsDarwin]> {
    let Inst{31-28} = 0b1110;
    bits<24> func;
    let Inst{23-0} = func;
  def BLr9_pred : ABI<0b1011, (outs), (ins bltarget:$func, variable_ops),
                   [(ARMcall_pred tglobaladdr:$func)]>,
                  Requires<[IsARM, IsDarwin]> {
    bits<24> func;
    let Inst{23-0} = func;
  }

  // ARMv5T and above
  def BLXr9 : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm,
                [(ARMcall GPR:$func)]>, Requires<[IsARM, HasV5T, IsDarwin]> {
    bits<4> func;
    let Inst{27-4} = 0b000100101111111111110011;
    let Inst{3-0}   = func;
  // Note: Restrict $func to the tGPR regclass to prevent it being in LR.
  def BXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                  [(ARMcall_nolink tGPR:$func)]>,
             Requires<[IsARM, HasV4T, IsDarwin]> {
    bits<4> func;
    let Inst{27-4} = 0b000100101111111111110001;
    let Inst{3-0}   = func;

  // ARMv4
  def BMOVPCRXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
                 IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
                 [(ARMcall_nolink tGPR:$func)]>,
           Requires<[IsARM, NoV4T, IsDarwin]> {
    bits<4> func;
    let Inst{27-4} = 0b000110100000111100000000;
    let Inst{3-0}   = func;
// FIXME: These should probably be xformed into the non-TC versions of the
// instructions as part of MC lowering.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
  // Darwin versions.
  let Defs = [R0, R1, R2, R3, R9, R12,
              D0, D1, D2, D3, D4, D5, D6, D7,
              D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26,
              D27, D28, D29, D30, D31, PC],
      Uses = [SP] in {
    def TCRETURNdi : AInoP<(outs), (ins i32imm:$dst, variable_ops),
                       Pseudo, IIC_Br,
                       "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>;

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

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

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

    def TAILJMPr : AXI<(outs), (ins tcGPR:$dst, variable_ops),
                     BrMiscFrm, IIC_Br, "bx\t$dst  @ TAILCALL",
                   []>, Requires<[IsDarwin]> {
      bits<4> dst;
      let Inst{31-4} = 0b1110000100101111111111110001;
      let Inst{3-0}  = dst;
  }

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

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

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

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

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

// Secure Monitor Call is a system instruction -- for disassembly only
def SMC : ABI<0b0001, (outs), (ins i32imm:$opt), NoItinerary, "smc", "\t$opt",
              [/* For disassembly only; pattern left blank */]> {
  bits<4> opt;
  let Inst{23-4} = 0b01100000000000000111;
  let Inst{3-0} = opt;
// Supervisor Call (Software Interrupt) -- for disassembly only
let isCall = 1 in {
def SVC : ABI<0b1111, (outs), (ins i32imm:$svc), IIC_Br, "svc", "\t$svc",
              [/* For disassembly only; pattern left blank */]> {
  bits<24> svc;
  let Inst{23-0} = svc;
}
// Store Return State is a system instruction -- for disassembly only
let isCodeGenOnly = 1 in {  // FIXME: This should not use submode!
def SRSW : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, i32imm:$mode),
                NoItinerary, "srs${amode}\tsp!, $mode",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b110; // W = 1
}

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

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

def RFE  : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, GPR:$base),
                NoItinerary, "rfe${amode}\t$base",
                [/* For disassembly only; pattern left blank */]> {
  let Inst{31-28} = 0b1111;
  let Inst{22-20} = 0b001; // W = 0
}
//===----------------------------------------------------------------------===//
//  Load / store Instructions.
//
Rafael Espindola's avatar
Rafael Espindola committed

defm LDR  : AI_ldr1<0, "ldr", IIC_iLoad_r, IIC_iLoad_si,
defm LDRB : AI_ldr1<1, "ldrb", IIC_iLoad_bh_r, IIC_iLoad_bh_si,
defm STR  : AI_str1<0, "str", IIC_iStore_r, IIC_iStore_si,
                   BinOpFrag<(store node:$LHS, node:$RHS)>>;
defm STRB : AI_str1<1, "strb", IIC_iStore_bh_r, IIC_iStore_bh_si,
                   BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>;
// Special LDR for loads from non-pc-relative constpools.
let canFoldAsLoad = 1, mayLoad = 1, neverHasSideEffects = 1,
    isReMaterializable = 1 in
def LDRcp : AIldst1<0b010, 1, 0, (outs GPR:$Rt), (ins addrmode_imm12:$addr),
                 AddrMode_i12, LdFrm, IIC_iLoad_r, "ldr", "\t$Rt, $addr",
                 []> {
  bits<4> Rt;
  bits<17> addr;
  let Inst{23}    = addr{12};     // U (add = ('U' == 1))
  let Inst{19-16} = 0b1111;
  let Inst{15-12} = Rt;
  let Inst{11-0}  = addr{11-0};   // imm12
}
// Loads with zero extension
def LDRH  : AI3ldh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm,
                  IIC_iLoad_bh_r, "ldrh", "\t$dst, $addr",
                  [(set GPR:$dst, (zextloadi16 addrmode3:$addr))]>;

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

// Indexed loads
multiclass AI2_ldridx<bit isByte, string opc, InstrItinClass itin> {
  def _PRE  : AI2ldstidx<1, isByte, 1, (outs GPR:$Rt, GPR:$Rn_wb),
                      (ins addrmode2:$addr), IndexModePre, LdFrm, itin,
                      opc, "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> {
    let Inst{21} = 1; // W bit (overwrite)
  }
  def _POST : AI2ldstidx<1, isByte, 0, (outs GPR:$Rt, GPR:$Rn_wb),
                      (ins GPR:$Rn, am2offset:$offset),
                      IndexModePost, LdFrm, itin,
                      opc, "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", []>;
defm LDR  : AI2_ldridx<0, "ldr", IIC_iLoad_ru>;
defm LDRB : AI2_ldridx<1, "ldrb", IIC_iLoad_bh_ru>;
def LDRH_PRE  : AI3ldhpr<(outs GPR:$Rt, GPR:$Rn_wb),
                     (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                     "ldrh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>;
def LDRH_POST : AI3ldhpo<(outs GPR:$Rt, GPR:$Rn_wb),
                  (ins GPR:$Rn,am3offset:$offset), LdMiscFrm, IIC_iLoad_bh_ru,
                    "ldrh", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", []>;
def LDRSH_PRE : AI3ldshpr<(outs GPR:$Rt, GPR:$Rn_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                      "ldrsh", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>;
def LDRSH_POST: AI3ldshpo<(outs GPR:$Rt, GPR:$Rn_wb),
                  (ins GPR:$Rn,am3offset:$offset), LdMiscFrm, IIC_iLoad_bh_ru,
                   "ldrsh", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", []>;
def LDRSB_PRE : AI3ldsbpr<(outs GPR:$Rt, GPR:$Rn_wb),
                      (ins addrmode3:$addr), LdMiscFrm, IIC_iLoad_bh_ru,
                      "ldrsb", "\t$Rt, $addr!", "$addr.base = $Rn_wb", []>;
def LDRSB_POST: AI3ldsbpo<(outs GPR:$Rt, GPR:$Rn_wb),
                    (ins GPR:$Rn,am3offset:$offset), LdMiscFrm, IIC_iLoad_ru,
                   "ldrsb", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", []>;

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

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

} // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1
// LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only.
def LDRT : AI2ldstidx<1, 0, 0, (outs GPR:$dst, GPR:$base_wb),
                   (ins GPR:$base, am2offset:$offset), IndexModeNone,
                   LdFrm, IIC_iLoad_ru,
                   "ldrt", "\t$dst, [$base], $offset", "$base = $base_wb", []> {
  let Inst{21} = 1; // overwrite
}

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

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

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

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

// Store

// Stores with truncate
def STRH : AI3sth<(outs), (ins GPR:$Rt, addrmode3:$addr), StMiscFrm,
               IIC_iStore_bh_r, "strh", "\t$Rt, $addr",
               [(truncstorei16 GPR:$Rt, addrmode3:$addr)]>;

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

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

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

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

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

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

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

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

// STRT, STRBT, and STRHT are for disassembly only.
def STRT : AI2ldstidx<0, 0, 0, (outs GPR:$base_wb),
Jim Grosbach's avatar
Jim Grosbach committed
                    (ins GPR:$src, GPR:$base,am2offset:$offset),
                    IndexModeNone, StFrm, IIC_iStore_ru,
                    "strt", "\t$src, [$base], $offset", "$base = $base_wb",
                    [/* For disassembly only; pattern left blank */]> {
  let Inst{21} = 1; // overwrite
}

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

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

//===----------------------------------------------------------------------===//
//  Load / store multiple Instructions.
//
let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1,
    isCodeGenOnly = 1 in {
def LDM : AXI4ld<(outs), (ins GPR:$Rn, ldstm_mode:$amode, pred:$p,
                 IndexModeNone, LdStMulFrm, IIC_iLoad_m,
                 "ldm${amode}${p}\t$Rn, $dsts", "", []> {
  let Inst{21} = 0;
}
def LDM_UPD : AXI4ld<(outs GPR:$wb), (ins GPR:$Rn, ldstm_mode:$amode, pred:$p,
                     IndexModeUpd, LdStMulFrm, IIC_iLoad_mu,
                     "$Rn = $wb", []> {
  let Inst{21} = 1;
}
} // mayLoad, neverHasSideEffects, hasExtraDefRegAllocReq
let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1,
    isCodeGenOnly = 1 in {
def STM : AXI4st<(outs), (ins GPR:$Rn, ldstm_mode:$amode, pred:$p,
                 IndexModeNone, LdStMulFrm, IIC_iStore_m,
                 "stm${amode}${p}\t$Rn, $srcs", "", []> {
  let Inst{21} = 0;
}
def STM_UPD : AXI4st<(outs GPR:$wb), (ins GPR:$Rn, ldstm_mode:$amode, pred:$p,
                     IndexModeUpd, LdStMulFrm, IIC_iStore_mu,
                     "$Rn = $wb", []> {
  bits<4> p;
  let Inst{31-28} = p;
  let Inst{21} = 1;
}
} // mayStore, neverHasSideEffects, hasExtraSrcRegAllocReq
//===----------------------------------------------------------------------===//
//  Move Instructions.
//
let neverHasSideEffects = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr,
                "mov", "\t$Rd, $Rm", []>, UnaryDP {
  bits<4> Rd;
  bits<4> Rm;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{3-0} = Rm;
  let Inst{15-12} = Rd;
// A version for the smaller set of tail call registers.
let neverHasSideEffects = 1 in
Jim Grosbach's avatar
Jim Grosbach committed
def MOVr_TC : AsI1<0b1101, (outs tcGPR:$Rd), (ins tcGPR:$Rm), DPFrm,
Jim Grosbach's avatar
Jim Grosbach committed
                IIC_iMOVr, "mov", "\t$Rd, $Rm", []>, UnaryDP {
  bits<4> Rd;
  bits<4> Rm;
  let Inst{11-4} = 0b00000000;
  let Inst{25} = 0;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{3-0} = Rm;
  let Inst{15-12} = Rd;
def MOVs : AsI1<0b1101, (outs GPR:$Rd), (ins shift_so_reg:$src),
                "mov", "\t$Rd, $src", [(set GPR:$Rd, shift_so_reg:$src)]>,
                UnaryDP {
  bits<12> src;
  let Inst{15-12} = Rd;
  let Inst{11-0} = src;
Evan Cheng's avatar
Evan Cheng committed
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMOVi,
                "mov", "\t$Rd, $imm", [(set GPR:$Rd, so_imm:$imm)]>, UnaryDP {
Jim Grosbach's avatar
Jim Grosbach committed
  bits<4> Rd;
Jim Grosbach's avatar
Jim Grosbach committed
  let Inst{15-12} = Rd;
  let Inst{19-16} = 0b0000;
}

let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins i32imm:$imm),
                 "movw", "\t$Rd, $imm",
                 [(set GPR:$Rd, imm0_65535:$imm)]>,
  bits<4> Rd;
  bits<16> imm;
  let Inst{15-12} = Rd;
  let Inst{11-0}  = imm{11-0};
  let Inst{19-16} = imm{15-12};
  let Inst{20} = 0;
let Constraints = "$src = $Rd" in
def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, i32imm:$imm),
                  "movt", "\t$Rd, $imm",
                  [(set GPR:$Rd,
Jim Grosbach's avatar
Jim Grosbach committed
                        (or (and GPR:$src, 0xffff),
                            lo16AllZero:$imm))]>, UnaryDP,
                  Requires<[IsARM, HasV6T2]> {
  bits<4> Rd;
  bits<16> imm;
  let Inst{15-12} = Rd;
  let Inst{11-0}  = imm{11-0};
  let Inst{19-16} = imm{15-12};
  let Inst{20} = 0;
Evan Cheng's avatar
Evan Cheng committed
def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>,
      Requires<[IsARM, HasV6T2]>;

David Goodwin's avatar
David Goodwin committed
let Uses = [CPSR] in
def RRX: PseudoInst<(outs GPR:$Rd), (ins GPR:$Rm), IIC_iMOVsi, "",
                    [(set GPR:$Rd, (ARMrrx GPR:$Rm))]>, UnaryDP,
                    Requires<[IsARM]>;
// These aren't really mov instructions, but we have to define them this way
// due to flag operands.
def MOVsrl_flag : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, "",
                      [(set GPR:$dst, (ARMsrl_flag GPR:$src))]>, UnaryDP,
                      Requires<[IsARM]>;
def MOVsra_flag : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, "",
                      [(set GPR:$dst, (ARMsra_flag GPR:$src))]>, UnaryDP,
                      Requires<[IsARM]>;
//===----------------------------------------------------------------------===//
//  Extend Instructions.
//
// Sign extenders
Rafael Espindola's avatar
Rafael Espindola committed

defm SXTB  : AI_ext_rrot<0b01101010,
                         "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>;
defm SXTH  : AI_ext_rrot<0b01101011,
                         "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>;
defm SXTAB : AI_exta_rrot<0b01101010,
               "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>;
defm SXTAH : AI_exta_rrot<0b01101011,
               "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>;
defm SXTB16  : AI_ext_rrot_np<0b01101000, "sxtb16">;
defm SXTAB16 : AI_exta_rrot_np<0b01101000, "sxtab16">;
// Zero extenders
let AddedComplexity = 16 in {
defm UXTB   : AI_ext_rrot<0b01101110,
                          "uxtb"  , UnOpFrag<(and node:$Src, 0x000000FF)>>;
defm UXTH   : AI_ext_rrot<0b01101111,
                          "uxth"  , UnOpFrag<(and node:$Src, 0x0000FFFF)>>;
defm UXTB16 : AI_ext_rrot<0b01101100,
                          "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>;
// FIXME: This pattern incorrectly assumes the shl operator is a rotate.
//        The transformation should probably be done as a combiner action
//        instead so we can include a check for masking back in the upper
//        eight bits of the source into the lower eight bits of the result.
//def : ARMV6Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF),
//               (UXTB16r_rot GPR:$Src, 24)>;
def : ARMV6Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF),
               (UXTB16r_rot GPR:$Src, 8)>;

defm UXTAB : AI_exta_rrot<0b01101110, "uxtab",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>;
defm UXTAH : AI_exta_rrot<0b01101111, "uxtah",
                        BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>;
// This isn't safe in general, the add is two 16-bit units, not a 32-bit add.
defm UXTAB16 : AI_exta_rrot_np<0b01101100, "uxtab16">;
def SBFX  : I<(outs GPR:$Rd),
              (ins GPR:$Rn, imm0_31:$lsb, imm0_31_m1:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
               "sbfx", "\t$Rd, $Rn, $lsb, $width", "", []>,
  bits<4> Rd;
  bits<4> Rn;
  bits<5> lsb;
  bits<5> width;
  let Inst{27-21} = 0b0111101;
  let Inst{6-4}   = 0b101;
  let Inst{20-16} = width;
  let Inst{15-12} = Rd;
  let Inst{11-7}  = lsb;
  let Inst{3-0}   = Rn;
def UBFX  : I<(outs GPR:$Rd),
              (ins GPR:$Rn, imm0_31:$lsb, imm0_31_m1:$width),
               AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi,
               "ubfx", "\t$Rd, $Rn, $lsb, $width", "", []>,
  bits<4> Rd;
  bits<4> Rn;
  bits<5> lsb;
  bits<5> width;
  let Inst{27-21} = 0b0111111;
  let Inst{6-4}   = 0b101;
  let Inst{20-16} = width;
  let Inst{15-12} = Rd;
  let Inst{11-7}  = lsb;
  let Inst{3-0}   = Rn;
//===----------------------------------------------------------------------===//
//  Arithmetic Instructions.
//

                         BinOpFrag<(add  node:$LHS, node:$RHS)>, 1>;
                         BinOpFrag<(sub  node:$LHS, node:$RHS)>>;
defm ADDS : AI1_bin_s_irs<0b0100, "adds",
                          BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>;
defm SUBS : AI1_bin_s_irs<0b0010, "subs",
                          BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>, 1>;
                          BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>>;
defm ADCS : AI1_adde_sube_s_irs<0b0101, "adcs",
                          BinOpFrag<(adde_live_carry node:$LHS, node:$RHS)>, 1>;
defm SBCS : AI1_adde_sube_s_irs<0b0110, "sbcs",
                          BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>;
def RSBri : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm,
                 IIC_iALUi, "rsb", "\t$Rd, $Rn, $imm",
                 [(set GPR:$Rd, (sub so_imm:$imm, GPR:$Rn))]> {
  bits<4> Rd;
  bits<4> Rn;
  bits<12> imm;
  let Inst{25} = 1;
  let Inst{15-12} = Rd;
  let Inst{19-16} = Rn;