On Fri, 2021-12-24 at 17:28 +0800, chenglulu wrote:
> +(define_insn "*zero_extendsidi2_internal"
> +  [(set (match_operand:DI 0 "register_operand" "=r,r,r")
> +       (subreg:DI (match_operand:SI 1 "nonimmediate_operand" "r,ZC,W") 0))]
> +  "TARGET_64BIT"
> +  "@
> +   bstrpick.d\t%0,%1,31,0
> +   ldptr.w\t%0,%1\n\tlu32i.d\t%0,0
> +   ld.wu\t%0,%1"
> +  [(set_attr "move_type" "arith,load,load")
> +   (set_attr "mode" "DI")
> +   (set_attr "insn_count" "1,2,1")])

This pattern is generating wrong code, causing

FAIL: gcc.dg/compat/scalar-by-value-3 c_compat_x_tst.o-c_compat_y_tst.o execute

This failure is a real bug, the reduced testcase is attached.  In the
assembly:

        # ...
        bstrins.d       $r5,$r13,31,0
        addi.d  $r12,$r22,-228
        bstrpick.d      $r12,$r12,31,0
        bstrins.d       $r5,$r12,63,32
        addi.w  $r4,$r0,14                      # 0xe
        bl      testvaci

This obviously does not make any sense: it calculates the *address* of
g[0]'s imaginary part, truncates it to 32-bit, then pass it as the
*value* of the imaginary part to testvaci().

The problem is: before the reload pass, the compiler consider g[0] a
(virtual) register.  It only becomes MEM after the reload pass.  Adding
reload_completed as the condition of this insn seems able to fix the
issue.  However I'm not sure if other insns need the change too.

> +;; See the comment before the *and<mode>3 pattern why this is generated by
> +;; combine.

A minor issue: the comment before 'and<mode>3' does not exist.
-- 
Xi Ruoyao <xry...@mengyan1223.wang>
School of Aerospace Science and Technology, Xidian University
#include <stdarg.h>
#include <assert.h>

extern void testvaci (int n, ...);

int main() {
        int i;
        volatile _Complex int g[14];
        for (i = 0; i < 14; i++)
                g[i] = i + 3 + 3i;
        testvaci (14, g[0], g[1], g[2], g[3], g[4], g[5], g[6], g[7], g[8], g[9], g[10], g[11], g[12], g[13]); 
        return 0;
}

void testvaci (int n, ...) {
        int i;
        va_list ap;
        va_start(ap, n);
        for (i = 0; i < n; i++) {
                _Complex int t = __builtin_va_arg(ap, _Complex int);
                assert(t == i + 3 + 3i);
        }
        va_end(ap);
}

Reply via email to