This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: A happy problem caused by loongson2f's div.g instruction
- From: "Eric Fisher" <joefoxreal at gmail dot com>
- To: "Andrew Haley" <aph at redhat dot com>
- Cc: "Zhang Le" <r0bertz at gentoo dot org>, gcc at gcc dot gnu dot org, ruanbeihong at gmail dot com
- Date: Mon, 10 Nov 2008 09:18:11 +0800
- Subject: Re: A happy problem caused by loongson2f's div.g instruction
- References: <20081109180903.GA2912@adriano.hkcable.com.hk> <49172C7B.3000106@redhat.com>
> So I think one of the possible solution would be to reverse the div.g and teq insn.
> And I think this is not hard to do, just modify mips_output_division() function.
> Also I think this is a better solution, since we can save a register.
Do you mean the modification like this?
+
+
+/* Used to output (d)div(u).g or (d)mod(u).g instruction of loongson,
+ + which takes three operands, and put the result in the rd register.
+ + Hence emit the divide-by-zeor check before the DIVISION, in case
+ + that the rd and rt are the same one. */
+const char *
+mips_output_division_g (const char *division, rtx *operands)
+{
+ if (TARGET_CHECK_ZERO_DIV)
+ {
+ output_asm_insn ("bne\t%2,%.,1f%#\n\tbreak\t7\n1:", operands);
+ }
+ return division;
+}
+
+;; For loongson
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (div:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_LOONGSON2E || TARGET_LOONGSON2F"
+ { return mips_output_division_g ("div.g\t%0,%1,%2", operands); }
+ [(set_attr "type" "divg")
+ (set_attr "mode" "SI")
+ (set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CHECK_ZERO_DIV") (const_int 0))
+ (const_int 16)
+ (const_int 4)))])
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (udiv:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_LOONGSON2E || TARGET_LOONGSON2F"
+ { return mips_output_division_g ("divu.g\t%0,%1,%2", operands); }
+ [(set_attr "type" "divg")
+ (set_attr "mode" "SI")
+ (set (attr "length")
+ (if_then_else (ne (symbol_ref "TARGET_CHECK_ZERO_DIV") (const_int 0))
+ (const_int 16)
+ (const_int 4)))])
2008/11/10 Andrew Haley <aph@redhat.com>:
> Zhang Le wrote:
>
>>
>> The other would be make sure the destination register is different from source registers.
>> I have read some docs, but still not sure how to do it.
>
> That's just an earlyclobber. Search for that.
>
> Andrew.
>