From: Richard Sandiford Date: Mon, 2 May 2016 09:39:09 +0000 (+0000) Subject: Support <, <=, > and >= for offset_int and widest_int X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=032c80e999eac4288ff1b0f752e15c8e7c5cdf51;p=gcc.git Support <, <=, > and >= for offset_int and widest_int offset_int and widest_int are supposed to be at least one bit wider than all the values they need to represent, with the extra bits being signs. Thus offset_int is effectively int128_t and widest_int is effectively intNNN_t, for target-dependent NNN. Because the types are signed, there's not really any need to specify a sign for operations like comparison. I think things would be clearer if we supported <, <=, > and >= for them (but not for wide_int, which doesn't have a sign). Tested on x86_64-linux-gnu and aarch64-linux-gnu. gcc/ * wide-int.h: Update offset_int and widest_int documentation. (WI_SIGNED_BINARY_PREDICATE_RESULT): New macro. (wi::binary_traits): Allow ordered comparisons between offset_int and offset_int, between widest_int and widest_int, and between either of these types and basic C types. (operator <, <=, >, >=): Define for the same combinations. * tree.h (tree_int_cst_lt): Use comparison operators instead of wi:: comparisons. (tree_int_cst_le): Likewise. * gimple-fold.c (fold_array_ctor_reference): Likewise. (fold_nonarray_ctor_reference): Likewise. * gimple-ssa-strength-reduction.c (record_increment): Likewise. * tree-affine.c (aff_comb_cannot_overlap_p): Likewise. * tree-parloops.c (try_transform_to_exit_first_loop_alt): Likewise. * tree-sra.c (completely_scalarize): Likewise. * tree-ssa-alias.c (stmt_kills_ref_p): Likewise. * tree-ssa-reassoc.c (extract_bit_test_mask): Likewise. * tree-vrp.c (extract_range_from_binary_expr_1): Likewise. (check_for_binary_op_overflow): Likewise. (search_for_addr_array): Likewise. * ubsan.c (ubsan_expand_objsize_ifn): Likewise. From-SVN: r235719 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3edd2aaaf5..acc6b798eee 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2016-05-02 Richard Sandiford + + * wide-int.h: Update offset_int and widest_int documentation. + (WI_SIGNED_BINARY_PREDICATE_RESULT): New macro. + (wi::binary_traits): Allow ordered comparisons between offset_int and + offset_int, between widest_int and widest_int, and between either + of these types and basic C types. + (operator <, <=, >, >=): Define for the same combinations. + * tree.h (tree_int_cst_lt): Use comparison operators instead + of wi:: comparisons. + (tree_int_cst_le): Likewise. + * gimple-fold.c (fold_array_ctor_reference): Likewise. + (fold_nonarray_ctor_reference): Likewise. + * gimple-ssa-strength-reduction.c (record_increment): Likewise. + * tree-affine.c (aff_comb_cannot_overlap_p): Likewise. + * tree-parloops.c (try_transform_to_exit_first_loop_alt): Likewise. + * tree-sra.c (completely_scalarize): Likewise. + * tree-ssa-alias.c (stmt_kills_ref_p): Likewise. + * tree-ssa-reassoc.c (extract_bit_test_mask): Likewise. + * tree-vrp.c (extract_range_from_binary_expr_1): Likewise. + (check_for_binary_op_overflow): Likewise. + (search_for_addr_array): Likewise. + * ubsan.c (ubsan_expand_objsize_ifn): Likewise. + 2016-05-02 Claudiu Zissulescu * config/arc/arc.c (arc_preferred_simd_mode): Remove enum keyword. diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 6cd0a4b8f53..6ed72dc5883 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -5380,7 +5380,7 @@ fold_array_ctor_reference (tree type, tree ctor, be larger than size of array element. */ if (!TYPE_SIZE_UNIT (type) || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || wi::lts_p (elt_size, wi::to_offset (TYPE_SIZE_UNIT (type))) + || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)) || elt_size == 0) return NULL_TREE; @@ -5457,7 +5457,7 @@ fold_nonarray_ctor_reference (tree type, tree ctor, fields. */ if (wi::cmps (access_end, bitoffset_end) > 0) return NULL_TREE; - if (wi::lts_p (offset, bitoffset)) + if (offset < bitoffset) return NULL_TREE; return fold_ctor_reference (type, cval, inner_offset.to_uhwi (), size, diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c index 46ee7a75b76..b2351511fe0 100644 --- a/gcc/gimple-ssa-strength-reduction.c +++ b/gcc/gimple-ssa-strength-reduction.c @@ -2506,8 +2506,7 @@ record_increment (slsr_cand_t c, widest_int increment, bool is_phi_adjust) if (c->kind == CAND_ADD && !is_phi_adjust && c->index == increment - && (wi::gts_p (increment, 1) - || wi::lts_p (increment, -1)) + && (increment > 1 || increment < -1) && (gimple_assign_rhs_code (c->cand_stmt) == PLUS_EXPR || gimple_assign_rhs_code (c->cand_stmt) == POINTER_PLUS_EXPR)) { diff --git a/gcc/tree-affine.c b/gcc/tree-affine.c index 4251a5b606d..32f23013374 100644 --- a/gcc/tree-affine.c +++ b/gcc/tree-affine.c @@ -929,7 +929,7 @@ aff_comb_cannot_overlap_p (aff_tree *diff, const widest_int &size1, else { /* We succeed if the second object starts after the first one ends. */ - return wi::les_p (size1, diff->offset); + return size1 <= diff->offset; } } diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c index 2e55b7961d8..25a29bdcb28 100644 --- a/gcc/tree-parloops.c +++ b/gcc/tree-parloops.c @@ -1868,7 +1868,7 @@ try_transform_to_exit_first_loop_alt (struct loop *loop, /* Check if nit + 1 overflows. */ widest_int type_max = wi::to_widest (TYPE_MAXVAL (nit_type)); - if (!wi::lts_p (nit_max, type_max)) + if (nit_max >= type_max) return false; gimple *def = SSA_NAME_DEF_STMT (nit); diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 6fafe559cf2..936d3a6bfcf 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -1055,7 +1055,7 @@ completely_scalarize (tree base, tree decl_type, HOST_WIDE_INT offset, tree ref) idx = wi::sext (idx, TYPE_PRECISION (domain)); max = wi::sext (max, TYPE_PRECISION (domain)); } - for (int el_off = offset; wi::les_p (idx, max); ++idx) + for (int el_off = offset; idx <= max; ++idx) { tree nref = build4 (ARRAY_REF, elemtype, ref, diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index f801b013092..4ffefaf3f4f 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2440,10 +2440,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) rbase = TREE_OPERAND (rbase, 0); } if (base == rbase - && wi::les_p (offset, roffset) - && wi::les_p (roffset + ref->max_size, - offset + wi::lshift (wi::to_offset (len), - LOG2_BITS_PER_UNIT))) + && offset <= roffset + && (roffset + ref->max_size + <= offset + wi::lshift (wi::to_offset (len), + LOG2_BITS_PER_UNIT))) return true; break; } diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index d23dabde7b6..740897756bd 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -2464,7 +2464,7 @@ extract_bit_test_mask (tree exp, int prec, tree totallow, tree low, tree high, return NULL_TREE; bias = wi::to_widest (tbias); bias -= wi::to_widest (totallow); - if (wi::ges_p (bias, 0) && wi::lts_p (bias, prec - max)) + if (bias >= 0 && bias < prec - max) { *mask = wi::lshift (*mask, bias); return ret; diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c index 3cb470bef65..4cd1ab30b30 100644 --- a/gcc/tree-vrp.c +++ b/gcc/tree-vrp.c @@ -2749,17 +2749,17 @@ extract_range_from_binary_expr_1 (value_range *vr, /* Sort the 4 products so that min is in prod0 and max is in prod3. */ /* min0min1 > max0max1 */ - if (wi::gts_p (prod0, prod3)) + if (prod0 > prod3) std::swap (prod0, prod3); /* min0max1 > max0min1 */ - if (wi::gts_p (prod1, prod2)) + if (prod1 > prod2) std::swap (prod1, prod2); - if (wi::gts_p (prod0, prod1)) + if (prod0 > prod1) std::swap (prod0, prod1); - if (wi::gts_p (prod2, prod3)) + if (prod2 > prod3) std::swap (prod2, prod3); /* diff = max - min. */ @@ -3775,7 +3775,7 @@ check_for_binary_op_overflow (enum tree_code subcode, tree type, /* If all values in [wmin, wmax] are smaller than [wtmin, wtmax] or all are larger than [wtmin, wtmax], the arithmetic operation will always overflow. */ - if (wi::lts_p (wmax, wtmin) || wi::gts_p (wmin, wtmax)) + if (wmax < wtmin || wmin > wtmax) return true; return false; } @@ -6587,7 +6587,7 @@ search_for_addr_array (tree t, location_t location) idx = mem_ref_offset (t); idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz)); - if (wi::lts_p (idx, 0)) + if (idx < 0) { if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -6599,8 +6599,8 @@ search_for_addr_array (tree t, location_t location) "array subscript is below array bounds"); TREE_NO_WARNING (t) = 1; } - else if (wi::gts_p (idx, (wi::to_offset (up_bound) - - wi::to_offset (low_bound) + 1))) + else if (idx > (wi::to_offset (up_bound) + - wi::to_offset (low_bound) + 1)) { if (dump_file && (dump_flags & TDF_DETAILS)) { diff --git a/gcc/tree.h b/gcc/tree.h index 259a2bff688..aa76f50bab5 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5318,7 +5318,7 @@ wi::max_value (const_tree type) inline bool tree_int_cst_lt (const_tree t1, const_tree t2) { - return wi::lts_p (wi::to_widest (t1), wi::to_widest (t2)); + return wi::to_widest (t1) < wi::to_widest (t2); } /* Return true if INTEGER_CST T1 is less than or equal to INTEGER_CST T2, @@ -5327,7 +5327,7 @@ tree_int_cst_lt (const_tree t1, const_tree t2) inline bool tree_int_cst_le (const_tree t1, const_tree t2) { - return wi::les_p (wi::to_widest (t1), wi::to_widest (t2)); + return wi::to_widest (t1) <= wi::to_widest (t2); } /* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2. T1 and T2 diff --git a/gcc/ubsan.c b/gcc/ubsan.c index d3fbfd177e6..802341e9995 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -911,8 +911,8 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi) /* Yes, __builtin_object_size couldn't determine the object size. */; else if (TREE_CODE (offset) == INTEGER_CST - && wi::ges_p (wi::to_widest (offset), -OBJSZ_MAX_OFFSET) - && wi::les_p (wi::to_widest (offset), -1)) + && wi::to_widest (offset) >= -OBJSZ_MAX_OFFSET + && wi::to_widest (offset) <= -1) /* The offset is in range [-16K, -1]. */; else { @@ -928,8 +928,8 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi) /* If the offset is small enough, we don't need the second run-time check. */ if (TREE_CODE (offset) == INTEGER_CST - && wi::ges_p (wi::to_widest (offset), 0) - && wi::les_p (wi::to_widest (offset), OBJSZ_MAX_OFFSET)) + && wi::to_widest (offset) >= 0 + && wi::to_widest (offset) <= OBJSZ_MAX_OFFSET) *gsi = gsi_after_labels (then_bb); else { diff --git a/gcc/wide-int.h b/gcc/wide-int.h index fa133f0561a..b1dfcff6ad1 100644 --- a/gcc/wide-int.h +++ b/gcc/wide-int.h @@ -53,22 +53,26 @@ along with GCC; see the file COPYING3. If not see multiply, division, shifts, comparisons, and operations that need overflow detected), the signedness must be specified separately. - 2) offset_int. This is a fixed size representation that is - guaranteed to be large enough to compute any bit or byte sized - address calculation on the target. Currently the value is 64 + 4 - bits rounded up to the next number even multiple of - HOST_BITS_PER_WIDE_INT (but this can be changed when the first - port needs more than 64 bits for the size of a pointer). - - This flavor can be used for all address math on the target. In - this representation, the values are sign or zero extended based - on their input types to the internal precision. All math is done - in this precision and then the values are truncated to fit in the - result type. Unlike most gimple or rtl intermediate code, it is - not useful to perform the address arithmetic at the same - precision in which the operands are represented because there has - been no effort by the front ends to convert most addressing - arithmetic to canonical types. + 2) offset_int. This is a fixed-precision integer that can hold + any address offset, measured in either bits or bytes, with at + least one extra sign bit. At the moment the maximum address + size GCC supports is 64 bits. With 8-bit bytes and an extra + sign bit, offset_int therefore needs to have at least 68 bits + of precision. We round this up to 128 bits for efficiency. + Values of type T are converted to this precision by sign- or + zero-extending them based on the signedness of T. + + The extra sign bit means that offset_int is effectively a signed + 128-bit integer, i.e. it behaves like int128_t. + + Since the values are logically signed, there is no need to + distinguish between signed and unsigned operations. Sign-sensitive + comparison operators <, <=, > and >= are therefore supported. + + [ Note that, even though offset_int is effectively int128_t, + it can still be useful to use unsigned comparisons like + wi::leu_p (a, b) as a more efficient short-hand for + "a >= 0 && a <= b". ] 3) widest_int. This representation is an approximation of infinite precision math. However, it is not really infinite @@ -76,9 +80,9 @@ along with GCC; see the file COPYING3. If not see precision math where the precision is 4 times the size of the largest integer that the target port can represent. - widest_int is supposed to be wider than any number that it needs to - store, meaning that there is always at least one leading sign bit. - All widest_int values are therefore signed. + Like offset_int, widest_int is wider than all the values that + it needs to represent, so the integers are logically signed. + Sign-sensitive comparison operators <, <=, > and >= are supported. There are several places in the GCC where this should/must be used: @@ -255,6 +259,12 @@ along with GCC; see the file COPYING3. If not see #define WI_BINARY_RESULT(T1, T2) \ typename wi::binary_traits ::result_type +/* The type of result produced by a signed binary predicate on types T1 and T2. + This is bool if signed comparisons make sense for T1 and T2 and leads to + substitution failure otherwise. */ +#define WI_SIGNED_BINARY_PREDICATE_RESULT(T1, T2) \ + typename wi::binary_traits ::signed_predicate_result + /* The type of result produced by a unary operation on type T. */ #define WI_UNARY_RESULT(T) \ typename wi::unary_traits ::result_type @@ -316,7 +326,7 @@ namespace wi VAR_PRECISION, /* The integer has a constant precision (known at GCC compile time) - but no defined signedness. */ + and is signed. */ CONST_PRECISION }; @@ -379,6 +389,7 @@ namespace wi so as not to confuse gengtype. */ typedef generic_wide_int < fixed_wide_int_storage ::precision> > result_type; + typedef bool signed_predicate_result; }; template @@ -394,6 +405,7 @@ namespace wi so as not to confuse gengtype. */ typedef generic_wide_int < fixed_wide_int_storage ::precision> > result_type; + typedef bool signed_predicate_result; }; template @@ -404,6 +416,7 @@ namespace wi STATIC_ASSERT (int_traits ::precision == int_traits ::precision); typedef generic_wide_int < fixed_wide_int_storage ::precision> > result_type; + typedef bool signed_predicate_result; }; template @@ -3050,6 +3063,21 @@ wi::min_precision (const T &x, signop sgn) return get_precision (x) - clz (x); } +#define SIGNED_BINARY_PREDICATE(OP, F) \ + template \ + inline WI_SIGNED_BINARY_PREDICATE_RESULT (T1, T2) \ + OP (const T1 &x, const T2 &y) \ + { \ + return wi::F (x, y); \ + } + +SIGNED_BINARY_PREDICATE (operator <, lts_p) +SIGNED_BINARY_PREDICATE (operator <=, les_p) +SIGNED_BINARY_PREDICATE (operator >, gts_p) +SIGNED_BINARY_PREDICATE (operator >=, ges_p) + +#undef SIGNED_BINARY_PREDICATE + template void gt_ggc_mx (generic_wide_int *)