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); }