From: Loeka Rogge Date: Wed, 29 Oct 2025 13:57:55 +0000 (-0700) Subject: arc: Fix wrong vector ordering on big-endian architecture X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d7ff7435b47c5fb3b17fed14d3624176b121be64;p=thirdparty%2Fgcc.git arc: Fix wrong vector ordering on big-endian architecture V2HI vectors, explicitly or auto-generated, could be stored in memory wrongly due to endianness. For example in the following c code stores to the struct are SLP vectorized, causing them to be stored in the wrong order: struct S {short a; short b;}; s.a = 520; s.b = -1; in the split2 pass the following register set: (const_vector:V2HI [ (const_int 520 [0x208]) (const_int -1 [0xffffffffffffffff]) ])) "smallTest.c":16:9 484 {*movv2hi_insn} is converted to: (const_int -65016 [0xffffffffffff0208])) "smallTest.c":16:9 3 {*movsi_insn} and is then loaded into the struct. For big-endian this is wrong because the most significant bytes are written first in memory, storing -1 instead of 520 in s.a . This patch swaps the 2 values in this step if the target is big-endian. The added test creates a vector of 2 shorts and verifies the order when it is passed in a register or in memory. Regtested for arc and big-endian arc. gcc/ChangeLog: * config/arc/simdext.md(movv2hi_insn): Change order for movv2hi for big-endian. gcc/testsuite/ChangeLog: * gcc.target/arc/movv2hi-be.c: New test. Signed-off-by: Loeka Rogge --- diff --git a/gcc/config/arc/simdext.md b/gcc/config/arc/simdext.md index a53b2ba737e..53e0c83a924 100644 --- a/gcc/config/arc/simdext.md +++ b/gcc/config/arc/simdext.md @@ -1438,11 +1438,15 @@ "reload_completed && GET_CODE (operands[1]) == CONST_VECTOR" [(set (match_dup 0) (match_dup 2))] { - HOST_WIDE_INT intval = INTVAL (XVECEXP (operands[1], 0, 1)) << 16; - intval |= INTVAL (XVECEXP (operands[1], 0, 0)) & 0xFFFF; - - operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); - operands[2] = GEN_INT (trunc_int_for_mode (intval, SImode)); + int hi = TARGET_BIG_ENDIAN ? 0 : 1; + int lo = TARGET_BIG_ENDIAN ? 1 : 0; + HOST_WIDE_INT hi_val = INTVAL (XVECEXP (operands[1], 0, hi)); + HOST_WIDE_INT lo_val = INTVAL (XVECEXP (operands[1], 0, lo)); + hi_val = zext_hwi (hi_val, 16); + lo_val = zext_hwi (lo_val, 16); + HOST_WIDE_INT intval = lo_val | (hi_val << 16); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[2] = GEN_INT (trunc_int_for_mode (intval, SImode)); } [(set_attr "type" "move,move,load,store") (set_attr "predicable" "yes,yes,no,no") diff --git a/gcc/testsuite/gcc.target/arc/movv2hi-be.c b/gcc/testsuite/gcc.target/arc/movv2hi-be.c new file mode 100644 index 00000000000..7d4b8e2e5c1 --- /dev/null +++ b/gcc/testsuite/gcc.target/arc/movv2hi-be.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +typedef short v2hi __attribute__((vector_size(4))); + +__attribute__((noinline)) void foo3(short a) +{ + if (a != 520) + { + __builtin_abort(); + } +} + +__attribute__((noinline)) void foo2(v2hi v) +{ + foo3(v[0]); +} + +__attribute__((noinline)) void foo(v2hi *v) +{ + foo2(*v); +} + +int main (void) +{ + v2hi v; + v[0] = 520; + v[1] = -1; + foo(&v); + foo2(v); + return 0; +}