Hi!

The PR119190 patch I've posted regresses the PR119120 testcase (not adding
to testsuite, as it is fairly hard to scan for that problem).
The issue is that for the partial setting of _Complex floating vars
through __real__ on it first and __imag__ later (or vice versa) and since
we forced all complex vars into SSA form we often have undefined (D)
arguments of those COMPLEX_EXPRs.  When we don't DCE them (for -O0 debug
info reasons), their expansion will copy both the real and imag parts
using the floating mode and on some targets like 387 that copying alone can
unfortunately trigger exceptions on sNaNs or other problematic bit patterns
and for uninitialized memory it can be triggered randomly based on whatever
is on the stack before.

The following patch deals just with the unused COMPLEX_EXPRs at -O0,
if it is used, either complex lowering should have replaced its parts or
it represents a user store somewhere, or passing to function argument etc.,
all that should be really avoided for partially uninitialized complex.
And the patch attempts to find the uninitialized arguments (unfortunately
at -O0 we don't forward propagate the (D) SSA_NAMEs) and only copy the
initialized parts.  Another option would be to arrange for the copying
to be done in integral mode rather than floating, kind of VCE and back.
Though, not sure how to handle then XFmode or on 32-bit targets TFmode
when there is no corresponding intergral mode or it isn't usable.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
Or shall I go the VCE route instead?

2025-03-11  Jakub Jelinek  <ja...@redhat.com>

        PR target/119120
        * cfgexpand.cc (expand_gimple_stmt_1): At -O0 expand a COMPLEX_EXPR
        with zero uses of lhs if it has complex floating point mode as
        stores of just the parts which aren't known to be uninitialized.

--- gcc/cfgexpand.cc.jj 2025-01-07 20:11:04.632662813 +0100
+++ gcc/cfgexpand.cc    2025-03-10 21:28:01.071078448 +0100
@@ -4294,6 +4294,70 @@ expand_gimple_stmt_1 (gimple *stmt)
            if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
              promoted = true;
 
+           /* At -O0 an unused COMPLEX_EXPR might be kept in the IL by
+              cplxlower0 pass to ensure correct debug info.  If one or both
+              arguments of COMPLEX_EXPR is unitialized and it is a complex
+              floating-point mode, don't actually copy the uninitialized
+              part(s) using floating-point mode, as that could cause extra
+              exceptions.  */
+           if (!optimize
+               && gimple_assign_rhs_code (assign_stmt) == COMPLEX_EXPR
+               && TREE_CODE (lhs) == SSA_NAME
+               && has_zero_uses (lhs)
+               && MEM_P (target)
+               && SCALAR_FLOAT_MODE_P (GET_MODE_INNER (GET_MODE (target))))
+             {
+               op0 = gimple_assign_rhs1 (assign_stmt);
+               tree op1 = gimple_assign_rhs2 (assign_stmt);
+               gimple *g;
+               bool ignore_op0 = (TREE_CODE (op0) == SSA_NAME
+                                  && SSA_NAME_IS_DEFAULT_DEF (op0)
+                                  && (!SSA_NAME_VAR (op0)
+                                      || VAR_P (SSA_NAME_VAR (op0))));
+               bool ignore_op1 = (TREE_CODE (op1) == SSA_NAME
+                                  && SSA_NAME_IS_DEFAULT_DEF (op1)
+                                  && (!SSA_NAME_VAR (op1)
+                                      || VAR_P (SSA_NAME_VAR (op1))));
+               tree tem = op0;
+               while (!ignore_op0
+                      && TREE_CODE (tem) == SSA_NAME
+                      && (g = SSA_NAME_DEF_STMT (tem))
+                      && is_gimple_assign (g)
+                      && gimple_assign_rhs_code (g) == SSA_NAME)
+                 {
+                   tem = gimple_assign_rhs1 (g);
+                   if (SSA_NAME_IS_DEFAULT_DEF (tem)
+                       && (!SSA_NAME_VAR (tem) || VAR_P (SSA_NAME_VAR (tem))))
+                     ignore_op0 = true;
+                 }
+               tem = op1;
+               while (!ignore_op1
+                      && TREE_CODE (tem) == SSA_NAME
+                      && (g = SSA_NAME_DEF_STMT (tem))
+                      && is_gimple_assign (g)
+                      && gimple_assign_rhs_code (g) == SSA_NAME)
+                 {
+                   tem = gimple_assign_rhs1 (g);
+                   if (SSA_NAME_IS_DEFAULT_DEF (tem)
+                       && (!SSA_NAME_VAR (tem) || VAR_P (SSA_NAME_VAR (tem))))
+                     ignore_op1 = true;
+                 }
+               if (ignore_op0 || ignore_op1)
+                 {
+                   if (!ignore_op0)
+                     {
+                       rtx rop0 = expand_normal (op0);
+                       write_complex_part (target, rop0, 0, true);
+                     }
+                   else if (!ignore_op1)
+                     {
+                       rtx rop1 = expand_normal (op1);
+                       write_complex_part (target, rop1, 1, true);
+                     }
+                   break;
+                 }
+             }
+
           /* If we store into a promoted register, don't directly
              expand to target.  */
            temp = promoted ? NULL_RTX : target;

        Jakub

Reply via email to