Proper patterns for thumb2 shift and rotate instructions.
authorEvan Cheng <evan.cheng@apple.com>
Tue, 23 Jun 2009 19:39:13 +0000 (19:39 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Tue, 23 Jun 2009 19:39:13 +0000 (19:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@73987 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrThumb2.td
test/CodeGen/ARM/thumb2-shifter.ll

index e0617e466208af8aedebc45e38b6bcd1c7b58418..2196eab1b7801fcef913ead6c9cda86db3d48c7f 100644 (file)
@@ -69,6 +69,11 @@ def t2_so_imm_neg : Operand<i32>,
   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<string opc, PatFrag opnode, bit Cheap = 0, bit ReMat = 0>{
+   // 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<string opc, PatFrag opnode> {
+multiclass T2I_bin_irs<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))]>;
+   // 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<string opc, PatFrag opnode> {
+/// T2I_2bin_is - Same as T2I_bin_irs except the order of operands are reversed.
+multiclass T2I_rbin_irs<string opc, PatFrag opnode> {
    // 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<string opc, PatFrag opnode> {
+multiclass T2I_bin_s_irs<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))]>;
-
+   // 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<string opc, PatFrag opnode> {
 }
 }
 
-/// 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<string opc, PatFrag opnode> {
+multiclass T2I_rbin_s_irs<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))]>;
-
+   // 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<string opc, PatFrag opnode> {
 }
 }
 
-/// 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> {
+/// 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<string opc, PatFrag opnode> {
    // 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<string opc, PatFrag opnode> {
    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<string opc, PatFrag opnode> {
+multiclass T2I_bin_c_irs<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))]>;
-
+   // 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<string opc, PatFrag opnode> {
 }
 }
 
-/// 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<string opc, PatFrag opnode> {
+multiclass T2I_rbin_c_irs<string opc, PatFrag opnode> {
    // 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<string opc, PatFrag opnode> {
 }
 }
 
+/// 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<string opc, PatFrag opnode> {
+   // 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<string opc, PatFrag opnode> {
@@ -242,7 +303,10 @@ multiclass T2I_cmp_is<string opc, PatFrag opnode> {
    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.
index f9ec5067ec016539b68df133a4261135e47f6d50..9bd6e43101a89269cf1c0afb830e379983db0332 100644 (file)
@@ -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