Skip to content
ARMInstrThumb2.td 46.4 KiB
Newer Older
// 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
//

// 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, mayLoad = 1 in
  def t2LDM_RET : T2XI<(outs),
                    (ins addrmode4:$addr, pred:$p, reglist:$dst1, variable_ops),
                    "ldm${addr:submode}${p} $addr, $dst1",
                    []>;

// 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,
          D24, D25, D26, D27, D28, D29, D31, D31, 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\t.align\t2\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\t.align\t2\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\t.align\t2\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)*/]>;

// IT block
def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
                    AddrModeNone, Size2Bytes,
                    "it$mask $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))>;