Skip to content
ARMInstrThumb2.td 93.1 KiB
Newer Older
                             IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
def t2MOVCCror : T2I_movcc_sh<0b11, (outs GPR:$dst),
                             (ins GPR:$false, GPR:$true, i32imm:$rhs),
                             IIC_iCMOVsi, "ror", ".w\t$dst, $true, $rhs", []>,
                 RegConstraint<"$false = $dst">;
//===----------------------------------------------------------------------===//
// Atomic operations intrinsics
//

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

def t2Int_SyncBarrierV7 : AInoP<(outs), (ins),
                        Pseudo, NoItinerary,
                        "dsb", "",
                        [(ARMSyncBarrierV7)]>,
  let Inst{31-4} = 0xF3BF8F4;
  // FIXME: add support for options other than a full system DSB
  let Inst{3-0} = 0b1111;
class T2I_ldrex<bits<2> opcod, dag oops, dag iops, AddrMode am, SizeFlagVal sz,
                InstrItinClass itin, string opc, string asm, string cstr,
                list<dag> pattern, bits<4> rt2 = 0b1111>
  : Thumb2I<oops, iops, am, sz, itin, opc, asm, cstr, pattern> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{11-8} = rt2;
  let Inst{7-6} = 0b01;
  let Inst{5-4} = opcod;
  let Inst{3-0} = 0b1111;
}
class T2I_strex<bits<2> opcod, dag oops, dag iops, AddrMode am, SizeFlagVal sz,
                InstrItinClass itin, string opc, string asm, string cstr,
                list<dag> pattern, bits<4> rt2 = 0b1111>
  : Thumb2I<oops, iops, am, sz, itin, opc, asm, cstr, pattern> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001100;
  let Inst{11-8} = rt2;
  let Inst{7-6} = 0b01;
  let Inst{5-4} = opcod;
}

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

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

// __aeabi_read_tp preserves the registers r1-r3.
let isCall = 1,
  Defs = [R0, R12, LR, CPSR] in {
  def t2TPsoft : T2XI<(outs), (ins), IIC_Br,
                     [(set R0, ARMthread_pointer)]> {
    let Inst{31-27} = 0b11110;
    let Inst{15-14} = 0b11;
    let Inst{12} = 1;
  }
//===----------------------------------------------------------------------===//
// SJLJ Exception handling intrinsics
Jim Grosbach's avatar
Jim Grosbach committed
//   eh_sjlj_setjmp() is an instruction sequence to store the return
//   address and save #0 in R0 for the non-longjmp case.
//   Since by its nature we may be coming from some other function to get
//   here, and we're using the stack frame for the containing function to
//   save/restore registers, we can't keep anything live in regs across
//   the eh_sjlj_setjmp(), else it will almost certainly have been tromped upon
//   when we get here from a longjmp(). We force everthing out of registers
//   except for our own input by listing the relevant registers in Defs. By
//   doing so, we also cause the prologue/epilogue code to actively preserve
//   all of the callee-saved resgisters, which is exactly what we want.
//   The current SP is passed in $val, and we reuse the reg 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,
    D31 ] in {
  def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins GPR:$src, tGPR:$val),
                               AddrModeNone, SizeSpecial, NoItinerary,
                               "str\t$val, [$src, #8]\t@ begin eh.setjmp\n"
                               "\tmov\t$val, pc\n"
                               "\tadds\t$val, #9\n"
                               "\tstr\t$val, [$src, #4]\n"
                               "\tmovs\tr0, #1\t@ end eh.setjmp\n"
Jim Grosbach's avatar
Jim Grosbach committed
                               "1:", "",
                          [(set R0, (ARMeh_sjlj_setjmp GPR:$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 in
  def t2LDM_RET : T2XI<(outs),
                    (ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops),
                    IIC_Br, "ldm${addr:submode}${p}${addr:wide}\t$addr, $wb",
                    []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-25} = 0b00;
  let Inst{24-23} = {?, ?}; // IA: '01', DB: '10'
  let Inst{22} = 0;
  let Inst{21} = ?; // The W bit.
  let Inst{20} = 1; // Load
}
let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
let isPredicable = 1 in
def t2B   : T2XI<(outs), (ins brtarget:$target), IIC_Br,
                 [(br bb:$target)]> {
  let Inst{31-27} = 0b11110;
  let Inst{15-14} = 0b10;
  let Inst{12} = 1;
}
let isNotDuplicable = 1, isIndirectBranch = 1 in {
    T2JTI<(outs),
          (ins GPR:$target, GPR:$index, jt2block_operand:$jt, i32imm:$id),
          [(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt, imm:$id)]> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0100100;
  let Inst{19-16} = 0b1111;
  let Inst{14-12} = 0b000;
  let Inst{11-8} = 0b1111; // Rd = pc
  let Inst{7-4} = 0b0000;
}
// FIXME: Add a non-pc based case that can be predicated.
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
         IIC_Br, "tbb\t$index\n$jt", []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction)
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0000; // B form
}
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
         IIC_Br, "tbh\t$index\n$jt", []> {
  let Inst{31-27} = 0b11101;
  let Inst{26-20} = 0b0001101;
  let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction)
  let Inst{15-8} = 0b11110000;
  let Inst{7-4} = 0b0001; // H form
}

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

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

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

// FIXME: should be able to write a pattern for ARMBrcond, but can't use
// a two-value operand where a dag node expects two operands. :(
let isBranch = 1, isTerminator = 1 in
def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br,
                [/*(ARMbrcond bb:$target, imm:$cc)*/]> {
  let Inst{31-27} = 0b11110;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// IT block
def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
                    AddrModeNone, Size2Bytes,  IIC_iALUx,
                    "it$mask\t$cc", "", []> {
  // 16-bit instruction.
  let Inst{15-8} = 0b10111111;
}
// Branch and Exchange Jazelle -- for disassembly only
// Rm = Inst{19-16}
def t2BXJ : T2I<(outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func",
              [/* For disassembly only; pattern left blank */]> {
  let Inst{31-27} = 0b11110;
  let Inst{26} = 0;
  let Inst{25-20} = 0b111100;
  let Inst{15-14} = 0b10;
  let Inst{12} = 0;
}

// Change Processor State is a system instruction -- for disassembly only.
// The singleton $opt operand contains the following information:
// opt{4-0} = mode from Inst{4-0}
// opt{5} = changemode from Inst{17}
// opt{8-6} = AIF from Inst{8-6}
// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable
def t2CPS : T2XI<(outs),(ins i32imm:$opt), NoItinerary, "cps${opt:cps}",
                 [/* 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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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