The C shift operators do not precisely match the associated ARM
instructions: shifts of negative values or by negative amounts are
undefined behavior in C, and GCC may substitute alternate instruction
sequences when it can determine that the application is using UB.

Replace C shift operators with inline asm to ensure the lsll and asrl
primitives always emit the indicated instruction.

This issue caused mis-compilation of the ARM cmsis-dsp code for
arm_biquad_cascade_df1_32x64_q31:

        https://github.com/ARM-software/CMSIS-DSP/pull/265

Signed-off-by: Keith Packard <kei...@keithp.com>
---
 gcc/config/arm/arm_mve.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/gcc/config/arm/arm_mve.h b/gcc/config/arm/arm_mve.h
index ee18a4714fb..c4fad3c6429 100644
--- a/gcc/config/arm/arm_mve.h
+++ b/gcc/config/arm/arm_mve.h
@@ -258,14 +258,16 @@ __extension__ extern __inline  uint64_t
 __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
 __arm_lsll (uint64_t value, int32_t shift)
 {
-  return (value << shift);
+  __asm__("lsll %Q0, %R0, %1" : "+r" (value) : "rPg" (shift));
+  return value;
 }
 
 __extension__ extern __inline int64_t
 __attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
 __arm_asrl (int64_t value, int32_t shift)
 {
-  return (value >> shift);
+  __asm__("asrl %Q0, %R0, %1" : "+r" (value) : "rPg" (shift));
+  return value;
 }
 
 __extension__ extern __inline uint64_t
-- 
2.49.0

Reply via email to