https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108623
Bug ID: 108623 Summary: We need to grow the precision field in tree_type_common for PowerPC Product: gcc Version: 13.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: other Assignee: unassigned at gcc dot gnu.org Reporter: meissner at gcc dot gnu.org Target Milestone: --- The current patches that have been submitted to the PowerPC back end need to grow the precision field in the tree_type_common structure (in tree-core.h). The current precision field is 10 bits but the type size for the dense math register is 1,024 bits. With the current 10 bit value, the precision of the TDO mode becomes 0 instead of 1,024. I noticed the tree-ssa-ccp.cc pass was dying with test programs that use the dense math registers when I run the test on a PowerPC, but they run fine on the x86_64. Ultimately I tracked this down to the sext_hwi (sign extend) function in hwint.h. The code in hwint.h is: static inline HOST_WIDE_INT 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 behavior. */ gcc_checking_assert (prec < HOST_BITS_PER_WIDE_INT); int shift = HOST_BITS_PER_WIDE_INT - prec; 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 } If the 'prec' argument is 0, the 'shift' variable will become 64. In C/C++, a 64-bit value that is shifted either left or right by 64 bits is undefined. It turns out that the x86_64 will happen to return the original value if you shift it left 64-bits and then shift it right with sign extension. From within the CCP pass, the original value is -1. On the other hand, the PowerPC always returns 0. Since it isn't returning -1, it leads the CCP pass to create a 0 constant for TDOmode. But since TDOmode is opaque, converting it to 0 generates an error when checking is enabled. The solution is to grow the precision to 11 bits and reduce the contains_placeholder_bits field to 1 bit. Alternatively, we could grow the precision to 16 bits, which will cause all trees to grow slightly, and keep contains_placeholder_bits at 2 bits. I see references to contains placeholder bits in tree.cc and cp/module.cc, but I don't see any place that actually sets the field.