Skip to content
ARMInstrThumb2.td 51.2 KiB
Newer Older
                         BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
defm t2CMPz : T2I_cmp_is<"cmp",
                         BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>;
defm t2CMN  : T2I_cmp_is<"cmn",
                         BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;
defm t2CMNz : T2I_cmp_is<"cmn",
                         BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>;
Evan Cheng's avatar
Evan Cheng committed
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),
Evan Cheng's avatar
Evan Cheng committed
            (t2CMNri   GPR:$src, t2_so_imm_neg:$imm)>;
defm t2TST  : T2I_cmp_is<"tst",
                         BinOpFrag<(ARMcmpZ (and node:$LHS, node:$RHS), 0)>>;
defm t2TEQ  : T2I_cmp_is<"teq",
                         BinOpFrag<(ARMcmpZ (xor node:$LHS, node:$RHS), 0)>>;

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


// Conditional moves
// FIXME: should be able to write a pattern for ARMcmov, but can't use
// a two-value operand where a dag node expects two operands. :( 
def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true), IIC_iCMOVr,
      [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">;

def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true),
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
                   RegConstraint<"$false = $dst">;
def t2MOVCClsl : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
                   IIC_iCMOVsi, "lsl", ".w\t$dst, $true, $rhs", []>,
                   RegConstraint<"$false = $dst">;
def t2MOVCClsr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
                   IIC_iCMOVsi, "lsr", ".w\t$dst, $true, $rhs", []>,
                   RegConstraint<"$false = $dst">;
def t2MOVCCasr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
                   IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>,
                   RegConstraint<"$false = $dst">;
def t2MOVCCror : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
                   IIC_iCMOVsi, "ror", ".w\t$dst, $true, $rhs", []>,
//===----------------------------------------------------------------------===//
// 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,
//===----------------------------------------------------------------------===//
// 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.
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),
                               AddrModeNone, SizeSpecial, NoItinerary,
                               "str.w\tsp, [$src, #+8] @ eh_setjmp begin\n"
                               "\tadr\tr12, 0f\n"
                               "\torr\tr12, #1\n"
                               "\tstr.w\tr12, [$src, #+4]\n"
                               "\tmovs\tr0, #0\n"
                               "\tb\t1f\n"
                               "0:\tmovs\tr0, #1 @ eh_setjmp end\n"
Jim Grosbach's avatar
Jim Grosbach committed
                               "1:", "",
                               [(set R0, (ARMeh_sjlj_setjmp GPR:$src))]>;
}



//===----------------------------------------------------------------------===//
// 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 isBranch = 1, isTerminator = 1, isBarrier = 1 in {
let isPredicable = 1 in
def t2B   : T2XI<(outs), (ins brtarget:$target), IIC_Br,
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)]>;

// FIXME: Add a non-pc based case that can be predicated.
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
        (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
} // 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)*/]>;

// IT block
def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
                    AddrModeNone, Size2Bytes,  IIC_iALUx,
//===----------------------------------------------------------------------===//
// 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<(sub GPR:$LHS, t2_so_imm2part:$RHS),
             (t2SUBri (t2SUBri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)),
                    (t2_so_imm2part_2 imm:$RHS))>;

Evan Cheng's avatar
Evan Cheng committed
// ConstantPool, GlobalAddress, and JumpTable
Evan Cheng's avatar
Evan Cheng committed
def : T2Pat<(ARMWrapper  tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>;
def : T2Pat<(ARMWrapper  tconstpool  :$dst), (t2LEApcrel tconstpool  :$dst)>;
def : T2Pat<(ARMWrapper  tblockaddress:$dst), (t2LEApcrel tblockaddress:$dst)>;
Evan Cheng's avatar
Evan Cheng committed
def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id),
            (t2LEApcrelJT tjumptable:$dst, imm:$id)>;
// 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}",