A happy problem caused by loongson2f's div.g instruction

Zhang Le r0bertz@gentoo.org
Mon Nov 10 11:20:00 GMT 2008


On 09:18 Mon 10 Nov     , Eric Fisher wrote:
> > 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)))])

Hi, Eric. This is my version:
--- trunk/gcc/config/mips/mips.c.orig   2008-11-10 02:23:33.000000000 +0800
+++ trunk/gcc/config/mips/mips.c        2008-11-10 02:24:56.000000000 +0800
@@ -10359,8 +10359,15 @@                                                                                    }                                                                                                  else if (GENERATE_DIVIDE_TRAPS)                                                                       {                                                                                          -         output_asm_insn (s, operands);                                                            -         s = "teq\t%2,%.,7";                                                                       +         if (TARGET_LOONGSON_2EF)                                                                  +           {                                                                                       +             output_asm_insn ("teq\t%2,%.,7", operands);                                           +           }                                                                                       +         else                                                                                      +           {                                                                                       +             output_asm_insn (s, operands);                                                        +             s = "teq\t%2,%.,7";
+           }                                                                                                }
       else
        {

I have tried it. It seems to be working.

However, now I think adding a earlyclobber constraint may be the way to go.
Since it is a less intrusive and more elegant (comparing with my patch above) change.

Zhang, Le



More information about the Gcc mailing list