This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch] Use FPU for integer division on Alpha
- From: Falk Hueffner <falk at debian dot org>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Sat, 19 Mar 2005 21:56:49 +0100
- Subject: Re: [patch] Use FPU for integer division on Alpha
- References: <87d5tyze2u.fsf@debian.org> <20050317125150.GA4219@redhat.com>
Richard Henderson <rth@redhat.com> writes:
> On Thu, Mar 17, 2005 at 12:50:17PM +0100, Falk Hueffner wrote:
>> problem. The Java frontend (and presumably other frontends where
>> division by zero is not undefined) checks for 0 before doing the
>> division.
>
> I'm not quite sure why libjava isn't using
>
> DIVIDESPEC=-fno-use-divide-subroutine
>
> on Alpha. Perhaps we missed some little bit?
>
> Anyway, the imprecise traps thing would be solvable by noting that
> DIVC can trap, and doing the "&" thing when precise traps are
> enabled. That should get a trapb insn added appropriately. And
> it'll work for Java, because we enable -mieee there.
But that'd also add lots of trapbs when compiling C with -mieee. Is
there some way to make this Java specific? Since Java currently uses
the divide subroutine anyway, I'd prefer to postpone this...
> And I'm not 100% convinced we shouldn't add an option to disable
> this change.
I couldn't find any software that would need that from a quick search.
But I don't have a strong opinion there, if anybody thinks this should
be optional, I can add that.
> Raw creation of subregs is wrong. You bork endianness.
OK, I changed it. I also simplified the modulo patterns a bit by
having them call the division patterns.
--
Falk
2005-03-19 Falk Hueffner <falk@debian.org>
* config/alpha/alpha.md (UNSPEC_DIVC): New constant.
(divsi3_fp, divsi3, udivsi3_fp, udivsi3, modsi3_fp, modsi3,
umodsi3_fp, umodsi3): New pattern.
(divsi3_libcall, udivsi3_libcall, modsi3_libcall,
umodsi3_libcall): Rename from divsi3, udivsi3, modsi3.
(divc): New pattern.
Index: gcc/config/alpha/alpha.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.md,v
retrieving revision 1.237
diff -u -p -r1.237 alpha.md
--- gcc/config/alpha/alpha.md 17 Mar 2005 10:43:19 -0000 1.237
+++ gcc/config/alpha/alpha.md 19 Mar 2005 18:40:55 -0000
@@ -26,6 +26,7 @@
(define_constants
[(UNSPEC_ARG_HOME 0)
+ (UNSPEC_DIVC 1)
(UNSPEC_INSXH 2)
(UNSPEC_MSKXH 3)
(UNSPEC_CVTQL 4)
@@ -779,6 +780,33 @@
[(set_attr "type" "imul")
(set_attr "opsize" "udi")])
+(define_expand "divsi3_fp"
+ [(set (match_dup 3)
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (match_dup 4)
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_dup 5)
+ (float:DF (match_dup 3)))
+ (set (match_dup 6)
+ (float:DF (match_dup 4)))
+ (set (match_dup 7)
+ (unspec:DF [(match_dup 5)
+ (match_dup 6)] UNSPEC_DIVC))
+ (set (match_dup 8)
+ (fix:DI (match_dup 7)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_dup 9))]
+ "TARGET_FP"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DFmode);
+ operands[6] = gen_reg_rtx (DFmode);
+ operands[7] = gen_reg_rtx (DFmode);
+ operands[8] = gen_reg_rtx (DImode);
+ operands[9] = lowpart_subreg (SImode, operands[8], DImode);
+})
+
;; The divide and remainder operations take their inputs from r24 and
;; r25, put their output in r27, and clobber r23 and r28 on all
;; systems except Unicos/Mk. On Unicos, the standard library provides
@@ -791,7 +819,7 @@
;; problem. Is it worth the complication here to eliminate the sign
;; extension?
-(define_expand "divsi3"
+(define_expand "divsi3_libcall"
[(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
(set (match_dup 4)
@@ -809,7 +837,49 @@
operands[5] = gen_reg_rtx (DImode);
})
-(define_expand "udivsi3"
+(define_expand "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (div:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+{
+ if (TARGET_FP && optimize && !optimize_size)
+ emit_insn (gen_divsi3_fp (operands[0], operands[1], operands[2]));
+ else if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK)
+ emit_insn (gen_divsi3_libcall (operands[0], operands[1], operands[2]));
+ else
+ FAIL;
+ DONE;
+})
+
+(define_expand "udivsi3_fp"
+ [(set (match_dup 3)
+ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (match_dup 4)
+ (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_dup 5)
+ (float:DF (match_dup 3)))
+ (set (match_dup 6)
+ (float:DF (match_dup 4)))
+ (set (match_dup 7)
+ (unspec:DF [(match_dup 5)
+ (match_dup 6)] UNSPEC_DIVC))
+ (set (match_dup 8)
+ (fix:DI (match_dup 7)))
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_dup 9))]
+ "TARGET_FP"
+{
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+ operands[5] = gen_reg_rtx (DFmode);
+ operands[6] = gen_reg_rtx (DFmode);
+ operands[7] = gen_reg_rtx (DFmode);
+ operands[8] = gen_reg_rtx (DImode);
+ operands[9] = lowpart_subreg (SImode, operands[8], DImode);
+})
+
+(define_expand "udivsi3_libcall"
[(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
(set (match_dup 4)
@@ -827,7 +897,36 @@
operands[5] = gen_reg_rtx (DImode);
})
-(define_expand "modsi3"
+(define_expand "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (udiv:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+{
+ if (TARGET_FP && optimize && !optimize_size)
+ emit_insn (gen_udivsi3_fp (operands[0], operands[1], operands[2]));
+ else if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK)
+ emit_insn (gen_udivsi3_libcall (operands[0], operands[1], operands[2]));
+ else
+ FAIL;
+ DONE;
+})
+
+(define_expand "modsi3_fp"
+ [(set (match_dup 4)
+ (mult:SI (match_dup 3)
+ (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_dup 4)))]
+ "TARGET_FP"
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ emit_insn (gen_divsi3_fp (operands[3], operands[1], operands[2]));
+})
+
+(define_expand "modsi3_libcall"
[(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
(set (match_dup 4)
@@ -845,7 +944,36 @@
operands[5] = gen_reg_rtx (DImode);
})
-(define_expand "umodsi3"
+(define_expand "modsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (mod:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+{
+ if (TARGET_FP && optimize && !optimize_size)
+ emit_insn (gen_modsi3_fp (operands[0], operands[1], operands[2]));
+ else if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK)
+ emit_insn (gen_modsi3_libcall (operands[0], operands[1], operands[2]));
+ else
+ FAIL;
+ DONE;
+})
+
+(define_expand "umodsi3_fp"
+ [(set (match_dup 4)
+ (mult:SI (match_dup 3)
+ (match_operand:SI 2 "nonimmediate_operand" "")))
+ (set (match_operand:SI 0 "nonimmediate_operand" "")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_dup 4)))]
+ "TARGET_FP"
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ emit_insn (gen_udivsi3_fp (operands[3], operands[1], operands[2]));
+})
+
+(define_expand "umodsi3_libcall"
[(set (match_dup 3)
(sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
(set (match_dup 4)
@@ -863,6 +991,21 @@
operands[5] = gen_reg_rtx (DImode);
})
+(define_expand "umodsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (umod:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))]
+ ""
+{
+ if (TARGET_FP && optimize && !optimize_size)
+ emit_insn (gen_umodsi3_fp (operands[0], operands[1], operands[2]));
+ else if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK)
+ emit_insn (gen_umodsi3_libcall (operands[0], operands[1], operands[2]));
+ else
+ FAIL;
+ DONE;
+})
+
(define_expand "divdi3"
[(parallel [(set (match_operand:DI 0 "register_operand" "")
(div:DI (match_operand:DI 1 "register_operand" "")
@@ -2783,6 +2926,18 @@
(set_attr "round_suffix" "normal")
(set_attr "trap_suffix" "u_su_sui")])
+;; This is only used for integer division, and can only trap for division by
+;; zero, which is undefined, so we don't bother to avoid imprecise traps and
+;; claim it cannot trap.
+(define_insn "divc"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (unspec:DF [(match_operand:DF 1 "reg_or_0_operand" "fG")
+ (match_operand:DF 2 "reg_or_0_operand" "fG")] UNSPEC_DIVC))]
+ "TARGET_FP"
+ "div%-%/ %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "round_suffix" "c")])
+
(define_insn "*divdf_ext1"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (float_extend:DF (match_operand:SF 1 "reg_or_0_operand" "fG"))