summaryrefslogtreecommitdiffstats
path: root/lib/Target/ARM/ARMInstrThumb2.td
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/ARM/ARMInstrThumb2.td')
-rw-r--r--lib/Target/ARM/ARMInstrThumb2.td502
1 files changed, 367 insertions, 135 deletions
diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td
index 0aba2d5..e0617e4 100644
--- a/lib/Target/ARM/ARMInstrThumb2.td
+++ b/lib/Target/ARM/ARMInstrThumb2.td
@@ -14,137 +14,239 @@
// Shifted operands. No register controlled shifts for Thumb2.
// Note: We do not support rrx shifted operands yet.
def t2_so_reg : Operand<i32>, // reg imm
- ComplexPattern<i32, 2, "SelectShifterOperand",
+ ComplexPattern<i32, 2, "SelectThumb2ShifterOperandReg",
[shl,srl,sra,rotr]> {
let PrintMethod = "printSOOperand";
let MIOperandInfo = (ops GPR, i32imm);
}
-def LO16 : SDNodeXForm<imm, [{
- // Transformation function: shift the immediate value down into the low bits.
- return getI32Imm((unsigned short)N->getZExtValue());
+// t2_so_imm_XFORM - Return a t2_so_imm value packed into the format
+// described for t2_so_imm def below.
+def t2_so_imm_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(
+ ARM_AM::getT2SOImmVal(N->getZExtValue()), MVT::i32);
}]>;
-def HI16 : SDNodeXForm<imm, [{
- // Transformation function: shift the immediate value down into the low bits.
- return getI32Imm((unsigned)N->getZExtValue() >> 16);
+// t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value
+def t2_so_imm_not_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(
+ ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())), MVT::i32);
}]>;
-def imm16high : PatLeaf<(i32 imm), [{
- // Returns true if all bits out of the [31..16] range are 0.
- return ((N->getZExtValue() & 0xFFFF0000ULL) == N->getZExtValue());
-}], HI16>;
+// t2_so_imm_neg_XFORM - Return the negation of a t2_so_imm value
+def t2_so_imm_neg_XFORM : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(
+ ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())), MVT::i32);
+}]>;
+
+// t2_so_imm - Match a 32-bit immediate operand, which is an
+// 8-bit immediate rotated by an arbitrary number of bits, or an 8-bit
+// immediate splatted into multiple bytes of the word. t2_so_imm values are
+// represented in the imm field in the same 12-bit form that they are encoded
+// into t2_so_imm instructions: the 8-bit immediate is the least significant bits
+// [bits 0-7], the 4-bit shift/splat amount is the next 4 bits [bits 8-11].
+def t2_so_imm : Operand<i32>,
+ PatLeaf<(imm), [{
+ return ARM_AM::getT2SOImmVal((uint32_t)N->getZExtValue()) != -1;
+ }], t2_so_imm_XFORM> {
+ let PrintMethod = "printT2SOImmOperand";
+}
-def imm16high0xffff : PatLeaf<(i32 imm), [{
- // Returns true if lo 16 bits are set and this is a 32-bit value.
- return ((N->getZExtValue() & 0x0000FFFFULL) == 0xFFFFULL);
-}], HI16>;
+// t2_so_imm_not - Match an immediate that is a complement
+// of a t2_so_imm.
+def t2_so_imm_not : Operand<i32>,
+ PatLeaf<(imm), [{
+ return ARM_AM::getT2SOImmVal(~((uint32_t)N->getZExtValue())) != -1;
+ }], t2_so_imm_not_XFORM> {
+ let PrintMethod = "printT2SOImmOperand";
+}
+
+// t2_so_imm_neg - Match an immediate that is a negation of a t2_so_imm.
+def t2_so_imm_neg : Operand<i32>,
+ PatLeaf<(imm), [{
+ return ARM_AM::getT2SOImmVal(-((int)N->getZExtValue())) != -1;
+ }], t2_so_imm_neg_XFORM> {
+ let PrintMethod = "printT2SOImmOperand";
+}
-def imm0_4095 : PatLeaf<(i32 imm), [{
- return (uint32_t)N->getZExtValue() < 4096;
-}]>;
+/// imm0_4095 predicate - True if the 32-bit immediate is in the range [0.4095].
+def imm0_4095 : PatLeaf<(i32 imm), [{
+ return (uint32_t)N->getZExtValue() < 4096;
+}]>;
def imm0_4095_neg : PatLeaf<(i32 imm), [{
- return (uint32_t)-N->getZExtValue() < 4096;
+ return (uint32_t)(-N->getZExtValue()) < 4096;
}], imm_neg_XFORM>;
-def imm0_65535 : PatLeaf<(i32 imm), [{
- return N->getZExtValue() < 65536;
-}]>;
-
-// A6.3.2 Modified immediate constants in Thumb instructions (#<const>)
-// FIXME: Move it the the addrmode matcher code.
-def t2_so_imm : PatLeaf<(i32 imm), [{
- uint64_t v = N->getZExtValue();
- if (v == 0 || v > 0xffffffffUL) return false;
- // variant1 - 0b0000x - 8-bit which could be zero (not supported for now)
-
- // variant2 - 0b00nnx - 8-bit repeated inside the 32-bit room
- unsigned hi16 = (unsigned)(v >> 16);
- unsigned lo16 = (unsigned)(v & 0xffffUL);
- bool valid = (hi16 == lo16) && (
- (v & 0x00ff00ffUL) == 0 || // type 0001x
- (v & 0xff00ff00UL) == 0 || // type 0010x
- ((lo16 >> 8) == (lo16 & 0xff))); // type 0011x
- if (valid) return true;
-
- // variant3 - 0b01000..0b11111 - 8-bit shifted inside the 32-bit room
- unsigned shift = CountLeadingZeros_32(v);
- uint64_t mask = (0xff000000ULL >> shift);
- // If valid, it is type 01000 + shift
- return ((shift < 24) && (v & mask) > 0) && ((v & (~mask)) == 0);
+/// imm0_65535 predicate - True if the 32-bit immediate is in the range
+/// [0.65535].
+def imm0_65535 : PatLeaf<(i32 imm), [{
+ return (uint32_t)N->getZExtValue() < 65536;
}]>;
+/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
+/// e.g., 0xf000ffff
+def bf_inv_mask_imm : Operand<i32>,
+ PatLeaf<(imm), [{
+ uint32_t v = (uint32_t)N->getZExtValue();
+ if (v == 0xffffffff)
+ return 0;
+ // naive checker. should do better, but simple is best for now since it's
+ // more likely to be correct.
+ while (v & 1) v >>= 1; // shift off the leading 1's
+ if (v)
+ {
+ while (!(v & 1)) v >>=1; // shift off the mask
+ while (v & 1) v >>= 1; // shift off the trailing 1's
+ }
+ // if this is a mask for clearing a bitfield, what's left should be zero.
+ return (v == 0);
+}] > {
+ let PrintMethod = "printBitfieldInvMaskImmOperand";
+}
+
+/// Split a 32-bit immediate into two 16 bit parts.
+def t2_lo16 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() & 0xffff,
+ MVT::i32);
+}]>;
+
+def t2_hi16 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32);
+}]>;
+
+def t2_lo16AllZero : PatLeaf<(i32 imm), [{
+ // Returns true if all low 16-bits are 0.
+ return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0;
+ }], t2_hi16>;
+
//===----------------------------------------------------------------------===//
-// Thumb-2 to cover the functionality of the ARM instruction set.
+// Thumb2 to cover the functionality of the ARM instruction set.
//
-/// T2I_bin_irs - Defines a set of (op reg, {so_imm|reg|so_reg}) patterns for a
+/// T2I_bin_is - Defines a set of (op reg, {so_imm|so_reg}) patterns for a
// binary operation that produces a value.
-multiclass T2I_bin_irs<string opc, PatFrag opnode> {
+multiclass T2I_bin_is<string opc, PatFrag opnode> {
+ // shifted imm
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+ // shifted register
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+}
+
+/// T2I_2bin_is - Same as T2I_bin_is except the order of operands are reversed.
+multiclass T2I_rbin_is<string opc, PatFrag opnode> {
// shifted imm
- def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
- Requires<[HasThumb2]>;
- // register
- def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
- Requires<[HasThumb2]>;
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
// shifted register
- def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, " $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
- Requires<[HasThumb2]>;
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
}
-/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the
+/// T2I_bin_s_is - Similar to T2I_bin_is except it sets the 's' bit so the
/// instruction modifies the CPSR register.
let Defs = [CPSR] in {
-multiclass T2I_bin_s_irs<string opc, PatFrag opnode> {
+multiclass T2I_bin_s_is<string opc, PatFrag opnode> {
+ // shifted imm
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+
+ // shifted register
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+}
+}
+
+/// T2I_rbin_s_is - Same as T2I_bin_s_is except the order of operands are
+/// reversed.
+let Defs = [CPSR] in {
+multiclass T2I_rbin_s_is<string opc, PatFrag opnode> {
+ // shifted imm
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
+
+ // shifted register
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs),
+ !strconcat(opc, "s $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
+}
+}
+
+/// T2I_bin_ii12s - Defines a set of (op reg, {so_imm|imm0_4095|so_reg}) patterns
+/// for a binary operation that produces a value.
+multiclass T2I_bin_ii12s<string opc, PatFrag opnode> {
// shifted imm
- def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
- Requires<[HasThumb2]>;
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
+ // 12-bit imm
+ def ri12 : T2I<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
+ !strconcat(opc, "w $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]>;
+ // shifted register
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
+ !strconcat(opc, " $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
+}
- // register
- def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
- Requires<[HasThumb2]>;
+/// T2I_bin_c_is - Defines a set of (op reg, {so_imm|reg}) patterns for a
+// binary operation that produces a value and set the carry bit. It can also
+/// optionally set CPSR.
+let Uses = [CPSR] in {
+multiclass T2I_bin_c_is<string opc, PatFrag opnode> {
+ // shifted imm
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>;
// shifted register
- def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs),
- !strconcat(opc, "s $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
- Requires<[HasThumb2]>;
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>;
}
}
-/// T2I_bin_c_irs - Similar to T2I_bin_irs except it uses the 's' bit. Also the
-/// instruction can optionally set the CPSR register.
+/// T2I_rbin_c_is - Same as T2I_bin_c_is except the order of operands are
+/// reversed.
let Uses = [CPSR] in {
-multiclass T2I_bin_c_irs<string opc, PatFrag opnode> {
+multiclass T2I_rbin_c_is<string opc, PatFrag opnode> {
// shifted imm
- def ri : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>,
- Requires<[HasThumb2]>;
+ def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]>;
- // register
- def rr : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>,
- Requires<[HasThumb2]>;
+ // shifted register
+ def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s),
+ !strconcat(opc, "${s} $dst, $lhs, $rhs"),
+ [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]>;
+}
+}
+
+
+/// T21_cmp_irs - Defines a set of (op r, {so_imm|so_reg}) cmp / test
+/// patterns. Similar to T2I_bin_is except the instruction does not produce
+/// a explicit result, only implicitly set CPSR.
+let Uses = [CPSR] in {
+multiclass T2I_cmp_is<string opc, PatFrag opnode> {
+ // shifted imm
+ def ri : T2I<(outs), (ins GPR:$lhs, t2_so_imm:$rhs),
+ !strconcat(opc, " $lhs, $rhs"),
+ [(opnode GPR:$lhs, t2_so_imm:$rhs)]>;
// shifted register
- def rs : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s),
- !strconcat(opc, "${s} $dst, $lhs, $rhs"),
- [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>,
- Requires<[HasThumb2]>;
+ def rs : T2I<(outs), (ins GPR:$lhs, t2_so_reg:$rhs),
+ !strconcat(opc, " $lhs, $rhs"),
+ [(opnode GPR:$lhs, t2_so_reg:$rhs)]>;
}
}
@@ -155,54 +257,184 @@ multiclass T2I_bin_c_irs<string opc, PatFrag opnode> {
//===----------------------------------------------------------------------===//
// Move Instructions.
//
-def tMOVi16 : PseudoInst<(outs GPR:$dst), (ins i32imm:$src),
- "movw $dst, $src",
- [(set GPR:$dst, imm0_65535:$src)]>,
- Requires<[HasThumb2]>;
-let Constraints = "$src = $dst" in
-def tMOVTi16 : PseudoInst<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
- "movt $dst, $imm",
- [(set GPR:$dst, (or (and GPR:$src, 0xffff),
- imm16high:$imm))]>,
- Requires<[HasThumb2]>;
+let neverHasSideEffects = 1 in
+def t2MOVr : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "mov $dst, $src", []>;
+
+def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src),
+ "movw $dst, $src",
+ [(set GPR:$dst, imm0_65535:$src)]>;
+
+
+// FIXME: Move (shifted register) is a pseudo-instruction for ASR, LSL, LSR,
+// ROR, and RRX. Consider splitting into multiple instructions.
+def t2MOVs : T2I<(outs GPR:$dst), (ins t2_so_reg:$src),
+ "mov $dst, $src",
+ [(set GPR:$dst, t2_so_reg:$src)]>;
+def t2MOVrx : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "mov $dst, $src, rrx",
+ [(set GPR:$dst, (ARMrrx GPR:$src))]>;
-def : Pat<(and (or GPR:$src, imm16high:$imm1), imm16high0xffff:$imm2),
- (tMOVTi16 GPR:$src, (HI16 imm16high:$imm1))>,
- Requires<[HasThumb2]>;
-def : Pat<(i32 imm:$imm),
- (tMOVTi16 (tMOVi16 (LO16 imm:$imm)),(HI16 imm:$imm))>,
- Requires<[HasThumb2]>;
+// FIXME: Also available in ARM mode.
+let Constraints = "$src = $dst" in
+def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
+ "movt $dst, $imm",
+ [(set GPR:$dst,
+ (or (and GPR:$src, 0xffff), t2_lo16AllZero:$imm))]>;
//===----------------------------------------------------------------------===//
// Arithmetic Instructions.
//
-defm t2ADD : T2I_bin_irs <"add", BinOpFrag<(add node:$LHS, node:$RHS)>>;
-defm t2SUB : T2I_bin_irs <"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
-
-def tADDri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- "add $dst, $lhs, $rhs",
- [(set GPR:$dst, (add GPR:$lhs, imm0_4095:$rhs))]>,
- Requires<[HasThumb2]>;
-def tSUBri12 : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs),
- "sub $dst, $lhs, $rhs",
- [(set GPR:$dst, (add GPR:$lhs, imm0_4095_neg:$rhs))]>,
- Requires<[HasThumb2]>;
-
-defm t2ADDS : T2I_bin_s_irs<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
-defm t2SUBS : T2I_bin_s_irs<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
-
-defm t2ADC : T2I_bin_c_irs<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
-defm t2SBC : T2I_bin_c_irs<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
-
-
-def tMLS : PseudoInst<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
- "mls $dst, $a, $b, $c",
- [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>,
- Requires<[HasThumb2]>;
-
-def tORNrs : PseudoInst<(outs GPR:$dst), (ins GPR:$src1, t2_so_reg:$src2),
- "orn $dst, $src1, $src2",
- [(set GPR:$dst, (or GPR:$src1, (not t2_so_reg: $src2)))]>,
- Requires<[HasThumb2]>;
+
+defm t2ADD : T2I_bin_ii12s<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>;
+defm t2SUB : T2I_bin_ii12s<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
+
+// ADD and SUB with 's' bit set. No 12-bit immediate (T4) variants.
+defm t2ADDS : T2I_bin_s_is<"add", BinOpFrag<(addc node:$LHS, node:$RHS)>>;
+defm t2SUBS : T2I_bin_s_is<"sub", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
+
+// FIXME: predication support
+defm t2ADC : T2I_bin_c_is<"adc", BinOpFrag<(adde node:$LHS, node:$RHS)>>;
+defm t2SBC : T2I_bin_c_is<"sbc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
+
+// RSB, RSC
+defm t2RSB : T2I_rbin_is <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>;
+defm t2RSBS : T2I_rbin_c_is<"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>;
+defm t2RSC : T2I_rbin_s_is<"rsc", BinOpFrag<(sube node:$LHS, node:$RHS)>>;
+
+// (sub X, imm) gets canonicalized to (add X, -imm). Match this form.
+def : Thumb2Pat<(add GPR:$src, t2_so_imm_neg:$imm),
+ (t2SUBri GPR:$src, t2_so_imm_neg:$imm)>;
+def : Thumb2Pat<(add GPR:$src, imm0_4095_neg:$imm),
+ (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>;
+
+
+//===----------------------------------------------------------------------===//
+// Bitwise Instructions.
+//
+
+defm t2AND : T2I_bin_is <"and", BinOpFrag<(and node:$LHS, node:$RHS)>>;
+defm t2ORR : T2I_bin_is <"orr", BinOpFrag<(or node:$LHS, node:$RHS)>>;
+defm t2EOR : T2I_bin_is <"eor", BinOpFrag<(xor node:$LHS, node:$RHS)>>;
+
+defm t2BIC : T2I_bin_is <"bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>;
+
+def : Thumb2Pat<(and GPR:$src, t2_so_imm_not:$imm),
+ (t2BICri GPR:$src, t2_so_imm_not:$imm)>;
+
+defm t2ORN : T2I_bin_is <"orn", BinOpFrag<(or node:$LHS, (not node:$RHS))>>;
+
+def : Thumb2Pat<(or GPR:$src, t2_so_imm_not:$imm),
+ (t2ORNri GPR:$src, t2_so_imm_not:$imm)>;
+
+
+def t2MVNr : T2I<(outs GPR:$dst), (ins t2_so_reg:$rhs),
+ "mvn $dst, $rhs",
+ [(set GPR:$dst, (not t2_so_reg:$rhs))]>;
+let isReMaterializable = 1, isAsCheapAsAMove = 1 in
+def t2MVNi : T2I<(outs GPR:$dst), (ins t2_so_imm_not:$rhs),
+ "mvn $dst, $rhs",
+ [(set GPR:$dst, t2_so_imm_not:$rhs)]>;
+
+// A8.6.17 BFC - Bitfield clear
+// FIXME: Also available in ARM mode.
+let Constraints = "$src = $dst" in
+def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm),
+ "bfc $dst, $imm",
+ [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>;
+
+// FIXME: A8.6.18 BFI - Bitfield insert (Encoding T1)
+
+//===----------------------------------------------------------------------===//
+// Multiply Instructions.
+//
+def t2MUL: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b),
+ "mul $dst, $a, $b",
+ [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>;
+
+def t2MLA: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
+ "mla $dst, $a, $b, $c",
+ [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>;
+
+def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c),
+ "mls $dst, $a, $b, $c",
+ [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>;
+
+// FIXME: SMULL, etc.
+
+//===----------------------------------------------------------------------===//
+// Misc. Arithmetic Instructions.
+//
+
+/////
+/// A8.6.31 CLZ
+/////
+// FIXME not firing? but ARM version does...
+def t2CLZ : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "clz $dst, $src",
+ [(set GPR:$dst, (ctlz GPR:$src))]>;
+
+def t2REV : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "rev $dst, $src",
+ [(set GPR:$dst, (bswap GPR:$src))]>;
+
+def t2REV16 : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "rev16 $dst, $src",
+ [(set GPR:$dst,
+ (or (and (srl GPR:$src, (i32 8)), 0xFF),
+ (or (and (shl GPR:$src, (i32 8)), 0xFF00),
+ (or (and (srl GPR:$src, (i32 8)), 0xFF0000),
+ (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>;
+
+/////
+/// A8.6.137 REVSH
+/////
+def t2REVSH : T2I<(outs GPR:$dst), (ins GPR:$src),
+ "revsh $dst, $src",
+ [(set GPR:$dst,
+ (sext_inreg
+ (or (srl (and GPR:$src, 0xFFFF), (i32 8)),
+ (shl GPR:$src, (i32 8))), i16))]>;
+
+// FIXME: PKHxx etc.
+
+//===----------------------------------------------------------------------===//
+// Comparison Instructions...
+//
+
+defm t2CMP : T2I_cmp_is<"cmp",
+ BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
+defm t2CMPnz : T2I_cmp_is<"cmp",
+ BinOpFrag<(ARMcmpNZ node:$LHS, node:$RHS)>>;
+
+defm t2CMN : T2I_cmp_is<"cmn",
+ BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>;
+defm t2CMNnz : T2I_cmp_is<"cmn",
+ BinOpFrag<(ARMcmpNZ node:$LHS,(ineg node:$RHS))>>;
+
+def : Thumb2Pat<(ARMcmp GPR:$src, t2_so_imm_neg:$imm),
+ (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
+
+def : Thumb2Pat<(ARMcmpNZ GPR:$src, t2_so_imm_neg:$imm),
+ (t2CMNri GPR:$src, t2_so_imm_neg:$imm)>;
+
+// FIXME: TST, TEQ, etc.
+
+// 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.
+
+// FIXME: Conditional moves
+
+
+//===----------------------------------------------------------------------===//
+// Non-Instruction Patterns
+//
+
+// Large immediate handling.
+
+def : Thumb2Pat<(i32 imm:$src),
+ (t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)),
+ (t2_hi16 imm:$src))>;
OpenPOWER on IntegriCloud