This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch committed] SH: Add a define_expand for ashldi3


The attached patch is to add an expander for DImode left shift
with a constant shift count greater than 1.  It's mainly to
workaround PR40154 on SH according to the suggestion by Michael
and Dave.  The last insn this expander generates is a SH's
movdi_i insn which will be splitted to two SImode moves after
reload and survives at combine pass.  It seems that there is
no easy way to solve 40154 in the middle-end and anyway it's
beyonds my powers.  I'd like to keep that PR open.

The patch is tested with bootstrap and the top level "make -k
check" on sh4-unknown-linux-gnu.  I've also confirmed that there
are no visible differences in CSiBE results both for size and
runtime, though with it, the function

long long foo (long long xx) { return xx << 3; }

is compiled to 14 instructions, while it's compiled to 15
instructions originally, at -O2.

The patch has been applied on trunk.  I'll backport it to 4.4
when all usual tests are done on 4.4 successfully.

Regards,
	kaz
--
2009-05-31  Kaz Kojima  <kkojima@gcc.gnu.org>

	* config/sh/sh.md (ashldi3_std): New define_expand.
	(ashldi3): Use it.

--- ../ORIG/trunk/gcc/config/sh/sh.md	2009-05-30 18:35:42.000000000 +0900
+++ trunk/gcc/config/sh/sh.md	2009-05-30 21:05:46.000000000 +0900
@@ -3850,6 +3850,34 @@ label:
   [(set_attr "length" "4")
    (set_attr "type" "arith")])
 
+;; Expander for DImode shift left with SImode operations.
+
+(define_expand "ashldi3_std"
+  [(set (match_operand:DI 0 "arith_reg_dest" "=r")
+	(ashift:DI (match_operand:DI 1 "arith_reg_operand" "r")
+                   (match_operand:DI 2 "const_int_operand" "n")))]
+  "TARGET_SH1 && INTVAL (operands[2]) < 32"
+  "
+{
+  int low_word = (TARGET_LITTLE_ENDIAN ? 0 : 1);
+  int high_word = (TARGET_LITTLE_ENDIAN ? 1 : 0);
+  rtx low_src = operand_subword (operands[1], low_word, 0, DImode);
+  rtx high_src = operand_subword (operands[1], high_word, 0, DImode);
+  rtx dst = gen_reg_rtx (DImode);
+  rtx low_dst = operand_subword (dst, low_word, 1, DImode);
+  rtx high_dst = operand_subword (dst, high_word, 1, DImode);
+  rtx tmp0, tmp1;
+
+  tmp0 = gen_reg_rtx (SImode);
+  tmp1 = gen_reg_rtx (SImode);
+  emit_insn (gen_lshrsi3 (tmp0, low_src, GEN_INT (32 - INTVAL (operands[2]))));
+  emit_insn (gen_ashlsi3 (low_dst, low_src, operands[2]));  
+  emit_insn (gen_ashlsi3 (tmp1, high_src, operands[2]));  
+  emit_insn (gen_iorsi3 (high_dst, tmp0, tmp1));
+  emit_move_insn (operands[0], dst);
+  DONE;
+}")
+
 (define_insn "ashldi3_media"
   [(set (match_operand:DI 0 "arith_reg_dest" "=r,r")
 	(ashift:DI (match_operand:DI 1 "arith_reg_operand" "r,r")
@@ -3882,8 +3910,19 @@ label:
       emit_insn (gen_ashldi3_media (operands[0], operands[1], operands[2]));
       DONE;
     }
-  if (GET_CODE (operands[2]) != CONST_INT
-      || INTVAL (operands[2]) != 1)
+  if (GET_CODE (operands[2]) == CONST_INT
+      && INTVAL (operands[2]) == 1)
+    {
+      emit_insn (gen_ashldi3_k (operands[0], operands[1]));
+      DONE;
+    }
+  else if (GET_CODE (operands[2]) == CONST_INT
+      && INTVAL (operands[2]) < 32)
+    {
+      emit_insn (gen_ashldi3_std (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+  else
     FAIL;
 }")
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]