https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111334
--- Comment #9 from Xi Ruoyao <xry111 at gcc dot gnu.org> --- (In reply to chenglulu from comment #7) > (In reply to Xi Ruoyao from comment #6) > > (In reply to Xi Ruoyao from comment #5) > > > (In reply to chenglulu from comment #3) > > > > This involves the template <optab>di3_fake: > > > > (define_insn "<optab>di3_fake" > > > > [(set (match_operand:DI 0 "register_operand" "=r,&r,&r") > > > > (sign_extend:DI > > > > (any_div:SI (match_operand:DI 1 "register_operand" "r,r,0") > > > > (match_operand:DI 2 "register_operand" > > > > "r,r,r"))))] > > > > "" > > > > { > > > > return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands); > > > > } > > > > [(set_attr "type" "idiv") > > > > (set_attr "mode" "SI") > > > > (set (attr "enabled") > > > > (if_then_else > > > > (match_test "!!which_alternative == > > > > loongarch_check_zero_div_p()") > > > > (const_string "yes") > > > > (const_string "no")))]) > > > > > > > > > > > > I think there is a problem with the implementation of this template. > > > > First, the instructions generated in the template are [u]div.w[u], etc. > > > > The > > > > description of such instructions in the instruction manual is that if > > > > the > > > > upper 32 bits are not extended by the 31st bit sign then the result is > > > > uncertain. > > > > > > I think this reason alone makes the pattern looks very wrong. > > > > > > I'll take a look... > > > > Hmm, I guess we should just make di3_fake an UNSPEC because there is no way > > to use div.w and its friends out of <optab:any_div><mode>3. > > I agree with your idea, so I tried changing it to something like this.Do you > think it's okay for me to change like this? > > > (define_insn "<optab>di3_fake" > [(set (match_operand:DI 0 "register_operand" "=r,&r,&r") > (sign_extend:DI > (unspec:SI [(any_div:SI (match_operand:DI 1 "register_operand" > "r,r,0") > (match_operand:DI 2 "register_operand" "r,r,r"))] > UNSPEC_ANY_DIV)))] > "" > { > return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands); > } > [(set_attr "type" "idiv") > (set_attr "mode" "SI") > (set (attr "enabled") > (if_then_else > (match_test "!!which_alternative == loongarch_check_zero_div_p()") > (const_string "yes") > (const_string "no")))]) I'm not sure if we can use a single UNSPEC_ANY_DIV value for 4 different operations (I'm afraid it will make a further CSE pass believe "a % b" is same as "a / b" but maybe I'm wrong here). I came up with a more detailed template: diff --git a/gcc/config/loongarch/loongarch.md b/gcc/config/loongarch/loongarch.md index 75f641b38ee..d162013695f 100644 --- a/gcc/config/loongarch/loongarch.md +++ b/gcc/config/loongarch/loongarch.md @@ -64,6 +64,9 @@ (define_c_enum "unspec" [ UNSPEC_CRC UNSPEC_CRCC + ;; {div,mod}.w{,u} with bad input + UNSPEC_BAD_DIVW + UNSPEC_LOAD_FROM_GOT UNSPEC_PCALAU12I UNSPEC_ORI_L_LO12 @@ -880,7 +883,7 @@ (define_expand "<optab><mode>3" (match_operand:GPR 2 "register_operand")))] "" { - if (GET_MODE (operands[0]) == SImode) + if (TARGET_64BIT && GET_MODE (operands[0]) == SImode) { rtx reg1 = gen_reg_rtx (DImode); rtx reg2 = gen_reg_rtx (DImode); @@ -917,10 +920,16 @@ (define_insn "*<optab><mode>3" (define_insn "<optab>di3_fake" [(set (match_operand:DI 0 "register_operand" "=r,&r,&r") - (sign_extend:DI - (any_div:SI (match_operand:DI 1 "register_operand" "r,r,0") - (match_operand:DI 2 "register_operand" "r,r,r"))))] - "" + (if_then_else + (and (eq (match_operand:DI 1 "register_operand" "r,r,0") + (sign_extend:DI (subreg:SI (match_dup 1) 0))) + (eq (match_operand:DI 2 "register_operand" "r,r,r") + (sign_extend:DI (subreg:SI (match_dup 2) 0)))) + (sign_extend:DI + (any_div:SI (subreg:SI (match_dup 1) 0) + (subreg:SI (match_dup 2) 0))) + (unspec:DI [(const_int 0)] UNSPEC_BAD_DIVW)))] + "TARGET_64BIT" { return loongarch_output_division ("<insn>.w<u>\t%0,%1,%2", operands); }