From: Mikael Morin Date: Wed, 19 Aug 2015 13:42:36 +0000 (+0000) Subject: Avoid signed left shift undefined behaviour in sext_hwi X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d63c864834782e37f78834d168e7e383d2c080b3;p=gcc.git Avoid signed left shift undefined behaviour in sext_hwi gcc/ PR other/67042 * hwint.h (sext_hwi): Switch to unsigned for the left shift, and conditionalize the whole on __GNUC__. Add fallback code depending neither on undefined nor implementation-defined behaviour. From-SVN: r227008 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index efee1223ee5..bae3c94585c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,9 +1,16 @@ +2015-08-19 Mikael Morin + + PR other/67042 + * hwint.h (sext_hwi): Switch to unsigned for the left shift, and + conditionalize the whole on __GNUC__. Add fallback code + depending neither on undefined nor implementation-defined behaviour. + 2015-08-19 Jiong Wang * config/aarch64/aarch64.c (aarch64_load_symref_appropriately): Replace whitespaces with tab. -2015-08-13 Florian Weimer +2015-08-19 Florian Weimer * prj.adb (For_Every_Project_Imported_Context.Recursive_Check_Context): Move Name_Id_Set instantiation to the Prj package, to avoid trampolines. diff --git a/gcc/hwint.h b/gcc/hwint.h index 3793986cf6c..4acbf8e79ca 100644 --- a/gcc/hwint.h +++ b/gcc/hwint.h @@ -244,11 +244,27 @@ sext_hwi (HOST_WIDE_INT src, unsigned int prec) if (prec == HOST_BITS_PER_WIDE_INT) return src; else +#if defined (__GNUC__) { + /* Take the faster path if the implementation-defined bits it's relying + on are implemented the way we expect them to be. Namely, conversion + from unsigned to signed preserves bit pattern, and right shift of + a signed value propagates the sign bit. + We have to convert from signed to unsigned and back, because when left + shifting signed values, any overflow is undefined behaviour. */ gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT); int shift = HOST_BITS_PER_WIDE_INT - prec; - return (src << shift) >> shift; + return ((HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) src << shift)) >> shift; } +#else + { + /* Fall back to the slower, well defined path otherwise. */ + gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT); + HOST_WIDE_INT sign_mask = HOST_WIDE_INT_1 << (prec - 1); + HOST_WIDE_INT value_mask = (HOST_WIDE_INT_1U << prec) - HOST_WIDE_INT_1U; + return (((src & value_mask) ^ sign_mask) - sign_mask); + } +#endif } /* Zero extend SRC starting from PREC. */