/* Translation of constants
- Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
Contributed by Paul Brook
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 2, or (at your option) any later
+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
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* trans-const.c -- convert constant values */
#include "system.h"
#include "coretypes.h"
#include "tree.h"
-#include "ggc.h"
-#include "toplev.h"
-#include "real.h"
+#include "realmpfr.h"
+#include "diagnostic-core.h" /* For fatal_error. */
+#include "double-int.h"
#include "gfortran.h"
#include "trans.h"
#include "trans-const.h"
#include "trans-types.h"
+#include "target-memory.h"
tree gfc_rank_cst[GFC_MAX_DIMENSIONS + 1];
return val;
}
+/* Build a string constant with C char type. */
+
tree
gfc_build_string_const (int length, const char *s)
{
tree len;
str = build_string (length, s);
- len = build_int_cst (NULL_TREE, length);
+ len = size_int (length);
TREE_TYPE (str) =
build_array_type (gfc_character1_type_node,
build_range_type (gfc_charlen_type_node,
- integer_one_node, len));
+ size_one_node, len));
+ return str;
+}
+
+
+/* Build a string constant with a type given by its kind; take care of
+ non-default character kinds. */
+
+tree
+gfc_build_wide_string_const (int kind, int length, const gfc_char_t *string)
+{
+ int i;
+ tree str, len;
+ size_t size;
+ char *s;
+
+ i = gfc_validate_kind (BT_CHARACTER, kind, false);
+ size = length * gfc_character_kinds[i].bit_size / 8;
+
+ s = XCNEWVAR (char, size);
+ gfc_encode_character (kind, length, string, (unsigned char *) s, size);
+
+ str = build_string (size, s);
+ free (s);
+
+ len = size_int (length);
+ TREE_TYPE (str) =
+ build_array_type (gfc_get_char_type (kind),
+ build_range_type (gfc_charlen_type_node,
+ size_one_node, len));
return str;
}
+
/* Build a Fortran character constant from a zero-terminated string.
- Since this is mainly used for error messages, the string will get
- translated. */
+ There a two version of this function, one that translates the string
+ and one that doesn't. */
+tree
+gfc_build_cstring_const (const char *string)
+{
+ return gfc_build_string_const (strlen (string) + 1, string);
+}
+
tree
-gfc_build_cstring_const (const char *msgid)
+gfc_build_localized_cstring_const (const char *msgid)
{
- return gfc_build_string_const (strlen (msgid) + 1, _(msgid));
+ const char *localized = _(msgid);
+ return gfc_build_string_const (strlen (localized) + 1, localized);
}
+
/* Return a string constant with the given length. Used for static
initializers. The constant will be padded or truncated to match
length. */
tree
gfc_conv_string_init (tree length, gfc_expr * expr)
{
- char *s;
+ gfc_char_t *s;
HOST_WIDE_INT len;
int slen;
tree str;
+ bool free_s = false;
gcc_assert (expr->expr_type == EXPR_CONSTANT);
- gcc_assert (expr->ts.type == BT_CHARACTER && expr->ts.kind == 1);
+ gcc_assert (expr->ts.type == BT_CHARACTER);
gcc_assert (INTEGER_CST_P (length));
gcc_assert (TREE_INT_CST_HIGH (length) == 0);
if (len > slen)
{
- s = gfc_getmem (len);
- memcpy (s, expr->value.character.string, slen);
- memset (&s[slen], ' ', len - slen);
- str = gfc_build_string_const (len, s);
- gfc_free (s);
+ s = gfc_get_wide_string (len);
+ memcpy (s, expr->value.character.string, slen * sizeof (gfc_char_t));
+ gfc_wide_memset (&s[slen], ' ', len - slen);
+ free_s = true;
}
else
- str = gfc_build_string_const (len, expr->value.character.string);
+ s = expr->value.character.string;
+
+ str = gfc_build_wide_string_const (expr->ts.kind, len, s);
+
+ if (free_s)
+ free (s);
return str;
}
void
gfc_conv_const_charlen (gfc_charlen * cl)
{
- if (cl->backend_decl)
+ if (!cl || cl->backend_decl)
return;
if (cl->length && cl->length->expr_type == EXPR_CONSTANT)
}
/* Converts a GMP integer into a backend tree node. */
+
tree
gfc_conv_mpz_to_tree (mpz_t i, int kind)
{
- HOST_WIDE_INT high;
- unsigned HOST_WIDE_INT low;
-
- if (mpz_fits_slong_p (i))
- {
- /* Note that HOST_WIDE_INT is never smaller than long. */
- low = mpz_get_si (i);
- high = mpz_sgn (i) < 0 ? -1 : 0;
- }
- else
- {
- unsigned HOST_WIDE_INT words[2];
- size_t count;
-
- /* Since we know that the value is not zero (mpz_fits_slong_p),
- we know that at least one word will be written, but we don't know
- about the second. It's quicker to zero the second word before
- than conditionally clear it later. */
- words[1] = 0;
-
- /* Extract the absolute value into words. */
- mpz_export (words, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, i);
-
- /* We assume that all numbers are in range for its type, and that
- we never create a type larger than 2*HWI, which is the largest
- that the middle-end can handle. */
- gcc_assert (count == 1 || count == 2);
-
- low = words[0];
- high = words[1];
+ double_int val = mpz_get_double_int (gfc_get_int_type (kind), i, true);
+ return double_int_to_tree (gfc_get_int_type (kind), val);
+}
- /* Negate if necessary. */
- if (mpz_sgn (i) < 0)
- {
- if (low == 0)
- high = -high;
- else
- low = -low, high = ~high;
- }
- }
+/* Converts a backend tree into a GMP integer. */
- return build_int_cst_wide (gfc_get_int_type (kind), low, high);
+void
+gfc_conv_tree_to_mpz (mpz_t i, tree source)
+{
+ double_int val = tree_to_double_int (source);
+ mpz_set_double_int (i, val, TYPE_UNSIGNED (TREE_TYPE (source)));
}
-/* Converts a real constant into backend form. Uses an intermediate string
- representation. */
+/* Converts a real constant into backend form. */
tree
-gfc_conv_mpfr_to_tree (mpfr_t f, int kind)
+gfc_conv_mpfr_to_tree (mpfr_t f, int kind, int is_snan)
{
- tree res;
tree type;
- mp_exp_t exp;
- char *p, *q;
int n;
REAL_VALUE_TYPE real;
n = gfc_validate_kind (BT_REAL, kind, false);
-
gcc_assert (gfc_real_kinds[n].radix == 2);
type = gfc_get_real_type (kind);
+ if (mpfr_nan_p (f) && is_snan)
+ real_from_string (&real, "SNaN");
+ else
+ real_from_mpfr (&real, f, type, GFC_RND_MODE);
+
+ return build_real (type, real);
+}
- /* Take care of Infinity and NaN. */
- if (mpfr_inf_p (f))
+/* Returns a real constant that is +Infinity if the target
+ supports infinities for this floating-point mode, and
+ +HUGE_VAL otherwise (the largest representable number). */
+
+tree
+gfc_build_inf_or_huge (tree type, int kind)
+{
+ if (HONOR_INFINITIES (TYPE_MODE (type)))
{
+ REAL_VALUE_TYPE real;
real_inf (&real);
- if (mpfr_sgn (f) < 0)
- real = REAL_VALUE_NEGATE(real);
- res = build_real (type , real);
- return res;
+ return build_real (type, real);
}
-
- if (mpfr_nan_p (f))
+ else
{
- real_nan (&real, "", 0, TYPE_MODE (type));
- res = build_real (type , real);
- return res;
+ int k = gfc_validate_kind (BT_REAL, kind, false);
+ return gfc_conv_mpfr_to_tree (gfc_real_kinds[k].huge, kind, 0);
}
+}
- /* mpfr chooses too small a number of hexadecimal digits if the
- number of binary digits is not divisible by four, therefore we
- have to explicitly request a sufficient number of digits here. */
- p = mpfr_get_str (NULL, &exp, 16, gfc_real_kinds[n].digits / 4 + 1,
- f, GFC_RND_MODE);
-
- /* REAL_VALUE_ATOF expects the exponent for mantissa * 2**exp,
- mpfr_get_str returns the exponent for mantissa * 16**exp, adjust
- for that. */
- exp *= 4;
-
- /* The additional 12 characters add space for the sprintf below.
- This leaves 6 digits for the exponent which is certainly enough. */
- q = (char *) gfc_getmem (strlen (p) + 12);
-
- if (p[0] == '-')
- sprintf (q, "-0x.%sp%d", &p[1], (int) exp);
- else
- sprintf (q, "0x.%sp%d", p, (int) exp);
-
- res = build_real (type, REAL_VALUE_ATOF (q, TYPE_MODE (type)));
-
- gfc_free (q);
- gfc_free (p);
+/* Converts a backend tree into a real constant. */
- return res;
+void
+gfc_conv_tree_to_mpfr (mpfr_ptr f, tree source)
+{
+ mpfr_from_real (f, TREE_REAL_CST_PTR (source), GFC_RND_MODE);
}
-
/* Translate any literal constant to a tree. Constants never have
pre or post chains. Character literal constants are special
special because they have a value and a length, so they cannot be
tree
gfc_conv_constant_to_tree (gfc_expr * expr)
{
+ tree res;
+
gcc_assert (expr->expr_type == EXPR_CONSTANT);
- /* If it is converted from Hollerith constant, we build string constant
- and VIEW_CONVERT to its type. */
+ /* If it is has a prescribed memory representation, we build a string
+ constant and VIEW_CONVERT to its type. */
switch (expr->ts.type)
{
case BT_INTEGER:
- if (expr->from_H)
- return build1 (VIEW_CONVERT_EXPR,
- gfc_get_int_type (expr->ts.kind),
- gfc_build_string_const (expr->value.character.length,
- expr->value.character.string));
+ if (expr->representation.string)
+ return fold_build1_loc (input_location, VIEW_CONVERT_EXPR,
+ gfc_get_int_type (expr->ts.kind),
+ gfc_build_string_const (expr->representation.length,
+ expr->representation.string));
else
return gfc_conv_mpz_to_tree (expr->value.integer, expr->ts.kind);
case BT_REAL:
- if (expr->from_H)
- return build1 (VIEW_CONVERT_EXPR,
- gfc_get_real_type (expr->ts.kind),
- gfc_build_string_const (expr->value.character.length,
- expr->value.character.string));
+ if (expr->representation.string)
+ return fold_build1_loc (input_location, VIEW_CONVERT_EXPR,
+ gfc_get_real_type (expr->ts.kind),
+ gfc_build_string_const (expr->representation.length,
+ expr->representation.string));
else
- return gfc_conv_mpfr_to_tree (expr->value.real, expr->ts.kind);
+ return gfc_conv_mpfr_to_tree (expr->value.real, expr->ts.kind, expr->is_snan);
case BT_LOGICAL:
- if (expr->from_H)
- return build1 (VIEW_CONVERT_EXPR,
- gfc_get_logical_type (expr->ts.kind),
- gfc_build_string_const (expr->value.character.length,
- expr->value.character.string));
+ if (expr->representation.string)
+ {
+ tree tmp = fold_build1_loc (input_location, VIEW_CONVERT_EXPR,
+ gfc_get_int_type (expr->ts.kind),
+ gfc_build_string_const (expr->representation.length,
+ expr->representation.string));
+ if (!integer_zerop (tmp) && !integer_onep (tmp))
+ gfc_warning ("Assigning value other than 0 or 1 to LOGICAL"
+ " has undefined result at %L", &expr->where);
+ return fold_convert (gfc_get_logical_type (expr->ts.kind), tmp);
+ }
else
return build_int_cst (gfc_get_logical_type (expr->ts.kind),
- expr->value.logical);
+ expr->value.logical);
case BT_COMPLEX:
- if (expr->from_H)
- return build1 (VIEW_CONVERT_EXPR,
- gfc_get_complex_type (expr->ts.kind),
- gfc_build_string_const (expr->value.character.length,
- expr->value.character.string));
+ if (expr->representation.string)
+ return fold_build1_loc (input_location, VIEW_CONVERT_EXPR,
+ gfc_get_complex_type (expr->ts.kind),
+ gfc_build_string_const (expr->representation.length,
+ expr->representation.string));
else
{
- tree real = gfc_conv_mpfr_to_tree (expr->value.complex.r,
- expr->ts.kind);
- tree imag = gfc_conv_mpfr_to_tree (expr->value.complex.i,
- expr->ts.kind);
+ tree real = gfc_conv_mpfr_to_tree (mpc_realref (expr->value.complex),
+ expr->ts.kind, expr->is_snan);
+ tree imag = gfc_conv_mpfr_to_tree (mpc_imagref (expr->value.complex),
+ expr->ts.kind, expr->is_snan);
return build_complex (gfc_typenode_for_spec (&expr->ts),
real, imag);
}
case BT_CHARACTER:
+ res = gfc_build_wide_string_const (expr->ts.kind,
+ expr->value.character.length,
+ expr->value.character.string);
+ return res;
+
case BT_HOLLERITH:
- return gfc_build_string_const (expr->value.character.length,
- expr->value.character.string);
+ return gfc_build_string_const (expr->representation.length,
+ expr->representation.string);
default:
fatal_error ("gfc_conv_constant_to_tree(): invalid type: %s",
void
gfc_conv_constant (gfc_se * se, gfc_expr * expr)
{
- gcc_assert (expr->expr_type == EXPR_CONSTANT);
+ gfc_ss *ss;
- if (se->ss != NULL)
+ /* We may be receiving an expression for C_NULL_PTR or C_NULL_FUNPTR. If
+ so, the expr_type will not yet be an EXPR_CONSTANT. We need to make
+ it so here. */
+ if (expr->ts.type == BT_DERIVED && expr->ts.u.derived
+ && expr->ts.u.derived->attr.is_iso_c)
{
- gcc_assert (se->ss != gfc_ss_terminator);
- gcc_assert (se->ss->type == GFC_SS_SCALAR);
- gcc_assert (se->ss->expr == expr);
+ if (expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_PTR
+ || expr->symtree->n.sym->intmod_sym_id == ISOCBINDING_NULL_FUNPTR)
+ {
+ /* Create a new EXPR_CONSTANT expression for our local uses. */
+ expr = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
+ }
+ }
+
+ if (expr->expr_type != EXPR_CONSTANT)
+ {
+ gfc_expr *e = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
+ gfc_error ("non-constant initialization expression at %L", &expr->where);
+ se->expr = gfc_conv_constant_to_tree (e);
+ return;
+ }
+
+ ss = se->ss;
+ if (ss != NULL)
+ {
+ gfc_ss_info *ss_info;
+
+ ss_info = ss->info;
+ gcc_assert (ss != gfc_ss_terminator);
+ gcc_assert (ss_info->type == GFC_SS_SCALAR);
+ gcc_assert (ss_info->expr == expr);
- se->expr = se->ss->data.scalar.expr;
- se->string_length = se->ss->string_length;
+ se->expr = ss_info->data.scalar.value;
+ se->string_length = ss_info->string_length;
gfc_advance_se_ss_chain (se);
return;
}