Newer
Older
0xFFFF)))]>;
// Alternate cases for PKHTB where identities eliminate some nodes. Note that
// a shift amount of 0 is *not legal* here, it is PKHBT instead.
def : T2Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, (i32 16))),
(t2PKHTB GPR:$src1, GPR:$src2, 16)>;
def : T2Pat<(or (and GPR:$src1, 0xFFFF0000),
(and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)),
(t2PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>;
Evan Cheng
committed
//===----------------------------------------------------------------------===//
// Comparison Instructions...
//
defm t2CMP : T2I_cmp_is<"cmp",
BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
David Goodwin
committed
defm t2CMPz : T2I_cmp_is<"cmp",
BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>;
Evan Cheng
committed
defm t2CMN : T2I_cmp_is<"cmn",
BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;
David Goodwin
committed
defm t2CMNz : T2I_cmp_is<"cmn",
BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>;
Evan Cheng
committed
def : T2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm),
(t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
Evan Cheng
committed
David Goodwin
committed
def : T2Pat<(ARMcmpZ GPR:$src, t2_so_imm_neg:$imm),
Evan Cheng
committed
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)>>;
Evan Cheng
committed
// 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,
Evan Cheng
committed
"mov", ".w\t$dst, $true",
[/*(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),
Evan Cheng
committed
IIC_iCMOVi, "mov", ".w\t$dst, $true",
[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>,
RegConstraint<"$false = $dst">;
Evan Cheng
committed
Evan Cheng
committed
def t2MOVCClsl : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
Evan Cheng
committed
IIC_iCMOVsi, "lsl", ".w\t$dst, $true, $rhs", []>,
Evan Cheng
committed
RegConstraint<"$false = $dst">;
def t2MOVCClsr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
Evan Cheng
committed
IIC_iCMOVsi, "lsr", ".w\t$dst, $true, $rhs", []>,
Evan Cheng
committed
RegConstraint<"$false = $dst">;
def t2MOVCCasr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
Evan Cheng
committed
IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>,
Evan Cheng
committed
RegConstraint<"$false = $dst">;
def t2MOVCCror : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true, i32imm:$rhs),
Evan Cheng
committed
IIC_iCMOVsi, "ror", ".w\t$dst, $true, $rhs", []>,
Evan Cheng
committed
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", "",
Jim Grosbach
committed
Requires<[IsThumb2]> {
// FIXME: add support for options other than a full system DMB
}
def t2Int_SyncBarrierV7 : AInoP<(outs), (ins),
Pseudo, NoItinerary,
"dsb", "",
Jim Grosbach
committed
Requires<[IsThumb2]> {
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
// FIXME: add support for options other than a full system DSB
}
}
let mayLoad = 1 in {
def t2LDREXB : Thumb2I<(outs GPR:$dest), (ins GPR:$ptr), AddrModeNone,
Size4Bytes, NoItinerary,
"ldrexb", "\t$dest, [$ptr]", "",
[]>;
def t2LDREXH : Thumb2I<(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]", "",
[]>;
def t2LDREXD : Thumb2I<(outs GPR:$dest, GPR:$dest2), (ins GPR:$ptr),
AddrModeNone, Size4Bytes, NoItinerary,
"ldrexd", "\t$dest, $dest2, [$ptr]", "",
[]>;
}
let mayStore = 1 in {
def t2STREXB : Thumb2I<(outs GPR:$success), (ins GPR:$src, GPR:$ptr),
AddrModeNone, Size4Bytes, NoItinerary,
"strexb", "\t$success, $src, [$ptr]", "",
[]>;
def t2STREXH : Thumb2I<(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]", "",
[]>;
def t2STREXD : Thumb2I<(outs GPR:$success),
(ins GPR:$src, GPR:$src2, GPR:$ptr),
AddrModeNone, Size4Bytes, NoItinerary,
"strexd", "\t$success, $src, $src2, [$ptr]", "",
[]>;
}
David Goodwin
committed
//===----------------------------------------------------------------------===//
// TLS Instructions
//
// __aeabi_read_tp preserves the registers r1-r3.
let isCall = 1,
Defs = [R0, R12, LR, CPSR] in {
David Goodwin
committed
def t2TPsoft : T2XI<(outs), (ins), IIC_Br,
Evan Cheng
committed
"bl\t__aeabi_read_tp",
David Goodwin
committed
[(set R0, ARMthread_pointer)]>;
}
//===----------------------------------------------------------------------===//
// SJLJ Exception handling intrinsics
// 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,
Evan Cheng
committed
"str.w\tsp, [$src, #+8] @ eh_setjmp begin\n"
"\tadr\tr12, 0f\n"
Evan Cheng
committed
"\torr.w\tr12, r12, #1\n"
Evan Cheng
committed
"\tstr.w\tr12, [$src, #+4]\n"
"\tmovs\tr0, #0\n"
"\tb\t1f\n"
"0:\tmovs\tr0, #1 @ eh_setjmp end\n"
[(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?
Evan Cheng
committed
let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1,
hasExtraDefRegAllocReq = 1 in
(ins addrmode4:$addr, pred:$p, reglist:$wb, variable_ops),
Evan Cheng
committed
IIC_Br, "ldm${addr:submode}${p}${addr:wide}\t$addr, $wb",
let isBranch = 1, isTerminator = 1, isBarrier = 1 in {
let isPredicable = 1 in
David Goodwin
committed
def t2B : T2XI<(outs), (ins brtarget:$target), IIC_Br,
Evan Cheng
committed
"b.w\t$target",
[(br bb:$target)]>;
Evan Cheng
committed
let isNotDuplicable = 1, isIndirectBranch = 1 in {
def t2BR_JT :
Evan Cheng
committed
T2JTI<(outs),
(ins GPR:$target, GPR:$index, jt2block_operand:$jt, i32imm:$id),
Evan Cheng
committed
IIC_Br, "mov\tpc, $target\n$jt",
Evan Cheng
committed
[(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt, imm:$id)]>;
// FIXME: Add a non-pc based case that can be predicated.
Evan Cheng
committed
def t2TBB :
Evan Cheng
committed
(ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
Evan Cheng
committed
IIC_Br, "tbb\t$index\n$jt", []>;
Evan Cheng
committed
def t2TBH :
Evan Cheng
committed
(ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id),
Evan Cheng
committed
IIC_Br, "tbh\t$index\n$jt", []>;
Evan Cheng
committed
} // isNotDuplicable, 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
David Goodwin
committed
def t2Bcc : T2I<(outs), (ins brtarget:$target), IIC_Br,
Evan Cheng
committed
"b", ".w\t$target",
[/*(ARMbrcond bb:$target, imm:$cc)*/]>;
Evan Cheng
committed
// IT block
def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask),
AddrModeNone, Size2Bytes, IIC_iALUx,
Evan Cheng
committed
"it$mask\t$cc", "", []>;
Evan Cheng
committed
//===----------------------------------------------------------------------===//
// Non-Instruction Patterns
//
Jim Grosbach
committed
// 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))>;
Jim Grosbach
committed
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))>;
Jim Grosbach
committed
Evan Cheng
committed
// 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,
Evan Cheng
committed
"movw", "\t$dst, ${src:lo16}\n\tmovt${p}\t$dst, ${src:hi16}",
Evan Cheng
committed
[(set GPR:$dst, (i32 imm:$src))]>;
Evan Cheng
committed
// 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)>;
Evan Cheng
committed
// 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, mayHaveSideEffects = 1 in
Evan Cheng
committed
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]>;