This patch also make casts of ABI-extended large/huge _BitInts behave the same as the small/middle case, i.e. no-op for casts to a higher precision _BitInt with the same number of limbs / extension for casts that turns a full top limb into a partial limb. This conveniently helps keep some code with implementation-specific extension semantics (e.g. BEXTC from gcc.dg/bitintext.h) the same for _BitInts of any precision.
gcc/ChangeLog: * gimple-lower-bitint.cc (bitint_large_huge::limb_access): Add a parameter abi_load_p. If set, load a limb directly in its actual precision without casting from m_limb_type. (struct bitint_large_huge): Same. (bitint_large_huge::handle_load): Use. --- gcc/gimple-lower-bitint.cc | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index 8fb7a604591..631a7844790 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -429,7 +429,7 @@ struct bitint_large_huge void insert_before (gimple *); tree limb_access_type (tree, tree); - tree limb_access (tree, tree, tree, bool); + tree limb_access (tree, tree, tree, bool, bool = false); tree build_bit_field_ref (tree, tree, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT); void if_then (gimple *, profile_probability, edge &, edge &); @@ -610,11 +610,15 @@ bitint_large_huge::limb_access_type (tree type, tree idx) TYPE. If WRITE_P is true, it will be a store, otherwise a read. */ tree -bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) +bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p, + bool abi_load_p) { tree atype = (tree_fits_uhwi_p (idx) ? limb_access_type (type, idx) : m_limb_type); - tree ltype = m_limb_type; + + tree ltype = (tree_fits_uhwi_p (idx) && bitint_extended && abi_load_p + ? limb_access_type (type, idx) : m_limb_type); + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (var)); if (as != TYPE_ADDR_SPACE (ltype)) ltype = build_qualified_type (ltype, TYPE_QUALS (ltype) @@ -651,12 +655,12 @@ bitint_large_huge::limb_access (tree type, tree var, tree idx, bool write_p) { unsigned HOST_WIDE_INT nelts = CEIL (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (var))), limb_prec); - tree atype = build_array_type_nelts (ltype, nelts); + tree atype = build_array_type_nelts (m_limb_type, nelts); var = build1 (VIEW_CONVERT_EXPR, atype, var); } ret = build4 (ARRAY_REF, ltype, var, idx, NULL_TREE, NULL_TREE); } - if (!write_p && !useless_type_conversion_p (atype, m_limb_type)) + if (!write_p && !useless_type_conversion_p (atype, ltype)) { gimple *g = gimple_build_assign (make_ssa_name (m_limb_type), ret); insert_before (g); @@ -1964,6 +1968,7 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs_type = TREE_TYPE (rhs1); bool eh = stmt_ends_bb_p (stmt); + bool load_bitfield_p = false; edge eh_edge = NULL; gimple *g; @@ -1987,12 +1992,18 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) if (!bitint_big_endian && DECL_OFFSET_ALIGN (fld) >= TYPE_ALIGN (TREE_TYPE (rhs1)) && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % limb_prec) == 0) - goto normal_load; + { + load_bitfield_p = true; + goto normal_load; + } /* Even if DECL_FIELD_BIT_OFFSET (fld) is a multiple of BITS_PER_UNIT, handle it normally for now. */ if (!bitint_big_endian && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % BITS_PER_UNIT) == 0) - goto normal_load; + { + load_bitfield_p = true; + goto normal_load; + } tree repr = DECL_BIT_FIELD_REPRESENTATIVE (fld); poly_int64 bitoffset; poly_uint64 field_offset, repr_offset; @@ -2241,7 +2252,7 @@ normal_load: /* Use write_p = true for loads with EH edges to make sure limb_access doesn't add a cast as separate statement after it. */ - rhs1 = limb_access (rhs_type, rhs1, idx, eh); + rhs1 = limb_access (rhs_type, rhs1, idx, eh, !load_bitfield_p); tree ret = make_ssa_name (TREE_TYPE (rhs1)); g = gimple_build_assign (ret, rhs1); insert_before (g); -- 2.46.0