diff options
Diffstat (limited to 'gcc/ch/typeck.c')
-rw-r--r-- | gcc/ch/typeck.c | 3822 |
1 files changed, 0 insertions, 3822 deletions
diff --git a/gcc/ch/typeck.c b/gcc/ch/typeck.c deleted file mode 100644 index 84ee56ebd39..00000000000 --- a/gcc/ch/typeck.c +++ /dev/null @@ -1,3822 +0,0 @@ -/* Build expressions with type checking for CHILL compiler. - Copyright (C) 1992, 1993, 1994, 1998, 1999, 2000 - Free Software Foundation, Inc. - -This file is part of GNU CC. - -GNU CC 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 version. - -GNU CC 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 GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ - - -/* This file is part of the CHILL front end. - It contains routines to build C expressions given their operands, - including computing the modes of the result, C-specific error checks, - and some optimization. - - There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, - and to process initializations in declarations (since they work - like a strange sort of assignment). */ - -#include "config.h" -#include "system.h" -#include "tree.h" -#include "ch-tree.h" -#include "flags.h" -#include "rtl.h" -#include "expr.h" -#include "lex.h" -#include "toplev.h" -#include "output.h" - -/* forward declarations */ -static int chill_l_equivalent PARAMS ((tree, tree, struct mode_chain*)); -static tree extract_constant_from_buffer PARAMS ((tree, const unsigned char *, int)); -static int expand_constant_to_buffer PARAMS ((tree, unsigned char *, int)); -static tree build_empty_string PARAMS ((tree)); -static tree make_chill_pointer_type PARAMS ((tree, enum tree_code)); -static unsigned int min_precision PARAMS ((tree, int)); -static tree make_chill_range_type PARAMS ((tree, tree, tree)); -static void apply_chill_array_layout PARAMS ((tree)); -static int field_decl_cmp PARAMS ((tree *, tree*)); -static tree make_chill_struct_type PARAMS ((tree)); -static int apply_chill_field_layout PARAMS ((tree, int *)); - -/* - * This function checks an array access. - * It calls error (ERROR_MESSAGE) if the condition (index <= domain max value - * index >= domain min value) - * is not met at compile time, - * If a runtime test is required and permitted, - * check_expression is used to do so. - * the global RANGE_CHECKING flags controls the - * generation of runtime checking code. - */ -tree -valid_array_index_p (array, idx, error_message, is_varying_lhs) - tree array, idx; - const char *error_message; - int is_varying_lhs; -{ - tree cond, low_limit, high_cond, atype, domain; - tree orig_index = idx; - enum chill_tree_code condition; - - if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK - || idx == NULL_TREE || TREE_CODE (idx) == ERROR_MARK) - return error_mark_node; - - if (TREE_CODE (idx) == TYPE_DECL - || TREE_CODE_CLASS (TREE_CODE (idx)) == 't') - { - error ("array or string index is a mode (instead of a value)"); - return error_mark_node; - } - - atype = TREE_TYPE (array); - - if (chill_varying_type_p (atype)) - { - domain = TYPE_DOMAIN (CH_VARYING_ARRAY_TYPE (atype)); - high_cond = build_component_ref (array, var_length_id); - if (chill_varying_string_type_p (atype)) - { - if (is_varying_lhs) - condition = GT_EXPR; - else - condition = GE_EXPR; - } - else - condition = GT_EXPR; - } - else - { - domain = TYPE_DOMAIN (atype); - high_cond = TYPE_MAX_VALUE (domain); - condition = GT_EXPR; - } - - if (CH_STRING_TYPE_P (atype)) - { - if (! CH_SIMILAR (TREE_TYPE (orig_index), integer_type_node)) - { - error ("index is not an integer expression"); - return error_mark_node; - } - } - else - { - if (! CH_COMPATIBLE (orig_index, domain)) - { - error ("index not compatible with index mode"); - return error_mark_node; - } - } - - /* Convert BOOLS(1) to BOOL and CHARS(1) to CHAR. */ - if (flag_old_strings) - { - idx = convert_to_discrete (idx); - if (idx == NULL) /* should never happen */ - error ("index is not discrete"); - } - - /* we know we'll refer to this value twice */ - if (range_checking) - idx = save_expr (idx); - - low_limit = TYPE_MIN_VALUE (domain); - high_cond = build_compare_discrete_expr (condition, idx, high_cond); - - /* an invalid index expression meets this condition */ - cond = fold (build (TRUTH_ORIF_EXPR, boolean_type_node, - build_compare_discrete_expr (LT_EXPR, idx, low_limit), - high_cond)); - - /* strip a redundant NOP_EXPR */ - if (TREE_CODE (cond) == NOP_EXPR - && TREE_TYPE (cond) == boolean_type_node - && TREE_CODE (TREE_OPERAND (cond, 0)) == INTEGER_CST) - cond = TREE_OPERAND (cond, 0); - - idx = convert (CH_STRING_TYPE_P (atype) ? integer_type_node : domain, - idx); - - if (TREE_CODE (cond) == INTEGER_CST) - { - if (tree_int_cst_equal (cond, boolean_false_node)) - return idx; /* condition met at compile time */ - error ("%s", error_message); /* condition failed at compile time */ - return error_mark_node; - } - else if (range_checking) - { - /* FIXME: often, several of these conditions will - be generated for the same source file and line number. - A great optimization would be to share the - cause_exception function call among them rather - than generating a cause_exception call for each. */ - return check_expression (idx, cond, - ridpointers[(int) RID_RANGEFAIL]); - } - else - return idx; /* don't know at compile time */ -} - -/* - * Extract a slice from an array, which could look like a - * SET_TYPE if it's a bitstring. The array could also be VARYING - * if the element type is CHAR. The min_value and length values - * must have already been checked with valid_array_index_p. No - * checking is done here. - */ -tree -build_chill_slice (array, min_value, length) - tree array, min_value, length; -{ - tree result; - tree array_type = TREE_TYPE (array); - - if (!CH_REFERABLE (array) && TREE_CODE (array) != SAVE_EXPR - && (TREE_CODE (array) != COMPONENT_REF - || TREE_CODE (TREE_OPERAND (array, 0)) != SAVE_EXPR)) - { - if (!TREE_CONSTANT (array)) - warning ("possible internal error - slice argument is neither referable nor constant"); - else - { - /* Force to storage. - NOTE: This could mean multiple identical copies of - the same constant. FIXME. */ - tree mydecl = decl_temp1 (get_unique_identifier("SLICEE"), - array_type, 1, array, 0, 0); - TREE_READONLY (mydecl) = 1; - /* mark_addressable (mydecl); FIXME: necessary? */ - array = mydecl; - } - } - - /* - The code-generation which uses a slice tree needs not only to - know the dynamic upper and lower limits of that slice, but the - original static allocation, to use to build temps where one or both - of the dynamic limits must be calculated at runtime.. We pass the - dynamic size by building a new array_type whose limits are the - min_value and min_value + length values passed to us. - - The static allocation info is passed by using the parent array's - limits to compute a temp_size, which is passed in the lang_specific - field of the slice_type. */ - - if (TREE_CODE (array_type) == ARRAY_TYPE) - { - tree domain_type = TYPE_DOMAIN (array_type); - tree domain_min = TYPE_MIN_VALUE (domain_type); - tree domain_max - = fold (build (PLUS_EXPR, domain_type, - domain_min, - fold (build (MINUS_EXPR, integer_type_node, - length, integer_one_node)))); - tree index_type = build_chill_range_type (TYPE_DOMAIN (array_type), - domain_min, - domain_max); - - tree element_type = TREE_TYPE (array_type); - tree slice_type = build_simple_array_type (element_type, index_type, NULL_TREE); - tree slice_pointer_type; - tree max_size; - - if (CH_CHARS_TYPE_P (array_type)) - MARK_AS_STRING_TYPE (slice_type); - else - TYPE_PACKED (slice_type) = TYPE_PACKED (array_type); - - SET_CH_NOVELTY (slice_type, CH_NOVELTY (array_type)); - - if (TREE_CONSTANT (array) && host_integerp (min_value, 0) - && host_integerp (length, 0)) - { - unsigned HOST_WIDE_INT type_size = int_size_in_bytes (array_type); - unsigned char *buffer = (unsigned char *) alloca (type_size); - int delta = (int_size_in_bytes (element_type) - * (tree_low_cst (min_value, 0) - - tree_low_cst (domain_min, 0))); - - memset (buffer, 0, type_size); - if (expand_constant_to_buffer (array, buffer, type_size)) - { - result = extract_constant_from_buffer (slice_type, - buffer + delta, - type_size - delta); - if (result) - return result; - } - } - - /* Kludge used by case CONCAT_EXPR in chill_expand_expr. - Set TYPE_ARRAY_MAX_SIZE to a constant upper bound on the - bytes needed. */ - max_size = size_in_bytes (slice_type); - if (TREE_CODE (max_size) != INTEGER_CST) - { - max_size = TYPE_ARRAY_MAX_SIZE (array_type); - if (max_size == NULL_TREE) - max_size = size_in_bytes (array_type); - } - TYPE_ARRAY_MAX_SIZE (slice_type) = max_size; - - mark_addressable (array); - /* Contruct a SLICE_EXPR to represent a slice of a packed array of bits. */ - if (TYPE_PACKED (array_type)) - { - if (pass == 2 && TREE_CODE (length) != INTEGER_CST) - { - sorry ("bit array slice with non-constant length"); - return error_mark_node; - } - if (domain_min && ! integer_zerop (domain_min)) - min_value = size_binop (MINUS_EXPR, min_value, - convert (sizetype, domain_min)); - result = build (SLICE_EXPR, slice_type, array, min_value, length); - TREE_READONLY (result) - = TREE_READONLY (array) | TYPE_READONLY (TREE_TYPE (array_type)); - return result; - } - - slice_pointer_type = build_chill_pointer_type (slice_type); - if (TREE_CODE (min_value) == INTEGER_CST - && domain_min && TREE_CODE (domain_min) == INTEGER_CST - && compare_int_csts (EQ_EXPR, min_value, domain_min)) - result = fold (build1 (ADDR_EXPR, slice_pointer_type, array)); - else - { - min_value = convert (sizetype, min_value); - if (domain_min && ! integer_zerop (domain_min)) - min_value = size_binop (MINUS_EXPR, min_value, - convert (sizetype, domain_min)); - min_value = size_binop (MULT_EXPR, min_value, - size_in_bytes (element_type)); - result = fold (build (PLUS_EXPR, slice_pointer_type, - build1 (ADDR_EXPR, slice_pointer_type, - array), - convert (slice_pointer_type, min_value))); - } - /* Return the final array value. */ - result = fold (build1 (INDIRECT_REF, slice_type, result)); - TREE_READONLY (result) - = TREE_READONLY (array) | TYPE_READONLY (element_type); - return result; - } - else if (TREE_CODE (array_type) == SET_TYPE) /* actually a bitstring */ - { - if (pass == 2 && TREE_CODE (length) != INTEGER_CST) - { - sorry ("bitstring slice with non-constant length"); - return error_mark_node; - } - result = build (SLICE_EXPR, build_bitstring_type (length), - array, min_value, length); - TREE_READONLY (result) - = TREE_READONLY (array) | TYPE_READONLY (TREE_TYPE (array_type)); - return result; - } - else if (chill_varying_type_p (array_type)) - return build_chill_slice (varying_to_slice (array), min_value, length); - else - { - error ("slice operation on non-array, non-bitstring value not supported"); - return error_mark_node; - } -} - -static tree -build_empty_string (type) - tree type; -{ - int orig_pass = pass; - tree range, result; - - range = build_chill_range_type (type, integer_zero_node, - integer_minus_one_node); - result = build_chill_array_type (type, - tree_cons (NULL_TREE, range, NULL_TREE), 0, NULL_TREE); - pass = 2; - range = build_chill_range_type (type, integer_zero_node, - integer_minus_one_node); - result = build_chill_array_type (type, - tree_cons (NULL_TREE, range, NULL_TREE), 0, NULL_TREE); - pass = orig_pass; - - return decl_temp1 (get_unique_identifier ("EMPTY_STRING"), - result, 0, NULL_TREE, 0, 0); -} - -/* We build the runtime range-checking as a separate list - * rather than making a compound_expr with min_value - * (for example), to control when that comparison gets - * generated. We cannot allow it in a TYPE_MAX_VALUE or - * TYPE_MIN_VALUE expression, for instance, because that code - * will get generated when the slice is laid out, which would - * put it outside the scope of an exception handler for the - * statement we're generating. I.e. we would be generating - * cause_exception calls which might execute before the - * necessary ch_link_handler call. - */ -tree -build_chill_slice_with_range (array, min_value, max_value) - tree array, min_value, max_value; -{ - if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK - || min_value == NULL_TREE || TREE_CODE(min_value) == ERROR_MARK - || max_value == NULL_TREE || TREE_CODE(max_value) == ERROR_MARK) - return error_mark_node; - - if (TREE_TYPE (array) == NULL_TREE - || (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE - && TREE_CODE (TREE_TYPE (array)) != SET_TYPE - && !chill_varying_type_p (TREE_TYPE (array)))) - { - error ("can only take slice of array or string"); - return error_mark_node; - } - - array = save_if_needed (array); - - /* FIXME: test here for max_value >= min_value, except - for max_value == -1, min_value == 0 (empty string) */ - min_value = valid_array_index_p (array, min_value, - "slice lower limit out-of-range", 0); - if (TREE_CODE (min_value) == ERROR_MARK) - return min_value; - - /* FIXME: suppress this test if max_value is the LENGTH of a - varying array, which has presumably already been checked. */ - max_value = valid_array_index_p (array, max_value, - "slice upper limit out-of-range", 0); - if (TREE_CODE (max_value) == ERROR_MARK) - return error_mark_node; - - if (TREE_CODE (min_value) == INTEGER_CST - && TREE_CODE (max_value) == INTEGER_CST - && tree_int_cst_lt (max_value, min_value)) - return build_empty_string (TREE_TYPE (TREE_TYPE (array))); - - return - build_chill_slice - (array, min_value, - save_expr (fold (build (PLUS_EXPR, integer_type_node, - fold (build (MINUS_EXPR, integer_type_node, - max_value, min_value)), - integer_one_node)))); -} - -tree -build_chill_slice_with_length (array, min_value, length) - tree array, min_value, length; -{ - tree max_index; - tree cond, high_cond, atype; - - if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK - || min_value == NULL_TREE || TREE_CODE(min_value) == ERROR_MARK - || length == NULL_TREE || TREE_CODE(length) == ERROR_MARK) - return error_mark_node; - - if (TREE_TYPE (array) == NULL_TREE - || (TREE_CODE (TREE_TYPE (array)) != ARRAY_TYPE - && TREE_CODE (TREE_TYPE (array)) != SET_TYPE - && !chill_varying_type_p (TREE_TYPE (array)))) - { - error ("can only take slice of array or string"); - return error_mark_node; - } - - if (TREE_CONSTANT (length) - && tree_int_cst_lt (length, integer_zero_node)) - return build_empty_string (TREE_TYPE (TREE_TYPE (array))); - - array = save_if_needed (array); - min_value = save_expr (min_value); - length = save_expr (length); - - if (! CH_SIMILAR (TREE_TYPE (length), integer_type_node)) - { - error ("slice length is not an integer"); - length = integer_one_node; - } - - max_index = fold (build (MINUS_EXPR, integer_type_node, - fold (build (PLUS_EXPR, integer_type_node, - length, min_value)), - integer_one_node)); - max_index = convert_to_class (chill_expr_class (min_value), max_index); - - min_value = valid_array_index_p (array, min_value, - "slice start index out-of-range", 0); - if (TREE_CODE (min_value) == ERROR_MARK) - return error_mark_node; - - atype = TREE_TYPE (array); - - if (chill_varying_type_p (atype)) - high_cond = build_component_ref (array, var_length_id); - else - high_cond = TYPE_MAX_VALUE (TYPE_DOMAIN (atype)); - - /* an invalid index expression meets this condition */ - cond = fold (build (TRUTH_ORIF_EXPR, boolean_type_node, - build_compare_discrete_expr (LT_EXPR, - length, integer_zero_node), - build_compare_discrete_expr (GT_EXPR, - max_index, high_cond))); - - if (TREE_CODE (cond) == INTEGER_CST) - { - if (! tree_int_cst_equal (cond, boolean_false_node)) - { - error ("slice length out-of-range"); - return error_mark_node; - } - - } - else if (range_checking) - { - min_value = check_expression (min_value, cond, - ridpointers[(int) RID_RANGEFAIL]); - } - - return build_chill_slice (array, min_value, length); -} - -tree -build_chill_array_ref (array, indexlist) - tree array, indexlist; -{ - tree idx; - - if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK) - return error_mark_node; - if (indexlist == NULL_TREE || TREE_CODE (indexlist) == ERROR_MARK) - return error_mark_node; - - idx = TREE_VALUE (indexlist); /* handle first index */ - - idx = valid_array_index_p (array, idx, - "array index out-of-range", 0); - if (TREE_CODE (idx) == ERROR_MARK) - return error_mark_node; - - array = build_chill_array_ref_1 (array, idx); - - if (array && TREE_CODE (array) != ERROR_MARK - && TREE_CHAIN (indexlist)) - { - /* Z.200 (1988) section 4.2.8 says that: - <array> '(' <expression {',' <expression> }* ')' - is derived syntax (i.e. syntactic sugar) for: - <array> '(' <expression ')' { '(' <expression> ')' }* - The intent is clear if <array> has mode: ARRAY (...) ARRAY (...) XXX. - But what if <array> has mode: ARRAY (...) CHARS (N) - or: ARRAY (...) BOOLS (N). - Z.200 doesn't explicitly prohibit it, but the intent is unclear. - We'll allow it, since it seems reasonable and useful. - However, we won't allow it if <array> is: - ARRAY (...) PROC (...). - (The latter would make sense if we allowed general - Currying, which Chill doesn't.) */ - if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE - || chill_varying_type_p (TREE_TYPE (array)) - || CH_BOOLS_TYPE_P (TREE_TYPE (array))) - array = build_generalized_call (array, TREE_CHAIN (indexlist)); - else - error ("too many index expressions"); - } - return array; -} - -/* - * Don't error check the index in here. It's supposed to be - * checked by the caller. - */ -tree -build_chill_array_ref_1 (array, idx) - tree array, idx; -{ - tree type; - tree domain; - tree rval; - - if (array == NULL_TREE || TREE_CODE (array) == ERROR_MARK - || idx == NULL_TREE || TREE_CODE (idx) == ERROR_MARK) - return error_mark_node; - - if (chill_varying_type_p (TREE_TYPE (array))) - array = varying_to_slice (array); - - domain = TYPE_DOMAIN (TREE_TYPE (array)); - -#if 0 - if (! integer_zerop (TYPE_MIN_VALUE (domain))) - { - /* The C part of the compiler doesn't understand how to do - arithmetic with dissimilar enum types. So we check compatibility - here, and perform the math in INTEGER_TYPE. */ - if (TREE_CODE (TREE_TYPE (idx)) == ENUMERAL_TYPE - && chill_comptypes (TREE_TYPE (idx), domain, 0)) - idx = convert (TREE_TYPE (TYPE_MIN_VALUE (domain)), idx); - idx = build_binary_op (MINUS_EXPR, idx, TYPE_MIN_VALUE (domain), 0); - } -#endif - - if (CH_STRING_TYPE_P (TREE_TYPE (array))) - { - /* Could be bitstring or char string. */ - if (TREE_TYPE (TREE_TYPE (array)) == boolean_type_node) - { - rval = build (SET_IN_EXPR, boolean_type_node, idx, array); - TREE_READONLY (rval) = TREE_READONLY (array); - return rval; - } - } - - if (!discrete_type_p (TREE_TYPE (idx))) - { - error ("array index is not discrete"); - return error_mark_node; - } - - /* An array that is indexed by a non-constant - cannot be stored in a register; we must be able to do - address arithmetic on its address. - Likewise an array of elements of variable size. */ - if (TREE_CODE (idx) != INTEGER_CST - || (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0 - && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST)) - { - if (mark_addressable (array) == 0) - return error_mark_node; - } - - type = TREE_TYPE (TREE_TYPE (array)); - - /* Do constant folding */ - if (TREE_CODE (idx) == INTEGER_CST && TREE_CONSTANT (array)) - { - struct ch_class class; - class.kind = CH_VALUE_CLASS; - class.mode = type; - - if (TREE_CODE (array) == CONSTRUCTOR) - { - tree list = CONSTRUCTOR_ELTS (array); - for ( ; list != NULL_TREE; list = TREE_CHAIN (list)) - { - if (tree_int_cst_equal (TREE_PURPOSE (list), idx)) - return convert_to_class (class, TREE_VALUE (list)); - } - } - else if (TREE_CODE (array) == STRING_CST - && CH_CHARS_TYPE_P (TREE_TYPE (array))) - { - HOST_WIDE_INT i = tree_low_cst (idx, 0); - - if (i >= 0 && i < TREE_STRING_LENGTH (array)) - return - convert_to_class - (class, - build_int_2 - ((unsigned char) TREE_STRING_POINTER (array) [i], 0)); - } - } - - if (TYPE_PACKED (TREE_TYPE (array))) - rval = build (PACKED_ARRAY_REF, type, array, idx); - else - rval = build (ARRAY_REF, type, array, idx); - - /* Array ref is const/volatile if the array elements are - or if the array is. */ - TREE_READONLY (rval) = TREE_READONLY (array) | TYPE_READONLY (type); - TREE_SIDE_EFFECTS (rval) - |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) - | TREE_SIDE_EFFECTS (array)); - TREE_THIS_VOLATILE (rval) - |= (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (array))) - /* This was added by rms on 16 Nov 91. - It fixes vol struct foo *a; a->elts[1] - in an inline function. - Hope it doesn't break something else. */ - | TREE_THIS_VOLATILE (array)); - return fold (rval); -} - -tree -build_chill_bitref (bitstring, indexlist) - tree bitstring, indexlist; -{ - if (TREE_CODE (bitstring) == ERROR_MARK) - return bitstring; - if (TREE_CODE (indexlist) == ERROR_MARK) - return indexlist; - - if (TREE_CHAIN (indexlist) != NULL_TREE) - { - error ("invalid compound index for bitstring mode"); - return error_mark_node; - } - - if (TREE_CODE (indexlist) == TREE_LIST) - { - tree result = build (SET_IN_EXPR, boolean_type_node, - TREE_VALUE (indexlist), bitstring); - TREE_READONLY (result) = TREE_READONLY (bitstring); - return result; - } - else abort (); -} - - -int -discrete_type_p (type) - tree type; -{ - return INTEGRAL_TYPE_P (type); -} - -/* Checks that EXP has discrete type, or can be converted to discrete. - Otherwise, returns NULL_TREE. - Normally returns the (possibly-converted) EXP. */ - -tree -convert_to_discrete (exp) - tree exp; -{ - if (! discrete_type_p (TREE_TYPE (exp))) - { - if (flag_old_strings) - { - if (CH_CHARS_ONE_P (TREE_TYPE (exp))) - return convert (char_type_node, exp); - if (CH_BOOLS_ONE_P (TREE_TYPE (exp))) - return convert (boolean_type_node, exp); - } - return NULL_TREE; - } - return exp; -} - -/* Write into BUFFER the target-machine representation of VALUE. - Returns 1 on success, or 0 on failure. (Either the VALUE was - not constant, or we don't know how to do the conversion.) */ - -static int -expand_constant_to_buffer (value, buffer, buf_size) - tree value; - unsigned char *buffer; - int buf_size; -{ - tree type = TREE_TYPE (value); - int size = int_size_in_bytes (type); - int i; - if (size < 0 || size > buf_size) - return 0; - switch (TREE_CODE (value)) - { - case INTEGER_CST: - { - unsigned HOST_WIDE_INT lo = TREE_INT_CST_LOW (value); - HOST_WIDE_INT hi = TREE_INT_CST_HIGH (value); - for (i = 0; i < size; i++) - { - /* Doesn't work if host and target BITS_PER_UNIT differ. */ - unsigned char byte = lo & ((1 << BITS_PER_UNIT) - 1); - - if (BYTES_BIG_ENDIAN) - buffer[size - i - 1] = byte; - else - buffer[i] = byte; - - rshift_double (lo, hi, BITS_PER_UNIT, BITS_PER_UNIT * size, - &lo, &hi, 0); - } - } - break; - case STRING_CST: - { - size = TREE_STRING_LENGTH (value); - if (size > buf_size) - return 0; - bcopy (TREE_STRING_POINTER (value), buffer, size); - break; - } - case CONSTRUCTOR: - if (TREE_CODE (type) == ARRAY_TYPE) - { - tree element_type = TREE_TYPE (type); - int element_size = int_size_in_bytes (element_type); - tree list = CONSTRUCTOR_ELTS (value); - HOST_WIDE_INT next_index; - HOST_WIDE_INT min_index = 0; - if (element_size < 0) - return 0; - - if (TYPE_DOMAIN (type) != 0) - { - tree min_val = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - if (min_val) - { - if (! host_integerp (min_val, 0)) - return 0; - else - min_index = tree_low_cst (min_val, 0); - } - } - - next_index = min_index; - - for (; list != NULL_TREE; list = TREE_CHAIN (list)) - { - HOST_WIDE_INT offset; - HOST_WIDE_INT last_index; - tree purpose = TREE_PURPOSE (list); - - if (purpose) - { - if (host_integerp (purpose, 0)) - last_index = next_index = tree_low_cst (purpose, 0); - else if (TREE_CODE (purpose) == RANGE_EXPR) - { - next_index = tree_low_cst (TREE_OPERAND (purpose, 0), 0); - last_index = tree_low_cst (TREE_OPERAND (purpose, 1), 0); - } - else - return 0; - } - else - last_index = next_index; - for ( ; next_index <= last_index; next_index++) - { - offset = (next_index - min_index) * element_size; - if (!expand_constant_to_buffer (TREE_VALUE (list), - buffer + offset, - buf_size - offset)) - return 0; - } - } - break; - } - else if (TREE_CODE (type) == RECORD_TYPE) - { - tree list = CONSTRUCTOR_ELTS (value); - for (; list != NULL_TREE; list = TREE_CHAIN (list)) - { - tree field = TREE_PURPOSE (list); - HOST_WIDE_INT offset; - - if (field == NULL_TREE || TREE_CODE (field) != FIELD_DECL) - return 0; - - if (DECL_BIT_FIELD (field)) - return 0; - - offset = int_byte_position (field); - if (!expand_constant_to_buffer (TREE_VALUE (list), - buffer + offset, - buf_size - offset)) - return 0; - } - break; - } - else if (TREE_CODE (type) == SET_TYPE) - { - if (get_set_constructor_bytes (value, buffer, buf_size) - != NULL_TREE) - return 0; - } - break; - default: - return 0; - } - return 1; -} - -/* Given that BUFFER contains a target-machine representation of - a value of type TYPE, return that value as a tree. - Returns NULL_TREE on failure. (E.g. the TYPE might be variable size, - or perhaps we don't know how to do the conversion.) */ - -static tree -extract_constant_from_buffer (type, buffer, buf_size) - tree type; - const unsigned char *buffer; - int buf_size; -{ - tree value; - HOST_WIDE_INT size = int_size_in_bytes (type); - HOST_WIDE_INT i; - - if (size < 0 || size > buf_size) - return 0; - - switch (TREE_CODE (type)) - { - case INTEGER_TYPE: - case CHAR_TYPE: - case BOOLEAN_TYPE: - case ENUMERAL_TYPE: - case POINTER_TYPE: - { - HOST_WIDE_INT lo = 0, hi = 0; - /* Accumulate (into (lo,hi) the bytes (from buffer). */ - for (i = size; --i >= 0; ) - { - unsigned char byte; - /* Get next byte (in big-endian order). */ - if (BYTES_BIG_ENDIAN) - byte = buffer[size - i - 1]; - else - byte = buffer[i]; - lshift_double (lo, hi, BITS_PER_UNIT, TYPE_PRECISION (type), - &lo, &hi, 0); - add_double (lo, hi, byte, 0, &lo, &hi); - } - value = build_int_2 (lo, hi); - TREE_TYPE (value) = type; - return value; - } - case ARRAY_TYPE: - { - tree element_type = TREE_TYPE (type); - int element_size = int_size_in_bytes (element_type); - tree list = NULL_TREE; - HOST_WIDE_INT min_index = 0, max_index, cur_index; - if (element_size == 1 && CH_CHARS_TYPE_P (type)) - { - value = build_string (size, buffer); - CH_DERIVED_FLAG (value) = 1; - TREE_TYPE (value) = type; - return value; - } - if (TYPE_DOMAIN (type) == 0) - return 0; - value = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - if (value) - { - if (! host_integerp (value, 0)) - return 0; - else - min_index = tree_low_cst (value, 0); - } - - value = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - if (value == NULL_TREE || ! host_integerp (value, 0)) - return 0; - else - max_index = tree_low_cst (value, 0); - - for (cur_index = max_index; cur_index >= min_index; cur_index--) - { - HOST_WIDE_INT offset = (cur_index - min_index) * element_size; - value = extract_constant_from_buffer (element_type, - buffer + offset, - buf_size - offset); - if (value == NULL_TREE) - return NULL_TREE; - list = tree_cons (build_int_2 (cur_index, 0), value, list); - } - value = build (CONSTRUCTOR, type, NULL_TREE, list); - TREE_CONSTANT (value) = 1; - TREE_STATIC (value) = 1; - return value; - } - case RECORD_TYPE: - { - tree list = NULL_TREE; - tree field = TYPE_FIELDS (type); - for (; field != NULL_TREE; field = TREE_CHAIN (field)) - { - HOST_WIDE_INT offset = int_byte_position (field); - - if (DECL_BIT_FIELD (field)) - return 0; - value = extract_constant_from_buffer (TREE_TYPE (field), - buffer + offset, - buf_size - offset); - if (value == NULL_TREE) - return NULL_TREE; - list = tree_cons (field, value, list); - } - value = build (CONSTRUCTOR, type, NULL_TREE, nreverse (list)); - TREE_CONSTANT (value) = 1; - TREE_STATIC (value) = 1; - return value; - } - - case UNION_TYPE: - { - tree longest_variant = NULL_TREE; - unsigned HOST_WIDE_INT longest_size = 0; - tree field = TYPE_FIELDS (type); - - /* This is a kludge. We assume that converting the data to te - longest variant will provide valid data for the "correct" - variant. This is usually the case, but is not guaranteed. - For example, the longest variant may include holes. - Also incorrect interpreting the given value as the longest - variant may confuse the compiler if that should happen - to yield invalid values. ??? */ - - for (; field != NULL_TREE; field = TREE_CHAIN (field)) - { - unsigned HOST_WIDE_INT size - = int_size_in_bytes (TREE_TYPE (field)); - - if (size > longest_size) - { - longest_size = size; - longest_variant = field; - } - } - - if (longest_variant == NULL_TREE) - return NULL_TREE; - - return - extract_constant_from_buffer (TREE_TYPE (longest_variant), - buffer, buf_size); - } - - case SET_TYPE: - { - tree list = NULL_TREE; - int i; - HOST_WIDE_INT min_index, max_index; - - if (TYPE_DOMAIN (type) == 0) - return 0; - - value = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); - if (value == NULL_TREE) - min_index = 0; - - else if (! host_integerp (value, 0)) - return 0; - else - min_index = tree_low_cst (value, 0); - - value = TYPE_MAX_VALUE (TYPE_DOMAIN (type)); - if (value == NULL_TREE) - max_index = 0; - else if (! host_integerp (value, 0)) - return 0; - else - max_index = tree_low_cst (value, 0); - - for (i = max_index + 1 - min_index; --i >= 0; ) - { - unsigned char byte = (unsigned char) buffer[i / BITS_PER_UNIT]; - unsigned bit_pos = (unsigned) i % (unsigned) BITS_PER_UNIT; - - if (BYTES_BIG_ENDIAN - ? (byte & (1 << (BITS_PER_UNIT - 1 - bit_pos))) - : (byte & (1 << bit_pos))) - list = tree_cons (NULL_TREE, - build_int_2 (i + min_index, 0), list); - } - value = build (CONSTRUCTOR, type, NULL_TREE, list); - TREE_CONSTANT (value) = 1; - TREE_STATIC (value) = 1; - return value; - } - - default: - return NULL_TREE; - } -} - -tree -build_chill_cast (type, expr) - tree type, expr; -{ - tree expr_type; - int expr_type_size; - int type_size; - int type_is_discrete; - int expr_type_is_discrete; - - if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) - return error_mark_node; - - /* if expression was untyped because of its context (an - if_expr or case_expr in a tuple, perhaps) just apply - the type */ - expr_type = TREE_TYPE (expr); - if (expr_type == NULL_TREE - || TREE_CODE (expr_type) == ERROR_MARK) - return convert (type, expr); - - if (expr_type == type) - return expr; - - expr_type_size = int_size_in_bytes (expr_type); - type_size = int_size_in_bytes (type); - - if (expr_type_size == -1) - { - error ("conversions from variable_size value"); - return error_mark_node; - } - if (type_size == -1) - { - error ("conversions to variable_size mode"); - return error_mark_node; - } - - /* FIXME: process REAL ==> INT && INT ==> REAL && REAL ==> REAL. I hope this is correct. */ - if ((TREE_CODE (expr_type) == INTEGER_TYPE && TREE_CODE (type) == REAL_TYPE) || - (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == INTEGER_TYPE) || - (TREE_CODE (expr_type) == REAL_TYPE && TREE_CODE (type) == REAL_TYPE)) - return convert (type, expr); - - /* FIXME: Don't know if this is correct */ - /* Don't allow conversions to or from REAL with others then integer */ - if (TREE_CODE (type) == REAL_TYPE) - { - error ("cannot convert to float"); - return error_mark_node; - } - else if (TREE_CODE (expr_type) == REAL_TYPE) - { - error ("cannot convert float to this mode"); - return error_mark_node; - } - - if (expr_type_size == type_size && CH_REFERABLE (expr)) - goto do_location_conversion; - - type_is_discrete - = discrete_type_p (type) || TREE_CODE (type) == POINTER_TYPE; - expr_type_is_discrete - = discrete_type_p (expr_type) || TREE_CODE (expr_type) == POINTER_TYPE; - if (expr_type_is_discrete && type_is_discrete) - { - /* do an overflow check - FIXME: is this always necessary ??? */ - /* FIXME: don't do range chacking when target type is PTR. - PTR doesn't have MIN and MAXVALUE. result is sigsegv. */ - if (range_checking && type != ptr_type_node) - { - tree tmp = expr; - - STRIP_NOPS (tmp); - if (TREE_CONSTANT (tmp) && TREE_CODE (tmp) != ADDR_EXPR) - { - if (compare_int_csts (LT_EXPR, tmp, TYPE_MIN_VALUE (type)) || - compare_int_csts (GT_EXPR, tmp, TYPE_MAX_VALUE (type))) - { - error ("OVERFLOW in expression conversion"); - return error_mark_node; - } - } - else - { - int cond1 = tree_int_cst_lt (TYPE_SIZE (type), - TYPE_SIZE (expr_type)); - int cond2 = TREE_UNSIGNED (type) && (! TREE_UNSIGNED (expr_type)); - int cond3 = (! TREE_UNSIGNED (type)) - && TREE_UNSIGNED (expr_type) - && tree_int_cst_equal (TYPE_SIZE (type), - TYPE_SIZE (expr_type)); - int cond4 = TREE_TYPE (type) && type_is_discrete; - - if (cond1 || cond2 || cond3 || cond4) - { - tree type_min = TYPE_MIN_VALUE (type); - tree type_max = TYPE_MAX_VALUE (type); - - expr = save_if_needed (expr); - if (expr && type_min && type_max) - { - tree check = test_range (expr, type_min, type_max); - if (!integer_zerop (check)) - { - if (current_function_decl == NULL_TREE) - { - if (TREE_CODE (check) == INTEGER_CST) - error ("overflow (not inside function)"); - else - warning ("possible overflow (not inside function)"); - } - else - { - if (TREE_CODE (check) == INTEGER_CST) - warning ("expression will always cause OVERFLOW"); - expr = check_expression (expr, check, - ridpointers[(int) RID_OVERFLOW]); - } - } - } - } - } - } - return convert (type, expr); - } - - if (TREE_CODE (expr) == INTEGER_CST && expr_type_size != type_size) - { - /* There should probably be a pedwarn here ... */ - tree itype = type_for_size (type_size * BITS_PER_UNIT, 1); - if (itype) - { - expr = convert (itype, expr); - expr_type = TREE_TYPE (expr); - expr_type_size= type_size; - } - } - - /* If expr is a constant of the right size, use it to to - initialize a static variable. */ - if (expr_type_size == type_size && TREE_CONSTANT (expr) && !pedantic) - { - unsigned char *buffer = (unsigned char*) alloca (type_size); - tree value; - memset (buffer, 0, type_size); - if (!expand_constant_to_buffer (expr, buffer, type_size)) - { - error ("not implemented: constant conversion from that kind of expression"); - return error_mark_node; - } - value = extract_constant_from_buffer (type, buffer, type_size); - if (value == NULL_TREE) - { - error ("not implemented: constant conversion to that kind of mode"); - return error_mark_node; - } - return value; - } - - if (!CH_REFERABLE (expr) && expr_type_size == type_size) - { - tree temp = decl_temp1 (get_unique_identifier ("CAST"), - TREE_TYPE (expr), 0, 0, 0, 0); - tree convert1 = build_chill_modify_expr (temp, expr); - pedwarn ("non-standard, non-portable value conversion"); - return build (COMPOUND_EXPR, type, convert1, - build_chill_cast (type, temp)); - } - - if (CH_REFERABLE (expr) && expr_type_size != type_size) - error ("location conversion between differently-sized modes"); - else - error ("unsupported value conversion"); - return error_mark_node; - - do_location_conversion: - /* To avoid confusing other parts of gcc, - represent this as the C expression: *(TYPE*)EXPR. */ - mark_addressable (expr); - expr = build1 (INDIRECT_REF, type, - build1 (NOP_EXPR, build_pointer_type (type), - build1 (ADDR_EXPR, build_pointer_type (expr_type), - expr))); - TREE_READONLY (expr) = TYPE_READONLY (type); - return expr; -} - -/* Given a set_type, build an integer array from it that C will grok. */ - -tree -build_array_from_set (type) - tree type; -{ - tree bytespint, bit_array_size, int_array_count; - - if (type == NULL_TREE || type == error_mark_node - || TREE_CODE (type) != SET_TYPE) - return error_mark_node; - - /* ??? Should this really be *HOST*?? */ - bytespint = size_int (HOST_BITS_PER_INT / HOST_BITS_PER_CHAR); - bit_array_size = size_in_bytes (type); - int_array_count = size_binop (TRUNC_DIV_EXPR, bit_array_size, bytespint); - if (integer_zerop (int_array_count)) - int_array_count = size_one_node; - type = build_array_type (integer_type_node, - build_index_type (int_array_count)); - return type; -} - - -tree -build_chill_bin_type (size) - tree size; -{ -#if 0 - HOST_WIDE_INT isize; - - if (! host_integerp (size, 1)) - { - error ("operand to bin must be a non-negative integer literal"); - return error_mark_node; - } - - isize = tree_low_cst (size, 1); - - if (isize <= TYPE_PRECISION (unsigned_char_type_node)) - return unsigned_char_type_node; - if (isize <= TYPE_PRECISION (short_unsigned_type_node)) - return short_unsigned_type_node; - if (isize <= TYPE_PRECISION (unsigned_type_node)) - return unsigned_type_node; - if (isize <= TYPE_PRECISION (long_unsigned_type_node)) - return long_unsigned_type_node; - if (isize <= TYPE_PRECISION (long_long_unsigned_type_node)) - return long_long_unsigned_type_node; - error ("size %d of BIN too big - no such integer mode", isize); - return error_mark_node; -#endif - tree bintype; - - if (pass == 1) - { - bintype = make_node (INTEGER_TYPE); - TREE_TYPE (bintype) = ridpointers[(int) RID_BIN]; - TYPE_MIN_VALUE (bintype) = size; - TYPE_MAX_VALUE (bintype) = size; - } - else - { - error ("BIN in pass 2"); - return error_mark_node; - } - return bintype; -} - -tree -chill_expand_tuple (type, constructor) - tree type, constructor; -{ - const char *name; - tree nonreft = type; - - if (TYPE_NAME (type) != NULL_TREE) - { - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - name = IDENTIFIER_POINTER (TYPE_NAME (type)); - else - name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); - } - else - name = ""; - - /* get to actual underlying type for digest_init */ - while (nonreft && TREE_CODE (nonreft) == REFERENCE_TYPE) - nonreft = TREE_TYPE (nonreft); - - if (TREE_CODE (nonreft) == ARRAY_TYPE - || TREE_CODE (nonreft) == RECORD_TYPE - || TREE_CODE (nonreft) == SET_TYPE) - return convert (nonreft, constructor); - else - { - error ("mode of tuple is neither ARRAY, STRUCT, nor POWERSET"); - return error_mark_node; - } -} - -/* This function classifies an expr into the Null class, - the All class, the M-Value, the M-derived, or the M-reference class. - It probably has some inaccuracies. */ - -struct ch_class -chill_expr_class (expr) - tree expr; -{ - struct ch_class class; - /* The Null class contains the NULL pointer constant (only). */ - if (expr == null_pointer_node) - { - class.kind = CH_NULL_CLASS; - class.mode = NULL_TREE; - return class; - } - - /* The All class contains the <undefined value> "*". */ - if (TREE_CODE (expr) == UNDEFINED_EXPR) - { - class.kind = CH_ALL_CLASS; - class.mode = NULL_TREE; - return class; - } - - if (CH_DERIVED_FLAG (expr)) - { - class.kind = CH_DERIVED_CLASS; - class.mode = TREE_TYPE (expr); - return class; - } - - /* The M-Reference contains <references location> (address-of) expressions. - Note that something that's been converted to a reference doesn't count. */ - if (TREE_CODE (expr) == ADDR_EXPR - && TREE_CODE (TREE_TYPE (expr)) != REFERENCE_TYPE) - { - class.kind = CH_REFERENCE_CLASS; - class.mode = TREE_TYPE (TREE_TYPE (expr)); - return class; - } - - /* The M-Value class contains expressions with a known, specific mode M. */ - class.kind = CH_VALUE_CLASS; - class.mode = TREE_TYPE (expr); - return class; -} - -/* Returns >= 1 iff REF is a location. Return 2 if it is referable. */ - -int chill_location (ref) - tree ref; -{ - register enum tree_code code = TREE_CODE (ref); - - switch (code) - { - case REALPART_EXPR: - case IMAGPART_EXPR: - case ARRAY_REF: - case PACKED_ARRAY_REF: - case COMPONENT_REF: - case NOP_EXPR: /* RETYPE_EXPR */ - return chill_location (TREE_OPERAND (ref, 0)); - case COMPOUND_EXPR: - return chill_location (TREE_OPERAND (ref, 1)); - - case BIT_FIELD_REF: - case SLICE_EXPR: - /* A bit-string slice is nor referable. */ - return chill_location (TREE_OPERAND (ref, 0)) == 0 ? 0 : 1; - - case CONSTRUCTOR: - case STRING_CST: - return 0; - - case INDIRECT_REF: - case VAR_DECL: - case PARM_DECL: - case RESULT_DECL: - case ERROR_MARK: - if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE - && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE) - return 2; - break; - - default: - break; - } - return 0; -} - -int -chill_referable (val) - tree val; -{ - return chill_location (val) > 1; -} - -/* Make a copy of MODE, but with the given NOVELTY. */ - -tree -copy_novelty (novelty, mode) - tree novelty, mode; -{ - if (CH_NOVELTY (mode) != novelty) - { - mode = copy_node (mode); - TYPE_MAIN_VARIANT (mode) = mode; - TYPE_NEXT_VARIANT (mode) = 0; - TYPE_POINTER_TO (mode) = 0; - TYPE_REFERENCE_TO (mode) = 0; - SET_CH_NOVELTY (mode, novelty); - } - return mode; -} - - -struct mode_chain -{ - struct mode_chain *prev; - tree mode1, mode2; -}; - -/* Tests if MODE1 and MODE2 are SIMILAR. - This is more or less as defined in the Blue Book, though - see FIXME for parts that are unfinished. - CHAIN is used to catch infinite recursion: It is a list of pairs - of mode arguments to calls to chill_similar "outer" to this call. */ - -int -chill_similar (mode1, mode2, chain) - tree mode1, mode2; - struct mode_chain *chain; -{ - int varying1, varying2; - tree t1, t2; - struct mode_chain *link, node; - if (mode1 == NULL_TREE || mode2 == NULL_TREE) - return 0; - - while (TREE_CODE (mode1) == REFERENCE_TYPE) - mode1 = TREE_TYPE (mode1); - while (TREE_CODE (mode2) == REFERENCE_TYPE) - mode2 = TREE_TYPE (mode2); - - /* Range modes are similar to their parent types. */ - while (TREE_CODE (mode1) == INTEGER_TYPE && TREE_TYPE (mode1) != NULL_TREE) - mode1 = TREE_TYPE (mode1); - while (TREE_CODE (mode2) == INTEGER_TYPE && TREE_TYPE (mode2) != NULL_TREE) - mode2 = TREE_TYPE (mode2); - - - /* see Z.200 sections 12.1.2.2 and 13.2 - all integer precisions - are similar to INT and to each other */ - if (mode1 == mode2 || - (TREE_CODE (mode1) == INTEGER_TYPE && TREE_CODE (mode2) == INTEGER_TYPE)) - return 1; - - /* This guards against certain kinds of recursion. - For example: - SYNMODE a = STRUCT ( next REF a ); - SYNMODE b = STRUCT ( next REF b ); - These moes are similar, but will get an infite recursion trying - to prove that. So, if we are recursing, assume the moes are similar. - If they are not, we'll find some other discrepancy. */ - for (link = chain; link != NULL; link = link->prev) - { - if (link->mode1 == mode1 && link->mode2 == mode2) - return 1; - } - - node.mode1 = mode1; - node.mode2 = mode2; - node.prev = chain; - - varying1 = chill_varying_type_p (mode1); - varying2 = chill_varying_type_p (mode2); - /* FIXME: This isn't quite strict enough. */ - if ((varying1 && varying2) - || (varying1 && TREE_CODE (mode2) == ARRAY_TYPE) - || (varying2 && TREE_CODE (mode1) == ARRAY_TYPE)) - return 1; - - if (TREE_CODE(mode1) != TREE_CODE(mode2)) - { - if (flag_old_strings) - { - /* The recursion is to handle varying strings. */ - if ((TREE_CODE (mode1) == CHAR_TYPE - && CH_SIMILAR (mode2, string_one_type_node)) - || (TREE_CODE (mode2) == CHAR_TYPE - && CH_SIMILAR (mode1, string_one_type_node))) - return 1; - if ((TREE_CODE (mode1) == BOOLEAN_TYPE - && CH_SIMILAR (mode2, bitstring_one_type_node)) - || (TREE_CODE (mode2) == BOOLEAN_TYPE - && CH_SIMILAR (mode1, bitstring_one_type_node))) - return 1; - } - if (TREE_CODE (mode1) == FUNCTION_TYPE - && TREE_CODE (mode2) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (mode2)) == FUNCTION_TYPE) - mode2 = TREE_TYPE (mode2); - else if (TREE_CODE (mode2) == FUNCTION_TYPE - && TREE_CODE (mode1) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (mode1)) == FUNCTION_TYPE) - mode1 = TREE_TYPE (mode1); - else - return 0; - } - - if (CH_IS_BUFFER_MODE (mode1) && CH_IS_BUFFER_MODE (mode2)) - { - tree len1 = max_queue_size (mode1); - tree len2 = max_queue_size (mode2); - return tree_int_cst_equal (len1, len2); - } - else if (CH_IS_EVENT_MODE (mode1) && CH_IS_EVENT_MODE (mode2)) - { - tree len1 = max_queue_size (mode1); - tree len2 = max_queue_size (mode2); - return tree_int_cst_equal (len1, len2); - } - else if (CH_IS_ACCESS_MODE (mode1) && CH_IS_ACCESS_MODE (mode2)) - { - tree index1 = access_indexmode (mode1); - tree index2 = access_indexmode (mode2); - tree record1 = access_recordmode (mode1); - tree record2 = access_recordmode (mode2); - if (! chill_read_compatible (index1, index2)) - return 0; - return chill_read_compatible (record1, record2); - } - switch ((enum chill_tree_code)TREE_CODE (mode1)) - { - case INTEGER_TYPE: - case BOOLEAN_TYPE: - case CHAR_TYPE: - return 1; - case ENUMERAL_TYPE: - if (TYPE_VALUES (mode1) == TYPE_VALUES (mode2)) - return 1; - else - { - /* FIXME: This is more strict than z.200, which seems to - allow the elements to be reordered, as long as they - have the same values. */ - - tree field1 = TYPE_VALUES (mode1); - tree field2 = TYPE_VALUES (mode2); - - while (field1 != NULL_TREE && field2 != NULL_TREE) - { - tree value1, value2; - /* Check that the names are equal. */ - if (TREE_PURPOSE (field1) != TREE_PURPOSE (field2)) - break; - - value1 = TREE_VALUE (field1); - value2 = TREE_VALUE (field2); - /* This isn't quite sufficient in general, but will do ... */ - /* Note that proclaim_decl can cause the SET modes to be - compared BEFORE they are satisfied, but otherwise - chill_similar is mostly called after satisfaction. */ - if (TREE_CODE (value1) == CONST_DECL) - value1 = DECL_INITIAL (value1); - if (TREE_CODE (value2) == CONST_DECL) - value2 = DECL_INITIAL (value2); - /* Check that the values are equal or both NULL. */ - if (!(value1 == NULL_TREE && value2 == NULL_TREE) - && (value1 == NULL_TREE || value2 == NULL_TREE - || ! tree_int_cst_equal (value1, value2))) - break; - field1 = TREE_CHAIN (field1); - field2 = TREE_CHAIN (field2); - } - return field1 == NULL_TREE && field2 == NULL_TREE; - } - case SET_TYPE: - /* check for bit strings */ - if (CH_BOOLS_TYPE_P (mode1)) - return CH_BOOLS_TYPE_P (mode2); - if (CH_BOOLS_TYPE_P (mode2)) - return CH_BOOLS_TYPE_P (mode1); - /* both are powerset modes */ - return CH_EQUIVALENT (TYPE_DOMAIN (mode1), TYPE_DOMAIN (mode2)); - - case POINTER_TYPE: - /* Are the referenced modes equivalent? */ - return !integer_zerop (chill_equivalent (TREE_TYPE (mode1), - TREE_TYPE (mode2), - &node)); - - case ARRAY_TYPE: - /* char for char strings */ - if (CH_CHARS_TYPE_P (mode1)) - return CH_CHARS_TYPE_P (mode2); - if (CH_CHARS_TYPE_P (mode2)) - return CH_CHARS_TYPE_P (mode1); - /* array modes */ - if (CH_V_EQUIVALENT (TYPE_DOMAIN (mode1), TYPE_DOMAIN (mode2)) - /* Are the elements modes equivalent? */ - && !integer_zerop (chill_equivalent (TREE_TYPE (mode1), - TREE_TYPE (mode2), - &node))) - { - /* FIXME: Check that element layouts are equivalent */ - - tree count1 = fold (build (MINUS_EXPR, sizetype, - TYPE_MAX_VALUE (TYPE_DOMAIN (mode1)), - TYPE_MIN_VALUE (TYPE_DOMAIN (mode1)))); - tree count2 = fold (build (MINUS_EXPR, sizetype, - TYPE_MAX_VALUE (TYPE_DOMAIN (mode2)), - TYPE_MIN_VALUE (TYPE_DOMAIN (mode2)))); - tree cond = build_compare_discrete_expr (EQ_EXPR, count1, count2); - if (TREE_CODE (cond) == INTEGER_CST) - return !integer_zerop (cond); - else - { -#if 0 - extern int ignoring; - if (!ignoring - && range_checking - && current_function_decl) - return cond; -#endif - return 1; - } - } - return 0; - - case RECORD_TYPE: - case UNION_TYPE: - for (t1 = TYPE_FIELDS (mode1), t2 = TYPE_FIELDS (mode2); - t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) - { - if (TREE_CODE (t1) != TREE_CODE (t2)) - return 0; - /* Are the field modes equivalent? */ - if (integer_zerop (chill_equivalent (TREE_TYPE (t1), - TREE_TYPE (t2), - &node))) - return 0; - } - return t1 == t2; - - case FUNCTION_TYPE: - if (!chill_l_equivalent (TREE_TYPE (mode1), TREE_TYPE (mode2), &node)) - return 0; - for (t1 = TYPE_ARG_TYPES (mode1), t2 = TYPE_ARG_TYPES (mode2); - t1 != NULL_TREE && t2 != NULL_TREE; - t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2)) - { - tree attr1 = TREE_PURPOSE (t1) - ? TREE_PURPOSE (t1) : ridpointers[(int) RID_IN]; - tree attr2 = TREE_PURPOSE (t2) - ? TREE_PURPOSE (t2) : ridpointers[(int) RID_IN]; - if (attr1 != attr2) - return 0; - if (!chill_l_equivalent (TREE_VALUE (t1), TREE_VALUE (t2), &node)) - return 0; - } - if (t1 != t2) /* Both NULL_TREE */ - return 0; - /* check list of exception names */ - t1 = TYPE_RAISES_EXCEPTIONS (mode1); - t2 = TYPE_RAISES_EXCEPTIONS (mode2); - if (t1 == NULL_TREE && t2 != NULL_TREE) - return 0; - if (t1 != NULL_TREE && t2 == NULL_TREE) - return 0; - if (list_length (t1) != list_length (t2)) - return 0; - while (t1 != NULL_TREE) - { - if (value_member (TREE_VALUE (t1), t2) == NULL_TREE) - return 0; - t1 = TREE_CHAIN (t1); - } - /* FIXME: Should also check they have the same RECURSIVITY */ - return 1; - - default: - ; - /* Need to handle row modes, instance modes, - association modes, access modes, text modes, - duration modes, absolute time modes, structure modes, - parameterized structure modes */ - } - return 1; -} - -/* Return a node that is true iff MODE1 and MODE2 are equivalent. - This is normally boolean_true_node or boolean_false_node, - but can be dynamic for dynamic types. - CHAIN is as for chill_similar. */ - -tree -chill_equivalent (mode1, mode2, chain) - tree mode1, mode2; - struct mode_chain *chain; -{ - int varying1, varying2; - int is_string1, is_string2; - tree base_mode1, base_mode2; - - /* Are the modes v-equivalent? */ -#if 0 - if (!chill_similar (mode1, mode2, chain) - || CH_NOVELTY(mode1) != CH_NOVELTY(mode2)) - return boolean_false_node; -#endif - if (!chill_similar (mode1, mode2, chain)) - return boolean_false_node; - else if (TREE_CODE (mode2) == FUNCTION_TYPE - && TREE_CODE (mode1) == POINTER_TYPE - && TREE_CODE (TREE_TYPE (mode1)) == FUNCTION_TYPE) - /* don't check novelty in this case to avoid error in case of - NEWMODE'd proceduremode gets assigned a function */ - return boolean_true_node; - else if (CH_NOVELTY(mode1) != CH_NOVELTY(mode2)) - return boolean_false_node; - - varying1 = chill_varying_type_p (mode1); - varying2 = chill_varying_type_p (mode2); - - if (varying1 != varying2) - return boolean_false_node; - base_mode1 = varying1 ? CH_VARYING_ARRAY_TYPE (mode1) : mode1; - base_mode2 = varying2 ? CH_VARYING_ARRAY_TYPE (mode2) : mode2; - is_string1 = CH_STRING_TYPE_P (base_mode1); - is_string2 = CH_STRING_TYPE_P (base_mode2); - if (is_string1 || is_string2) - { - if (is_string1 != is_string2) - return boolean_false_node; - return fold (build (EQ_EXPR, boolean_type_node, - TYPE_SIZE (base_mode1), - TYPE_SIZE (base_mode2))); - } - - /* && some more stuff FIXME! */ - if (TREE_CODE(mode1) == INTEGER_TYPE || TREE_CODE(mode2) == INTEGER_TYPE) - { - if (TREE_CODE(mode1) != INTEGER_TYPE || TREE_CODE(mode2) != INTEGER_TYPE) - return boolean_false_node; - /* If one is a range, the other has to be a range. */ - if ((TREE_TYPE (mode1) != NULL_TREE) != (TREE_TYPE (mode2) != NULL_TREE)) - return boolean_false_node; - if (TYPE_PRECISION (mode1) != TYPE_PRECISION (mode2)) - return boolean_false_node; - if (!tree_int_cst_equal (TYPE_MIN_VALUE (mode1), TYPE_MIN_VALUE (mode2))) - return boolean_false_node; - if (!tree_int_cst_equal (TYPE_MAX_VALUE (mode1), TYPE_MAX_VALUE (mode2))) - return boolean_false_node; - } - return boolean_true_node; -} - -static int -chill_l_equivalent (mode1, mode2, chain) - tree mode1, mode2; - struct mode_chain *chain; -{ - /* Are the modes equivalent? */ - if (integer_zerop (chill_equivalent (mode1, mode2, chain))) - return 0; - if (TYPE_READONLY (mode1) != TYPE_READONLY (mode2)) - return 0; -/* - ... other conditions ...; - */ - return 1; -} - -/* See Z200 12.1.2.12 */ - -int -chill_read_compatible (modeM, modeN) - tree modeM, modeN; -{ - while (TREE_CODE (modeM) == REFERENCE_TYPE) - modeM = TREE_TYPE (modeM); - while (TREE_CODE (modeN) == REFERENCE_TYPE) - modeN = TREE_TYPE (modeN); - - if (!CH_EQUIVALENT (modeM, modeN)) - return 0; - if (TYPE_READONLY (modeN)) - { - if (!TYPE_READONLY (modeM)) - return 0; - if (CH_IS_BOUND_REFERENCE_MODE (modeM) - && CH_IS_BOUND_REFERENCE_MODE (modeN)) - { - return chill_l_equivalent (TREE_TYPE (modeM), TREE_TYPE (modeN), 0); - } -/* - ...; -*/ - } - return 1; -} - -/* Tests if MODE is compatible with the class of EXPR. - Cfr. Chill Blue Book 12.1.2.15. */ - -int -chill_compatible (expr, mode) - tree expr, mode; -{ - struct ch_class class; - - if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) - return 0; - if (mode == NULL_TREE || TREE_CODE (mode) == ERROR_MARK) - return 0; - - while (TREE_CODE (mode) == REFERENCE_TYPE) - mode = TREE_TYPE (mode); - - if (TREE_TYPE (expr) == NULL_TREE) - { - if (TREE_CODE (expr) == CONSTRUCTOR) - return TREE_CODE (mode) == RECORD_TYPE - || ((TREE_CODE (mode) == SET_TYPE || TREE_CODE (mode) == ARRAY_TYPE) - && ! TYPE_STRING_FLAG (mode)); - else - return TREE_CODE (expr) == CASE_EXPR || TREE_CODE (expr) == COND_EXPR; - } - - class = chill_expr_class (expr); - switch (class.kind) - { - case CH_ALL_CLASS: - return 1; - case CH_NULL_CLASS: - return CH_IS_REFERENCE_MODE (mode) || CH_IS_PROCEDURE_MODE (mode) - || CH_IS_INSTANCE_MODE (mode); - case CH_VALUE_CLASS: - if (CH_HAS_REFERENCING_PROPERTY (mode)) - return CH_RESTRICTABLE_TO(mode, class.mode); - else - return CH_V_EQUIVALENT(mode, class.mode); - case CH_DERIVED_CLASS: - return CH_SIMILAR (class.mode, mode); - case CH_REFERENCE_CLASS: - if (!CH_IS_REFERENCE_MODE (mode)) - return 0; -/* FIXME! - if (class.mode is a row mode) - ...; - else if (class.mode is not a static mode) - return 0; is this possible? -*/ - return !CH_IS_BOUND_REFERENCE_MODE(mode) - || CH_READ_COMPATIBLE (TREE_TYPE (mode), class.mode); - } - return 0; /* ERROR! */ -} - -/* Tests if the class of of EXPR1 and EXPR2 are compatible. - Cfr. Chill Blue Book 12.1.2.16. */ - -int -chill_compatible_classes (expr1, expr2) - tree expr1, expr2; -{ - struct ch_class temp; - struct ch_class class1, class2; - class1 = chill_expr_class (expr1); - class2 = chill_expr_class (expr2); - - switch (class1.kind) - { - case CH_ALL_CLASS: - return 1; - case CH_NULL_CLASS: - switch (class2.kind) - { - case CH_ALL_CLASS: - case CH_NULL_CLASS: - case CH_REFERENCE_CLASS: - return 1; - case CH_VALUE_CLASS: - case CH_DERIVED_CLASS: - goto rule4; - } - case CH_REFERENCE_CLASS: - switch (class2.kind) - { - case CH_ALL_CLASS: - case CH_NULL_CLASS: - return 1; - case CH_REFERENCE_CLASS: - return CH_EQUIVALENT (class1.mode, class2.mode); - case CH_VALUE_CLASS: - goto rule6; - case CH_DERIVED_CLASS: - return 0; - } - case CH_DERIVED_CLASS: - switch (class2.kind) - { - case CH_ALL_CLASS: - return 1; - case CH_VALUE_CLASS: - case CH_DERIVED_CLASS: - return CH_SIMILAR (class1.mode, class2.mode); - case CH_NULL_CLASS: - class2 = class1; - goto rule4; - case CH_REFERENCE_CLASS: - return 0; - } - case CH_VALUE_CLASS: - switch (class2.kind) - { - case CH_ALL_CLASS: - return 1; - case CH_DERIVED_CLASS: - return CH_SIMILAR (class1.mode, class2.mode); - case CH_VALUE_CLASS: - return CH_V_EQUIVALENT (class1.mode, class2.mode); - case CH_NULL_CLASS: - class2 = class1; - goto rule4; - case CH_REFERENCE_CLASS: - temp = class1; class1 = class2; class2 = temp; - goto rule6; - } - } - rule4: - /* The Null class is Compatible with the M-derived class or M-value class - if and only if M is a reference mdoe, procedure mode or instance mode.*/ - return CH_IS_REFERENCE_MODE (class2.mode) - || CH_IS_PROCEDURE_MODE (class2.mode) - || CH_IS_INSTANCE_MODE (class2.mode); - - rule6: - /* The M-reference class is compatible with the N-value class if and - only if N is a reference mode and ... */ - if (!CH_IS_REFERENCE_MODE (class2.mode)) - return 0; - if (1) /* If M is a static mode - FIXME */ - { - if (!CH_IS_BOUND_REFERENCE_MODE (class2.mode)) - return 1; - if (CH_EQUIVALENT (TREE_TYPE (class2.mode), class1.mode)) - return 1; - } - /* If N is a row mode whose .... FIXME */ - return 0; -} - -/* Cfr. Blue Book 12.1.1.6, with some "extensions." */ - -tree -chill_root_mode (mode) - tree mode; -{ - /* Reference types are not user-visible types. - This seems like a good place to get rid of them. */ - if (TREE_CODE (mode) == REFERENCE_TYPE) - mode = TREE_TYPE (mode); - - while (TREE_CODE (mode) == INTEGER_TYPE && TREE_TYPE (mode) != NULL_TREE) - mode = TREE_TYPE (mode); /* a sub-range */ - - /* This extension in not in the Blue Book - which only has a - single Integer type. - We should probably use chill_integer_type_node rather - than integer_type_node, but that is likely to bomb. - At some point, these will become the same, I hope. FIXME */ - if (TREE_CODE (mode) == INTEGER_TYPE - && TYPE_PRECISION (mode) < TYPE_PRECISION (integer_type_node) - && CH_NOVELTY (mode) == NULL_TREE) - mode = integer_type_node; - - if (TREE_CODE (mode) == FUNCTION_TYPE) - return build_pointer_type (mode); - - return mode; -} - -/* Cfr. Blue Book 12.1.1.7. */ - -tree -chill_resulting_mode (mode1, mode2) - tree mode1, mode2; -{ - mode1 = CH_ROOT_MODE (mode1); - mode2 = CH_ROOT_MODE (mode2); - if (chill_varying_type_p (mode1)) - return mode1; - if (chill_varying_type_p (mode2)) - return mode2; - return mode1; -} - -/* Cfr. Blue Book (z200, 1988) 12.1.1.7 Resulting class. */ - -struct ch_class -chill_resulting_class (class1, class2) - struct ch_class class1, class2; -{ - struct ch_class class; - switch (class1.kind) - { - case CH_VALUE_CLASS: - switch (class2.kind) - { - case CH_DERIVED_CLASS: - case CH_ALL_CLASS: - class.kind = CH_VALUE_CLASS; - class.mode = CH_ROOT_MODE (class1.mode); - return class; - case CH_VALUE_CLASS: - class.kind = CH_VALUE_CLASS; - class.mode - = CH_ROOT_MODE (CH_RESULTING_MODE (class1.mode, class2.mode)); - return class; - default: - break; - } - break; - case CH_DERIVED_CLASS: - switch (class2.kind) - { - case CH_VALUE_CLASS: - class.kind = CH_VALUE_CLASS; - class.mode = CH_ROOT_MODE (class2.mode); - return class; - case CH_DERIVED_CLASS: - class.kind = CH_DERIVED_CLASS; - class.mode = CH_RESULTING_MODE (class1.mode, class2.mode); - return class; - case CH_ALL_CLASS: - class.kind = CH_DERIVED_CLASS; - class.mode = CH_ROOT_MODE (class1.mode); - return class; - default: - break; - } - break; - case CH_ALL_CLASS: - switch (class2.kind) - { - case CH_VALUE_CLASS: - class.kind = CH_VALUE_CLASS; - class.mode = CH_ROOT_MODE (class2.mode); - return class; - case CH_ALL_CLASS: - class.kind = CH_ALL_CLASS; - class.mode = NULL_TREE; - return class; - case CH_DERIVED_CLASS: - class.kind = CH_DERIVED_CLASS; - class.mode = CH_ROOT_MODE (class2.mode); - return class; - default: - break; - } - break; - default: - break; - } - error ("internal error in chill_root_resulting_mode"); - class.kind = CH_VALUE_CLASS; - class.mode = CH_ROOT_MODE (class1.mode); - return class; -} - - -/* - * See Z.200, section 6.3, static conditions. This function - * returns bool_false_node if the condition is not met at compile time, - * bool_true_node if the condition is detectably met at compile time - * an expression if a runtime check would be required or was generated. - * It should only be called with string modes and values. - */ -tree -string_assignment_condition (lhs_mode, rhs_value) - tree lhs_mode, rhs_value; -{ - tree lhs_size, rhs_size, cond; - tree rhs_mode = TREE_TYPE (rhs_value); - int lhs_varying = chill_varying_type_p (lhs_mode); - - if (lhs_varying) - lhs_size = size_in_bytes (CH_VARYING_ARRAY_TYPE (lhs_mode)); - else if (CH_BOOLS_TYPE_P (lhs_mode)) - lhs_size = TYPE_MAX_VALUE (TYPE_DOMAIN (lhs_mode)); - else - lhs_size = size_in_bytes (lhs_mode); - lhs_size = convert (chill_unsigned_type_node, lhs_size); - - if (rhs_mode && TREE_CODE (rhs_mode) == REFERENCE_TYPE) - rhs_mode = TREE_TYPE (rhs_mode); - if (rhs_mode == NULL_TREE) - { - /* actually, count constructor's length */ - abort (); - } - else if (chill_varying_type_p (rhs_mode)) - rhs_size = build_component_ref (rhs_value, var_length_id); - else if (CH_BOOLS_TYPE_P (rhs_mode)) - rhs_size = TYPE_MAX_VALUE (TYPE_DOMAIN (rhs_mode)); - else - rhs_size = size_in_bytes (rhs_mode); - rhs_size = convert (chill_unsigned_type_node, rhs_size); - - /* validity condition */ - cond = fold (build (lhs_varying ? GE_EXPR : EQ_EXPR, - boolean_type_node, lhs_size, rhs_size)); - return cond; -} - -/* - * take a basic CHILL type and wrap it in a VARYING structure. - * Be sure the length field is initialized. Return the wrapper. - */ -tree -build_varying_struct (type) - tree type; -{ - tree decl1, decl2, result; - - if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - - decl1 = build_decl (FIELD_DECL, var_length_id, chill_integer_type_node); - decl2 = build_decl (FIELD_DECL, var_data_id, type); - TREE_CHAIN (decl1) = decl2; - TREE_CHAIN (decl2) = NULL_TREE; - result = build_chill_struct_type (decl1); - - /* mark this so we don't complain about missing initializers. - It's fine for a VARYING array to be partially initialized.. */ - C_TYPE_VARIABLE_SIZE(type) = 1; - return result; -} - - -/* - * This is the struct type that forms the runtime initializer - * list. There's at least one of these generated per module. - * It's attached to the global initializer list by the module's - * 'constructor' code. Should only be called in pass 2. - */ -tree -build_init_struct () -{ - tree decl1, decl2, result; - /* We temporarily reset the maximum_field_alignment to zero so the - compiler's init data structures can be compatible with the - run-time system, even when we're compiling with -fpack. */ - unsigned int save_maximum_field_alignment = maximum_field_alignment; - maximum_field_alignment = 0; - - decl1 = build_decl (FIELD_DECL, get_identifier ("__INIT_ENTRY"), - build_chill_pointer_type ( - build_function_type (void_type_node, NULL_TREE))); - - decl2 = build_decl (FIELD_DECL, get_identifier ("__INIT_NEXT"), - build_chill_pointer_type (void_type_node)); - - TREE_CHAIN (decl1) = decl2; - TREE_CHAIN (decl2) = NULL_TREE; - result = build_chill_struct_type (decl1); - maximum_field_alignment = save_maximum_field_alignment; - return result; -} - - -/* - * Return 1 if the given type is a single-bit boolean set, - * in which the domain's min and max values - * are both zero, - * 0 if not. This can become a macro later.. - */ -int -ch_singleton_set (type) - tree type; -{ - if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) - return 0; - if (TREE_CODE (type) != SET_TYPE) - return 0; - if (TREE_TYPE (type) == NULL_TREE - || TREE_CODE (TREE_TYPE (type)) != BOOLEAN_TYPE) - return 0; - if (TYPE_DOMAIN (type) == NULL_TREE) - return 0; - if (! tree_int_cst_equal (TYPE_MIN_VALUE (TYPE_DOMAIN (type)), - integer_zero_node)) - return 0; - if (! tree_int_cst_equal (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), - integer_zero_node)) - return 0; - return 1; -} - -/* return non-zero if TYPE is a compiler-generated VARYING - array of some base type */ -int -chill_varying_type_p (type) - tree type; -{ - if (type == NULL_TREE) - return 0; - if (TREE_CODE (type) != RECORD_TYPE) - return 0; - if (TYPE_FIELDS (type) == NULL_TREE - || TREE_CHAIN (TYPE_FIELDS (type)) == NULL_TREE) - return 0; - if (DECL_NAME (TYPE_FIELDS (type)) != var_length_id) - return 0; - if (DECL_NAME (TREE_CHAIN (TYPE_FIELDS (type))) != var_data_id) - return 0; - if (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (type))) != NULL_TREE) - return 0; - return 1; -} - -/* return non-zero if TYPE is a compiler-generated VARYING - string record */ -int -chill_varying_string_type_p (type) - tree type; -{ - tree var_data_type; - - if (!chill_varying_type_p (type)) - return 0; - - var_data_type = CH_VARYING_ARRAY_TYPE (type); - return CH_CHARS_TYPE_P (var_data_type); -} - -/* swiped from c-typeck.c */ -/* Build an assignment expression of lvalue LHS from value RHS. */ - -tree -build_chill_modify_expr (lhs, rhs) - tree lhs, rhs; -{ - register tree result; - - - tree lhstype = TREE_TYPE (lhs); - - /* Avoid duplicate error messages from operands that had errors. */ - if (lhs == NULL_TREE || TREE_CODE (lhs) == ERROR_MARK || rhs == NULL_TREE || TREE_CODE (rhs) == ERROR_MARK) - return error_mark_node; - - /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */ - /* Do not use STRIP_NOPS here. We do not want an enumerator - whose value is 0 to count as a null pointer constant. */ - if (TREE_CODE (rhs) == NON_LVALUE_EXPR) - rhs = TREE_OPERAND (rhs, 0); - -#if 0 - /* Handle a cast used as an "lvalue". - We have already performed any binary operator using the value as cast. - Now convert the result to the cast type of the lhs, - and then true type of the lhs and store it there; - then convert result back to the cast type to be the value - of the assignment. */ - - switch (TREE_CODE (lhs)) - { - case NOP_EXPR: - case CONVERT_EXPR: - case FLOAT_EXPR: - case FIX_TRUNC_EXPR: - case FIX_FLOOR_EXPR: - case FIX_ROUND_EXPR: - case FIX_CEIL_EXPR: - { - tree inner_lhs = TREE_OPERAND (lhs, 0); - tree result; - result = build_chill_modify_expr (inner_lhs, - convert (TREE_TYPE (inner_lhs), - convert (lhstype, rhs))); - pedantic_lvalue_warning (CONVERT_EXPR); - return convert (TREE_TYPE (lhs), result); - } - } - - /* Now we have handled acceptable kinds of LHS that are not truly lvalues. - Reject anything strange now. */ - - if (!lvalue_or_else (lhs, "assignment")) - return error_mark_node; -#endif - /* FIXME: need to generate a RANGEFAIL if the RHS won't - fit into the LHS. */ - - if (TREE_CODE (lhs) != VAR_DECL - && ((TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE && - (TREE_TYPE (rhs) && TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE)) || - chill_varying_type_p (TREE_TYPE (lhs)) || - chill_varying_type_p (TREE_TYPE (rhs)))) - { - int lhs_varying = chill_varying_type_p (TREE_TYPE (lhs)); - int rhs_varying = chill_varying_type_p (TREE_TYPE (rhs)); - - /* point at actual RHS data's type */ - tree rhs_data_type = rhs_varying ? - CH_VARYING_ARRAY_TYPE (TREE_TYPE (rhs)) : - TREE_TYPE (rhs); - { - /* point at actual LHS data's type */ - tree lhs_data_type = lhs_varying ? - CH_VARYING_ARRAY_TYPE (TREE_TYPE (lhs)) : - TREE_TYPE (lhs); - - int lhs_bytes = int_size_in_bytes (lhs_data_type); - int rhs_bytes = int_size_in_bytes (rhs_data_type); - - /* if both sides not varying, and sizes not dynamically - computed, sizes must *match* */ - if (! lhs_varying && ! rhs_varying && lhs_bytes != rhs_bytes - && lhs_bytes > 0 && rhs_bytes > 0) - { - error ("string lengths not equal"); - return error_mark_node; - } - /* Must have enough space on LHS for static size of RHS */ - - if (lhs_bytes > 0 && rhs_bytes > 0 - && lhs_bytes < rhs_bytes) - { - if (rhs_varying) - { - /* FIXME: generate runtime test for room */ - ; - } - else - { - error ("can't do ARRAY assignment - too large"); - return error_mark_node; - } - } - } - - /* now we know the RHS will fit in LHS, build trees for the - emit_block_move parameters */ - - if (lhs_varying) - rhs = convert (TREE_TYPE (lhs), rhs); - else - { - if (rhs_varying) - rhs = build_component_ref (rhs, var_data_id); - - if (! mark_addressable (rhs)) - { - error ("rhs of array assignment is not addressable"); - return error_mark_node; - } - - lhs = force_addr_of (lhs); - rhs = build1 (ADDR_EXPR, const_ptr_type_node, rhs); - return - build_chill_function_call (lookup_name (get_identifier ("memmove")), - tree_cons (NULL_TREE, lhs, - tree_cons (NULL_TREE, rhs, - tree_cons (NULL_TREE, size_in_bytes (rhs_data_type), - NULL_TREE)))); - } - } - - result = build (MODIFY_EXPR, lhstype, lhs, rhs); - TREE_SIDE_EFFECTS (result) = 1; - - return result; -} - -/* Constructors for pointer, array and function types. - (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are - constructed by language-dependent code, not here.) */ - -/* Construct, lay out and return the type of pointers to TO_TYPE. - If such a type has already been constructed, reuse it. */ - -static tree -make_chill_pointer_type (to_type, code) - tree to_type; - enum tree_code code; /* POINTER_TYPE or REFERENCE_TYPE */ -{ - extern struct obstack *current_obstack; - extern struct obstack *saveable_obstack; - extern struct obstack permanent_obstack; - tree t; - register struct obstack *ambient_obstack = current_obstack; - register struct obstack *ambient_saveable_obstack = saveable_obstack; - - /* If TO_TYPE is permanent, make this permanent too. */ - if (TREE_PERMANENT (to_type)) - { - current_obstack = &permanent_obstack; - saveable_obstack = &permanent_obstack; - } - - t = make_node (code); - TREE_TYPE (t) = to_type; - - current_obstack = ambient_obstack; - saveable_obstack = ambient_saveable_obstack; - return t; -} - - -tree -build_chill_pointer_type (to_type) - tree to_type; -{ - int is_type_node = TREE_CODE_CLASS (TREE_CODE (to_type)) == 't'; - register tree t = is_type_node ? TYPE_POINTER_TO (to_type) : NULL_TREE; - - /* First, if we already have a type for pointers to TO_TYPE, use it. */ - - if (t) - return t; - - /* We need a new one. */ - t = make_chill_pointer_type (to_type, POINTER_TYPE); - - /* Lay out the type. This function has many callers that are concerned - with expression-construction, and this simplifies them all. - Also, it guarantees the TYPE_SIZE is permanent if the type is. */ - if ((is_type_node && (TYPE_SIZE (to_type) != NULL_TREE)) - || pass == 2) - { - /* Record this type as the pointer to TO_TYPE. */ - TYPE_POINTER_TO (to_type) = t; - layout_type (t); - } - - return t; -} - -tree -build_chill_reference_type (to_type) - tree to_type; -{ - int is_type_node = TREE_CODE_CLASS (TREE_CODE (to_type)) == 't'; - register tree t = is_type_node ? TYPE_REFERENCE_TO (to_type) : NULL_TREE; - - /* First, if we already have a type for references to TO_TYPE, use it. */ - - if (t) - return t; - - /* We need a new one. */ - t = make_chill_pointer_type (to_type, REFERENCE_TYPE); - - /* Lay out the type. This function has many callers that are concerned - with expression-construction, and this simplifies them all. - Also, it guarantees the TYPE_SIZE is permanent if the type is. */ - if ((is_type_node && (TYPE_SIZE (to_type) != NULL_TREE)) - || pass == 2) - { - /* Record this type as the reference to TO_TYPE. */ - TYPE_REFERENCE_TO (to_type) = t; - layout_type (t); - CH_NOVELTY (t) = CH_NOVELTY (to_type); - } - - return t; -} - -static tree -make_chill_range_type (type, lowval, highval) - tree type, lowval, highval; -{ - register tree itype = make_node (INTEGER_TYPE); - TREE_TYPE (itype) = type; - TYPE_MIN_VALUE (itype) = lowval; - TYPE_MAX_VALUE (itype) = highval; - return itype; -} - - -/* Return the minimum number of bits needed to represent VALUE in a - signed or unsigned type, UNSIGNEDP says which. */ - -static unsigned int -min_precision (value, unsignedp) - tree value; - int unsignedp; -{ - int log; - - /* If the value is negative, compute its negative minus 1. The latter - adjustment is because the absolute value of the largest negative value - is one larger than the largest positive value. This is equivalent to - a bit-wise negation, so use that operation instead. */ - - if (tree_int_cst_sgn (value) < 0) - value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value)); - - /* Return the number of bits needed, taking into account the fact - that we need one more bit for a signed than unsigned type. */ - - if (integer_zerop (value)) - log = 0; - else - log = tree_floor_log2 (value); - - return log + 1 + ! unsignedp; -} - -tree -layout_chill_range_type (rangetype, must_be_const) - tree rangetype; - int must_be_const; -{ - tree type = TREE_TYPE (rangetype); - tree lowval = TYPE_MIN_VALUE (rangetype); - tree highval = TYPE_MAX_VALUE (rangetype); - int bad_limits = 0; - - if (TYPE_SIZE (rangetype) != NULL_TREE) - return rangetype; - - /* process BIN */ - if (type == ridpointers[(int) RID_BIN]) - { - int binsize; - - /* Make a range out of it */ - if (TREE_CODE (highval) != INTEGER_CST) - { - error ("non-constant expression for BIN"); - return error_mark_node; - } - else if (tree_int_cst_sgn (highval) < 0) - { - error ("expression for BIN must not be negative"); - return error_mark_node; - } - else if (compare_tree_int (highval, 32) > 0) - { - error ("cannot process BIN (>32)"); - return error_mark_node; - } - - binsize = tree_low_cst (highval, 1); - type = ridpointers [(int) RID_RANGE]; - lowval = integer_zero_node; - highval = build_int_2 ((1 << binsize) - 1, 0); - } - - if (TREE_CODE (lowval) == ERROR_MARK - || TREE_CODE (highval) == ERROR_MARK) - return error_mark_node; - - if (!CH_COMPATIBLE_CLASSES (lowval, highval)) - { - error ("bounds of range are not compatible"); - return error_mark_node; - } - - if (type == string_index_type_dummy) - { - if (TREE_CODE (highval) == INTEGER_CST - && compare_int_csts (LT_EXPR, highval, integer_minus_one_node)) - { - error ("negative string length"); - highval = integer_minus_one_node; - } - if (compare_int_csts (EQ_EXPR, highval, integer_minus_one_node)) - type = integer_type_node; - else - type = sizetype; - TREE_TYPE (rangetype) = type; - } - else if (type == ridpointers[(int) RID_RANGE]) - { - /* This isn't 100% right, since the Blue Book definition - uses Resulting Class, rather than Resulting Mode, - but it's close enough. */ - type = CH_ROOT_RESULTING_CLASS (lowval, highval).mode; - - /* The default TYPE is the type of the constants - - except if the constants are integers, we choose an - integer type that fits. */ - if (TREE_CODE (type) == INTEGER_TYPE - && TREE_CODE (lowval) == INTEGER_CST - && TREE_CODE (highval) == INTEGER_CST) - { - int unsignedp = tree_int_cst_sgn (lowval) >= 0; - unsigned int precision = MAX (min_precision (highval, unsignedp), - min_precision (lowval, unsignedp)); - - type = type_for_size (precision, unsignedp); - - } - - TREE_TYPE (rangetype) = type; - } - else - { - if (!CH_COMPATIBLE (lowval, type)) - { - error ("range's lower bound and parent mode don't match"); - return integer_type_node; /* an innocuous fake */ - } - if (!CH_COMPATIBLE (highval, type)) - { - error ("range's upper bound and parent mode don't match"); - return integer_type_node; /* an innocuous fake */ - } - } - - if (TREE_CODE (type) == ERROR_MARK) - return type; - else if (TREE_CODE_CLASS (TREE_CODE (type)) != 't') - { - error ("making range from non-mode"); - return error_mark_node; - } - - if (TREE_CODE (lowval) == REAL_CST || TREE_CODE (highval) == REAL_CST) - { - sorry ("floating point ranges"); - return integer_type_node; /* another fake */ - } - - if (TREE_CODE (lowval) != INTEGER_CST || TREE_CODE (highval) != INTEGER_CST) - { - if (must_be_const) - { - error ("range mode has non-constant limits"); - bad_limits = 1; - } - } - else if (tree_int_cst_equal (lowval, integer_zero_node) - && tree_int_cst_equal (highval, integer_minus_one_node)) - ; /* do nothing - this is the index type for an empty string */ - else if (compare_int_csts (LT_EXPR, highval, TYPE_MIN_VALUE (type))) - { - error ("range's high bound < mode's low bound"); - bad_limits = 1; - } - else if (compare_int_csts (GT_EXPR, highval, TYPE_MAX_VALUE (type))) - { - error ("range's high bound > mode's high bound"); - bad_limits = 1; - } - else if (compare_int_csts (LT_EXPR, highval, lowval)) - { - error ("range mode high bound < range mode low bound"); - bad_limits = 1; - } - else if (compare_int_csts (LT_EXPR, lowval, TYPE_MIN_VALUE (type))) - { - error ("range's low bound < mode's low bound"); - bad_limits = 1; - } - else if (compare_int_csts (GT_EXPR, lowval, TYPE_MAX_VALUE (type))) - { - error ("range's low bound > mode's high bound"); - bad_limits = 1; - } - - if (bad_limits) - { - lowval = TYPE_MIN_VALUE (type); - highval = lowval; - } - - highval = convert (type, highval); - lowval = convert (type, lowval); - TYPE_MIN_VALUE (rangetype) = lowval; - TYPE_MAX_VALUE (rangetype) = highval; - TYPE_PRECISION (rangetype) = TYPE_PRECISION (type); - TYPE_MODE (rangetype) = TYPE_MODE (type); - TYPE_SIZE (rangetype) = TYPE_SIZE (type); - TYPE_SIZE_UNIT (rangetype) = TYPE_SIZE_UNIT (type); - TYPE_ALIGN (rangetype) = TYPE_ALIGN (type); - TYPE_USER_ALIGN (rangetype) = TYPE_USER_ALIGN (type); - TREE_UNSIGNED (rangetype) = TREE_UNSIGNED (type); - CH_NOVELTY (rangetype) = CH_NOVELTY (type); - return rangetype; -} - -/* Build a _TYPE node that has range bounds associated with its values. - TYPE is the base type for the range type. */ -tree -build_chill_range_type (type, lowval, highval) - tree type, lowval, highval; -{ - tree rangetype; - - if (type == NULL_TREE) - type = ridpointers[(int) RID_RANGE]; - else if (TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - - rangetype = make_chill_range_type (type, lowval, highval); - if (pass != 1) - rangetype = layout_chill_range_type (rangetype, 0); - - return rangetype; -} - -/* Build a CHILL array type, but with minimal checking etc. */ - -tree -build_simple_array_type (type, idx, layout) - tree type, idx, layout; -{ - tree array_type = make_node (ARRAY_TYPE); - TREE_TYPE (array_type) = type; - TYPE_DOMAIN (array_type) = idx; - TYPE_ATTRIBUTES (array_type) = layout; - if (pass != 1) - array_type = layout_chill_array_type (array_type); - return array_type; -} - -static void -apply_chill_array_layout (array_type) - tree array_type; -{ - tree layout, temp, what, element_type; - HOST_WIDE_INT stepsize = 0; - HOST_WIDE_INT word, start_bit = 0, length; - HOST_WIDE_INT natural_length; - int stepsize_specified; - int start_bit_error = 0; - int length_error = 0; - - layout = TYPE_ATTRIBUTES (array_type); - if (layout == NULL_TREE) - return; - - if (layout == integer_zero_node) /* NOPACK */ - { - TYPE_PACKED (array_type) = 0; - return; - } - - /* Allow for the packing of 1 bit discrete modes at the bit level. */ - element_type = TREE_TYPE (array_type); - if (discrete_type_p (element_type) - && get_type_precision (TYPE_MIN_VALUE (element_type), - TYPE_MAX_VALUE (element_type)) == 1) - natural_length = 1; - else if (host_integerp (TYPE_SIZE (element_type), 1)) - natural_length = tree_low_cst (TYPE_SIZE (element_type), 1); - else - natural_length = -1; - - if (layout == integer_one_node) /* PACK */ - { - if (natural_length == 1) - TYPE_PACKED (array_type) = 1; - return; - } - - /* The layout is a STEP (...). - The current implementation restricts STEP specifications to be of the form - STEP(POS(0,0,n),n) where n is the natural size of the element mode. */ - stepsize_specified = 0; - temp = TREE_VALUE (layout); - if (TREE_VALUE (temp) != NULL_TREE) - { - if (! host_integerp (TREE_VALUE (temp), 0)) - error ("stepsize in STEP must be an integer constant"); - else - { - if (tree_int_cst_sgn (TREE_VALUE (temp)) <= 0) - error ("stepsize in STEP must be > 0"); - else - stepsize_specified = 1; - - stepsize = tree_low_cst (TREE_VALUE (temp), 1); - if (stepsize != natural_length) - sorry ("stepsize in STEP must be the natural width of the array element mode"); - } - } - - temp = TREE_PURPOSE (temp); - if (! host_integerp (TREE_PURPOSE (temp), 0)) - error ("starting word in POS must be an integer constant"); - else - { - if (tree_int_cst_sgn (TREE_PURPOSE (temp)) < 0) - error ("starting word in POS must be >= 0"); - if (! integer_zerop (TREE_PURPOSE (temp))) - sorry ("starting word in POS within STEP must be 0"); - - word = tree_low_cst (TREE_PURPOSE (temp), 0); - } - - length = natural_length; - temp = TREE_VALUE (temp); - if (temp != NULL_TREE) - { - int wordsize = TYPE_PRECISION (chill_integer_type_node); - if (! host_integerp (TREE_PURPOSE (temp), 0)) - { - error ("starting bit in POS must be an integer constant"); - start_bit_error = 1; - } - else - { - if (! integer_zerop (TREE_PURPOSE (temp))) - sorry ("starting bit in POS within STEP must be 0"); - - if (tree_int_cst_sgn (TREE_PURPOSE (temp)) < 0) - { - error ("starting bit in POS must be >= 0"); - start_bit = 0; - start_bit_error = 1; - } - - start_bit = tree_low_cst (TREE_PURPOSE (temp), 0); - if (start_bit >= wordsize) - { - error ("starting bit in POS must be < the width of a word"); - start_bit = 0; - start_bit_error = 1; - } - } - - temp = TREE_VALUE (temp); - if (temp != NULL_TREE) - { - what = TREE_PURPOSE (temp); - if (what == integer_zero_node) - { - if (! host_integerp (TREE_VALUE (temp), 0)) - { - error ("length in POS must be an integer constant"); - length_error = 1; - } - else - { - length = tree_low_cst (TREE_VALUE (temp), 0); - if (length <= 0) - error ("length in POS must be > 0"); - } - } - else - { - if (! host_integerp (TREE_VALUE (temp), 0)) - { - error ("end bit in POS must be an integer constant"); - length_error = 1; - } - else - { - HOST_WIDE_INT end_bit = tree_low_cst (TREE_VALUE (temp), 0); - - if (end_bit < start_bit) - { - error ("end bit in POS must be >= the start bit"); - end_bit = wordsize - 1; - length_error = 1; - } - else if (end_bit >= wordsize) - { - error ("end bit in POS must be < the width of a word"); - end_bit = wordsize - 1; - length_error = 1; - } - else if (start_bit_error) - length_error = 1; - else - length = end_bit - start_bit + 1; - } - } - - if (! length_error && length != natural_length) - sorry ("the length specified on POS within STEP must be the natural length of the array element type"); - } - } - - if (! length_error && stepsize_specified && stepsize < length) - error ("step size in STEP must be >= the length in POS"); - - if (length == 1) - TYPE_PACKED (array_type) = 1; -} - -tree -layout_chill_array_type (array_type) - tree array_type; -{ - tree itype; - tree element_type = TREE_TYPE (array_type); - - if (TREE_CODE (element_type) == ARRAY_TYPE - && TYPE_SIZE (element_type) == 0) - layout_chill_array_type (element_type); - - itype = TYPE_DOMAIN (array_type); - - if (TREE_CODE (itype) == ERROR_MARK - || TREE_CODE (element_type) == ERROR_MARK) - return error_mark_node; - - /* do a lower/upper bound check. */ - if (TREE_CODE (itype) == INTEGER_CST) - { - error ("array index must be a range, not a single integer"); - return error_mark_node; - } - if (TREE_CODE_CLASS (TREE_CODE (itype)) != 't' - || !discrete_type_p (itype)) - { - error ("array index is not a discrete mode"); - return error_mark_node; - } - - /* apply the array layout, if specified. */ - apply_chill_array_layout (array_type); - TYPE_ATTRIBUTES (array_type) = NULL_TREE; - - /* Make sure TYPE_POINTER_TO (element_type) is filled in. */ - build_pointer_type (element_type); - - if (TYPE_SIZE (array_type) == 0) - layout_type (array_type); - - if (TYPE_READONLY_PROPERTY (element_type)) - TYPE_FIELDS_READONLY (array_type) = 1; - - TYPE_ARRAY_MAX_SIZE (array_type) = size_in_bytes (array_type); - return array_type; -} - -/* Build a CHILL array type. - - TYPE is the element type of the array. - IDXLIST is the list of dimensions of the array. - VARYING_P is non-zero if the array is a varying array. - LAYOUT is (NULL_TREE, integer_one_node, integer_zero_node, tree_list), - meaning (default, pack, nopack, STEP (...) ). */ -tree -build_chill_array_type (type, idxlist, varying_p, layouts) - tree type, idxlist; - int varying_p; - tree layouts; -{ - tree array_type = type; - - if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) - return error_mark_node; - if (idxlist == NULL_TREE || TREE_CODE (idxlist) == ERROR_MARK) - return error_mark_node; - - /* We have to walk down the list of index decls, building inner - array types as we go. We need to reverse the list of layouts so that the - first layout applies to the last index etc. */ - layouts = nreverse (layouts); - for ( ; idxlist; idxlist = TREE_CHAIN (idxlist)) - { - if (layouts != NULL_TREE) - { - type = build_simple_array_type ( - type, TREE_VALUE (idxlist), TREE_VALUE (layouts)); - layouts = TREE_CHAIN (layouts); - } - else - type = build_simple_array_type (type, TREE_VALUE (idxlist), NULL_TREE); - } - array_type = type; - if (varying_p) - array_type = build_varying_struct (array_type); - return array_type; -} - -/* Function to help qsort sort FIELD_DECLs by name order. */ - -static int -field_decl_cmp (x, y) - tree *x, *y; -{ - return (long)DECL_NAME (*x) - (long)DECL_NAME (*y); -} - -static tree -make_chill_struct_type (fieldlist) - tree fieldlist; -{ - tree t, x; - - t = make_node (TREE_UNION_ELEM (fieldlist) ? UNION_TYPE : RECORD_TYPE); - - /* Install struct as DECL_CONTEXT of each field decl. */ - for (x = fieldlist; x; x = TREE_CHAIN (x)) - DECL_CONTEXT (x) = t; - - /* Delete all duplicate fields from the fieldlist */ - for (x = fieldlist; x && TREE_CHAIN (x);) - /* Anonymous fields aren't duplicates. */ - if (DECL_NAME (TREE_CHAIN (x)) == 0) - x = TREE_CHAIN (x); - else - { - register tree y = fieldlist; - - while (1) - { - if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) - break; - if (y == x) - break; - y = TREE_CHAIN (y); - } - if (DECL_NAME (y) == DECL_NAME (TREE_CHAIN (x))) - { - error_with_decl (TREE_CHAIN (x), "duplicate member `%s'"); - TREE_CHAIN (x) = TREE_CHAIN (TREE_CHAIN (x)); - } - else x = TREE_CHAIN (x); - } - - TYPE_FIELDS (t) = fieldlist; - - return t; -} - -/* DECL is a FIELD_DECL. - DECL_INIT (decl) is - (NULL_TREE, integer_one_node, integer_zero_node, tree_list) - meaning - (default, pack, nopack, POS (...) ). - - The return value is a boolean: 1 if POS specified, 0 if not */ - -static int -apply_chill_field_layout (decl, next_struct_offset) - tree decl; - int *next_struct_offset; -{ - tree layout = DECL_INITIAL (decl); - tree type = TREE_TYPE (decl); - tree temp, what; - HOST_WIDE_INT word = 0; - HOST_WIDE_INT wordsize, start_bit, offset, length, natural_length; - int pos_error = 0; - int is_discrete = discrete_type_p (type); - - if (is_discrete) - natural_length - = get_type_precision (TYPE_MIN_VALUE (type), TYPE_MAX_VALUE (type)); - else if (host_integerp (TYPE_SIZE (type), 1)) - natural_length = tree_low_cst (TYPE_SIZE (type), 1); - else - natural_length = -1; - - if (layout == integer_zero_node) /* NOPACK */ - { - *next_struct_offset += natural_length; - return 0; /* not POS */ - } - - if (layout == integer_one_node) /* PACK */ - { - if (is_discrete) - { - DECL_BIT_FIELD (decl) = 1; - DECL_SIZE (decl) = bitsize_int (natural_length); - } - else - { - DECL_ALIGN (decl) = BITS_PER_UNIT; - DECL_USER_ALIGN (decl) = 0; - } - - DECL_PACKED (decl) = 1; - *next_struct_offset += natural_length; - return 0; /* not POS */ - } - - /* The layout is a POS (...). The current implementation restricts the use - of POS to monotonically increasing fields whose width must be the - natural width of the underlying type. */ - temp = TREE_PURPOSE (layout); - - if (! host_integerp (TREE_PURPOSE (temp), 0)) - { - error ("starting word in POS must be an integer constant"); - pos_error = 1; - } - else - { - if (tree_int_cst_sgn (TREE_PURPOSE (temp)) < 0) - { - error ("starting word in POS must be >= 0"); - word = 0; - pos_error = 1; - } - else - word = tree_low_cst (TREE_PURPOSE (temp), 0); - } - - wordsize = TYPE_PRECISION (chill_integer_type_node); - offset = word * wordsize; - length = natural_length; - - temp = TREE_VALUE (temp); - if (temp != NULL_TREE) - { - if (! host_integerp (TREE_PURPOSE (temp), 0)) - { - error ("starting bit in POS must be an integer constant"); - start_bit = *next_struct_offset - offset; - pos_error = 1; - } - else - { - if (tree_int_cst_sgn (TREE_PURPOSE (temp)) < 0) - { - error ("starting bit in POS must be >= 0"); - start_bit = *next_struct_offset - offset; - pos_error = 1; - } - - start_bit = tree_low_cst (TREE_PURPOSE (temp), 0); - if (start_bit >= wordsize) - { - error ("starting bit in POS must be < the width of a word"); - start_bit = *next_struct_offset - offset; - pos_error = 1; - } - } - - temp = TREE_VALUE (temp); - if (temp != NULL_TREE) - { - what = TREE_PURPOSE (temp); - if (what == integer_zero_node) - { - if (! host_integerp (TREE_VALUE (temp), 0)) - { - error ("length in POS must be an integer constant"); - pos_error = 1; - } - else - { - if (tree_int_cst_sgn (TREE_VALUE (temp)) < 0) - { - error ("length in POS must be > 0"); - length = natural_length; - pos_error = 1; - } - else - length = tree_low_cst (TREE_VALUE (temp), 0); - - } - } - else - { - if (! host_integerp (TREE_VALUE (temp), 0)) - { - error ("end bit in POS must be an integer constant"); - pos_error = 1; - } - else - { - HOST_WIDE_INT end_bit = tree_low_cst (TREE_VALUE (temp), 0); - - if (end_bit < start_bit) - { - error ("end bit in POS must be >= the start bit"); - pos_error = 1; - } - else if (end_bit >= wordsize) - { - error ("end bit in POS must be < the width of a word"); - pos_error = 1; - } - else - length = end_bit - start_bit + 1; - } - } - - if (length != natural_length && ! pos_error) - { - sorry ("the length specified on POS must be the natural length of the field type"); - length = natural_length; - } - } - - offset += start_bit; - } - - if (offset != *next_struct_offset && ! pos_error) - sorry ("STRUCT fields must be layed out in monotonically increasing order"); - - DECL_PACKED (decl) = 1; - DECL_BIT_FIELD (decl) = is_discrete; - - if (is_discrete) - DECL_SIZE (decl) = bitsize_int (length); - - *next_struct_offset += natural_length; - - return 1; /* was POS */ -} - -tree -layout_chill_struct_type (t) - tree t; -{ - tree fieldlist = TYPE_FIELDS (t); - tree x; - int old_momentary; - int was_pos; - int pos_seen = 0; - int pos_error = 0; - int next_struct_offset; - - old_momentary = suspend_momentary (); - - /* Process specified field sizes. */ - next_struct_offset = 0; - for (x = fieldlist; x; x = TREE_CHAIN (x)) - { - /* An EVENT or BUFFER mode is implemented as a RECORD_TYPE - which may contain a CONST_DECL for the maximum queue size. */ - if (TREE_CODE (x) == CONST_DECL) - continue; - - /* If any field is const, the structure type is pseudo-const. */ - /* A field that is pseudo-const makes the structure likewise. */ - if (TREE_READONLY (x) || TYPE_READONLY_PROPERTY (TREE_TYPE (x))) - TYPE_FIELDS_READONLY (t) = 1; - - /* Any field that is volatile means variables of this type must be - treated in some ways as volatile. */ - if (TREE_THIS_VOLATILE (x)) - C_TYPE_FIELDS_VOLATILE (t) = 1; - - if (DECL_INITIAL (x) != NULL_TREE) - { - was_pos = apply_chill_field_layout (x, &next_struct_offset); - DECL_INITIAL (x) = NULL_TREE; - } - else - { - unsigned int min_align = TYPE_ALIGN (TREE_TYPE (x)); - DECL_ALIGN (x) = MAX (DECL_ALIGN (x), min_align); - was_pos = 0; - } - if ((! was_pos && pos_seen) || (was_pos && ! pos_seen && x != fieldlist)) - pos_error = 1; - pos_seen |= was_pos; - } - - if (pos_error) - error ("if one field has a POS layout, then all fields must have a POS layout"); - - /* Now DECL_INITIAL is null on all fields. */ - - layout_type (t); - - /* Now we have the truly final field list. - Store it in this type and in the variants. */ - - TYPE_FIELDS (t) = fieldlist; - - /* If there are lots of fields, sort so we can look through them fast. - We arbitrarily consider 16 or more elts to be "a lot". */ - { - int len = 0; - - for (x = fieldlist; x; x = TREE_CHAIN (x)) - { - if (len > 15) - break; - len += 1; - } - if (len > 15) - { - tree *field_array; - char *space; - - len += list_length (x); - /* Use the same allocation policy here that make_node uses, to - ensure that this lives as long as the rest of the struct decl. - All decls in an inline function need to be saved. */ - if (allocation_temporary_p ()) - space = savealloc (sizeof (struct lang_type) + len * sizeof (tree)); - else - space = oballoc (sizeof (struct lang_type) + len * sizeof (tree)); - - TYPE_LANG_SPECIFIC (t) = (struct lang_type *) space; - TYPE_LANG_SPECIFIC (t)->foo.rec.len = len; - - field_array = &TYPE_LANG_SPECIFIC (t)->foo.rec.elts[0]; - len = 0; - for (x = fieldlist; x; x = TREE_CHAIN (x)) - field_array[len++] = x; - - qsort (field_array, len, sizeof (tree), - (int (*) PARAMS ((const void *, const void *))) field_decl_cmp); - } - } - - for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) - { - TYPE_FIELDS (x) = TYPE_FIELDS (t); - TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t); - TYPE_ALIGN (x) = TYPE_ALIGN (t); - TYPE_USER_ALIGN (x) = TYPE_USER_ALIGN (t); - } - - resume_momentary (old_momentary); - - return t; -} - -/* Given a list of fields, FIELDLIST, return a structure - type that contains these fields. The returned type is - always a new type. */ -tree -build_chill_struct_type (fieldlist) - tree fieldlist; -{ - register tree t; - - if (fieldlist == NULL_TREE || TREE_CODE (fieldlist) == ERROR_MARK) - return error_mark_node; - - t = make_chill_struct_type (fieldlist); - if (pass != 1) - t = layout_chill_struct_type (t); - -/* pushtag (NULL_TREE, t); */ - - return t; -} - -/* Fix a LANG_TYPE. These are used for three different uses: - - representing a 'READ M' (in which case TYPE_READONLY is set); - - for a NEWMODE or SYNMODE (CH_NOVELTY is set for a NEWMODE); and - - for a parameterised type (TREE_TYPE points to base type, - while TYPE_DOMAIN is the parameter or parameter list). - Called from satisfy. */ -tree -smash_dummy_type (type) - tree type; -{ - /* Save fields that we don't want to copy from ORIGIN. */ - tree origin = TREE_TYPE (type); - tree main_tree = TYPE_MAIN_VARIANT (origin); - int save_uid = TYPE_UID (type); - struct obstack *save_obstack = TYPE_OBSTACK (type); - tree save_name = TYPE_NAME (type); - int save_permanent = TREE_PERMANENT (type); - int save_readonly = TYPE_READONLY (type); - tree save_novelty = CH_NOVELTY (type); - tree save_domain = TYPE_DOMAIN (type); - - if (origin == NULL_TREE) - abort (); - - if (save_domain) - { - if (TREE_CODE (save_domain) == ERROR_MARK) - return error_mark_node; - if (origin == char_type_node) - { /* Old-fashioned CHAR(N) declaration. */ - origin = build_string_type (origin, save_domain); - } - else - { /* Handle parameterised modes. */ - int is_varying = chill_varying_type_p (origin); - tree new_max = save_domain; - tree origin_novelty = CH_NOVELTY (origin); - if (is_varying) - origin = CH_VARYING_ARRAY_TYPE (origin); - if (CH_STRING_TYPE_P (origin)) - { - tree oldindex = TYPE_DOMAIN (origin); - new_max = check_range (new_max, new_max, NULL_TREE, - fold (build (PLUS_EXPR, integer_type_node, - TYPE_MAX_VALUE (oldindex), - integer_one_node))); - origin = build_string_type (TREE_TYPE (origin), new_max); - } - else if (TREE_CODE (origin) == ARRAY_TYPE) - { - tree oldindex = TYPE_DOMAIN (origin); - tree upper = check_range (new_max, new_max, NULL_TREE, - TYPE_MAX_VALUE (oldindex)); - tree newindex - = build_chill_range_type (TREE_TYPE (oldindex), - TYPE_MIN_VALUE (oldindex), upper); - origin = build_simple_array_type (TREE_TYPE (origin), newindex, NULL_TREE); - } - else if (TREE_CODE (origin) == RECORD_TYPE) - { - error ("parameterized structures not implemented"); - return error_mark_node; - } - else - { - error ("invalid parameterized type"); - return error_mark_node; - } - - SET_CH_NOVELTY (origin, origin_novelty); - if (is_varying) - { - origin = build_varying_struct (origin); - SET_CH_NOVELTY (origin, origin_novelty); - } - } - save_domain = NULL_TREE; - } - - if (TREE_CODE (origin) == ERROR_MARK) - return error_mark_node; - - *(struct tree_type*)type = *(struct tree_type*)origin; - /* The following is so that the debug code for - the copy is different from the original type. - The two statements usually duplicate each other - (because they clear fields of the same union), - but the optimizer should catch that. */ - TYPE_SYMTAB_POINTER (type) = 0; - TYPE_SYMTAB_ADDRESS (type) = 0; - - /* Restore fields that we didn't want copied from ORIGIN. */ - TYPE_UID (type) = save_uid; - TYPE_OBSTACK (type) = save_obstack; - TREE_PERMANENT (type) = save_permanent; - TYPE_NAME (type) = save_name; - - TREE_CHAIN (type) = NULL_TREE; - TYPE_VOLATILE (type) = 0; - TYPE_POINTER_TO (type) = 0; - TYPE_REFERENCE_TO (type) = 0; - - if (save_readonly) - { /* TYPE is READ ORIGIN. - Add this type to the chain of variants of TYPE. */ - TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (main_tree); - TYPE_NEXT_VARIANT (main_tree) = type; - TYPE_READONLY (type) = save_readonly; - } - else - { - /* TYPE is the copy of the RHS in a NEWMODE or SYNMODE. - We also get here after old-fashioned CHAR(N) declaration (see above). */ - TYPE_MAIN_VARIANT (type) = type; - TYPE_NEXT_VARIANT (type) = NULL_TREE; - if (save_name) - DECL_ORIGINAL_TYPE (save_name) = origin; - - if (save_novelty != NULL_TREE) /* A NEWMODE declaration. */ - { - CH_NOVELTY (type) = save_novelty; - - /* Z.200: "If the DEFINING mode of the NEWMODE name is a range mode, - then the virtual mode &name is introduced as the PARENT mode - of the NEWMODE name. The DEFINING mode of &name is the PARENT - mode of the range mode, and the NOVELTY of &name is that of - the NEWMODE name." */ - - if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type)) - { - tree parent; - /* PARENT is the virtual mode &name mentioned above. */ - push_obstacks_nochange (); - end_temporary_allocation (); - parent = copy_novelty (save_novelty,TREE_TYPE (type)); - pop_obstacks (); - - TREE_TYPE (type) = parent; - TYPE_MIN_VALUE (type) = convert (parent, TYPE_MIN_VALUE (type)); - TYPE_MAX_VALUE (type) = convert (parent, TYPE_MAX_VALUE (type)); - } - } - } - return type; -} - -/* This generates a LANG_TYPE node that represents 'READ TYPE'. */ - -tree -build_readonly_type (type) - tree type; -{ - tree node = make_node (LANG_TYPE); - TREE_TYPE (node) = type; - TYPE_READONLY (node) = 1; - if (pass != 1) - node = smash_dummy_type (node); - return node; -} - - -/* Return an unsigned type the same as TYPE in other respects. */ - -tree -unsigned_type (type) - tree type; -{ - tree type1 = TYPE_MAIN_VARIANT (type); - if (type1 == signed_char_type_node || type1 == char_type_node) - return unsigned_char_type_node; - if (type1 == integer_type_node) - return unsigned_type_node; - if (type1 == short_integer_type_node) - return short_unsigned_type_node; - if (type1 == long_integer_type_node) - return long_unsigned_type_node; - if (type1 == long_long_integer_type_node) - return long_long_unsigned_type_node; - - return signed_or_unsigned_type (1, type); -} - -/* Return a signed type the same as TYPE in other respects. */ - -tree -signed_type (type) - tree type; -{ - tree type1 = TYPE_MAIN_VARIANT (type); - while (TREE_CODE (type1) == INTEGER_TYPE && TREE_TYPE (type1) != NULL_TREE) - type1 = TREE_TYPE (type1); - if (type1 == unsigned_char_type_node || type1 == char_type_node) - return signed_char_type_node; - if (type1 == unsigned_type_node) - return integer_type_node; - if (type1 == short_unsigned_type_node) - return short_integer_type_node; - if (type1 == long_unsigned_type_node) - return long_integer_type_node; - if (type1 == long_long_unsigned_type_node) - return long_long_integer_type_node; - if (TYPE_PRECISION (type1) == 1) - return signed_boolean_type_node; - - return signed_or_unsigned_type (0, type); -} - -/* Return a type the same as TYPE except unsigned or - signed according to UNSIGNEDP. */ - -tree -signed_or_unsigned_type (unsignedp, type) - int unsignedp; - tree type; -{ - if (! INTEGRAL_TYPE_P (type) - || TREE_UNSIGNED (type) == unsignedp) - return type; - - if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - return type; -} - -/* Mark EXP saying that we need to be able to take the - address of it; it should not be allocated in a register. - Value is 1 if successful. */ - -int -mark_addressable (exp) - tree exp; -{ - register tree x = exp; - while (1) - switch (TREE_CODE (x)) - { - case ADDR_EXPR: - case COMPONENT_REF: - case ARRAY_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - x = TREE_OPERAND (x, 0); - break; - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case COMPOUND_EXPR: - x = TREE_OPERAND (x, 1); - break; - - case COND_EXPR: - return mark_addressable (TREE_OPERAND (x, 1)) - & mark_addressable (TREE_OPERAND (x, 2)); - - case CONSTRUCTOR: - TREE_ADDRESSABLE (x) = 1; - return 1; - - case INDIRECT_REF: - /* We sometimes add a cast *(TYPE*)&FOO to handle type and mode - incompatibility problems. Handle this case by marking FOO. */ - if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR - && TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR) - { - x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); - break; - } - if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) - { - x = TREE_OPERAND (x, 0); - break; - } - return 1; - - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x) - && DECL_NONLOCAL (x)) - { - if (TREE_PUBLIC (x)) - { - error ("global register variable `%s' used in nested function", - IDENTIFIER_POINTER (DECL_NAME (x))); - return 0; - } - pedwarn ("register variable `%s' used in nested function", - IDENTIFIER_POINTER (DECL_NAME (x))); - } - else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)) - { - if (TREE_PUBLIC (x)) - { - error ("address of global register variable `%s' requested", - IDENTIFIER_POINTER (DECL_NAME (x))); - return 0; - } - - /* If we are making this addressable due to its having - volatile components, give a different error message. Also - handle the case of an unnamed parameter by not trying - to give the name. */ - - else if (C_TYPE_FIELDS_VOLATILE (TREE_TYPE (x))) - { - error ("cannot put object with volatile field into register"); - return 0; - } - - pedwarn ("address of register variable `%s' requested", - IDENTIFIER_POINTER (DECL_NAME (x))); - } - put_var_into_stack (x); - - /* drops through */ - case FUNCTION_DECL: - TREE_ADDRESSABLE (x) = 1; -#if 0 /* poplevel deals with this now. */ - if (DECL_CONTEXT (x) == 0) - TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; -#endif - /* drops through */ - default: - return 1; - } -} - -/* Return an integer type with BITS bits of precision, - that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ - -tree -type_for_size (bits, unsignedp) - unsigned bits; - int unsignedp; -{ - if (bits == TYPE_PRECISION (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if (bits == TYPE_PRECISION (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if (bits == TYPE_PRECISION (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if (bits == TYPE_PRECISION (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if (bits == TYPE_PRECISION (long_long_integer_type_node)) - return (unsignedp ? long_long_unsigned_type_node - : long_long_integer_type_node); - - if (bits <= TYPE_PRECISION (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if (bits <= TYPE_PRECISION (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if (bits <= TYPE_PRECISION (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if (bits <= TYPE_PRECISION (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - -#if HOST_BITS_PER_WIDE_INT >= 64 - if (bits <= TYPE_PRECISION (intTI_type_node)) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - - return 0; -} - -/* Return a data type that has machine mode MODE. - If the mode is an integer, - then UNSIGNEDP selects between signed and unsigned types. */ - -tree -type_for_mode (mode, unsignedp) - enum machine_mode mode; - int unsignedp; -{ - if ((int)mode == (int)TYPE_MODE (integer_type_node)) - return unsignedp ? unsigned_type_node : integer_type_node; - - if ((int)mode == (int)TYPE_MODE (signed_char_type_node)) - return unsignedp ? unsigned_char_type_node : signed_char_type_node; - - if ((int)mode == (int)TYPE_MODE (short_integer_type_node)) - return unsignedp ? short_unsigned_type_node : short_integer_type_node; - - if ((int)mode == (int)TYPE_MODE (long_integer_type_node)) - return unsignedp ? long_unsigned_type_node : long_integer_type_node; - - if ((int)mode == (int)TYPE_MODE (long_long_integer_type_node)) - return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node; - - if ((int)mode == (int)TYPE_MODE (intQI_type_node)) - return unsignedp ? unsigned_intQI_type_node : intQI_type_node; - - if ((int)mode == (int)TYPE_MODE (intHI_type_node)) - return unsignedp ? unsigned_intHI_type_node : intHI_type_node; - - if ((int)mode == (int)TYPE_MODE (intSI_type_node)) - return unsignedp ? unsigned_intSI_type_node : intSI_type_node; - - if ((int)mode == (int)TYPE_MODE (intDI_type_node)) - return unsignedp ? unsigned_intDI_type_node : intDI_type_node; - -#if HOST_BITS_PER_WIDE_INT >= 64 - if ((int)mode == (int)TYPE_MODE (intTI_type_node)) - return unsignedp ? unsigned_intTI_type_node : intTI_type_node; -#endif - - if ((int)mode == (int)TYPE_MODE (float_type_node)) - return float_type_node; - - if ((int)mode == (int)TYPE_MODE (double_type_node)) - return double_type_node; - - if ((int)mode == (int)TYPE_MODE (long_double_type_node)) - return long_double_type_node; - - if ((int)mode == (int)TYPE_MODE (build_pointer_type (char_type_node))) - return build_pointer_type (char_type_node); - - if ((int)mode == (int)TYPE_MODE (build_pointer_type (integer_type_node))) - return build_pointer_type (integer_type_node); - - return 0; -} |