📄 simplify.c
字号:
/* Simplify intrinsic functions at compile-time. Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Contributed by Andy Vaught & Katherine HolcombThis file is part of GCC.GCC is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.GCC is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public Licensealong with GCC; see the file COPYING. If not, write to the FreeSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA02110-1301, USA. */#include "config.h"#include "system.h"#include "flags.h"#include "gfortran.h"#include "arith.h"#include "intrinsic.h"gfc_expr gfc_bad_expr;/* Note that 'simplification' is not just transforming expressions. For functions that are not simplified at compile time, range checking is done if possible. The return convention is that each simplification function returns: A new expression node corresponding to the simplified arguments. The original arguments are destroyed by the caller, and must not be a part of the new expression. NULL pointer indicating that no simplification was possible and the original expression should remain intact. If the simplification function sets the type and/or the function name via the pointer gfc_simple_expression, then this type is retained. An expression pointer to gfc_bad_expr (a static placeholder) indicating that some error has prevented simplification. For example, sqrt(-1.0). The error is generated within the function and should be propagated upwards By the time a simplification function gets control, it has been decided that the function call is really supposed to be the intrinsic. No type checking is strictly necessary, since only valid types will be passed on. On the other hand, a simplification subroutine may have to look at the type of an argument as part of its processing. Array arguments are never passed to these subroutines. The functions in this file don't have much comment with them, but everything is reasonably straight-forward. The Standard, chapter 13 is the best comment you'll find for this file anyway. *//* Static table for converting non-ascii character sets to ascii. The xascii_table[] is the inverse table. */static int ascii_table[256] = { '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\b', '\t', '\n', '\v', '\0', '\r', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', ' ', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\?'};static int xascii_table[256];/* Range checks an expression node. If all goes well, returns the node, otherwise returns &gfc_bad_expr and frees the node. */static gfc_expr *range_check (gfc_expr * result, const char *name){ if (gfc_range_check (result) == ARITH_OK) return result; gfc_error ("Result of %s overflows its kind at %L", name, &result->where); gfc_free_expr (result); return &gfc_bad_expr;}/* A helper function that gets an optional and possibly missing kind parameter. Returns the kind, -1 if something went wrong. */static intget_kind (bt type, gfc_expr * k, const char *name, int default_kind){ int kind; if (k == NULL) return default_kind; if (k->expr_type != EXPR_CONSTANT) { gfc_error ("KIND parameter of %s at %L must be an initialization " "expression", name, &k->where); return -1; } if (gfc_extract_int (k, &kind) != NULL || gfc_validate_kind (type, kind, true) < 0) { gfc_error ("Invalid KIND parameter of %s at %L", name, &k->where); return -1; } return kind;}/* Checks if X, which is assumed to represent a two's complement integer of binary width BITSIZE, has the signbit set. If so, makes X the corresponding negative number. */static voidtwos_complement (mpz_t x, int bitsize){ mpz_t mask; if (mpz_tstbit (x, bitsize - 1) == 1) { mpz_init_set_ui(mask, 1); mpz_mul_2exp(mask, mask, bitsize); mpz_sub_ui(mask, mask, 1); /* We negate the number by hand, zeroing the high bits, that is make it the corresponding positive number, and then have it negated by GMP, giving the correct representation of the negative number. */ mpz_com (x, x); mpz_add_ui (x, x, 1); mpz_and (x, x, mask); mpz_neg (x, x); mpz_clear (mask); }}/********************** Simplification functions *****************************/gfc_expr *gfc_simplify_abs (gfc_expr * e){ gfc_expr *result; if (e->expr_type != EXPR_CONSTANT) return NULL; switch (e->ts.type) { case BT_INTEGER: result = gfc_constant_result (BT_INTEGER, e->ts.kind, &e->where); mpz_abs (result->value.integer, e->value.integer); result = range_check (result, "IABS"); break; case BT_REAL: result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); mpfr_abs (result->value.real, e->value.real, GFC_RND_MODE); result = range_check (result, "ABS"); break; case BT_COMPLEX: result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); gfc_set_model_kind (e->ts.kind); mpfr_hypot (result->value.real, e->value.complex.r, e->value.complex.i, GFC_RND_MODE); result = range_check (result, "CABS"); break; default: gfc_internal_error ("gfc_simplify_abs(): Bad type"); } return result;}gfc_expr *gfc_simplify_achar (gfc_expr * e){ gfc_expr *result; int index; if (e->expr_type != EXPR_CONSTANT) return NULL; /* We cannot assume that the native character set is ASCII in this function. */ if (gfc_extract_int (e, &index) != NULL || index < 0 || index > 127) { gfc_error ("Extended ASCII not implemented: argument of ACHAR at %L " "must be between 0 and 127", &e->where); return &gfc_bad_expr; } result = gfc_constant_result (BT_CHARACTER, gfc_default_character_kind, &e->where); result->value.character.string = gfc_getmem (2); result->value.character.length = 1; result->value.character.string[0] = ascii_table[index]; result->value.character.string[1] = '\0'; /* For debugger */ return result;}gfc_expr *gfc_simplify_acos (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; if (mpfr_cmp_si (x->value.real, 1) > 0 || mpfr_cmp_si (x->value.real, -1) < 0) { gfc_error ("Argument of ACOS at %L must be between -1 and 1", &x->where); return &gfc_bad_expr; } result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ACOS");}gfc_expr *gfc_simplify_acosh (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; if (mpfr_cmp_si (x->value.real, 1) < 0) { gfc_error ("Argument of ACOSH at %L must not be less than 1", &x->where); return &gfc_bad_expr; } result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_acosh (result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ACOSH");}gfc_expr *gfc_simplify_adjustl (gfc_expr * e){ gfc_expr *result; int count, i, len; char ch; if (e->expr_type != EXPR_CONSTANT) return NULL; len = e->value.character.length; result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); result->value.character.length = len; result->value.character.string = gfc_getmem (len + 1); for (count = 0, i = 0; i < len; ++i) { ch = e->value.character.string[i]; if (ch != ' ') break; ++count; } for (i = 0; i < len - count; ++i) { result->value.character.string[i] = e->value.character.string[count + i]; } for (i = len - count; i < len; ++i) { result->value.character.string[i] = ' '; } result->value.character.string[len] = '\0'; /* For debugger */ return result;}gfc_expr *gfc_simplify_adjustr (gfc_expr * e){ gfc_expr *result; int count, i, len; char ch; if (e->expr_type != EXPR_CONSTANT) return NULL; len = e->value.character.length; result = gfc_constant_result (BT_CHARACTER, e->ts.kind, &e->where); result->value.character.length = len; result->value.character.string = gfc_getmem (len + 1); for (count = 0, i = len - 1; i >= 0; --i) { ch = e->value.character.string[i]; if (ch != ' ') break; ++count; } for (i = 0; i < count; ++i) { result->value.character.string[i] = ' '; } for (i = count; i < len; ++i) { result->value.character.string[i] = e->value.character.string[i - count]; } result->value.character.string[len] = '\0'; /* For debugger */ return result;}gfc_expr *gfc_simplify_aimag (gfc_expr * e){ gfc_expr *result; if (e->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (BT_REAL, e->ts.kind, &e->where); mpfr_set (result->value.real, e->value.complex.i, GFC_RND_MODE); return range_check (result, "AIMAG");}gfc_expr *gfc_simplify_aint (gfc_expr * e, gfc_expr * k){ gfc_expr *rtrunc, *result; int kind; kind = get_kind (BT_REAL, k, "AINT", e->ts.kind); if (kind == -1) return &gfc_bad_expr; if (e->expr_type != EXPR_CONSTANT) return NULL; rtrunc = gfc_copy_expr (e); mpfr_trunc (rtrunc->value.real, e->value.real); result = gfc_real2real (rtrunc, kind); gfc_free_expr (rtrunc); return range_check (result, "AINT");}gfc_expr *gfc_simplify_dint (gfc_expr * e){ gfc_expr *rtrunc, *result; if (e->expr_type != EXPR_CONSTANT) return NULL; rtrunc = gfc_copy_expr (e); mpfr_trunc (rtrunc->value.real, e->value.real); result = gfc_real2real (rtrunc, gfc_default_double_kind); gfc_free_expr (rtrunc); return range_check (result, "DINT");}gfc_expr *gfc_simplify_anint (gfc_expr * e, gfc_expr * k){ gfc_expr *result; int kind; kind = get_kind (BT_REAL, k, "ANINT", e->ts.kind); if (kind == -1) return &gfc_bad_expr; if (e->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (e->ts.type, kind, &e->where); mpfr_round (result->value.real, e->value.real); return range_check (result, "ANINT");}gfc_expr *gfc_simplify_and (gfc_expr * x, gfc_expr * y){ gfc_expr *result; int kind; if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) return NULL; kind = x->ts.kind > y->ts.kind ? x->ts.kind : y->ts.kind; if (x->ts.type == BT_INTEGER) { result = gfc_constant_result (BT_INTEGER, kind, &x->where); mpz_and (result->value.integer, x->value.integer, y->value.integer); } else /* BT_LOGICAL */ { result = gfc_constant_result (BT_LOGICAL, kind, &x->where); result->value.logical = x->value.logical && y->value.logical; } return range_check (result, "AND");}gfc_expr *gfc_simplify_dnint (gfc_expr * e){ gfc_expr *result; if (e->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (BT_REAL, gfc_default_double_kind, &e->where); mpfr_round (result->value.real, e->value.real); return range_check (result, "DNINT");}gfc_expr *gfc_simplify_asin (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; if (mpfr_cmp_si (x->value.real, 1) > 0 || mpfr_cmp_si (x->value.real, -1) < 0) { gfc_error ("Argument of ASIN at %L must be between -1 and 1", &x->where); return &gfc_bad_expr; } result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_asin(result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ASIN");}gfc_expr *gfc_simplify_asinh (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_asinh(result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ASINH");}gfc_expr *gfc_simplify_atan (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_atan(result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ATAN");}gfc_expr *gfc_simplify_atanh (gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT) return NULL; if (mpfr_cmp_si (x->value.real, 1) >= 0 || mpfr_cmp_si (x->value.real, -1) <= 0) { gfc_error ("Argument of ATANH at %L must be inside the range -1 to 1", &x->where); return &gfc_bad_expr; } result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); mpfr_atanh(result->value.real, x->value.real, GFC_RND_MODE); return range_check (result, "ATANH");}gfc_expr *gfc_simplify_atan2 (gfc_expr * y, gfc_expr * x){ gfc_expr *result; if (x->expr_type != EXPR_CONSTANT || y->expr_type != EXPR_CONSTANT) return NULL; result = gfc_constant_result (x->ts.type, x->ts.kind, &x->where); if (mpfr_sgn (y->value.real) == 0 && mpfr_sgn (x->value.real) == 0) { gfc_error ("If first argument of ATAN2 %L is zero, then the second argument " "must not be zero", &x->where); gfc_free_expr (result); return &gfc_bad_expr; } arctangent2 (y->value.real, x->value.real, result->value.real); return range_check (result, "ATAN2");}gfc_expr *gfc_simplify_bit_size (gfc_expr * e){ gfc_expr *result; int i; i = gfc_validate_kind (e->ts.type, e->ts.kind, false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -