Skip to content
ARMInstrThumb2.td 46.8 KiB
Newer Older
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),
                   "mov", " $dst, $true",
      [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>,
                RegConstraint<"$false = $dst">;

def t2MOVCCs : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_reg:$true),
                   "mov", " $dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_reg:$true, imm:$cc, CCR:$ccr))*/]>,
                   RegConstraint<"$false = $dst">;

def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true),
                   "mov", " $dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
                   RegConstraint<"$false = $dst">;
//===----------------------------------------------------------------------===//
// TLS Instructions
//

// __aeabi_read_tp preserves the registers r1-r3.
let isCall = 1,
  Defs = [R0, R12, LR, CPSR] in {
  def t2TPsoft : T2XI<(outs), (ins),
                     "bl __aeabi_read_tp",
                     [(set R0, ARMthread_pointer)]>;
}

//===----------------------------------------------------------------------===//
// Control-Flow Instructions
//

let isReturn = 1, isTerminator = 1 in
  def t2BX_RET : T2XI<(outs), (ins), "bx lr", [(ARMretflag)]>;

// On non-Darwin platforms R9 is callee-saved.
let isCall = 1,
  Defs = [R0, R1, R2, R3, R12, LR,
          D0, D1, D2, D3, D4, D5, D6, D7, CPSR] in {
def t2BL  : T2XI<(outs), (ins i32imm:$func, variable_ops),
                 "bl ${func:call}",
                  [(ARMcall tglobaladdr:$func)]>, Requires<[IsNotDarwin]>;

def t2BLX : T2XI<(outs), (ins GPR:$func, variable_ops),
                "blx $func",
                [(ARMcall GPR:$func)]>, Requires<[IsNotDarwin]>;
}
let isCall = 1,
  Defs = [R0, R1, R2, R3, R9, R12, LR,
          D0, D1, D2, D3, D4, D5, D6, D7, CPSR] in {
def t2BLr9  : T2XI<(outs), (ins i32imm:$func, variable_ops),
                  "bl ${func:call}",
                  [(ARMcall tglobaladdr:$func)]>, Requires<[IsDarwin]>;

def t2BLXr9 : T2XI<(outs), (ins GPR:$func, variable_ops),
                  "blx $func",
                  [(ARMcall GPR:$func)]>, Requires<[IsDarwin]>;
}
let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
let isPredicable = 1 in
def t2B   : T2XI<(outs), (ins brtarget:$target),
                 "b $target",
                 [(br bb:$target)]>;

let isNotDuplicable = 1, isIndirectBranch = 1 in {
def t2BR_JTr : T2JTI<(outs), (ins GPR:$target, jtblock_operand:$jt, i32imm:$id),
                     "mov pc, $target \n$jt",
                     [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]>;

def t2BR_JTm : 
    T2JTI<(outs),
          (ins t2addrmode_so_reg:$target, jtblock_operand:$jt, i32imm:$id),
          "ldr pc, $target \n$jt",
          [(ARMbrjt (i32 (load t2addrmode_so_reg:$target)), tjumptable:$jt,
             imm:$id)]>;

def t2BR_JTadd : 
    T2JTI<(outs),
          (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, i32imm:$id),
          "add pc, $target, $idx \n$jt",
          [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, imm:$id)]>;
} // isNotDuplicate, isIndirectBranch
} // 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), 
                "b", " $target",
                [/*(ARMbrcond bb:$target, imm:$cc)*/]>;

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

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<(ARMWrapperJT tjumptable:$dst, imm:$id),
            (t2LEApcrelJT tjumptable:$dst, imm:$id)>;
Evan Cheng's avatar
Evan Cheng committed
def : T2Pat<(i32 imm:$src),
            (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)), (t2_hi16 imm:$src))>;