diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index e0617e46620..2196eab1b78 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -69,6 +69,11 @@ def t2_so_imm_neg : Operand, let PrintMethod = "printT2SOImmOperand"; } +/// imm1_31 predicate - True if the 32-bit immediate is in the range [1,31]. +def imm1_31 : PatLeaf<(i32 imm), [{ + return (int32_t)N->getZExtValue() >= 1 && (int32_t)N->getZExtValue() < 32; +}]>; + /// 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; @@ -125,40 +130,71 @@ def t2_lo16AllZero : PatLeaf<(i32 imm), [{ // Thumb2 to cover the functionality of the ARM instruction set. // -/// T2I_bin_is - Defines a set of (op reg, {so_imm|so_reg}) patterns for a +/// T2I_un_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a +// unary operation that produces a value. +multiclass T2I_un_irs{ + // shifted imm + def i : T2I<(outs GPR:$dst), (ins t2_so_imm:$src), + !strconcat(opc, " $dst, $src"), + [(set GPR:$dst, (opnode t2_so_imm:$src))]> { + let isAsCheapAsAMove = Cheap; + let isReMaterializable = ReMat; + } + // register + def r : T2I<(outs GPR:$dst), (ins GPR:$src), + !strconcat(opc, " $dst, $src"), + [(set GPR:$dst, (opnode GPR:$src))]>; + // shifted register + def s : T2I<(outs GPR:$dst), (ins t2_so_reg:$src), + !strconcat(opc, " $dst, $src"), + [(set GPR:$dst, (opnode t2_so_reg:$src))]>; +} + +/// T2I_bin_irs - Defines a set of (op reg, {so_imm|r|so_reg}) patterns for a // binary operation that produces a value. -multiclass T2I_bin_is { +multiclass T2I_bin_irs { // 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))]>; + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$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 { +/// T2I_2bin_is - Same as T2I_bin_irs except the order of operands are reversed. +multiclass T2I_rbin_irs { // shifted imm 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))]>; + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register 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_is - Similar to T2I_bin_is except it sets the 's' bit so the +/// T2I_bin_s_irs - Similar to T2I_bin_irs except it sets the 's' bit so the /// instruction modifies the CPSR register. let Defs = [CPSR] in { -multiclass T2I_bin_s_is { +multiclass T2I_bin_s_irs { // 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))]>; - + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), !strconcat(opc, "s $dst, $lhs, $rhs"), @@ -166,15 +202,18 @@ multiclass T2I_bin_s_is { } } -/// T2I_rbin_s_is - Same as T2I_bin_s_is except the order of operands are +/// T2I_rbin_s_irs - Same as T2I_bin_s_irs except the order of operands are /// reversed. let Defs = [CPSR] in { -multiclass T2I_rbin_s_is { +multiclass T2I_rbin_s_irs { // 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))]>; - + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), !strconcat(opc, "s $dst, $lhs, $rhs"), @@ -182,9 +221,9 @@ multiclass T2I_rbin_s_is { } } -/// 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 { +/// T2I_bin_ii12rs - Defines a set of (op reg, {so_imm|imm0_4095|r|so_reg}) +/// patterns for a binary operation that produces a value. +multiclass T2I_bin_ii12rs { // shifted imm def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), !strconcat(opc, " $dst, $lhs, $rhs"), @@ -193,22 +232,29 @@ multiclass T2I_bin_ii12s { 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))]>; + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$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_bin_c_is - Defines a set of (op reg, {so_imm|reg}) patterns for a +/// T2I_bin_c_irs - Defines a set of (op reg, {so_imm|r|so_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 { +multiclass T2I_bin_c_irs { // 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))]>; - + // register + def rr : T2I<(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))]>; // shifted register def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs, cc_out:$s), !strconcat(opc, "${s} $dst, $lhs, $rhs"), @@ -216,15 +262,18 @@ multiclass T2I_bin_c_is { } } -/// T2I_rbin_c_is - Same as T2I_bin_c_is except the order of operands are +/// T2I_rbin_c_irs - Same as T2I_bin_c_irs except the order of operands are /// reversed. let Uses = [CPSR] in { -multiclass T2I_rbin_c_is { +multiclass T2I_rbin_c_irs { // shifted imm 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 : T2I<(outs GPR:$dst), (ins GPR:$rhs, GPR:$lhs, cc_out:$s), + !strconcat(opc, "${s} $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>; // shifted register def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs, cc_out:$s), !strconcat(opc, "${s} $dst, $lhs, $rhs"), @@ -232,9 +281,21 @@ multiclass T2I_rbin_c_is { } } +/// T2I_sh_ir - Defines a set of (op reg, {so_imm|r}) patterns for a shift / +// rotate operation that produces a value. +multiclass T2I_sh_ir { + // 5-bit imm + def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$lhs, imm1_31:$rhs))]>; + // register + def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, " $dst, $lhs, $rhs"), + [(set GPR:$dst, (opnode GPR:$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 +/// T21_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test +/// patterns. Similar to T2I_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. let Uses = [CPSR] in { multiclass T2I_cmp_is { @@ -242,7 +303,10 @@ multiclass T2I_cmp_is { def ri : T2I<(outs), (ins GPR:$lhs, t2_so_imm:$rhs), !strconcat(opc, " $lhs, $rhs"), [(opnode GPR:$lhs, t2_so_imm:$rhs)]>; - + // register + def rr : T2I<(outs), (ins GPR:$lhs, GPR:$rhs), + !strconcat(opc, " $lhs, $rhs"), + [(opnode GPR:$lhs, GPR:$rhs)]>; // shifted register def rs : T2I<(outs), (ins GPR:$lhs, t2_so_reg:$rhs), !strconcat(opc, " $lhs, $rhs"), @@ -262,21 +326,11 @@ let neverHasSideEffects = 1 in def t2MOVr : T2I<(outs GPR:$dst), (ins GPR:$src), "mov $dst, $src", []>; +let isReMaterializable = 1, isAsCheapAsAMove = 1 in 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))]>; - - // FIXME: Also available in ARM mode. let Constraints = "$src = $dst" in def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), @@ -288,21 +342,21 @@ def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), // Arithmetic Instructions. // -defm t2ADD : T2I_bin_ii12s<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>; -defm t2SUB : T2I_bin_ii12s<"sub", BinOpFrag<(sub node:$LHS, node:$RHS)>>; +defm t2ADD : T2I_bin_ii12rs<"add", BinOpFrag<(add node:$LHS, node:$RHS)>>; +defm t2SUB : T2I_bin_ii12rs<"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)>>; +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)>>; // 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)>>; +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)>>; // 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)>>; +defm t2RSB : T2I_rbin_irs <"rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; +defm t2RSBS : T2I_rbin_c_irs<"rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>; +defm t2RSC : T2I_rbin_s_irs<"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), @@ -311,32 +365,38 @@ def : Thumb2Pat<(add GPR:$src, imm0_4095_neg:$imm), (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>; +//===----------------------------------------------------------------------===// +// Shift and rotate Instructions. +// + +defm t2LSL : T2I_sh_ir<"lsl", BinOpFrag<(shl node:$LHS, node:$RHS)>>; +defm t2LSR : T2I_sh_ir<"lsr", BinOpFrag<(srl node:$LHS, node:$RHS)>>; +defm t2ASR : T2I_sh_ir<"asr", BinOpFrag<(sra node:$LHS, node:$RHS)>>; +defm t2ROR : T2I_sh_ir<"ror", BinOpFrag<(rotr node:$LHS, node:$RHS)>>; + +def t2MOVrx : T2I<(outs GPR:$dst), (ins GPR:$src), + "mov $dst, $src, rrx", + [(set GPR:$dst, (ARMrrx GPR:$src))]>; + //===----------------------------------------------------------------------===// // 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 t2AND : T2I_bin_irs<"and", BinOpFrag<(and node:$LHS, node:$RHS)>>; +defm t2ORR : T2I_bin_irs<"orr", BinOpFrag<(or node:$LHS, node:$RHS)>>; +defm t2EOR : T2I_bin_irs<"eor", BinOpFrag<(xor node:$LHS, node:$RHS)>>; -defm t2BIC : T2I_bin_is <"bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>; +defm t2BIC : T2I_bin_irs<"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))>>; +defm t2ORN : T2I_bin_irs<"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)]>; +defm t2MVN : T2I_un_irs <"mvn", UnOpFrag<(not node:$Src)>, 1, 1>; // A8.6.17 BFC - Bitfield clear // FIXME: Also available in ARM mode. diff --git a/test/CodeGen/ARM/thumb2-shifter.ll b/test/CodeGen/ARM/thumb2-shifter.ll index f9ec5067ec0..9bd6e43101a 100644 --- a/test/CodeGen/ARM/thumb2-shifter.ll +++ b/test/CodeGen/ARM/thumb2-shifter.ll @@ -2,7 +2,7 @@ ; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep lsr ; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep asr ; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep ror -; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | grep mov +; RUN: llvm-as < %s | llc -march=thumb -mattr=+thumb2 | not grep mov define i32 @t2ADDrs_lsl(i32 %X, i32 %Y) { %A = shl i32 %Y, 16