From f1f59bc72456d213ef80a7f5688ffeb2af2dc020 Mon Sep 17 00:00:00 2001
From: Georg-Johann Lay <avr@gjlay.de>
Date: Tue, 1 Nov 2011 14:10:13 +0000
Subject: [PATCH] re PR target/50910 ([avr] inefficient division by 2)

	PR target/50910
	* config/avr/avr.opt (-mbranch-cost=): New option.
	* config/avr/avr.h (BRANCH_COST): Define to avr_branch_cost.
	* config/avr/avr.c (avr_rtx_costs_1): Adjust [U]DIV/[U]MOD costs.
	* config/avr/avr.md (*addqi3.lt0, *addhi3.lt0, *addsi3.lt0): New insns.
	(*addhi3_zero_extend1): Remov % in constraint of operand 1.
	(*addhi3.sign_extend1, *subhi3.sign_extend2): New insns.

From-SVN: r180739
---
 gcc/ChangeLog          | 10 ++++++
 gcc/config/avr/avr.c   | 11 ++++--
 gcc/config/avr/avr.h   |  2 +-
 gcc/config/avr/avr.md  | 81 +++++++++++++++++++++++++++++++++++-------
 gcc/config/avr/avr.opt |  8 +++++
 5 files changed, 96 insertions(+), 16 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index af01b0e7f947..d8476c27c6be 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2011-11-01  Georg-Johann Lay  <avr@gjlay.de>
+
+	PR target/50910
+	* config/avr/avr.opt (-mbranch-cost=): New option.
+	* config/avr/avr.h (BRANCH_COST): Define to avr_branch_cost.
+	* config/avr/avr.c (avr_rtx_costs_1): Adjust [U]DIV/[U]MOD costs.
+	* config/avr/avr.md (*addqi3.lt0, *addhi3.lt0, *addsi3.lt0): New insns.
+	(*addhi3_zero_extend1): Remov % in constraint of operand 1.
+	(*addhi3.sign_extend1, *subhi3.sign_extend2): New insns.
+
 2011-11-01  Tom de Vries  <tom@codesourcery.com>
 
 	PR tree-optimization/50908
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 187dcb149128..6435c4854f5e 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -6477,11 +6477,16 @@ avr_rtx_costs_1 (rtx x, int codearg, int outer_code ATTRIBUTE_UNUSED,
     case UDIV:
     case UMOD:
       if (!speed)
-	*total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
+        *total = COSTS_N_INSNS (AVR_HAVE_JMP_CALL ? 2 : 1);
       else
-	return false;
+        *total = COSTS_N_INSNS (15 * GET_MODE_SIZE (mode));
       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code, 0, speed);
-      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code, 1, speed);
+      /* For div/mod with const-int divisor we have at least the cost of
+         loading the divisor. */
+      if (CONST_INT_P (XEXP (x, 1)))
+        *total += COSTS_N_INSNS (GET_MODE_SIZE (mode));
+      /* Add some overall penaly for clobbering and moving around registers */
+      *total += COSTS_N_INSNS (2);
       return true;
 
     case ROTATE:
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 50f64884c07d..47ca8ff759af 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -385,7 +385,7 @@ typedef struct avr_args {
       }                                                                 \
   } while (0)
 
-#define BRANCH_COST(speed_p, predictable_p) 0
+#define BRANCH_COST(speed_p, predictable_p) avr_branch_cost
 
 #define SLOW_BYTE_ACCESS 0
 
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index faf18797bc18..f3edbbcd026c 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -776,27 +776,36 @@
 
 
 (define_insn "*addhi3_zero_extend"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-	(plus:HI (zero_extend:HI
-		  (match_operand:QI 1 "register_operand" "r"))
-		 (match_operand:HI 2 "register_operand" "0")))]
+  [(set (match_operand:HI 0 "register_operand"                         "=r")
+        (plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "r"))
+                 (match_operand:HI 2 "register_operand"                 "0")))]
   ""
