/* Fixed-point arithmetic support.
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 2006-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
#include "diagnostic-core.h"
FIXED_MAX_EPS, if it is equal to the maximum plus the epsilon. */
static enum fixed_value_range_code
-check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, enum machine_mode mode)
+check_real_for_fixed_mode (REAL_VALUE_TYPE *real_value, machine_mode mode)
{
REAL_VALUE_TYPE max_value, min_value, epsilon_value;
return FIXED_OK;
}
+
+/* Construct a CONST_FIXED from a bit payload and machine mode MODE.
+ The bits in PAYLOAD are sign-extended/zero-extended according to MODE. */
+
+FIXED_VALUE_TYPE
+fixed_from_double_int (double_int payload, machine_mode mode)
+{
+ FIXED_VALUE_TYPE value;
+
+ gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_DOUBLE_INT);
+
+ if (SIGNED_SCALAR_FIXED_POINT_MODE_P (mode))
+ value.data = payload.sext (1 + GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode));
+ else if (UNSIGNED_SCALAR_FIXED_POINT_MODE_P (mode))
+ value.data = payload.zext (GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode));
+ else
+ gcc_unreachable ();
+
+ value.mode = mode;
+
+ return value;
+}
+
+
/* Initialize from a decimal or hexadecimal string. */
void
-fixed_from_string (FIXED_VALUE_TYPE *f, const char *str, enum machine_mode mode)
+fixed_from_string (FIXED_VALUE_TYPE *f, const char *str, machine_mode mode)
{
REAL_VALUE_TYPE real_value, fixed_value, base_value;
unsigned int fbit;
enum fixed_value_range_code temp;
+ bool fail;
f->mode = mode;
fbit = GET_MODE_FBIT (mode);
"large fixed-point constant implicitly truncated to fixed-point type");
real_2expN (&base_value, fbit, mode);
real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value);
- real_to_integer2 ((HOST_WIDE_INT *)&f->data.low, &f->data.high,
- &fixed_value);
+ wide_int w = real_to_integer (&fixed_value, &fail,
+ GET_MODE_PRECISION (mode));
+ f->data.low = w.elt (0);
+ f->data.high = w.elt (1);
if (temp == FIXED_MAX_EPS && ALL_FRACT_MODE_P (f->mode))
{
{
REAL_VALUE_TYPE real_value, base_value, fixed_value;
+ signop sgn = UNSIGNED_FIXED_POINT_MODE_P (f_orig->mode) ? UNSIGNED : SIGNED;
real_2expN (&base_value, GET_MODE_FBIT (f_orig->mode), f_orig->mode);
- real_from_integer (&real_value, VOIDmode, f_orig->data.low, f_orig->data.high,
- UNSIGNED_FIXED_POINT_MODE_P (f_orig->mode));
+ real_from_integer (&real_value, VOIDmode,
+ wide_int::from (f_orig->data,
+ GET_MODE_PRECISION (f_orig->mode), sgn),
+ sgn);
real_arithmetic (&fixed_value, RDIV_EXPR, &real_value, &base_value);
real_to_decimal (str, &fixed_value, buf_size, 0, 1);
}
Return true, if !SAT_P and overflow. */
static bool
-fixed_saturate1 (enum machine_mode mode, double_int a, double_int *f,
+fixed_saturate1 (machine_mode mode, double_int a, double_int *f,
bool sat_p)
{
bool overflow_p = false;
Return true, if !SAT_P and overflow. */
static bool
-fixed_saturate2 (enum machine_mode mode, double_int a_high, double_int a_low,
+fixed_saturate2 (machine_mode mode, double_int a_high, double_int a_low,
double_int *f, bool sat_p)
{
bool overflow_p = false;
if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT)
{
f->data = a->data * b->data;
- f->data = f->data.lshift ((-GET_MODE_FBIT (f->mode)),
- HOST_BITS_PER_DOUBLE_INT,
- !unsigned_p);
+ f->data = f->data.lshift (-GET_MODE_FBIT (f->mode),
+ HOST_BITS_PER_DOUBLE_INT, !unsigned_p);
overflow_p = fixed_saturate1 (f->mode, f->data, &f->data, sat_p);
}
else
f->data.high = f->data.high | s.high;
s.low = f->data.low;
s.high = f->data.high;
- r = r.lshift ((-GET_MODE_FBIT (f->mode)),
- HOST_BITS_PER_DOUBLE_INT,
- !unsigned_p);
+ r = r.lshift (-GET_MODE_FBIT (f->mode),
+ HOST_BITS_PER_DOUBLE_INT, !unsigned_p);
}
overflow_p = fixed_saturate2 (f->mode, r, s, &f->data, sat_p);
if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT)
{
f->data = a->data.lshift (GET_MODE_FBIT (f->mode),
- HOST_BITS_PER_DOUBLE_INT,
- !unsigned_p);
+ HOST_BITS_PER_DOUBLE_INT, !unsigned_p);
f->data = f->data.div (b->data, unsigned_p, TRUNC_DIV_EXPR);
overflow_p = fixed_saturate1 (f->mode, f->data, &f->data, sat_p);
}
int leftmost_mod = (mod.high < 0);
/* Shift left mod by 1 bit. */
- mod = mod.llshift (1, HOST_BITS_PER_DOUBLE_INT);
+ mod = mod.lshift (1);
/* Test the leftmost bit of s to add to mod. */
if (s.high < 0)
mod.low += 1;
/* Shift left quo_s by 1 bit. */
- quo_s = quo_s.llshift (1, HOST_BITS_PER_DOUBLE_INT);
+ quo_s = quo_s.lshift (1);
/* Try to calculate (mod - pos_b). */
temp = mod - pos_b;
}
/* Shift left s by 1 bit. */
- s = s.llshift (1, HOST_BITS_PER_DOUBLE_INT);
+ s = s.lshift (1);
}
if (GET_MODE_PRECISION (f->mode) <= HOST_BITS_PER_WIDE_INT || (!left_p))
{
- f->data = a->data.lshift (left_p ? b->data.low : (-b->data.low),
- HOST_BITS_PER_DOUBLE_INT,
- !unsigned_p);
+ f->data = a->data.lshift (left_p ? b->data.low : -b->data.low,
+ HOST_BITS_PER_DOUBLE_INT, !unsigned_p);
if (left_p) /* Only left shift saturates. */
overflow_p = fixed_saturate1 (f->mode, f->data, &f->data, sat_p);
}
else
{
temp_low = a->data.lshift (b->data.low,
- HOST_BITS_PER_DOUBLE_INT,
- !unsigned_p);
+ HOST_BITS_PER_DOUBLE_INT, !unsigned_p);
/* Logical shift right to temp_high. */
temp_high = a->data.llshift (b->data.low - HOST_BITS_PER_DOUBLE_INT,
HOST_BITS_PER_DOUBLE_INT);
Return true, if !SAT_P and overflow. */
bool
-fixed_convert (FIXED_VALUE_TYPE *f, enum machine_mode mode,
+fixed_convert (FIXED_VALUE_TYPE *f, machine_mode mode,
const FIXED_VALUE_TYPE *a, bool sat_p)
{
bool overflow_p = false;
double_int temp_high, temp_low;
int amount = GET_MODE_FBIT (mode) - GET_MODE_FBIT (a->mode);
temp_low = a->data.lshift (amount,
- HOST_BITS_PER_DOUBLE_INT,
- SIGNED_FIXED_POINT_MODE_P (a->mode));
+ HOST_BITS_PER_DOUBLE_INT,
+ SIGNED_FIXED_POINT_MODE_P (a->mode));
/* Logical shift right to temp_high. */
temp_high = a->data.llshift (amount - HOST_BITS_PER_DOUBLE_INT,
HOST_BITS_PER_DOUBLE_INT);
/* Right shift a to temp based on a->mode. */
double_int temp;
temp = a->data.lshift (GET_MODE_FBIT (mode) - GET_MODE_FBIT (a->mode),
- HOST_BITS_PER_DOUBLE_INT,
- SIGNED_FIXED_POINT_MODE_P (a->mode));
+ HOST_BITS_PER_DOUBLE_INT,
+ SIGNED_FIXED_POINT_MODE_P (a->mode));
f->mode = mode;
f->data = temp;
if (SIGNED_FIXED_POINT_MODE_P (a->mode) ==
Return true, if !SAT_P and overflow. */
bool
-fixed_convert_from_int (FIXED_VALUE_TYPE *f, enum machine_mode mode,
+fixed_convert_from_int (FIXED_VALUE_TYPE *f, machine_mode mode,
double_int a, bool unsigned_p, bool sat_p)
{
bool overflow_p = false;
Return true, if !SAT_P and overflow. */
bool
-fixed_convert_from_real (FIXED_VALUE_TYPE *f, enum machine_mode mode,
+fixed_convert_from_real (FIXED_VALUE_TYPE *f, machine_mode mode,
const REAL_VALUE_TYPE *a, bool sat_p)
{
bool overflow_p = false;
int i_f_bits = GET_MODE_IBIT (mode) + GET_MODE_FBIT (mode);
unsigned int fbit = GET_MODE_FBIT (mode);
enum fixed_value_range_code temp;
+ bool fail;
real_value = *a;
f->mode = mode;
real_2expN (&base_value, fbit, mode);
real_arithmetic (&fixed_value, MULT_EXPR, &real_value, &base_value);
- real_to_integer2 ((HOST_WIDE_INT *)&f->data.low, &f->data.high, &fixed_value);
+
+ wide_int w = real_to_integer (&fixed_value, &fail,
+ GET_MODE_PRECISION (mode));
+ f->data.low = w.elt (0);
+ f->data.high = w.elt (1);
temp = check_real_for_fixed_mode (&real_value, mode);
if (temp == FIXED_UNDERFLOW) /* Minimum. */
{
/* Convert to a new real mode from a fixed-point. */
void
-real_convert_from_fixed (REAL_VALUE_TYPE *r, enum machine_mode mode,
+real_convert_from_fixed (REAL_VALUE_TYPE *r, machine_mode mode,
const FIXED_VALUE_TYPE *f)
{
REAL_VALUE_TYPE base_value, fixed_value, real_value;
+ signop sgn = UNSIGNED_FIXED_POINT_MODE_P (f->mode) ? UNSIGNED : SIGNED;
real_2expN (&base_value, GET_MODE_FBIT (f->mode), f->mode);
- real_from_integer (&fixed_value, VOIDmode, f->data.low, f->data.high,
- UNSIGNED_FIXED_POINT_MODE_P (f->mode));
+ real_from_integer (&fixed_value, VOIDmode,
+ wide_int::from (f->data, GET_MODE_PRECISION (f->mode),
+ sgn), sgn);
real_arithmetic (&real_value, RDIV_EXPR, &fixed_value, &base_value);
real_convert (r, mode, &real_value);
}