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 <[email protected]>
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);
}