Hi all, I encountered a wrong-code issue with my WIP store merging pass when it was trying to encode HFmode constants. I am using native_encode_real to write the constants to a byte array and it's breaking on big-endian. For a 2-byte constant it ended up writing bytes at offsets 3 and 2 rather than 1 and 0.
The fix in this patch makes the logic in native_encode_real match the logic in native_interpret_real, I just copied the logic across. I don't have a testcase against clean trunk that demonstrates the issue but with my store merging patch the testcase gcc.target/aarch64/advsimd-intrinsics/vldX.c starts failing without this patch because adjacent 16-bit float constants are not being merged correctly. Bootstrapped and tested on aarch64-none-linux-gnu. As this patch only affects the big-endian code path I also tested it on aarch64_be-none-elf. Ok for trunk? Do you think this needs to be backported? Thanks, Kyrill 2016-10-05 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * fold-const.c (native_encode_real): Fix logic for selecting offset to write to when BYTES_BIG_ENDIAN.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 81671e9fec68a3281b744626db1b94f26d19aabc..564d086e9636743104d629cd6f5620ac2ee6a544 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -7142,7 +7142,16 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len, int off) offset += byte % UNITS_PER_WORD; } else - offset = BYTES_BIG_ENDIAN ? 3 - byte : byte; + { + offset = byte; + if (BYTES_BIG_ENDIAN) + { + /* Reverse bytes within each long, or within the entire float + if it's smaller than a long (for HFmode). */ + offset = MIN (3, total_bytes - 1) - offset; + gcc_assert (offset >= 0); + } + } offset = offset + ((bitpos / BITS_PER_UNIT) & ~3); if (offset >= off && offset - off < len)