|
| STATIC_ASSERT (WIDE_INT_MAX_INL_ELTS< WIDE_INT_MAX_ELTS) |
|
typedef | FIXED_WIDE_INT (ADDR_MAX_PRECISION) offset_int |
|
template<typename T > |
unsigned int | wi::get_precision (const T &) |
|
template<typename T1 , typename T2 > |
unsigned int | wi::get_binary_precision (const T1 &, const T2 &) |
|
template<typename T1 , typename T2 > |
void | wi::copy (T1 &, const T2 &) |
|
UNARY_PREDICATE | wi::fits_shwi_p (const T &) |
|
UNARY_PREDICATE | wi::fits_uhwi_p (const T &) |
|
UNARY_PREDICATE | wi::neg_p (const T &, signop=SIGNED) |
|
template<typename T > |
HOST_WIDE_INT | wi::sign_mask (const T &) |
|
BINARY_PREDICATE | wi::eq_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::ne_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::lt_p (const T1 &, const T2 &, signop) |
|
BINARY_PREDICATE | wi::lts_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::ltu_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::le_p (const T1 &, const T2 &, signop) |
|
BINARY_PREDICATE | wi::les_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::leu_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::gt_p (const T1 &, const T2 &, signop) |
|
BINARY_PREDICATE | wi::gts_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::gtu_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::ge_p (const T1 &, const T2 &, signop) |
|
BINARY_PREDICATE | wi::ges_p (const T1 &, const T2 &) |
|
BINARY_PREDICATE | wi::geu_p (const T1 &, const T2 &) |
|
template<typename T1 , typename T2 > |
int | wi::cmp (const T1 &, const T2 &, signop) |
|
template<typename T1 , typename T2 > |
int | wi::cmps (const T1 &, const T2 &) |
|
template<typename T1 , typename T2 > |
int | wi::cmpu (const T1 &, const T2 &) |
|
UNARY_FUNCTION | wi::bit_not (const T &) |
|
UNARY_FUNCTION | wi::neg (const T &) |
|
UNARY_FUNCTION | wi::neg (const T &, overflow_type *) |
|
UNARY_FUNCTION | wi::abs (const T &) |
|
UNARY_FUNCTION | wi::ext (const T &, unsigned int, signop) |
|
UNARY_FUNCTION | wi::sext (const T &, unsigned int) |
|
UNARY_FUNCTION | wi::zext (const T &, unsigned int) |
|
UNARY_FUNCTION | wi::set_bit (const T &, unsigned int) |
|
UNARY_FUNCTION | wi::bswap (const T &) |
|
UNARY_FUNCTION | wi::bitreverse (const T &) |
|
BINARY_FUNCTION | wi::min (const T1 &, const T2 &, signop) |
|
BINARY_FUNCTION | wi::smin (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::umin (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::max (const T1 &, const T2 &, signop) |
|
BINARY_FUNCTION | wi::smax (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::umax (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::bit_and (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::bit_and_not (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::bit_or (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::bit_or_not (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::bit_xor (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::add (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::add (const T1 &, const T2 &, signop, overflow_type *) |
|
BINARY_FUNCTION | wi::sub (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::sub (const T1 &, const T2 &, signop, overflow_type *) |
|
BINARY_FUNCTION | wi::mul (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::mul (const T1 &, const T2 &, signop, overflow_type *) |
|
BINARY_FUNCTION | wi::smul (const T1 &, const T2 &, overflow_type *) |
|
BINARY_FUNCTION | wi::umul (const T1 &, const T2 &, overflow_type *) |
|
BINARY_FUNCTION | wi::mul_high (const T1 &, const T2 &, signop) |
|
BINARY_FUNCTION | wi::div_trunc (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::sdiv_trunc (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::udiv_trunc (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::div_floor (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::udiv_floor (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::sdiv_floor (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::div_ceil (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::udiv_ceil (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::div_round (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::divmod_trunc (const T1 &, const T2 &, signop, WI_BINARY_RESULT(T1, T2) *) |
|
BINARY_FUNCTION | wi::gcd (const T1 &, const T2 &, signop=UNSIGNED) |
|
BINARY_FUNCTION | wi::mod_trunc (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::smod_trunc (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::umod_trunc (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::mod_floor (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::umod_floor (const T1 &, const T2 &) |
|
BINARY_FUNCTION | wi::mod_ceil (const T1 &, const T2 &, signop, overflow_type *=0) |
|
BINARY_FUNCTION | wi::mod_round (const T1 &, const T2 &, signop, overflow_type *=0) |
|
template<typename T1 , typename T2 > |
bool | wi::multiple_of_p (const T1 &, const T2 &, signop) |
|
template<typename T1 , typename T2 > |
bool | wi::multiple_of_p (const T1 &, const T2 &, signop, WI_BINARY_RESULT(T1, T2) *) |
|
SHIFT_FUNCTION | wi::lshift (const T1 &, const T2 &) |
|
SHIFT_FUNCTION | wi::lrshift (const T1 &, const T2 &) |
|
SHIFT_FUNCTION | wi::arshift (const T1 &, const T2 &) |
|
SHIFT_FUNCTION | wi::rshift (const T1 &, const T2 &, signop sgn) |
|
SHIFT_FUNCTION | wi::lrotate (const T1 &, const T2 &, unsigned int=0) |
|
SHIFT_FUNCTION | wi::rrotate (const T1 &, const T2 &, unsigned int=0) |
|
bool | wi::only_sign_bit_p (const wide_int_ref &, unsigned int) |
|
bool | wi::only_sign_bit_p (const wide_int_ref &) |
|
int | wi::clz (const wide_int_ref &) |
|
int | wi::clrsb (const wide_int_ref &) |
|
int | wi::ctz (const wide_int_ref &) |
|
int | wi::exact_log2 (const wide_int_ref &) |
|
int | wi::floor_log2 (const wide_int_ref &) |
|
int | wi::ffs (const wide_int_ref &) |
|
int | wi::popcount (const wide_int_ref &) |
|
int | wi::parity (const wide_int_ref &) |
|
template<typename T > |
unsigned HOST_WIDE_INT | wi::extract_uhwi (const T &, unsigned int, unsigned int) |
|
template<typename T > |
unsigned int | wi::min_precision (const T &, signop) |
|
static void | wi::accumulate_overflow (overflow_type &, overflow_type) |
|
unsigned int | wi::force_to_size (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int, signop sgn) |
|
unsigned int | wi::from_array (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, bool=true) |
|
template<int N> |
| FIXED_WIDE_INT (N) fixed_wide_int_storage< N > |
|
template<typename T1 , typename T2 > |
| FIXED_WIDE_INT (N) wi |
|
template<int N> |
| WIDEST_INT (N) widest_int_storage< N > |
|
template<typename T1 , typename T2 > |
| WIDEST_INT (N) wi |
|
hwi_with_prec | wi::shwi (HOST_WIDE_INT, unsigned int) |
|
hwi_with_prec | wi::uhwi (unsigned HOST_WIDE_INT, unsigned int) |
|
hwi_with_prec | wi::minus_one (unsigned int) |
|
hwi_with_prec | wi::zero (unsigned int) |
|
hwi_with_prec | wi::one (unsigned int) |
|
hwi_with_prec | wi::two (unsigned int) |
|
bool | wi::eq_p_large (const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
bool | wi::lts_p_large (const HOST_WIDE_INT *, unsigned int, unsigned int, const HOST_WIDE_INT *, unsigned int) |
|
bool | wi::ltu_p_large (const HOST_WIDE_INT *, unsigned int, unsigned int, const HOST_WIDE_INT *, unsigned int) |
|
int | wi::cmps_large (const HOST_WIDE_INT *, unsigned int, unsigned int, const HOST_WIDE_INT *, unsigned int) |
|
int | wi::cmpu_large (const HOST_WIDE_INT *, unsigned int, unsigned int, const HOST_WIDE_INT *, unsigned int) |
|
unsigned int | wi::sext_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::zext_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::set_bit_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::bswap_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::bitreverse_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::lshift_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::lrshift_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::arshift_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, unsigned int, unsigned int) |
|
unsigned int | wi::and_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::and_not_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::or_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::or_not_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::xor_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int) |
|
unsigned int | wi::add_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int, signop, overflow_type *) |
|
unsigned int | wi::sub_large (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int, signop, overflow_type *) |
|
unsigned int | wi::mul_internal (HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int, signop, overflow_type *, bool) |
|
unsigned int | wi::divmod_internal (HOST_WIDE_INT *, unsigned int *, HOST_WIDE_INT *, const HOST_WIDE_INT *, unsigned int, unsigned int, const HOST_WIDE_INT *, unsigned int, unsigned int, signop, overflow_type *) |
|
template<typename T > |
| WI_UNARY_RESULT (T) wi |
|
template<typename T1 , typename T2 > |
| WI_BINARY_RESULT (T1, T2) wi |
|
template<typename T1 , typename T2 > |
| WI_UNARY_RESULT (T1) wi |
|
template<typename T1 , typename T2 > |
| WI_SIGNED_SHIFT_RESULT (T1, T2) operator>>(const T1 &x |
|
void | gt_ggc_mx (generic_wide_int< wide_int_storage > *)=delete |
|
void | gt_pch_nx (generic_wide_int< wide_int_storage > *)=delete |
|
void | gt_pch_nx (generic_wide_int< wide_int_storage > *, gt_pointer_operator, void *)=delete |
|
template<int N> |
void | gt_ggc_mx (generic_wide_int< fixed_wide_int_storage< N > > *) |
|
template<int N> |
void | gt_pch_nx (generic_wide_int< fixed_wide_int_storage< N > > *) |
|
template<int N> |
void | gt_pch_nx (generic_wide_int< fixed_wide_int_storage< N > > *, gt_pointer_operator, void *) |
|
template<int N> |
void | gt_ggc_mx (generic_wide_int< widest_int_storage< N > > *)=delete |
|
template<int N> |
void | gt_pch_nx (generic_wide_int< widest_int_storage< N > > *)=delete |
|
template<int N> |
void | gt_pch_nx (generic_wide_int< widest_int_storage< N > > *, gt_pointer_operator, void *)=delete |
|
template<int N> |
void | gt_ggc_mx (trailing_wide_ints< N > *) |
|
template<int N> |
void | gt_pch_nx (trailing_wide_ints< N > *) |
|
template<int N> |
void | gt_pch_nx (trailing_wide_ints< N > *, gt_pointer_operator, void *) |
|
wide_int | wi::min_value (unsigned int, signop) |
|
wide_int | wi::min_value (never_used1 *) |
|
wide_int | wi::min_value (never_used2 *) |
|
wide_int | wi::max_value (unsigned int, signop) |
|
wide_int | wi::max_value (never_used1 *) |
|
wide_int | wi::max_value (never_used2 *) |
|
wide_int | wi::from_buffer (const unsigned char *, unsigned int) |
|
void | wi::to_mpz (const wide_int_ref &, mpz_t, signop) |
|
wide_int | wi::mask (unsigned int, bool, unsigned int) |
|
wide_int | wi::shifted_mask (unsigned int, unsigned int, bool, unsigned int) |
|
wide_int | wi::set_bit_in_zero (unsigned int, unsigned int) |
|
wide_int | wi::insert (const wide_int &x, const wide_int &y, unsigned int, unsigned int) |
|
wide_int | wi::round_down_for_mask (const wide_int &, const wide_int &) |
|
wide_int | wi::round_up_for_mask (const wide_int &, const wide_int &) |
|
wide_int | wi::mod_inv (const wide_int &a, const wide_int &b) |
|
template<typename T > |
T | wi::mask (unsigned int, bool) |
|
template<typename T > |
T | wi::shifted_mask (unsigned int, unsigned int, bool) |
|
template<typename T > |
T | wi::set_bit_in_zero (unsigned int) |
|
unsigned int | wi::mask (HOST_WIDE_INT *, unsigned int, bool, unsigned int) |
|
unsigned int | wi::shifted_mask (HOST_WIDE_INT *, unsigned int, unsigned int, bool, unsigned int) |
|
#define WIDE_INT_MAX_INL_ELTS |
Value:Operations with very long integers. -*- C++ -*-
Copyright (C) 2012-2024 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>.
wide-int.[cc|h] implements a class that efficiently performs
mathematical operations on finite precision integers. wide_ints
are designed to be transient - they are not for long term storage
of values. There is tight integration between wide_ints and the
other longer storage GCC representations (rtl and tree).
The actual precision of a wide_int depends on the flavor. There
are three predefined flavors:
1) wide_int (the default). This flavor does the math in the
precision of its input arguments. It is assumed (and checked)
that the precisions of the operands and results are consistent.
This is the most efficient flavor. It is not possible to examine
bits above the precision that has been specified. Because of
this, the default flavor has semantics that are simple to
understand and in general model the underlying hardware that the
compiler is targetted for.
This flavor must be used at the RTL level of gcc because there
is, in general, not enough information in the RTL representation
to extend a value beyond the precision specified in the mode.
This flavor should also be used at the TREE and GIMPLE levels of
the compiler except for the circumstances described in the
descriptions of the other two flavors.
The default wide_int representation does not contain any
information inherent about signedness of the represented value,
so it can be used to represent both signed and unsigned numbers.
For operations where the results depend on signedness (full width
multiply, division, shifts, comparisons, and operations that need
overflow detected), the signedness must be specified separately.
For precisions up to WIDE_INT_MAX_INL_PRECISION, it uses an inline
buffer in the type, for larger precisions up to WIDEST_INT_MAX_PRECISION
it uses a pointer to heap allocated buffer.
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.
Shift operators << and >> are also supported, with >> being
an _arithmetic_ right shift.
[ 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
precision math as in the GMP library. It is really finite
precision math where the precision is WIDEST_INT_MAX_PRECISION.
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,
as are << and >>.
There are several places in the GCC where this should/must be used:
* Code that does induction variable optimizations. This code
works with induction variables of many different types at the
same time. Because of this, it ends up doing many different
calculations where the operands are not compatible types. The
widest_int makes this easy, because it provides a field where
nothing is lost when converting from any variable,
* There are a small number of passes that currently use the
widest_int that should use the default. These should be
changed.
There are surprising features of offset_int and widest_int
that the users should be careful about:
1) Shifts and rotations are just weird. You have to specify a
precision in which the shift or rotate is to happen in. The bits
above this precision are zeroed. While this is what you
want, it is clearly non obvious.
2) Larger precision math sometimes does not produce the same
answer as would be expected for doing the math at the proper
precision. In particular, a multiply followed by a divide will
produce a different answer if the first product is larger than
what can be represented in the input precision.
The offset_int and the widest_int flavors are more expensive
than the default wide int, so in addition to the caveats with these
two, the default is the prefered representation.
All three flavors of wide_int are represented as a vector of
HOST_WIDE_INTs. The default and widest_int vectors contain enough elements
to hold a value of MAX_BITSIZE_MODE_ANY_INT bits. offset_int contains only
enough elements to hold ADDR_MAX_PRECISION bits. The values are stored
in the vector with the least significant HOST_BITS_PER_WIDE_INT bits
in element 0.
The default wide_int contains three fields: the vector (VAL),
the precision and a length (LEN). The length is the number of HWIs
needed to represent the value. widest_int and offset_int have a
constant precision that cannot be changed, so they only store the
VAL and LEN fields.
Since most integers used in a compiler are small values, it is
generally profitable to use a representation of the value that is
as small as possible. LEN is used to indicate the number of
elements of the vector that are in use. The numbers are stored as
sign extended numbers as a means of compression. Leading
HOST_WIDE_INTs that contain strings of either -1 or 0 are removed
as long as they can be reconstructed from the top bit that is being
represented.
The precision and length of a wide_int are always greater than 0.
Any bits in a wide_int above the precision are sign-extended from the
most significant bit. For example, a 4-bit value 0x8 is represented as
VAL = { 0xf...fff8 }. However, as an optimization, we allow other integer
constants to be represented with undefined bits above the precision.
This allows INTEGER_CSTs to be pre-extended according to TYPE_SIGN,
so that the INTEGER_CST representation can be used both in TYPE_PRECISION
and in wider precisions.
There are constructors to create the various forms of wide_int from
trees, rtl and constants. For trees the options are:
tree t = ...;
wi::to_wide (t) // Treat T as a wide_int
wi::to_offset (t) // Treat T as an offset_int
wi::to_widest (t) // Treat T as a widest_int
All three are light-weight accessors that should have no overhead
in release builds. If it is useful for readability reasons to
store the result in a temporary variable, the preferred method is:
wi::tree_to_wide_ref twide = wi::to_wide (t);
wi::tree_to_offset_ref toffset = wi::to_offset (t);
wi::tree_to_widest_ref twidest = wi::to_widest (t);
To make an rtx into a wide_int, you have to pair it with a mode.
The canonical way to do this is with rtx_mode_t as in:
rtx r = ...
wide_int x = rtx_mode_t (r, mode);
Similarly, a wide_int can only be constructed from a host value if
the target precision is given explicitly, such as in:
wide_int x = wi::shwi (c, prec); // sign-extend C if necessary
wide_int y = wi::uhwi (c, prec); // zero-extend C if necessary
However, offset_int and widest_int have an inherent precision and so
can be initialized directly from a host value:
offset_int x = (int) c; // sign-extend C
widest_int x = (unsigned int) c; // zero-extend C
It is also possible to do arithmetic directly on rtx_mode_ts and
constants. For example:
wi::add (r1, r2); // add equal-sized rtx_mode_ts r1 and r2
wi::add (r1, 1); // add 1 to rtx_mode_t r1
wi::lshift (1, 100); // 1 << 100 as a widest_int
Many binary operations place restrictions on the combinations of inputs,
using the following rules:
- {rtx, wide_int} op {rtx, wide_int} -> wide_int
The inputs must be the same precision. The result is a wide_int
of the same precision
- {rtx, wide_int} op (un)signed HOST_WIDE_INT -> wide_int
(un)signed HOST_WIDE_INT op {rtx, wide_int} -> wide_int
The HOST_WIDE_INT is extended or truncated to the precision of
the other input. The result is a wide_int of the same precision
as that input.
- (un)signed HOST_WIDE_INT op (un)signed HOST_WIDE_INT -> widest_int
The inputs are extended to widest_int precision and produce a
widest_int result.
- offset_int op offset_int -> offset_int
offset_int op (un)signed HOST_WIDE_INT -> offset_int
(un)signed HOST_WIDE_INT op offset_int -> offset_int
- widest_int op widest_int -> widest_int
widest_int op (un)signed HOST_WIDE_INT -> widest_int
(un)signed HOST_WIDE_INT op widest_int -> widest_int
Other combinations like:
- widest_int op offset_int and
- wide_int op offset_int
are not allowed. The inputs should instead be extended or truncated
so that they match.
The inputs to comparison functions like wi::eq_p and wi::lts_p
follow the same compatibility rules, although their return types
are different. Unary functions on X produce the same result as
a binary operation X + X. Shift functions X op Y also produce
the same result as X + X; the precision of the shift amount Y
can be arbitrarily different from X.
The MAX_BITSIZE_MODE_ANY_INT is automatically generated by a very
early examination of the target's mode file. The WIDE_INT_MAX_INL_ELTS
can accomodate at least 1 more bit so that unsigned numbers of that
mode can be represented as a signed value. Note that it is still
possible to create fixed_wide_ints that have precisions greater than
MAX_BITSIZE_MODE_ANY_INT. This can be useful when representing a
double-width multiplication result, for example.
Referenced by build_replicated_int_cst(), pass_walloca::execute(), wi::from_mpz(), widest_int_storage< N >::get_val(), go_output_typedef(), lto_input_tree_1(), widest_int_storage< N >::operator=(), widest_int_storage< N >::operator=(), real_to_integer(), widest_int_storage< N >::set_len(), streamer_read_wide_int(), streamer_read_widest_int(), widest_int_storage< N >::widest_int_storage(), widest_int_storage< N >::write_val(), and widest_int_storage< N >::~widest_int_storage().
template<typename T1 , typename T2 >
WI_BINARY_RESULT |
( |
T1 | , |
|
|
T2 | ) |
|
inline |
Return the mininum of X and Y, treating them both as having
signedness SGN.
Return the minimum of X and Y, treating both as signed values.
Return the minimum of X and Y, treating both as unsigned values.
Return the maxinum of X and Y, treating them both as having
signedness SGN.
Return the maximum of X and Y, treating both as signed values.
Return the maximum of X and Y, treating both as unsigned values.
Return X & Y.
Return X & ~Y.
Return X | Y.
Return X | ~Y.
Return X ^ Y.
Return X + Y.
Return X + Y. Treat X and Y as having the signednes given by SGN
and indicate in *OVERFLOW whether the operation overflowed.
Return X - Y.
Return X - Y. Treat X and Y as having the signednes given by SGN
and indicate in *OVERFLOW whether the operation overflowed.
Return X * Y.
Return X * Y. Treat X and Y as having the signednes given by SGN
and indicate in *OVERFLOW whether the operation overflowed.
Return X * Y, treating both X and Y as signed values. Indicate in
*OVERFLOW whether the operation overflowed.
Return X * Y, treating both X and Y as unsigned values. Indicate in
*OVERFLOW if the result overflows.
Perform a widening multiplication of X and Y, extending the values
according to SGN, and return the high part of the result.
Return X / Y, rouding towards 0. Treat X and Y as having the
signedness given by SGN. Indicate in *OVERFLOW if the result
overflows.
Return X / Y, rouding towards 0. Treat X and Y as signed values.
Return X / Y, rouding towards 0. Treat X and Y as unsigned values.
Return X / Y, rouding towards -inf. Treat X and Y as having the
signedness given by SGN. Indicate in *OVERFLOW if the result
overflows.
Return X / Y, rouding towards -inf. Treat X and Y as signed values.
Return X / Y, rouding towards -inf. Treat X and Y as unsigned values.
??? Why do we have both this and udiv_trunc. Aren't they the same?
Return X / Y, rouding towards +inf. Treat X and Y as having the
signedness given by SGN. Indicate in *OVERFLOW if the result
overflows.
Return X / Y, rouding towards +inf. Treat X and Y as unsigned values.
Return X / Y, rouding towards nearest with ties away from zero.
Treat X and Y as having the signedness given by SGN. Indicate
in *OVERFLOW if the result overflows.
Return X / Y, rouding towards 0. Treat X and Y as having the
signedness given by SGN. Store the remainder in *REMAINDER_PTR.
Compute the greatest common divisor of two numbers A and B using
Euclid's algorithm.
Compute X / Y, rouding towards 0, and return the remainder.
Treat X and Y as having the signedness given by SGN. Indicate
in *OVERFLOW if the division overflows.
Compute X / Y, rouding towards 0, and return the remainder.
Treat X and Y as signed values.
Compute X / Y, rouding towards 0, and return the remainder.
Treat X and Y as unsigned values.
Compute X / Y, rouding towards -inf, and return the remainder.
Treat X and Y as having the signedness given by SGN. Indicate
in *OVERFLOW if the division overflows.
Compute X / Y, rouding towards -inf, and return the remainder.
Treat X and Y as unsigned values.
??? Why do we have both this and umod_trunc. Aren't they the same?
Compute X / Y, rouding towards +inf, and return the remainder.
Treat X and Y as having the signedness given by SGN. Indicate
in *OVERFLOW if the division overflows.
Compute X / Y, rouding towards nearest with ties away from zero,
and return the remainder. Treat X and Y as having the signedness
given by SGN. Indicate in *OVERFLOW if the division overflows.
References wi::copy(), wi::get_precision(), wi::le_p(), wi::precision, WI_BINARY_RESULT_VAR, WIDE_INT_REF_FOR, and y.