-  "add %A0,%1
-	adc %B0,__zero_reg__"
+  "add %A0,%1\;adc %B0,__zero_reg__"
   [(set_attr "length" "2")
    (set_attr "cc" "set_n")])
 
 (define_insn "*addhi3_zero_extend1"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-	(plus:HI (match_operand:HI 1 "register_operand" "%0")
-		 (zero_extend:HI
-		  (match_operand:QI 2 "register_operand" "r"))))]
+  [(set (match_operand:HI 0 "register_operand"                         "=r")
+        (plus:HI (match_operand:HI 1 "register_operand"                 "0")
+                 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
   ""
-  "add %A0,%2
-	adc %B0,__zero_reg__"
+  "add %A0,%2\;adc %B0,__zero_reg__"
   [(set_attr "length" "2")
    (set_attr "cc" "set_n")])
 
+(define_insn "*addhi3.sign_extend1"
+  [(set (match_operand:HI 0 "register_operand"                         "=r")
+        (plus:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "r"))
+                 (match_operand:HI 2 "register_operand"                 "0")))]
+  ""
+  {
+    return reg_overlap_mentioned_p (operands[0], operands[1])
+      ? "mov __tmp_reg__,%1\;add %A0,%1\;adc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;dec %B0"
+      : "add %A0,%1\;adc %B0,__zero_reg__\;sbrc %1,7\;dec %B0";
+  }
+  [(set_attr "length" "5")
+   (set_attr "cc" "clobber")])
+
 (define_insn "*addhi3_sp"
   [(set (match_operand:HI 1 "stack_register_operand"           "=q")
         (plus:HI (match_operand:HI 2 "stack_register_operand"   "q")
@@ -956,6 +965,19 @@
   [(set_attr "length" "2")
    (set_attr "cc" "set_czn")])
 
+(define_insn "*subhi3.sign_extend2"
+  [(set (match_operand:HI 0 "register_operand"                          "=r")
+        (minus:HI (match_operand:HI 1 "register_operand"                 "0")
+                  (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+  ""
+  {
+    return reg_overlap_mentioned_p (operands[0], operands[2])
+      ? "mov __tmp_reg__,%2\;sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc __tmp_reg__,7\;inc %B0"
+      : "sub %A0,%2\;sbc %B0,__zero_reg__\;sbrc %2,7\;inc %B0";
+  }
+  [(set_attr "length" "5")
+   (set_attr "cc" "clobber")])
+
 (define_insn "subsi3"
   [(set (match_operand:SI 0 "register_operand"          "=r")
         (minus:SI (match_operand:SI 1 "register_operand" "0")
@@ -1054,6 +1076,41 @@
   [(set_attr "length" "2")
    (set_attr "cc" "clobber")])
 
+(define_insn "*addqi3.lt0"
+  [(set (match_operand:QI 0 "register_operand"                 "=r")
+        (plus:QI (lt:QI (match_operand:QI 1 "register_operand"  "r")
+                        (const_int 0))
+                 (match_operand:QI 2 "register_operand"         "0")))]
+  ""
+  "sbrc %1,7\;inc %0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*addhi3.lt0"
+  [(set (match_operand:HI 0 "register_operand"                   "=w,r")
+        (plus:HI (lt:HI (match_operand:QI 1 "register_operand"    "r,r")
+                        (const_int 0))
+                 (match_operand:HI 2 "register_operand"           "0,0")))
+   (clobber (match_scratch:QI 3                                  "=X,&1"))]
+  ""
+  "@
+	sbrc %1,7\;adiw %0,1
+	lsl %1\;adc %A0,__zero_reg__\;adc %B0,__zero_reg__"
+  [(set_attr "length" "2,3")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*addsi3.lt0"
+  [(set (match_operand:SI 0 "register_operand"                       "=r")
+        (plus:SI (lshiftrt:SI (match_operand:SI 1 "register_operand"  "r")
+                              (const_int 31))
+                 (match_operand:SI 2 "register_operand"               "0")))]
+  ""
+  "mov __tmp_reg__,%D1\;lsl __tmp_reg__
+	adc %A0,__zero_reg__\;adc %B0,__zero_reg__\;adc %C0,__zero_reg__\;adc %D0,__zero_reg__"
+  [(set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+  
+
 ;; "umulqihi3"
 ;; "mulqihi3"
 (define_insn "<extend_u>mulqihi3"
diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt
index 8de929d12918..bb9c90ec36f3 100644
--- a/gcc/config/avr/avr.opt
+++ b/gcc/config/avr/avr.opt
@@ -40,6 +40,10 @@ mno-interrupts
 Target Report RejectNegative Mask(NO_INTERRUPTS)
 Change the stack pointer without disabling interrupts
 
+mbranch-cost=
+Target Report Joined RejectNegative UInteger Var(avr_branch_cost) Init(0)
+Set the branch costs for conditional branch instructions.  Reasonable values are small, non-negative integers.  The default branch cost is 0.
+
 morder1
 Target Report Undocumented Mask(ORDER_1)
 
@@ -69,3 +73,7 @@ Accumulate outgoing function arguments and acquire/release the needed stack spac
 mstrict-X
 Target Report Var(avr_strict_X) Init(0)
 When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decrement, post-increment and indirect addressing with the X register.  Without this option, the compiler may assume that there is an addressing mode X+const similar to Y+const and Z+const and emit instructions to emulate such an addressing mode for X.
+
+mbranch-cost=
+Target Report RejectNegative Joined UInteger Var(avr_branch_cost) Init(0)
+Set the cost of a branch instruction.  Default value is 0.
-- 
GitLab