diff options
Diffstat (limited to 'gcc/gimple-lower-bitint.cc')
-rw-r--r-- | gcc/gimple-lower-bitint.cc | 1178 |
1 files changed, 903 insertions, 275 deletions
diff --git a/gcc/gimple-lower-bitint.cc b/gcc/gimple-lower-bitint.cc index 6fefc83..8fb7a60 100644 --- a/gcc/gimple-lower-bitint.cc +++ b/gcc/gimple-lower-bitint.cc @@ -77,6 +77,7 @@ enum bitint_prec_kind { static int small_max_prec, mid_min_prec, large_min_prec, huge_min_prec; static int limb_prec; +static bool bitint_big_endian, bitint_extended; /* Categorize _BitInt(PREC) as small, middle, large or huge. */ @@ -101,6 +102,8 @@ bitint_precision_kind (int prec) small_max_prec = prec; return bitint_prec_small; } + bitint_big_endian = info.big_endian; + bitint_extended = info.extended; if (!large_min_prec && GET_MODE_PRECISION (limb_mode) < MAX_FIXED_MODE_SIZE) large_min_prec = MAX_FIXED_MODE_SIZE + 1; @@ -453,7 +456,7 @@ struct bitint_large_huge tree arith_overflow_extract_bits (unsigned int, unsigned int, tree, unsigned int, bool); void finish_arith_overflow (tree, tree, tree, tree, tree, tree, gimple *, - tree_code); + unsigned, tree_code); void lower_addsub_overflow (tree, gimple *); void lower_mul_overflow (tree, gimple *); void lower_cplxpart_stmt (tree, gimple *); @@ -594,7 +597,9 @@ bitint_large_huge::limb_access_type (tree type, tree idx) unsigned HOST_WIDE_INT i = tree_to_uhwi (idx); unsigned int prec = TYPE_PRECISION (type); gcc_assert (i * limb_prec < prec); - if ((i + 1) * limb_prec <= prec) + if (bitint_big_endian + ? (i != 0 || (prec % limb_prec) == 0) + : (i + 1) * limb_prec <= prec) return m_limb_type; else return build_nonstandard_integer_type (prec % limb_prec, @@ -886,6 +891,8 @@ bitint_large_huge::handle_operand (tree op, tree idx) m_data.safe_push (NULL_TREE); m_data.safe_push (NULL_TREE); } + if (bitint_big_endian) + i = CEIL (TYPE_PRECISION (TREE_TYPE (op)), limb_prec) - 1 - i; if (limb_prec != HOST_BITS_PER_WIDE_INT) { wide_int w = wi::rshift (wi::to_wide (op), i * limb_prec, @@ -964,22 +971,41 @@ bitint_large_huge::handle_operand (tree op, tree idx) min_prec = CEIL (min_prec, 2 * limb_prec) * (2 * limb_prec); tree type = build_bitint_type (min_prec, 1); tree c = tree_output_constant_def (fold_convert (type, op)); - tree idx2 = make_ssa_name (sizetype); - g = gimple_build_assign (idx2, PLUS_EXPR, idx, size_one_node); + tree ridx = idx; + if (bitint_big_endian) + { + ridx = make_ssa_name (sizetype); + g = gimple_build_assign (ridx, PLUS_EXPR, idx, + size_int (min_prec / limb_prec + - ((HOST_WIDE_INT) + CEIL (prec, + limb_prec)))); + insert_before (g); + } + tree ridx2 = make_ssa_name (sizetype); + g = gimple_build_assign (ridx2, PLUS_EXPR, ridx, + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); - g = gimple_build_cond (LT_EXPR, idx, - size_int (min_prec / limb_prec), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (GE_EXPR, idx, + size_int (CEIL (prec, limb_prec) + - min_prec / limb_prec), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (LT_EXPR, idx, + size_int (min_prec / limb_prec), + NULL_TREE, NULL_TREE); edge edge_true, edge_false; if_then (g, (min_prec >= (prec - rem) / 2 ? profile_probability::likely () : profile_probability::unlikely ()), edge_true, edge_false); - tree c1 = limb_access (TREE_TYPE (op), c, idx, false); + tree c1 = limb_access (TREE_TYPE (op), c, ridx, false); g = gimple_build_assign (make_ssa_name (TREE_TYPE (c1)), c1); insert_before (g); c1 = gimple_assign_lhs (g); - tree c2 = limb_access (TREE_TYPE (op), c, idx2, false); + tree c2 = limb_access (TREE_TYPE (op), c, ridx2, false); g = gimple_build_assign (make_ssa_name (TREE_TYPE (c2)), c2); insert_before (g); c2 = gimple_assign_lhs (g); @@ -1014,33 +1040,46 @@ bitint_large_huge::handle_operand (tree op, tree idx) m_data[m_data_cnt + 1] = integer_type_node; } t = m_data[m_data_cnt]; - if (m_data[m_data_cnt + 1] == NULL_TREE) + } + else + t = m_data[m_data_cnt + 1]; + if (m_data[m_data_cnt + 1] == NULL_TREE) + { + tree ridx = idx; + unsigned int prec = TYPE_PRECISION (TREE_TYPE (op)); + tree c = m_data[m_data_cnt]; + unsigned int min_prec = TYPE_PRECISION (TREE_TYPE (c)); + if (bitint_big_endian + && CEIL (min_prec, limb_prec) != CEIL (prec, limb_prec)) { - t = limb_access (TREE_TYPE (op), t, idx, false); - g = gimple_build_assign (make_ssa_name (TREE_TYPE (t)), t); + ridx = make_ssa_name (sizetype); + g = gimple_build_assign (ridx, PLUS_EXPR, idx, + size_int (CEIL (min_prec, limb_prec) + - ((HOST_WIDE_INT) + CEIL (prec, limb_prec)))); insert_before (g); - t = gimple_assign_lhs (g); } - } - else if (m_data[m_data_cnt + 1] == NULL_TREE) - { - t = limb_access (TREE_TYPE (op), m_data[m_data_cnt], idx, false); + t = limb_access (TREE_TYPE (op), c, ridx, false); g = gimple_build_assign (make_ssa_name (TREE_TYPE (t)), t); insert_before (g); t = gimple_assign_lhs (g); } - else - t = m_data[m_data_cnt + 1]; - if (m_data[m_data_cnt + 1] == integer_type_node) + else if (m_data[m_data_cnt + 1] == integer_type_node) { unsigned int prec = TYPE_PRECISION (TREE_TYPE (op)); unsigned rem = prec % ((m_upwards_2limb ? 2 : 1) * limb_prec); int ext = wi::neg_p (wi::to_wide (op)) ? -1 : 0; tree c = m_data[m_data_cnt]; unsigned min_prec = TYPE_PRECISION (TREE_TYPE (c)); - g = gimple_build_cond (LT_EXPR, idx, - size_int (min_prec / limb_prec), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (GE_EXPR, idx, + size_int (CEIL (prec, limb_prec) + - min_prec / limb_prec), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (LT_EXPR, idx, + size_int (min_prec / limb_prec), + NULL_TREE, NULL_TREE); edge edge_true, edge_false; if_then (g, (min_prec >= (prec - rem) / 2 ? profile_probability::likely () @@ -1048,7 +1087,18 @@ bitint_large_huge::handle_operand (tree op, tree idx) edge_true, edge_false); if (min_prec > (unsigned) limb_prec) { - c = limb_access (TREE_TYPE (op), c, idx, false); + tree ridx = idx; + if (bitint_big_endian) + { + ridx = make_ssa_name (sizetype); + g = gimple_build_assign (ridx, PLUS_EXPR, idx, + size_int (min_prec / limb_prec + - ((HOST_WIDE_INT) + CEIL (prec, + limb_prec)))); + insert_before (g); + } + c = limb_access (TREE_TYPE (op), c, ridx, false); g = gimple_build_assign (make_ssa_name (TREE_TYPE (c)), c); insert_before (g); c = gimple_assign_lhs (g); @@ -1312,7 +1362,24 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) && (m_upwards_2limb * limb_prec < TYPE_PRECISION (lhs_type)))))) { - rhs1 = handle_operand (rhs1, idx); + tree ridx = idx; + if (bitint_big_endian + && (CEIL (TYPE_PRECISION (lhs_type), limb_prec) + != CEIL (TYPE_PRECISION (rhs_type), limb_prec))) + { + HOST_WIDE_INT diff = CEIL (TYPE_PRECISION (rhs_type), limb_prec); + diff -= CEIL (TYPE_PRECISION (lhs_type), limb_prec); + if (tree_fits_uhwi_p (idx)) + ridx = size_int (tree_to_uhwi (idx) + diff); + else + { + tree t = make_ssa_name (sizetype); + g = gimple_build_assign (t, PLUS_EXPR, idx, size_int (diff)); + insert_before (g); + ridx = t; + } + } + rhs1 = handle_operand (rhs1, ridx); if (tree_fits_uhwi_p (idx)) { tree type = limb_access_type (lhs_type, idx); @@ -1327,6 +1394,8 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) - !TYPE_UNSIGNED (rhs_type)) / limb_prec; /* Indexes >= than this always contain an extension. */ unsigned high = CEIL ((unsigned) TYPE_PRECISION (rhs_type), limb_prec); + unsigned lcnt = CEIL ((unsigned) TYPE_PRECISION (lhs_type), limb_prec); + unsigned lowe = bitint_big_endian ? lcnt - 1 - low : low; bool save_first = m_first; if (m_first) { @@ -1351,7 +1420,8 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) else gsi_next (&m_gsi); m_data_cnt = save_data_cnt + 3; - t = handle_operand (rhs1, size_int (low)); + t = handle_operand (rhs1, size_int (bitint_big_endian + ? high - 1 - low : low)); m_first = false; m_data[save_data_cnt + 2] = build_int_cst (NULL_TREE, m_data_cnt); @@ -1389,6 +1459,18 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) if (m_upwards_2limb && low >= m_upwards_2limb - m_first) { + if (bitint_big_endian + && (CEIL (TYPE_PRECISION (lhs_type), limb_prec) + != CEIL (TYPE_PRECISION (rhs_type), limb_prec))) + { + HOST_WIDE_INT diff + = CEIL (TYPE_PRECISION (rhs_type), limb_prec); + diff -= CEIL (TYPE_PRECISION (lhs_type), limb_prec); + tree t = make_ssa_name (sizetype); + g = gimple_build_assign (t, PLUS_EXPR, idx, size_int (diff)); + insert_before (g); + idx = t; + } rhs1 = handle_operand (rhs1, idx); if (m_first) m_data[save_data_cnt + 2] @@ -1410,13 +1492,18 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) emits. So, instead of special-casing that, emit a low <= low comparison which cfg cleanup will clean up at the end of the pass. */ - idxc = size_int (low); - g = gimple_build_cond (single_comparison ? LT_EXPR : LE_EXPR, - idxc, size_int (low), NULL_TREE, NULL_TREE); + idxc = size_int (lowe); + if (bitint_big_endian) + g = gimple_build_cond (single_comparison ? GT_EXPR : GE_EXPR, + idxc, size_int (lowe), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (single_comparison ? LT_EXPR : LE_EXPR, + idxc, size_int (low), NULL_TREE, NULL_TREE); edge edge_true_true, edge_true_false, edge_false; if_then_if_then_else (g, (single_comparison ? NULL : gimple_build_cond (EQ_EXPR, idx, - size_int (low), + size_int (lowe), NULL_TREE, NULL_TREE)), profile_probability::likely (), @@ -1425,7 +1512,18 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) bool save_cast_conditional = m_cast_conditional; m_cast_conditional = true; m_bitfld_load = 0; - tree t1 = handle_operand (rhs1, idx), t2 = NULL_TREE; + tree t1 = idx, t2 = NULL_TREE; + if (bitint_big_endian + && (CEIL (TYPE_PRECISION (lhs_type), limb_prec) + != CEIL (TYPE_PRECISION (rhs_type), limb_prec))) + { + HOST_WIDE_INT diff = CEIL (TYPE_PRECISION (rhs_type), limb_prec); + diff -= CEIL (TYPE_PRECISION (lhs_type), limb_prec); + t1 = make_ssa_name (sizetype); + g = gimple_build_assign (t1, PLUS_EXPR, idx, size_int (diff)); + insert_before (g); + } + t1 = handle_operand (rhs1, t1); if (m_first) m_data[save_data_cnt + 2] = build_int_cst (NULL_TREE, m_data_cnt); @@ -1442,7 +1540,8 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) m_data[m_bitfld_load] = m_data[m_bitfld_load + 2]; m_bitfld_load = 0; } - t2 = handle_operand (rhs1, size_int (low)); + t2 = handle_operand (rhs1, size_int (bitint_big_endian + ? high - 1 - low : low)); if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (t2))) t2 = add_cast (m_limb_type, t2); if (!TYPE_UNSIGNED (rhs_type) && m_upwards_2limb) @@ -1548,16 +1647,20 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) else { unsigned tidx = tree_to_uhwi (idx); + if (bitint_big_endian) + tidx = lcnt - 1 - tidx; if (tidx < low) { - t = handle_operand (rhs1, idx); + t = handle_operand (rhs1, (bitint_big_endian + ? size_int (high - 1 - tidx) : idx)); if (m_first) m_data[save_data_cnt + 2] = build_int_cst (NULL_TREE, m_data_cnt); } else if (tidx < high) { - t = handle_operand (rhs1, size_int (low)); + t = handle_operand (rhs1, size_int (bitint_big_endian + ? high - 1 - low : low)); if (m_first) m_data[save_data_cnt + 2] = build_int_cst (NULL_TREE, m_data_cnt); @@ -1580,7 +1683,9 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) { if (TYPE_UNSIGNED (rhs_type) && m_first) { - handle_operand (rhs1, size_zero_node); + handle_operand (rhs1, (bitint_big_endian + ? size_int (high - 1) + : size_zero_node)); m_data[save_data_cnt + 2] = build_int_cst (NULL_TREE, m_data_cnt); } @@ -1695,13 +1800,17 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) m_data.safe_push (r2); m_data.safe_push (rext); } + unsigned lcnt = CEIL ((unsigned) TYPE_PRECISION (lhs_type), limb_prec); if (tree_fits_uhwi_p (idx)) { tree type = limb_access_type (lhs_type, idx); - if (integer_zerop (idx)) + if (bitint_big_endian + ? tree_to_uhwi (idx) == lcnt - 1 : integer_zerop (idx)) t = m_data[m_data_cnt]; else if (TYPE_PRECISION (rhs_type) > limb_prec - && integer_onep (idx)) + && (bitint_big_endian + ? tree_to_uhwi (idx) == lcnt - 2 + : integer_onep (idx))) t = m_data[m_data_cnt + 1]; else t = m_data[m_data_cnt + 2]; @@ -1710,13 +1819,17 @@ bitint_large_huge::handle_cast (tree lhs_type, tree rhs1, tree idx) m_data_cnt += 3; return t; } - g = gimple_build_cond (NE_EXPR, idx, size_zero_node, + g = gimple_build_cond (NE_EXPR, idx, + bitint_big_endian + ? size_int (lcnt - 1) : size_zero_node, NULL_TREE, NULL_TREE); edge e2, e3, e4 = NULL; if_then (g, profile_probability::likely (), e2, e3); if (m_data[m_data_cnt + 1]) { - g = gimple_build_cond (EQ_EXPR, idx, size_one_node, + g = gimple_build_cond (EQ_EXPR, idx, + bitint_big_endian + ? size_int (lcnt - 2) : size_one_node, NULL_TREE, NULL_TREE); insert_before (g); edge e5 = split_block (gsi_bb (m_gsi), g); @@ -1750,11 +1863,14 @@ bitint_large_huge::handle_bit_field_ref (tree op, tree idx) m_data.safe_push (NULL); ++m_data_cnt; unsigned HOST_WIDE_INT sz = tree_to_uhwi (TYPE_SIZE (m_limb_type)); + unsigned i = tree_to_uhwi (idx); + if (bitint_big_endian) + i = CEIL (TYPE_PRECISION (TREE_TYPE (op)), limb_prec) - 1 - i; tree bfr = build3 (BIT_FIELD_REF, m_limb_type, TREE_OPERAND (op, 0), TYPE_SIZE (m_limb_type), size_binop (PLUS_EXPR, TREE_OPERAND (op, 2), - bitsize_int (tree_to_uhwi (idx) * sz))); + bitsize_int (i * sz))); tree r = make_ssa_name (m_limb_type); gimple *g = gimple_build_assign (r, bfr); insert_before (g); @@ -1868,12 +1984,14 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) /* For little-endian, we can allow as inputs bit-fields which start at a limb boundary. */ gcc_assert (tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (fld))); - if (DECL_OFFSET_ALIGN (fld) >= TYPE_ALIGN (TREE_TYPE (rhs1)) + 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; - /* Even if DECL_FIELD_BIT_OFFSET (fld) is a multiple of UNITS_PER_BIT, + /* Even if DECL_FIELD_BIT_OFFSET (fld) is a multiple of BITS_PER_UNIT, handle it normally for now. */ - if ((tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % BITS_PER_UNIT) == 0) + if (!bitint_big_endian + && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % BITS_PER_UNIT) == 0) goto normal_load; tree repr = DECL_BIT_FIELD_REPRESENTATIVE (fld); poly_int64 bitoffset; @@ -1895,9 +2013,19 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) HOST_WIDE_INT bo = bitoffset.to_constant (); unsigned bo_idx = (unsigned HOST_WIDE_INT) bo / limb_prec; unsigned bo_bit = (unsigned HOST_WIDE_INT) bo % limb_prec; + unsigned bo_last = 0; + unsigned bo_shift = bo_bit; + unsigned nelts = CEIL (TYPE_PRECISION (rhs_type), limb_prec); + if (bitint_big_endian) + { + bo_last = CEIL (TYPE_PRECISION (rhs_type) + bo_bit, limb_prec) - 1; + bo_shift = (TYPE_PRECISION (rhs_type) + bo_bit) % limb_prec; + if (bo_shift) + bo_shift = limb_prec - bo_shift; + } if (m_first) { - if (m_upwards) + if (m_upwards && bo_shift) { gimple_stmt_iterator save_gsi = m_gsi; m_gsi = m_init_gsi; @@ -1905,7 +2033,8 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) m_gsi = gsi_after_labels (gsi_bb (m_gsi)); else gsi_next (&m_gsi); - tree t = limb_access (NULL_TREE, nrhs1, size_int (bo_idx), true); + tree t = limb_access (NULL_TREE, nrhs1, + size_int (bo_idx + bo_last), true); tree iv = make_ssa_name (m_limb_type); g = gimple_build_assign (iv, t); insert_before (g); @@ -1947,7 +2076,7 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) } } - tree nidx0 = NULL_TREE, nidx1; + tree nidx0 = NULL_TREE, nidx1 = NULL_TREE; tree iv = m_data[m_data_cnt]; if (m_cast_conditional && iv) { @@ -1958,8 +2087,12 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) { unsigned prec = TYPE_PRECISION (rhs_type); unsigned HOST_WIDE_INT i = tree_to_uhwi (idx); + if (bitint_big_endian) + i = nelts - 1 - i; gcc_assert (i * limb_prec < prec); - nidx1 = size_int (i + bo_idx + 1); + if (bo_shift) + nidx1 = size_int (bo_idx + (bitint_big_endian + ? bo_last - i - 1 : i + 1)); if ((i + 1) * limb_prec > prec) { prec %= limb_prec; @@ -1967,26 +2100,38 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) nidx1 = NULL_TREE; } if (!iv) - nidx0 = size_int (i + bo_idx); + nidx0 = size_int (bo_idx + (bitint_big_endian ? bo_last - i : i)); } else { + HOST_WIDE_INT adj = bo_idx; + if (bitint_big_endian) + adj += (HOST_WIDE_INT) bo_last + 1 - nelts; if (!iv) { - if (bo_idx == 0) + if (adj == 0) nidx0 = idx; else { nidx0 = make_ssa_name (sizetype); g = gimple_build_assign (nidx0, PLUS_EXPR, idx, - size_int (bo_idx)); + size_int (adj)); + insert_before (g); + } + } + if (bo_shift) + { + if (bitint_big_endian && adj == 1) + nidx1 = idx; + else + { + nidx1 = make_ssa_name (sizetype); + g = gimple_build_assign (nidx1, PLUS_EXPR, idx, + size_int (adj + (bitint_big_endian + ? -1 : 1))); insert_before (g); } } - nidx1 = make_ssa_name (sizetype); - g = gimple_build_assign (nidx1, PLUS_EXPR, idx, - size_int (bo_idx + 1)); - insert_before (g); } tree iv2 = NULL_TREE; @@ -1996,7 +2141,16 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) iv = make_ssa_name (m_limb_type); g = gimple_build_assign (iv, t); insert_before (g); - gcc_assert (!eh); + if (eh) + { + maybe_duplicate_eh_stmt (g, stmt); + if (eh_edge) + { + edge e = split_block (gsi_bb (m_gsi), g); + m_gsi = gsi_after_labels (e->dest); + add_eh_edge (e->src, eh_edge); + } + } } if (nidx1) { @@ -2012,7 +2166,9 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) if (conditional) { g = gimple_build_cond (NE_EXPR, idx, - size_int (prec / limb_prec), + bitint_big_endian + ? size_zero_node + : size_int (prec / limb_prec), NULL_TREE, NULL_TREE); if_then (g, profile_probability::likely (), edge_true, edge_false); @@ -2050,15 +2206,19 @@ bitint_large_huge::handle_load (gimple *stmt, tree idx) iv2 = iv3; } } - g = gimple_build_assign (make_ssa_name (m_limb_type), RSHIFT_EXPR, - iv, build_int_cst (unsigned_type_node, bo_bit)); - insert_before (g); - iv = gimple_assign_lhs (g); + if (bo_shift) + { + g = gimple_build_assign (make_ssa_name (m_limb_type), RSHIFT_EXPR, + iv, build_int_cst (unsigned_type_node, + bo_shift)); + insert_before (g); + iv = gimple_assign_lhs (g); + } if (iv2) { g = gimple_build_assign (make_ssa_name (m_limb_type), LSHIFT_EXPR, iv2, build_int_cst (unsigned_type_node, - limb_prec - bo_bit)); + limb_prec - bo_shift)); insert_before (g); g = gimple_build_assign (make_ssa_name (m_limb_type), BIT_IOR_EXPR, gimple_assign_lhs (g), iv); @@ -2221,6 +2381,8 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, { wide_int w; location_t loc_save = m_loc; + tree ret = NULL_TREE; + int precs = 0; if ((TREE_CODE (TREE_TYPE (op)) != BITINT_TYPE || bitint_precision_kind (TREE_TYPE (op)) < bitint_prec_large) && TREE_CODE (op) != INTEGER_CST) @@ -2244,30 +2406,29 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, limb mode smaller than half of largest supported normal integral type, this will not be needed. */ gcc_assert (nelts <= 2); - if (prec_stored) - *prec_stored = (TYPE_UNSIGNED (op_type) - ? TYPE_PRECISION (op_type) - : -TYPE_PRECISION (op_type)); + precs = (TYPE_UNSIGNED (op_type) + ? TYPE_PRECISION (op_type) : -TYPE_PRECISION (op_type)); if (*prec <= limb_prec && *prec >= -limb_prec) { nelts = 1; - if (prec_stored) + if (TYPE_UNSIGNED (op_type)) { - if (TYPE_UNSIGNED (op_type)) - { - if (*prec_stored > limb_prec) - *prec_stored = limb_prec; - } - else if (*prec_stored < -limb_prec) - *prec_stored = -limb_prec; + if (precs > limb_prec) + precs = limb_prec; } + else if (precs < -limb_prec) + precs = -limb_prec; } + if (prec_stored) + *prec_stored = precs; tree atype = build_array_type_nelts (m_limb_type, nelts); tree var = create_tmp_var (atype); tree t1 = op; if (!useless_type_conversion_p (m_limb_type, op_type)) t1 = add_cast (m_limb_type, t1); - tree v = build4 (ARRAY_REF, m_limb_type, var, size_zero_node, + tree v = build4 (ARRAY_REF, m_limb_type, var, + bitint_big_endian && nelts > 1 + ? size_one_node : size_zero_node, NULL_TREE, NULL_TREE); gimple *g = gimple_build_assign (v, t1); insert_before (g); @@ -2279,12 +2440,13 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, insert_before (g); tree t2 = gimple_assign_lhs (g); t2 = add_cast (m_limb_type, t2); - v = build4 (ARRAY_REF, m_limb_type, var, size_one_node, + v = build4 (ARRAY_REF, m_limb_type, var, + bitint_big_endian ? size_zero_node : size_one_node, NULL_TREE, NULL_TREE); g = gimple_build_assign (v, t2); insert_before (g); } - tree ret = build_fold_addr_expr (var); + ret = build_fold_addr_expr (var); if (!stmt_ends_bb_p (gsi_stmt (m_gsi))) { tree clobber = build_clobber (atype, CLOBBER_STORAGE_END); @@ -2292,7 +2454,7 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, gsi_insert_after (&m_gsi, g, GSI_SAME_STMT); } m_loc = loc_save; - return ret; + goto do_ret; } switch (TREE_CODE (op)) { @@ -2301,15 +2463,15 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, || !bitmap_bit_p (m_names, SSA_NAME_VERSION (op))) { gimple *g = SSA_NAME_DEF_STMT (op); - tree ret; m_loc = gimple_location (g); if (gimple_assign_load_p (g)) { *prec = range_to_prec (op, NULL); + precs = (TYPE_UNSIGNED (TREE_TYPE (op)) + ? TYPE_PRECISION (TREE_TYPE (op)) + : -TYPE_PRECISION (TREE_TYPE (op))); if (prec_stored) - *prec_stored = (TYPE_UNSIGNED (TREE_TYPE (op)) - ? TYPE_PRECISION (TREE_TYPE (op)) - : -TYPE_PRECISION (TREE_TYPE (op))); + *prec_stored = precs; ret = build_fold_addr_expr (gimple_assign_rhs1 (g)); ret = force_gimple_operand_gsi (&m_gsi, ret, true, NULL_TREE, true, GSI_SAME_STMT); @@ -2317,8 +2479,9 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, else if (gimple_code (g) == GIMPLE_NOP) { *prec = TYPE_UNSIGNED (TREE_TYPE (op)) ? limb_prec : -limb_prec; + precs = *prec; if (prec_stored) - *prec_stored = *prec; + *prec_stored = precs; tree var = create_tmp_var (m_limb_type); TREE_ADDRESSABLE (var) = 1; ret = build_fold_addr_expr (var); @@ -2346,6 +2509,7 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, tree rhs_type = TREE_TYPE (rhs1); int prec_stored_val = 0; ret = handle_operand_addr (rhs1, g, &prec_stored_val, prec); + precs = prec_stored_val; if (TYPE_PRECISION (lhs_type) > TYPE_PRECISION (rhs_type)) { if (TYPE_UNSIGNED (lhs_type) @@ -2378,18 +2542,20 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, } } m_loc = loc_save; - return ret; + goto do_ret; } else { int p = var_to_partition (m_map, op); gcc_assert (m_vars[p] != NULL_TREE); *prec = range_to_prec (op, stmt); + precs = (TYPE_UNSIGNED (TREE_TYPE (op)) + ? TYPE_PRECISION (TREE_TYPE (op)) + : -TYPE_PRECISION (TREE_TYPE (op))); if (prec_stored) - *prec_stored = (TYPE_UNSIGNED (TREE_TYPE (op)) - ? TYPE_PRECISION (TREE_TYPE (op)) - : -TYPE_PRECISION (TREE_TYPE (op))); - return build_fold_addr_expr (m_vars[p]); + *prec_stored = precs; + ret = build_fold_addr_expr (m_vars[p]); + goto do_ret; } case INTEGER_CST: unsigned int min_prec, mp; @@ -2430,18 +2596,37 @@ bitint_large_huge::handle_operand_addr (tree op, gimple *stmt, type = build_bitint_type (mp, 1); } } + if (tree_int_cst_sgn (op) >= 0) + precs = MAX (TYPE_PRECISION (type), 1); + else + precs = MIN ((int) -TYPE_PRECISION (type), -2); if (prec_stored) - { - if (tree_int_cst_sgn (op) >= 0) - *prec_stored = MAX (TYPE_PRECISION (type), 1); - else - *prec_stored = MIN ((int) -TYPE_PRECISION (type), -2); - } + *prec_stored = precs; op = tree_output_constant_def (fold_convert (type, op)); - return build_fold_addr_expr (op); + ret = build_fold_addr_expr (op); + goto do_ret; default: gcc_unreachable (); } +do_ret: + if (bitint_big_endian && prec_stored == NULL) + { + int p1 = *prec < 0 ? -*prec : *prec; + int p2 = precs < 0 ? -precs : precs; + int c1 = CEIL (p1, limb_prec); + int c2 = CEIL (p2, limb_prec); + gcc_assert (c1 <= c2); + if (c1 != c2) + { + gimple *g + = gimple_build_assign (make_ssa_name (TREE_TYPE (ret)), + POINTER_PLUS_EXPR, ret, + size_int ((c2 - c1) * m_limb_size)); + insert_before (g); + ret = gimple_assign_lhs (g); + } + } + return ret; } /* Helper function, create a loop before the current location, @@ -2518,6 +2703,9 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, tree nlhs = NULL_TREE; unsigned HOST_WIDE_INT bo_idx = 0; unsigned HOST_WIDE_INT bo_bit = 0; + unsigned bo_shift = 0; + unsigned bo_last = 0; + bool bo_be_p = false; tree bf_cur = NULL_TREE, bf_next = NULL_TREE; if (gimple_store_p (stmt)) { @@ -2544,7 +2732,9 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, tree repr = DECL_BIT_FIELD_REPRESENTATIVE (fld); poly_int64 bitoffset; poly_uint64 field_offset, repr_offset; - if ((tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % BITS_PER_UNIT) == 0) + if (!bitint_big_endian + && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) + % BITS_PER_UNIT) == 0) nlhs = lhs; else { @@ -2566,6 +2756,15 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, HOST_WIDE_INT bo = bitoffset.to_constant (); bo_idx = (unsigned HOST_WIDE_INT) bo / limb_prec; bo_bit = (unsigned HOST_WIDE_INT) bo % limb_prec; + bo_shift = bo_bit; + if (bitint_big_endian) + { + bo_last = CEIL (prec + bo_bit, limb_prec) - 1; + bo_shift = (prec + bo_bit) % limb_prec; + bo_be_p = true; + if (bo_shift) + bo_shift = limb_prec - bo_shift; + } } } } @@ -2609,7 +2808,9 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, rem = (prec % (2 * limb_prec)); end = (prec - rem) / limb_prec; cnt = 2 + CEIL (rem, limb_prec); - idx = idx_first = create_loop (size_zero_node, &idx_next); + idx = idx_first = create_loop (bitint_big_endian + ? size_int (cnt - 2 + end - 1) + : size_zero_node, &idx_next); } basic_block edge_bb = NULL; @@ -2632,14 +2833,18 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, = (prec != (unsigned) TYPE_PRECISION (type) && (CEIL ((unsigned) TYPE_PRECISION (type), limb_prec) > CEIL (prec, limb_prec))); + unsigned dst_idx_off = 0; + if (separate_ext && bitint_big_endian) + dst_idx_off = (CEIL ((unsigned) TYPE_PRECISION (type), limb_prec) + - CEIL (prec, limb_prec)); for (unsigned i = 0; i < cnt; i++) { m_data_cnt = 0; if (kind == bitint_prec_large) - idx = size_int (i); + idx = size_int (bitint_big_endian ? cnt - 1 - i : i); else if (i >= 2) - idx = size_int (end + (i > 2)); + idx = size_int (bitint_big_endian ? cnt - 1 - i : end + (i > 2)); if (eq_p) { rhs1 = handle_operand (cmp_op1, idx); @@ -2666,22 +2871,27 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, if (sext && i == cnt - 1) ext = rhs1; tree nidx = idx; - if (bo_idx) + HOST_WIDE_INT adj = bo_idx; + if (bo_be_p) + adj += bo_last - (CEIL (prec, limb_prec) - 1); + else + adj += dst_idx_off; + if (adj) { if (tree_fits_uhwi_p (idx)) - nidx = size_int (tree_to_uhwi (idx) + bo_idx); + nidx = size_int (tree_to_uhwi (idx) + adj); else { nidx = make_ssa_name (sizetype); g = gimple_build_assign (nidx, PLUS_EXPR, idx, - size_int (bo_idx)); + size_int (adj)); insert_before (g); } } bool done = false; basic_block new_bb = NULL; /* Handle stores into bit-fields. */ - if (bo_bit) + if (bo_shift) { if (i == 0) { @@ -2692,7 +2902,11 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, idx, &bf_next); bf_next = m_data.pop (); bf_cur = m_data.pop (); - g = gimple_build_cond (EQ_EXPR, idx, size_zero_node, + g = gimple_build_cond (EQ_EXPR, idx, + bitint_big_endian + ? size_int (CEIL (prec, + limb_prec) - 1) + : size_zero_node, NULL_TREE, NULL_TREE); edge edge_true; if_then_else (g, profile_probability::unlikely (), @@ -2700,10 +2914,14 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, new_bb = e2->dest; } tree ftype - = build_nonstandard_integer_type (limb_prec - bo_bit, 1); + = build_nonstandard_integer_type (limb_prec - bo_shift, 1); tree bfr = build_bit_field_ref (ftype, unshare_expr (nlhs), - limb_prec - bo_bit, - bo_idx * limb_prec + bo_bit); + limb_prec - bo_shift, + bitint_big_endian + ? (bo_idx + bo_last) + * limb_prec + : bo_idx * limb_prec + + bo_bit); tree t = add_cast (ftype, rhs1); g = gimple_build_assign (bfr, t); insert_before (g); @@ -2733,11 +2951,12 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, tree t3 = make_ssa_name (m_limb_type); g = gimple_build_assign (t1, RSHIFT_EXPR, bf_cur, build_int_cst (unsigned_type_node, - limb_prec - bo_bit)); + limb_prec + - bo_shift)); insert_before (g); g = gimple_build_assign (t2, LSHIFT_EXPR, rhs1, build_int_cst (unsigned_type_node, - bo_bit)); + bo_shift)); insert_before (g); bf_cur = rhs1; g = gimple_build_assign (t3, BIT_IOR_EXPR, t1, t2); @@ -2760,21 +2979,23 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, { unsigned int tprec = TYPE_PRECISION (type); unsigned int rprec = (tprec - 1) % limb_prec + 1; - if (rprec + bo_bit < (unsigned) limb_prec) + if (rprec + bo_shift < (unsigned) limb_prec) { tree ftype - = build_nonstandard_integer_type (rprec + bo_bit, 1); + = build_nonstandard_integer_type (rprec + bo_shift, 1); tree bfr = build_bit_field_ref (ftype, unshare_expr (nlhs), - rprec + bo_bit, - (bo_idx + tprec / limb_prec) - * limb_prec); + rprec + bo_shift, + bitint_big_endian + ? bo_idx * limb_prec + bo_bit + : (bo_idx + tprec / limb_prec) + * limb_prec); tree t = add_cast (ftype, rhs1); g = gimple_build_assign (bfr, t); done = true; bf_cur = NULL_TREE; } - else if (rprec + bo_bit == (unsigned) limb_prec) + else if (rprec + bo_shift == (unsigned) limb_prec) bf_cur = NULL_TREE; } /* Otherwise, stores to any other lhs. */ @@ -2807,16 +3028,21 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, { idx = make_ssa_name (sizetype); g = gimple_build_assign (idx, PLUS_EXPR, idx_first, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); } else { g = gimple_build_assign (idx_next, PLUS_EXPR, idx_first, - size_int (2)); + size_int (bitint_big_endian ? -2 : 2)); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx_next, size_int (end), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, idx_first, size_int (cnt - 1), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (NE_EXPR, idx_next, size_int (end), + NULL_TREE, NULL_TREE); insert_before (g); if (eq_p) m_gsi = gsi_after_labels (edge_bb); @@ -2844,32 +3070,40 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, kind = bitint_precision_kind (type); unsigned start = CEIL (prec, limb_prec); prec = TYPE_PRECISION (type); + unsigned total = CEIL (prec, limb_prec); idx = idx_first = idx_next = NULL_TREE; - if (prec <= (start + 2 + (bo_bit != 0)) * limb_prec) + if (prec <= (start + 2 + (bo_shift != 0)) * limb_prec) kind = bitint_prec_large; if (kind == bitint_prec_large) - cnt = CEIL (prec, limb_prec) - start; + cnt = total - start; else { rem = prec % limb_prec; end = (prec - rem) / limb_prec; - cnt = (bo_bit != 0) + 1 + (rem != 0); + cnt = (bo_shift != 0) + 1 + (rem != 0); } + if (bitint_big_endian && bo_shift != 0 && (prec % limb_prec) == 0) + ++total; for (unsigned i = 0; i < cnt; i++) { - if (kind == bitint_prec_large || (i == 0 && bo_bit != 0)) - idx = size_int (start + i); - else if (i == cnt - 1 && (rem != 0)) - idx = size_int (end); - else if (i == (bo_bit != 0)) - idx = create_loop (size_int (start + i), &idx_next); + if (kind == bitint_prec_large || (i == 0 && bo_shift != 0)) + idx = size_int (bo_idx + + (bitint_big_endian + ? total - 1 - start - i : start + i)); + else if (i == cnt - 1 && rem != 0) + idx = size_int (bo_idx + (bitint_big_endian ? 0 : end)); + else if (i == (bo_shift != 0)) + idx = create_loop (size_int (bo_idx + + (bitint_big_endian + ? total - 1 - start - i + : start + i)), &idx_next); rhs1 = ext; if (bf_cur != NULL_TREE && bf_cur != ext) { tree t1 = make_ssa_name (m_limb_type); g = gimple_build_assign (t1, RSHIFT_EXPR, bf_cur, build_int_cst (unsigned_type_node, - limb_prec - bo_bit)); + limb_prec - bo_shift)); insert_before (g); if (integer_zerop (ext)) rhs1 = t1; @@ -2879,54 +3113,43 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, rhs1 = make_ssa_name (m_limb_type); g = gimple_build_assign (t2, LSHIFT_EXPR, ext, build_int_cst (unsigned_type_node, - bo_bit)); + bo_shift)); insert_before (g); g = gimple_build_assign (rhs1, BIT_IOR_EXPR, t1, t2); insert_before (g); } bf_cur = ext; } - tree nidx = idx; - if (bo_idx) - { - if (tree_fits_uhwi_p (idx)) - nidx = size_int (tree_to_uhwi (idx) + bo_idx); - else - { - nidx = make_ssa_name (sizetype); - g = gimple_build_assign (nidx, PLUS_EXPR, idx, - size_int (bo_idx)); - insert_before (g); - } - } bool done = false; /* Handle bit-field access to partial last limb if needed. */ if (nlhs && i == cnt - 1) { unsigned int tprec = TYPE_PRECISION (type); unsigned int rprec = (tprec - 1) % limb_prec + 1; - if (rprec + bo_bit < (unsigned) limb_prec) + if (rprec + bo_shift < (unsigned) limb_prec) { tree ftype - = build_nonstandard_integer_type (rprec + bo_bit, 1); + = build_nonstandard_integer_type (rprec + bo_shift, 1); tree bfr = build_bit_field_ref (ftype, unshare_expr (nlhs), - rprec + bo_bit, - (bo_idx + tprec / limb_prec) - * limb_prec); + rprec + bo_shift, + bitint_big_endian + ? bo_idx * limb_prec + bo_bit + : (bo_idx + tprec / limb_prec) + * limb_prec); tree t = add_cast (ftype, rhs1); g = gimple_build_assign (bfr, t); done = true; bf_cur = NULL_TREE; } - else if (rprec + bo_bit == (unsigned) limb_prec) + else if (rprec + bo_shift == (unsigned) limb_prec) bf_cur = NULL_TREE; } /* Otherwise, stores to any other lhs. */ if (!done) { tree l = limb_access (nlhs ? NULL_TREE : lhs_type, - nlhs ? nlhs : lhs, nidx, true); + nlhs ? nlhs : lhs, idx, true); g = gimple_build_assign (l, rhs1); } insert_before (g); @@ -2940,13 +3163,22 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, add_eh_edge (e->src, find_edge (gimple_bb (stmt), eh_pad)); } } - if (kind == bitint_prec_huge && i == (bo_bit != 0)) + if (kind == bitint_prec_huge && i == (bo_shift != 0)) { g = gimple_build_assign (idx_next, PLUS_EXPR, idx, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx_next, size_int (end), - NULL_TREE, NULL_TREE); + if (bitint_big_endian && rem != 0) + g = gimple_build_cond (NE_EXPR, idx, + size_int (bo_idx + 1), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (NE_EXPR, idx_next, + size_int (bo_idx + + (bitint_big_endian + ? 0 : end)), + NULL_TREE, NULL_TREE); insert_before (g); m_gsi = gsi_for_stmt (stmt); m_bb = NULL; @@ -2956,19 +3188,21 @@ bitint_large_huge::lower_mergeable_stmt (gimple *stmt, tree_code &cmp_code, if (bf_cur != NULL_TREE) { unsigned int tprec = TYPE_PRECISION (type); - unsigned int rprec = (tprec + bo_bit) % limb_prec; + unsigned int rprec = (tprec + bo_shift) % limb_prec; tree ftype = build_nonstandard_integer_type (rprec, 1); tree bfr = build_bit_field_ref (ftype, unshare_expr (nlhs), rprec, - (bo_idx + (tprec + bo_bit) / limb_prec) - * limb_prec); + bitint_big_endian + ? bo_idx * limb_prec + bo_bit + : (bo_idx + (tprec + bo_bit) / limb_prec) + * limb_prec); rhs1 = bf_cur; if (bf_cur != ext) { rhs1 = make_ssa_name (TREE_TYPE (rhs1)); g = gimple_build_assign (rhs1, RSHIFT_EXPR, bf_cur, build_int_cst (unsigned_type_node, - limb_prec - bo_bit)); + limb_prec - bo_shift)); insert_before (g); } rhs1 = add_cast (ftype, rhs1); @@ -3039,7 +3273,7 @@ bitint_large_huge::lower_comparison_stmt (gimple *stmt, tree_code &cmp_code, && (cmp_code == GE_EXPR || cmp_code == LT_EXPR)) { unsigned end = CEIL ((unsigned) TYPE_PRECISION (type), limb_prec) - 1; - tree idx = size_int (end); + tree idx = size_int (bitint_big_endian ? 0 : end); m_data_cnt = 0; tree rhs1 = handle_operand (cmp_op1, idx); if (TYPE_UNSIGNED (TREE_TYPE (rhs1))) @@ -3080,11 +3314,12 @@ bitint_large_huge::lower_comparison_stmt (gimple *stmt, tree_code &cmp_code, { m_data_cnt = 0; if (kind == bitint_prec_large) - idx = size_int (cnt - i - 1); + idx = size_int (bitint_big_endian ? i : cnt - i - 1); else if (i == cnt - 1) - idx = create_loop (size_int (end - 1), &idx_next); + idx = create_loop (size_int (bitint_big_endian ? cnt - 1 : end - 1), + &idx_next); else - idx = size_int (end); + idx = size_int (bitint_big_endian ? 0 : end); tree rhs1 = handle_operand (cmp_op1, idx); tree rhs2 = handle_operand (cmp_op2, idx); if (i == 0 @@ -3118,9 +3353,14 @@ bitint_large_huge::lower_comparison_stmt (gimple *stmt, tree_code &cmp_code, m_first = false; if (kind == bitint_prec_huge && i == cnt - 1) { - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_int (-1)); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian ? size_one_node + : size_int (-1)); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx, size_zero_node, + g = gimple_build_cond (NE_EXPR, idx, + bitint_big_endian + ? size_int (end - 1 + (cnt != 1)) + : size_zero_node, NULL_TREE, NULL_TREE); insert_before (g); edge true_edge, false_edge; @@ -3174,7 +3414,7 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) size_t n2 = n / limb_prec; size_t n3 = n1 != 0; unsigned n4 = (limb_prec - n1) % limb_prec; - (for power of 2 limb_prec n4 can be -n1 & (limb_prec)). */ + (for power of 2 limb_prec n4 can be -n1 & limb_prec). */ if (TREE_CODE (n) == INTEGER_CST) { tree lp = build_int_cst (TREE_TYPE (n), limb_prec); @@ -3290,7 +3530,9 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) dst[idx] = ext; */ tree pmn3; if (TYPE_UNSIGNED (type) && prec % limb_prec == 0) - pmn3 = p; + pmn3 = bitint_big_endian ? size_zero_node : p; + else if (bitint_big_endian) + pmn3 = n3; else if (TREE_CODE (n3) == INTEGER_CST) pmn3 = int_const_binop (MINUS_EXPR, p, n3); else @@ -3299,16 +3541,34 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) g = gimple_build_assign (pmn3, MINUS_EXPR, p, n3); insert_before (g); } - g = gimple_build_cond (LT_EXPR, n2, pmn3, NULL_TREE, NULL_TREE); + tree pmn2 = NULL_TREE; + if (bitint_big_endian) + { + if (TREE_CODE (n2) == INTEGER_CST) + pmn2 = int_const_binop (MINUS_EXPR, p, n2); + else + { + pmn2 = make_ssa_name (sizetype); + g = gimple_build_assign (pmn2, MINUS_EXPR, p, n2); + insert_before (g); + } + g = gimple_build_cond (GT_EXPR, pmn2, pmn3, NULL_TREE, NULL_TREE); + } + else + g = gimple_build_cond (LT_EXPR, n2, pmn3, NULL_TREE, NULL_TREE); edge edge_true, edge_false; if_then (g, profile_probability::likely (), edge_true, edge_false); tree idx_next; - tree idx = create_loop (n2, &idx_next); + tree idx = create_loop (bitint_big_endian ? pmn2 : n2, &idx_next); tree idxmn2 = make_ssa_name (sizetype); tree idxpn3 = make_ssa_name (sizetype); - g = gimple_build_assign (idxmn2, MINUS_EXPR, idx, n2); + g = gimple_build_assign (idxmn2, + bitint_big_endian ? PLUS_EXPR : MINUS_EXPR, + idx, n2); insert_before (g); - g = gimple_build_assign (idxpn3, PLUS_EXPR, idx, n3); + g = gimple_build_assign (idxpn3, + bitint_big_endian ? MINUS_EXPR : PLUS_EXPR, + idx, n3); insert_before (g); m_data_cnt = 0; tree t1 = handle_operand (rhs1, idx); @@ -3333,9 +3593,12 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) tree l = limb_access (TREE_TYPE (lhs), obj, idxmn2, true); g = gimple_build_assign (l, t1); insert_before (g); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_one_node); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian ? size_int (-1) + : size_one_node); insert_before (g); - g = gimple_build_cond (LT_EXPR, idx_next, pmn3, NULL_TREE, NULL_TREE); + g = gimple_build_cond (bitint_big_endian ? GT_EXPR : LT_EXPR, + idx_next, pmn3, NULL_TREE, NULL_TREE); insert_before (g); idx = make_ssa_name (sizetype); m_gsi = gsi_for_stmt (final_stmt); @@ -3343,17 +3606,22 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) edge_false = find_edge (edge_false->src, gsi_bb (m_gsi)); edge_true = EDGE_PRED (gsi_bb (m_gsi), EDGE_PRED (gsi_bb (m_gsi), 0) == edge_false); - add_phi_arg (phi, n2, edge_false, UNKNOWN_LOCATION); + add_phi_arg (phi, bitint_big_endian ? pmn2 : n2, edge_false, + UNKNOWN_LOCATION); add_phi_arg (phi, idx_next, edge_true, UNKNOWN_LOCATION); m_data_cnt = 0; - tree ms = handle_operand (rhs1, p); + tree ms = handle_operand (rhs1, bitint_big_endian ? size_zero_node : p); tree ext = ms; if (!types_compatible_p (TREE_TYPE (ms), m_limb_type)) ext = add_cast (m_limb_type, ms); if (!(TYPE_UNSIGNED (type) && prec % limb_prec == 0) && !integer_zerop (n3)) { - g = gimple_build_cond (LT_EXPR, idx, p, NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (GT_EXPR, idx, size_zero_node, + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (LT_EXPR, idx, p, NULL_TREE, NULL_TREE); if_then (g, profile_probability::likely (), edge_true, edge_false); m_data_cnt = 0; t1 = handle_operand (rhs1, idx); @@ -3370,13 +3638,16 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) insert_before (g); t1 = gimple_assign_lhs (g); idxmn2 = make_ssa_name (sizetype); - g = gimple_build_assign (idxmn2, MINUS_EXPR, idx, n2); + g = gimple_build_assign (idxmn2, bitint_big_endian + ? PLUS_EXPR : MINUS_EXPR, idx, n2); insert_before (g); l = limb_access (TREE_TYPE (lhs), obj, idxmn2, true); g = gimple_build_assign (l, t1); insert_before (g); idx_next = make_ssa_name (sizetype); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_one_node); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); m_gsi = gsi_for_stmt (final_stmt); tree nidx = make_ssa_name (sizetype); @@ -3388,7 +3659,9 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) add_phi_arg (phi, idx_next, edge_true, UNKNOWN_LOCATION); idx = nidx; } - g = gimple_build_assign (make_ssa_name (sizetype), MINUS_EXPR, idx, n2); + g = gimple_build_assign (make_ssa_name (sizetype), + bitint_big_endian ? PLUS_EXPR : MINUS_EXPR, + idx, n2); insert_before (g); idx = gimple_assign_lhs (g); tree sext = ext; @@ -3414,18 +3687,35 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) g = gimple_build_assign (l, t1); insert_before (g); g = gimple_build_assign (make_ssa_name (sizetype), PLUS_EXPR, idx, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); - idx = gimple_assign_lhs (g); - g = gimple_build_cond (LE_EXPR, idx, p, NULL_TREE, NULL_TREE); + if (bitint_big_endian) + { + tree new_idx = gimple_assign_lhs (g); + g = gimple_build_cond (NE_EXPR, idx, size_zero_node, + NULL_TREE, NULL_TREE); + idx = new_idx; + } + else + { + idx = gimple_assign_lhs (g); + g = gimple_build_cond (LE_EXPR, idx, p, NULL_TREE, NULL_TREE); + } if_then (g, profile_probability::likely (), edge_true, edge_false); idx = create_loop (idx, &idx_next); l = limb_access (TREE_TYPE (lhs), obj, idx, true); g = gimple_build_assign (l, ext); insert_before (g); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_one_node); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); - g = gimple_build_cond (LE_EXPR, idx_next, p, NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, idx, size_zero_node, + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (LE_EXPR, idx_next, p, NULL_TREE, NULL_TREE); insert_before (g); } else @@ -3457,6 +3747,18 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) g = gimple_build_assign (n2pn3, PLUS_EXPR, n2, n3); insert_before (g); } + if (bitint_big_endian) + { + if (TREE_CODE (n2pn3) == INTEGER_CST) + n2pn3 = int_const_binop (MINUS_EXPR, p, n2pn3); + else + { + g = gimple_build_assign (make_ssa_name (sizetype), + MINUS_EXPR, p, n2pn3); + insert_before (g); + n2pn3 = gimple_assign_lhs (g); + } + } /* For LSHIFT_EXPR, we can use handle_operand with non-INTEGER_CST idx even to access the most significant partial limb. */ m_var_msb = true; @@ -3465,17 +3767,25 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) counts. Emit if (true) condition that can be optimized later. */ g = gimple_build_cond (NE_EXPR, boolean_true_node, boolean_false_node, NULL_TREE, NULL_TREE); + else if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, n2pn3, size_int (-1), NULL_TREE, + NULL_TREE); else g = gimple_build_cond (LE_EXPR, n2pn3, p, NULL_TREE, NULL_TREE); edge edge_true, edge_false; if_then (g, profile_probability::likely (), edge_true, edge_false); tree idx_next; - tree idx = create_loop (p, &idx_next); + tree idx = create_loop (bitint_big_endian ? size_zero_node : p, + &idx_next); tree idxmn2 = make_ssa_name (sizetype); tree idxmn2mn3 = make_ssa_name (sizetype); - g = gimple_build_assign (idxmn2, MINUS_EXPR, idx, n2); + g = gimple_build_assign (idxmn2, + bitint_big_endian ? PLUS_EXPR : MINUS_EXPR, + idx, n2); insert_before (g); - g = gimple_build_assign (idxmn2mn3, MINUS_EXPR, idxmn2, n3); + g = gimple_build_assign (idxmn2mn3, + bitint_big_endian ? PLUS_EXPR : MINUS_EXPR, + idxmn2, n3); insert_before (g); m_data_cnt = 0; tree t1 = handle_operand (rhs1, idxmn2); @@ -3500,10 +3810,13 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) tree l = limb_access (TREE_TYPE (lhs), obj, idx, true); g = gimple_build_assign (l, t1); insert_before (g); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_int (-1)); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian + ? size_one_node : size_int (-1)); insert_before (g); tree sn2pn3 = add_cast (ssizetype, n2pn3); - g = gimple_build_cond (GE_EXPR, add_cast (ssizetype, idx_next), sn2pn3, + g = gimple_build_cond (bitint_big_endian ? LE_EXPR : GE_EXPR, + add_cast (ssizetype, idx_next), sn2pn3, NULL_TREE, NULL_TREE); insert_before (g); idx = make_ssa_name (sizetype); @@ -3512,7 +3825,8 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) edge_false = find_edge (edge_false->src, gsi_bb (m_gsi)); edge_true = EDGE_PRED (gsi_bb (m_gsi), EDGE_PRED (gsi_bb (m_gsi), 0) == edge_false); - add_phi_arg (phi, p, edge_false, UNKNOWN_LOCATION); + add_phi_arg (phi, bitint_big_endian ? size_zero_node : p, + edge_false, UNKNOWN_LOCATION); add_phi_arg (phi, idx_next, edge_true, UNKNOWN_LOCATION); m_data_cnt = 0; if (!integer_zerop (n3)) @@ -3521,7 +3835,9 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) NULL_TREE, NULL_TREE); if_then (g, profile_probability::likely (), edge_true, edge_false); idxmn2 = make_ssa_name (sizetype); - g = gimple_build_assign (idxmn2, MINUS_EXPR, idx, n2); + g = gimple_build_assign (idxmn2, + bitint_big_endian ? PLUS_EXPR : MINUS_EXPR, + idx, n2); insert_before (g); m_data_cnt = 0; t1 = handle_operand (rhs1, idxmn2); @@ -3533,7 +3849,9 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) g = gimple_build_assign (l, t1); insert_before (g); idx_next = make_ssa_name (sizetype); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_int (-1)); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian + ? size_one_node : size_int (-1)); insert_before (g); m_gsi = gsi_for_stmt (final_stmt); tree nidx = make_ssa_name (sizetype); @@ -3545,18 +3863,43 @@ bitint_large_huge::lower_shift_stmt (tree obj, gimple *stmt) add_phi_arg (phi, idx_next, edge_true, UNKNOWN_LOCATION); idx = nidx; } - g = gimple_build_cond (GE_EXPR, add_cast (ssizetype, idx), - ssize_int (0), NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (LE_EXPR, idx, p, NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (GE_EXPR, add_cast (ssizetype, idx), + ssize_int (0), NULL_TREE, NULL_TREE); if_then (g, profile_probability::likely (), edge_true, edge_false); idx = create_loop (idx, &idx_next); l = limb_access (TREE_TYPE (lhs), obj, idx, true); g = gimple_build_assign (l, build_zero_cst (m_limb_type)); insert_before (g); - g = gimple_build_assign (idx_next, PLUS_EXPR, idx, size_int (-1)); + g = gimple_build_assign (idx_next, PLUS_EXPR, idx, + bitint_big_endian + ? size_one_node : size_int (-1)); insert_before (g); - g = gimple_build_cond (GE_EXPR, add_cast (ssizetype, idx_next), - ssize_int (0), NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (LE_EXPR, idx_next, p, NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (GE_EXPR, add_cast (ssizetype, idx_next), + ssize_int (0), NULL_TREE, NULL_TREE); insert_before (g); + if (bitint_extended && prec % limb_prec != 0) + { + /* The most significant limb has been updated either in the + loop or in the if after it. To simplify the code, just + read it back from memory and extend. */ + m_gsi = gsi_after_labels (edge_false->dest); + idx = bitint_big_endian ? size_zero_node : p; + tree l = limb_access (TREE_TYPE (lhs), obj, idx, true); + tree type = limb_access_type (TREE_TYPE (lhs), idx); + tree v = make_ssa_name (m_limb_type); + g = gimple_build_assign (v, l); + insert_before (g); + v = add_cast (type, v); + l = limb_access (TREE_TYPE (lhs), obj, idx, true); + g = gimple_build_assign (l, add_cast (m_limb_type, v)); + insert_before (g); + } } } @@ -3803,7 +4146,8 @@ bitint_large_huge::arith_overflow_extract_bits (unsigned int start, void bitint_large_huge::finish_arith_overflow (tree var, tree obj, tree type, tree ovf, tree lhs, tree orig_obj, - gimple *stmt, tree_code code) + gimple *stmt, unsigned nelts, + tree_code code) { gimple *g; @@ -3821,7 +4165,9 @@ bitint_large_huge::finish_arith_overflow (tree var, tree obj, tree type, && bitint_precision_kind (type) == bitint_prec_middle) lhs_type = build_nonstandard_integer_type (TYPE_PRECISION (type), TYPE_UNSIGNED (type)); - tree r1 = limb_access (NULL_TREE, var, size_int (0), true); + tree r1 = limb_access (NULL_TREE, var, + bitint_big_endian + ? size_int (nelts - 1) : size_zero_node, true); g = gimple_build_assign (make_ssa_name (m_limb_type), r1); insert_before (g); r1 = gimple_assign_lhs (g); @@ -3829,7 +4175,9 @@ bitint_large_huge::finish_arith_overflow (tree var, tree obj, tree type, r1 = add_cast (lhs_type, r1); if (TYPE_PRECISION (lhs_type) > limb_prec) { - tree r2 = limb_access (NULL_TREE, var, size_int (1), true); + tree r2 = limb_access (NULL_TREE, var, + bitint_big_endian + ? size_int (nelts - 2) : size_one_node, true); g = gimple_build_assign (make_ssa_name (m_limb_type), r2); insert_before (g); r2 = gimple_assign_lhs (g); @@ -3854,45 +4202,65 @@ bitint_large_huge::finish_arith_overflow (tree var, tree obj, tree type, } else { - unsigned HOST_WIDE_INT nelts = 0; + unsigned HOST_WIDE_INT obj_nelts = 0; tree atype = NULL_TREE; if (obj) { - nelts = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (obj))) / limb_prec; + obj_nelts = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (obj))) / limb_prec; if (orig_obj == NULL_TREE) - nelts >>= 1; - atype = build_array_type_nelts (m_limb_type, nelts); + obj_nelts >>= 1; + atype = build_array_type_nelts (m_limb_type, obj_nelts); } if (var && obj) { tree v1, v2; - tree zero; + tree off; if (orig_obj == NULL_TREE) { - zero = build_zero_cst (build_pointer_type (TREE_TYPE (obj))); + off = build_zero_cst (build_pointer_type (TREE_TYPE (obj))); v1 = build2 (MEM_REF, atype, - build_fold_addr_expr (unshare_expr (obj)), zero); + build_fold_addr_expr (unshare_expr (obj)), off); } else if (!useless_type_conversion_p (atype, TREE_TYPE (obj))) v1 = build1 (VIEW_CONVERT_EXPR, atype, unshare_expr (obj)); else v1 = unshare_expr (obj); - zero = build_zero_cst (build_pointer_type (TREE_TYPE (var))); - v2 = build2 (MEM_REF, atype, build_fold_addr_expr (var), zero); + off = build_int_cst (build_pointer_type (TREE_TYPE (var)), + bitint_big_endian + ? (nelts - obj_nelts) * m_limb_size : 0); + v2 = build2 (MEM_REF, atype, build_fold_addr_expr (var), off); g = gimple_build_assign (v1, v2); insert_before (g); } + else if (obj && bitint_big_endian && nelts != obj_nelts) + { + gcc_assert (nelts > obj_nelts); + tree fn = builtin_decl_implicit (BUILT_IN_MEMMOVE); + tree off = build_int_cst (build_pointer_type (TREE_TYPE (obj)), + (nelts - obj_nelts) * m_limb_size); + tree src = build2 (MEM_REF, atype, + build_fold_addr_expr (unshare_expr (obj)), off); + g = gimple_build_call (fn, 3, + build_fold_addr_expr (unshare_expr (obj)), + src, build_int_cst (size_type_node, + obj_nelts * m_limb_size)); + insert_before (g); + } if (orig_obj == NULL_TREE && obj) { ovf = add_cast (m_limb_type, ovf); - tree l = limb_access (NULL_TREE, obj, size_int (nelts), true); + tree l = limb_access (NULL_TREE, obj, + size_int (bitint_big_endian + ? obj_nelts * 2 - 1 : obj_nelts), + true); g = gimple_build_assign (l, ovf); insert_before (g); - if (nelts > 1) + if (obj_nelts > 1) { - atype = build_array_type_nelts (m_limb_type, nelts - 1); + atype = build_array_type_nelts (m_limb_type, obj_nelts - 1); tree off = build_int_cst (build_pointer_type (TREE_TYPE (obj)), - (nelts + 1) * m_limb_size); + (obj_nelts + !bitint_big_endian) + * m_limb_size); tree v1 = build2 (MEM_REF, atype, build_fold_addr_expr (unshare_expr (obj)), off); @@ -4127,18 +4495,21 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) int prec4 = ovf != NULL_TREE ? prec : prec3; bitint_prec_kind kind = bitint_precision_kind (prec4); - unsigned cnt, rem = 0, fin = 0; + unsigned cnt, rem = 0, fin = 0, nelts; tree idx = NULL_TREE, idx_first = NULL_TREE, idx_next = NULL_TREE; bool last_ovf = (ovf == NULL_TREE && CEIL (prec2, limb_prec) > CEIL (prec3, limb_prec)); if (kind != bitint_prec_huge) - cnt = CEIL (prec4, limb_prec) + last_ovf; + nelts = cnt = CEIL (prec4, limb_prec) + last_ovf; else { - rem = (prec4 % (2 * limb_prec)); + rem = prec4 % (2 * limb_prec); fin = (prec4 - rem) / limb_prec; cnt = 2 + CEIL (rem, limb_prec) + last_ovf; - idx = idx_first = create_loop (size_zero_node, &idx_next); + nelts = fin + cnt - 2; + idx = idx_first = create_loop (bitint_big_endian + ? size_int (nelts - 1) : size_zero_node, + &idx_next); } if (kind == bitint_prec_huge) @@ -4172,19 +4543,52 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) m_data_cnt = 0; tree rhs1, rhs2; if (kind != bitint_prec_huge) - idx = size_int (i); + idx = size_int (bitint_big_endian ? nelts - 1 - i : i); else if (i >= 2) - idx = size_int (fin + i - 2); + idx = size_int (bitint_big_endian ? nelts + 1 - fin - i : fin + i - 2); if (!last_ovf || i < cnt - 1) { + tree idx0 = idx, idx1 = idx; + if (bitint_big_endian + && CEIL ((unsigned) TYPE_PRECISION (type0), limb_prec) != nelts) + { + HOST_WIDE_INT diff + = ((HOST_WIDE_INT) CEIL (TYPE_PRECISION (type0), limb_prec) + - (HOST_WIDE_INT) nelts); + if (tree_fits_uhwi_p (idx)) + idx0 = size_int (tree_to_uhwi (idx) + diff); + else + { + idx0 = make_ssa_name (sizetype); + g = gimple_build_assign (idx0, PLUS_EXPR, idx, + size_int (diff)); + insert_before (g); + } + } if (type0 != TREE_TYPE (arg0)) - rhs1 = handle_cast (type0, arg0, idx); + rhs1 = handle_cast (type0, arg0, idx0); else - rhs1 = handle_operand (arg0, idx); + rhs1 = handle_operand (arg0, idx0); + if (bitint_big_endian + && CEIL ((unsigned) TYPE_PRECISION (type1), limb_prec) != nelts) + { + HOST_WIDE_INT diff + = ((HOST_WIDE_INT) CEIL (TYPE_PRECISION (type1), limb_prec) + - (HOST_WIDE_INT) nelts); + if (tree_fits_uhwi_p (idx)) + idx1 = size_int (tree_to_uhwi (idx) + diff); + else + { + idx1 = make_ssa_name (sizetype); + g = gimple_build_assign (idx1, PLUS_EXPR, idx, + size_int (diff)); + insert_before (g); + } + } if (type1 != TREE_TYPE (arg1)) - rhs2 = handle_cast (type1, arg1, idx); + rhs2 = handle_cast (type1, arg1, idx1); else - rhs2 = handle_operand (arg1, idx); + rhs2 = handle_operand (arg1, idx1); if (i == 0) data_cnt = m_data_cnt; if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (rhs1))) @@ -4240,6 +4644,8 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) if (tree_fits_uhwi_p (idx)) { unsigned limb = tree_to_uhwi (idx); + if (bitint_big_endian) + limb = nelts - 1 - limb; if (limb >= startlimb && limb <= endlimb) { tree l = arith_overflow_extract_bits (start, end, rhs, @@ -4296,14 +4702,22 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) cmp_code = EQ_EXPR; else cmp_code = GT_EXPR; - g = gimple_build_cond (cmp_code, idx, size_int (startlimb), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (swap_tree_comparison (cmp_code), + idx, size_int (nelts - 1 + - startlimb), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (cmp_code, idx, size_int (startlimb), + NULL_TREE, NULL_TREE); edge edge_true_true, edge_true_false, edge_false; gimple *g2 = NULL; if (!single_comparison) g2 = gimple_build_cond (NE_EXPR, idx, - size_int (startlimb), NULL_TREE, - NULL_TREE); + size_int (bitint_big_endian + ? nelts - 1 - startlimb + : startlimb), + NULL_TREE, NULL_TREE); if_then_if_then_else (g, g2, profile_probability::likely (), profile_probability::likely (), edge_true_true, edge_true_false, @@ -4377,7 +4791,10 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) if (var || obj) { - if (tree_fits_uhwi_p (idx) && tree_to_uhwi (idx) >= prec_limbs) + if (tree_fits_uhwi_p (idx) + && (bitint_big_endian + ? nelts - 1 - tree_to_uhwi (idx) + : tree_to_uhwi (idx)) >= prec_limbs) ; else if (!tree_fits_uhwi_p (idx) && (unsigned) prec < (fin - (i == 0)) * limb_prec) @@ -4386,25 +4803,48 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) = (((unsigned) prec % limb_prec) == 0 || prec_limbs + 1 >= fin || (prec_limbs & 1) == (i & 1)); - g = gimple_build_cond (LE_EXPR, idx, size_int (prec_limbs - 1), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (GE_EXPR, idx, + size_int (nelts - prec_limbs), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (LE_EXPR, idx, size_int (prec_limbs - 1), + NULL_TREE, NULL_TREE); gimple *g2 = NULL; if (!single_comparison) g2 = gimple_build_cond (EQ_EXPR, idx, - size_int (prec_limbs - 1), + size_int (bitint_big_endian + ? nelts - prec_limbs + : prec_limbs - 1), NULL_TREE, NULL_TREE); edge edge_true_true, edge_true_false, edge_false; if_then_if_then_else (g, g2, profile_probability::likely (), profile_probability::unlikely (), edge_true_true, edge_true_false, edge_false); - tree l = limb_access (type, var ? var : obj, idx, true); + tree idxl = idx; + if (bitint_big_endian && prec_limbs != nelts) + { + HOST_WIDE_INT diff = ((HOST_WIDE_INT) prec_limbs + - (HOST_WIDE_INT) nelts); + if (tree_fits_uhwi_p (idx)) + idxl = size_int (tree_to_uhwi (idx) + diff); + else + { + idxl = make_ssa_name (sizetype); + g = gimple_build_assign (idxl, PLUS_EXPR, idx, + size_int (diff)); + insert_before (g); + } + } + tree l = limb_access (type, var ? var : obj, idxl, true); g = gimple_build_assign (l, rhs); insert_before (g); if (!single_comparison) { m_gsi = gsi_after_labels (edge_true_true->src); - tree plm1idx = size_int (prec_limbs - 1); + tree plm1idx = size_int (bitint_big_endian + ? 0 : prec_limbs - 1); tree plm1type = limb_access_type (type, plm1idx); l = limb_access (type, var ? var : obj, plm1idx, true); if (!useless_type_conversion_p (plm1type, TREE_TYPE (rhs))) @@ -4419,7 +4859,22 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) } else { - tree l = limb_access (type, var ? var : obj, idx, true); + tree idxl = idx; + if (bitint_big_endian && prec_limbs != nelts) + { + HOST_WIDE_INT diff = ((HOST_WIDE_INT) prec_limbs + - (HOST_WIDE_INT) nelts); + if (tree_fits_uhwi_p (idx)) + idxl = size_int (tree_to_uhwi (idx) + diff); + else + { + idxl = make_ssa_name (sizetype); + g = gimple_build_assign (idxl, PLUS_EXPR, idx, + size_int (diff)); + insert_before (g); + } + } + tree l = limb_access (type, var ? var : obj, idxl, true); if (!useless_type_conversion_p (TREE_TYPE (l), TREE_TYPE (rhs))) rhs = add_cast (TREE_TYPE (l), rhs); g = gimple_build_assign (l, rhs); @@ -4433,16 +4888,22 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) { idx = make_ssa_name (sizetype); g = gimple_build_assign (idx, PLUS_EXPR, idx_first, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); } else { g = gimple_build_assign (idx_next, PLUS_EXPR, idx_first, - size_int (2)); + size_int (bitint_big_endian ? -2 : 2)); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx_next, size_int (fin), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, idx_first, + size_int (nelts + 1 - fin), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (NE_EXPR, idx_next, size_int (fin), + NULL_TREE, NULL_TREE); insert_before (g); m_gsi = gsi_for_stmt (final_stmt); m_bb = NULL; @@ -4450,7 +4911,8 @@ bitint_large_huge::lower_addsub_overflow (tree obj, gimple *stmt) } } - finish_arith_overflow (var, obj, type, ovf, lhs, orig_obj, stmt, code); + finish_arith_overflow (var, obj, type, ovf, lhs, orig_obj, stmt, + prec_limbs, code); } /* Lower a .MUL_OVERFLOW call with at least one large/huge _BitInt @@ -4538,6 +5000,7 @@ bitint_large_huge::lower_mul_overflow (tree obj, gimple *stmt) { unsigned startlimb = start / limb_prec; unsigned endlimb = (end - 1) / limb_prec; + unsigned nelts = CEIL (MAX (prec, prec2), limb_prec); unsigned cnt; bool use_loop = false; if (startlimb == endlimb) @@ -4557,7 +5020,9 @@ bitint_large_huge::lower_mul_overflow (tree obj, gimple *stmt) if (cnt == 1) { tree l = limb_access (NULL_TREE, var ? var : obj, - size_int (startlimb), true); + size_int (bitint_big_endian + ? nelts - 1 - startlimb + : startlimb), true); g = gimple_build_assign (make_ssa_name (m_limb_type), l); insert_before (g); l = arith_overflow_extract_bits (start, end, gimple_assign_lhs (g), @@ -4591,20 +5056,25 @@ bitint_large_huge::lower_mul_overflow (tree obj, gimple *stmt) { tree idx, idx_next = NULL_TREE; if (i == 0) - idx = size_int (startlimb); + idx = size_int (bitint_big_endian + ? nelts - 1 - startlimb : startlimb); else if (i == 2) - idx = size_int (endlimb); + idx = size_int (bitint_big_endian + ? nelts - 1 - endlimb : endlimb); else if (use_loop) - idx = create_loop (size_int (startlimb + 1), &idx_next); + idx = create_loop (size_int (bitint_big_endian + ? nelts - startlimb - 2 + : startlimb + 1), &idx_next); else - idx = size_int (startlimb + 1); + idx = size_int (bitint_big_endian + ? nelts - startlimb - 2 : startlimb + 1); tree l = limb_access (NULL_TREE, var ? var : obj, idx, true); g = gimple_build_assign (make_ssa_name (m_limb_type), l); insert_before (g); l = gimple_assign_lhs (g); if (i == 0 || i == 2) l = arith_overflow_extract_bits (start, end, l, - tree_to_uhwi (idx), + i == 0 ? startlimb : endlimb, check_zero); if (i == 0 && !check_zero) { @@ -4632,11 +5102,18 @@ bitint_large_huge::lower_mul_overflow (tree obj, gimple *stmt) if (i == 1 && use_loop) { g = gimple_build_assign (idx_next, PLUS_EXPR, idx, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx_next, - size_int (endlimb + (cnt == 2)), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, idx, + size_int (nelts - endlimb + - (cnt == 2)), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (NE_EXPR, idx_next, + size_int (endlimb + (cnt == 2)), + NULL_TREE, NULL_TREE); insert_before (g); edge true_edge, false_edge; extract_true_false_edges_from_block (gsi_bb (m_gsi), @@ -4661,7 +5138,8 @@ bitint_large_huge::lower_mul_overflow (tree obj, gimple *stmt) } } - finish_arith_overflow (var, obj, type, ovf, lhs, orig_obj, stmt, MULT_EXPR); + finish_arith_overflow (var, obj, type, ovf, lhs, orig_obj, stmt, + CEIL (MAX (prec, prec2), limb_prec), MULT_EXPR); } /* Lower REALPART_EXPR or IMAGPART_EXPR stmt extracting part of result from @@ -4833,19 +5311,22 @@ bitint_large_huge::lower_bit_query (gimple *stmt) } tree fndecl = builtin_decl_explicit (fcode), res = NULL_TREE; unsigned cnt = 0, rem = 0, end = 0, prec = TYPE_PRECISION (type); + unsigned nelts = CEIL (prec, limb_prec); struct bq_details { edge e; tree val, addend; } *bqp = NULL; basic_block edge_bb = NULL; if (m_upwards) { tree idx = NULL_TREE, idx_first = NULL_TREE, idx_next = NULL_TREE; if (kind == bitint_prec_large) - cnt = CEIL (prec, limb_prec); + cnt = nelts; else { rem = (prec % (2 * limb_prec)); end = (prec - rem) / limb_prec; cnt = 2 + CEIL (rem, limb_prec); - idx = idx_first = create_loop (size_zero_node, &idx_next); + idx = idx_first = create_loop (bitint_big_endian + ? size_int (nelts - 1) + : size_zero_node, &idx_next); } if (ifn == IFN_CTZ || ifn == IFN_FFS) @@ -4867,9 +5348,10 @@ bitint_large_huge::lower_bit_query (gimple *stmt) { m_data_cnt = 0; if (kind == bitint_prec_large) - idx = size_int (i); + idx = size_int (bitint_big_endian ? nelts - 1 - i : i); else if (i >= 2) - idx = size_int (end + (i > 2)); + idx = size_int (bitint_big_endian + ? nelts - 1 - end - (i > 2) : end + (i > 2)); tree rhs1 = handle_operand (arg0, idx); if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (rhs1))) @@ -4909,7 +5391,9 @@ bitint_large_huge::lower_bit_query (gimple *stmt) if (tree_fits_uhwi_p (idx)) bqp[i].addend = build_int_cst (integer_type_node, - tree_to_uhwi (idx) * limb_prec + (bitint_big_endian + ? nelts - 1 - tree_to_uhwi (idx) + : tree_to_uhwi (idx)) * limb_prec + (ifn == IFN_FFS)); else { @@ -4968,16 +5452,23 @@ bitint_large_huge::lower_bit_query (gimple *stmt) { idx = make_ssa_name (sizetype); g = gimple_build_assign (idx, PLUS_EXPR, idx_first, - size_one_node); + bitint_big_endian + ? size_int (-1) : size_one_node); insert_before (g); } else { g = gimple_build_assign (idx_next, PLUS_EXPR, idx_first, - size_int (2)); + size_int (bitint_big_endian + ? -2 : 2)); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx_next, size_int (end), - NULL_TREE, NULL_TREE); + if (bitint_big_endian) + g = gimple_build_cond (NE_EXPR, idx_first, + size_int (cnt - 1), + NULL_TREE, NULL_TREE); + else + g = gimple_build_cond (NE_EXPR, idx_next, size_int (end), + NULL_TREE, NULL_TREE); insert_before (g); if (ifn == IFN_CTZ || ifn == IFN_FFS) m_gsi = gsi_after_labels (edge_bb); @@ -4993,7 +5484,7 @@ bitint_large_huge::lower_bit_query (gimple *stmt) tree idx = NULL_TREE, idx_next = NULL_TREE, first = NULL_TREE; int sub_one = 0; if (kind == bitint_prec_large) - cnt = CEIL (prec, limb_prec); + cnt = nelts; else { rem = prec % limb_prec; @@ -5026,11 +5517,12 @@ bitint_large_huge::lower_bit_query (gimple *stmt) { m_data_cnt = 0; if (kind == bitint_prec_large) - idx = size_int (cnt - i - 1); + idx = size_int (bitint_big_endian ? i : cnt - i - 1); else if (i == cnt - 1) - idx = create_loop (size_int (end - 1), &idx_next); + idx = create_loop (size_int (bitint_big_endian ? i : end - 1), + &idx_next); else - idx = size_int (end); + idx = bitint_big_endian ? size_zero_node : size_int (end); tree rhs1 = handle_operand (arg0, idx); if (!useless_type_conversion_p (m_limb_type, TREE_TYPE (rhs1))) @@ -5115,7 +5607,9 @@ bitint_large_huge::lower_bit_query (gimple *stmt) bqp[i].addend = build_int_cst (integer_type_node, (int) prec - - (((int) tree_to_uhwi (idx) + 1) + - (((int) (bitint_big_endian + ? nelts - 1 - tree_to_uhwi (idx) + : tree_to_uhwi (idx)) + 1) * limb_prec) - sub_one); else { @@ -5136,9 +5630,12 @@ bitint_large_huge::lower_bit_query (gimple *stmt) if (kind == bitint_prec_huge && i == cnt - 1) { g = gimple_build_assign (idx_next, PLUS_EXPR, idx, - size_int (-1)); + bitint_big_endian + ? size_one_node : size_int (-1)); insert_before (g); - g = gimple_build_cond (NE_EXPR, idx, size_zero_node, + g = gimple_build_cond (NE_EXPR, idx, + bitint_big_endian + ? size_int (nelts - 1) : size_zero_node, NULL_TREE, NULL_TREE); insert_before (g); edge true_edge, false_edge; @@ -5667,14 +6164,18 @@ bitint_large_huge::lower_stmt (gimple *stmt) TYPE_UNSIGNED (lhs_type)); m_data_cnt = 0; tree rhs1 = gimple_assign_rhs1 (stmt); - tree r1 = handle_operand (rhs1, size_int (0)); + unsigned int prec = TYPE_PRECISION (TREE_TYPE (rhs1)); + unsigned int cnt = CEIL (prec, limb_prec); + tree r1 = handle_operand (rhs1, size_int (bitint_big_endian + ? cnt - 1 : 0)); if (!useless_type_conversion_p (lhs_type, TREE_TYPE (r1))) r1 = add_cast (lhs_type, r1); if (TYPE_PRECISION (lhs_type) > limb_prec) { m_data_cnt = 0; m_first = false; - tree r2 = handle_operand (rhs1, size_int (1)); + tree r2 = handle_operand (rhs1, size_int (bitint_big_endian + ? cnt - 2 : 1)); r2 = add_cast (lhs_type, r2); g = gimple_build_assign (make_ssa_name (lhs_type), LSHIFT_EXPR, r2, build_int_cst (unsigned_type_node, @@ -5867,7 +6368,8 @@ bitint_dom_walker::before_dom_children (basic_block bb) tree fld = TREE_OPERAND (rhs1, 1); /* For little-endian, we can allow as inputs bit-fields which start at a limb boundary. */ - if (DECL_OFFSET_ALIGN (fld) >= TYPE_ALIGN (TREE_TYPE (rhs1)) + if (!bitint_big_endian + && DECL_OFFSET_ALIGN (fld) >= TYPE_ALIGN (TREE_TYPE (rhs1)) && tree_fits_uhwi_p (DECL_FIELD_BIT_OFFSET (fld)) && (tree_to_uhwi (DECL_FIELD_BIT_OFFSET (fld)) % limb_prec) == 0) @@ -5969,9 +6471,106 @@ build_bitint_stmt_ssa_conflicts (gimple *stmt, live_track *live, } } } + else if (bitint_big_endian + && is_gimple_call (stmt) + && gimple_call_internal_p (stmt)) + switch (gimple_call_internal_fn (stmt)) + { + case IFN_ADD_OVERFLOW: + case IFN_SUB_OVERFLOW: + case IFN_UBSAN_CHECK_ADD: + case IFN_UBSAN_CHECK_SUB: + case IFN_MUL_OVERFLOW: + case IFN_UBSAN_CHECK_MUL: + lhs = gimple_call_lhs (stmt); + if (lhs) + muldiv_p = true; + break; + default: + break; + } + auto_vec<tree, 16> worklist; ssa_op_iter iter; tree var; + /* On little-endian, mergeable ops process limbs from 0 up so except + for multiplication/division/modulo there is no risk in using the + same underlying variable for lhs and some operand, even when casts + are involved, the lhs limb is stored only after processing the source + limbs with the same index. + For multiplication/division/modulo, the libgcc library function requires + no aliasing between result and sources. + On big-endian, even mergeable ops limb processing can be problematic + though, because it can apply various index corrections e.g. when there + is a cast from operand with different number of limbs. So, make the + lhs conflict with all the operands which are (for now virtually) used on + the current stmt if there is any mismatch in the number of limbs between + operands and the lhs. */ + if (bitint_big_endian && lhs && !muldiv_p) + { + tree ltype = TREE_TYPE (lhs); + if (TREE_CODE (ltype) == COMPLEX_TYPE) + muldiv_p = true; + else if (TREE_CODE (lhs) == SSA_NAME + && TREE_CODE (ltype) == BITINT_TYPE + && bitint_precision_kind (ltype) >= bitint_prec_large) + { + unsigned lnelts = CEIL (TYPE_PRECISION (ltype), limb_prec); + FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE) + { + tree type = TREE_TYPE (var); + if (TREE_CODE (type) == COMPLEX_TYPE) + type = TREE_TYPE (type); + if (TREE_CODE (type) == BITINT_TYPE + && bitint_precision_kind (type) >= bitint_prec_large) + { + if (bitmap_bit_p (names, SSA_NAME_VERSION (var))) + { + unsigned nelts = CEIL (TYPE_PRECISION (type), limb_prec); + if (TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE + || lnelts != nelts) + { + muldiv_p = true; + break; + } + } + else + worklist.safe_push (var); + } + } + + while (!muldiv_p && worklist.length () > 0) + { + tree s = worklist.pop (); + FOR_EACH_SSA_TREE_OPERAND (var, SSA_NAME_DEF_STMT (s), iter, + SSA_OP_USE) + { + tree type = TREE_TYPE (var); + if (TREE_CODE (type) == COMPLEX_TYPE) + type = TREE_TYPE (type); + if (TREE_CODE (type) == BITINT_TYPE + && bitint_precision_kind (type) >= bitint_prec_large) + { + if (bitmap_bit_p (names, SSA_NAME_VERSION (var))) + { + unsigned nelts = CEIL (TYPE_PRECISION (type), + limb_prec); + if (TREE_CODE (TREE_TYPE (var)) == COMPLEX_TYPE + || lnelts != nelts) + { + muldiv_p = true; + break; + } + } + else + worklist.safe_push (var); + } + } + } + worklist.truncate (0); + } + } + if (!muldiv_p) { /* For stmts with more than one SSA_NAME definition pretend all the @@ -5995,7 +6594,6 @@ build_bitint_stmt_ssa_conflicts (gimple *stmt, live_track *live, def (live, var, graph); } - auto_vec<tree, 16> worklist; FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE) { tree type = TREE_TYPE (var); @@ -6072,6 +6670,7 @@ gimple_lower_bitint (void) { small_max_prec = mid_min_prec = large_min_prec = huge_min_prec = 0; limb_prec = 0; + bitint_big_endian = false; unsigned int i; for (i = 0; i < num_ssa_names; ++i) @@ -7056,9 +7655,25 @@ gimple_lower_bitint (void) break; } if (TREE_CODE (TREE_TYPE (c)) == INTEGER_TYPE) - g = gimple_build_assign (build1 (VIEW_CONVERT_EXPR, - TREE_TYPE (c), v1), - c); + { + if (bitint_big_endian) + { + tree ptype = build_pointer_type (TREE_TYPE (v1)); + tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (v1)); + tree sz2 = TYPE_SIZE_UNIT (TREE_TYPE (c)); + tree off = build_int_cst (ptype, + tree_to_uhwi (sz1) + - tree_to_uhwi (sz2)); + tree vd = build2 (MEM_REF, TREE_TYPE (c), + build_fold_addr_expr (v1), + off); + g = gimple_build_assign (vd, c); + } + else + g = gimple_build_assign (build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (c), + v1), c); + } else { unsigned HOST_WIDE_INT nelts @@ -7067,8 +7682,21 @@ gimple_lower_bitint (void) tree vtype = build_array_type_nelts (large_huge.m_limb_type, nelts); - g = gimple_build_assign (build1 (VIEW_CONVERT_EXPR, - vtype, v1), + tree vd; + if (bitint_big_endian) + { + tree ptype = build_pointer_type (TREE_TYPE (v1)); + tree sz1 = TYPE_SIZE_UNIT (TREE_TYPE (v1)); + tree sz2 = TYPE_SIZE_UNIT (vtype); + tree off = build_int_cst (ptype, + tree_to_uhwi (sz1) + - tree_to_uhwi (sz2)); + vd = build2 (MEM_REF, vtype, + build_fold_addr_expr (v1), off); + } + else + vd = build1 (VIEW_CONVERT_EXPR, vtype, v1); + g = gimple_build_assign (vd, build1 (VIEW_CONVERT_EXPR, vtype, c)); } @@ -7084,7 +7712,7 @@ gimple_lower_bitint (void) nelts); tree ptype = build_pointer_type (TREE_TYPE (v1)); tree off; - if (c) + if (c && !bitint_big_endian) off = fold_convert (ptype, TYPE_SIZE_UNIT (TREE_TYPE (c))); else @@ -7096,7 +7724,7 @@ gimple_lower_bitint (void) else { tree vd = v1; - if (c) + if (c && !bitint_big_endian) { tree ptype = build_pointer_type (TREE_TYPE (v1)); tree off |