/* Convert language-specific tree expression to rtl instructions, for GNU CHILL compiler. Copyright (C) 1992, 93, 1994 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config.h" #include #include "rtl.h" #include "tree.h" #include "flags.h" #include "expr.h" #include "ch-tree.h" #include "assert.h" #include "lex.h" #include "convert.h" #ifndef NULL #define NULL 0 #endif extern char **boolean_code_name; extern int flag_old_strings; extern tree long_unsigned_type_node; extern int ignore_case; extern int special_UC; extern void check_for_full_enumeration_handling PROTO((tree)); extern void chill_handle_case_default PROTO((void)); extern void error PROTO((char *, ...)); extern void error_with_decl PROTO((tree, char *, ...)); extern void fatal PROTO((char *, ...)); extern void sorry PROTO((char *, ...)); extern tree stabilize_reference PROTO((tree)); extern void warning PROTO((char *, ...)); /* definitions for duration built-ins */ #define MILLISECS_MULTIPLIER 1 #define SECS_MULTIPLIER MILLISECS_MULTIPLIER * 1000 #define MINUTES_MULTIPLIER SECS_MULTIPLIER * 60 #define HOURS_MULTIPLIER MINUTES_MULTIPLIER * 60 #define DAYS_MULTIPLIER HOURS_MULTIPLIER * 24 /* the maximum value for each of the calls */ #define MILLISECS_MAX 0xffffffff #define SECS_MAX 4294967 #define MINUTES_MAX 71582 #define HOURS_MAX 1193 #define DAYS_MAX 49 /* forward declaration */ rtx chill_expand_expr PROTO((tree, rtx, enum machine_mode, enum expand_modifier)); /* variable to hold the type the DESCR built-in returns */ static tree descr_type = NULL_TREE; /* called from ch-lex.l */ void init_chill_expand () { lang_expand_expr = chill_expand_expr; } /* Take the address of something that needs to be passed by reference. */ tree force_addr_of (value) tree value; { /* FIXME. Move to memory, if needed. */ if (TREE_CODE (value) == INDIRECT_REF) return convert_to_pointer (ptr_type_node, TREE_OPERAND (value, 0)); mark_addressable (value); return build1 (ADDR_EXPR, ptr_type_node, value); } /* Check that EXP has a known type. */ tree check_have_mode (exp, context) tree exp; char *context; { if (TREE_CODE (exp) != ERROR_MARK && TREE_TYPE (exp) == NULL_TREE) { if (TREE_CODE (exp) == CONSTRUCTOR) error ("tuple without specified mode not allowed in %s", context); else if (TREE_CODE (exp) == COND_EXPR || TREE_CODE (exp) == CASE_EXPR) error ("conditional expression not allowed in %s", context); else error ("internal error: unknown expression mode in %s", context); return error_mark_node; } return exp; } /* Check that EXP is discrete. Handle conversion if flag_old_strings. */ tree check_case_selector (exp) tree exp; { if (exp != NULL_TREE && TREE_TYPE (exp) != NULL_TREE) exp = convert_to_discrete (exp); if (exp) return exp; error ("CASE selector is not a discrete expression"); return error_mark_node; } tree check_case_selector_list (list) tree list; { tree selector, exp, return_list = NULL_TREE; for (selector = list; selector != NULL_TREE; selector = TREE_CHAIN (selector)) { exp = check_case_selector (TREE_VALUE (selector)); if (exp == error_mark_node) { return_list = error_mark_node; break; } return_list = tree_cons (TREE_PURPOSE (selector), exp, return_list); } return nreverse(return_list); } tree chill_expand_case_expr (expr) tree expr; { tree selector_list = TREE_OPERAND (expr, 0), selector; tree alternatives = TREE_OPERAND (expr, 1); tree type = TREE_TYPE (expr); int else_seen = 0; tree result; if (TREE_CODE (selector_list) != TREE_LIST || TREE_CODE (alternatives) != TREE_LIST) abort(); if (TREE_CHAIN (selector_list) != NULL_TREE) abort (); /* make a temp for the case result */ result = decl_temp1 (get_unique_identifier ("CASE_EXPR"), type, 0, NULL_TREE, 0, 0); selector = check_case_selector (TREE_VALUE (selector_list)); expand_start_case (1, selector, TREE_TYPE (selector), "CASE expression"); alternatives = nreverse (alternatives); for ( ; alternatives != NULL_TREE; alternatives = TREE_CHAIN (alternatives)) { tree labels = TREE_PURPOSE (alternatives), t; if (labels == NULL_TREE) { chill_handle_case_default (); else_seen++; } else { tree label; if (labels != NULL_TREE) { for (label = TREE_VALUE (labels); label != NULL_TREE; label = TREE_CHAIN (label)) chill_handle_case_label (TREE_VALUE (label), selector); labels = TREE_CHAIN (labels); if (labels != NULL_TREE) error ("The number of CASE selectors does not match the number " "of CASE label lists"); } } t = build (MODIFY_EXPR, type, result, convert (type, TREE_VALUE (alternatives))); TREE_SIDE_EFFECTS (t) = 1; expand_expr_stmt (t); expand_exit_something (); } if (!else_seen) { chill_handle_case_default (); expand_exit_something (); #if 0 expand_raise (); #endif check_missing_cases (TREE_TYPE (selector)); } expand_end_case (selector); return result; } /* Hook used by expand_expr to expand CHILL-specific tree codes. */ rtx chill_expand_expr (exp, target, tmode, modifier) tree exp; rtx target; enum machine_mode tmode; enum expand_modifier modifier; { tree type = TREE_TYPE (exp); register enum machine_mode mode = TYPE_MODE (type); register enum tree_code code = TREE_CODE (exp); rtx original_target = target; rtx op0, op1; int ignore = target == const0_rtx; char *lib_func; /* name of library routine */ if (ignore) target = 0, original_target = 0; /* No sense saving up arithmetic to be done if it's all in the wrong mode to form part of an address. And force_operand won't know whether to sign-extend or zero-extend. */ if (mode != Pmode && modifier == EXPAND_SUM) modifier = EXPAND_NORMAL; switch (code) { case STRING_EQ_EXPR: case STRING_LT_EXPR: { rtx func = gen_rtx (SYMBOL_REF, Pmode, code == STRING_EQ_EXPR ? "__eqstring" : "__ltstring"); tree exp0 = TREE_OPERAND (exp, 0); tree exp1 = TREE_OPERAND (exp, 1); tree size0, size1; rtx op0, op1, siz0, siz1; if (chill_varying_type_p (TREE_TYPE (exp0))) { exp0 = save_if_needed (exp0); size0 = convert (integer_type_node, build_component_ref (exp0, var_length_id)); exp0 = build_component_ref (exp0, var_data_id); } else size0 = size_in_bytes (TREE_TYPE (exp0)); if (chill_varying_type_p (TREE_TYPE (exp1))) { exp1 = save_if_needed (exp1); size1 = convert (integer_type_node, build_component_ref (exp1, var_length_id)); exp1 = build_component_ref (exp1, var_data_id); } else size1 = size_in_bytes (TREE_TYPE (exp1)); op0 = expand_expr (force_addr_of (exp0), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); op1 = expand_expr (force_addr_of (exp1), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); siz0 = expand_expr (size0, NULL_RTX, VOIDmode, 0); siz1 = expand_expr (size1, NULL_RTX, VOIDmode, 0); return emit_library_call_value (func, target, 0, QImode, 4, op0, GET_MODE (op0), siz0, TYPE_MODE (sizetype), op1, GET_MODE (op1), siz1, TYPE_MODE (sizetype)); } case CASE_EXPR: return expand_expr (chill_expand_case_expr (exp), NULL_RTX, VOIDmode, 0); break; case SLICE_EXPR: { tree func_call; tree array = TREE_OPERAND (exp, 0); tree min_value = TREE_OPERAND (exp, 1); tree length = TREE_OPERAND (exp, 2); tree new_type = TREE_TYPE (exp); tree temp = decl_temp1 (get_unique_identifier ("BITSTRING"), new_type, 0, NULL_TREE, 0, 0); if (! CH_REFERABLE (array) && TYPE_MODE (TREE_TYPE (array)) != BLKmode) array = decl_temp1 (get_unique_identifier ("BSTRINGVAL"), TREE_TYPE (array), 0, array, 0, 0); func_call = build_chill_function_call ( lookup_name (get_identifier ("__psslice")), tree_cons (NULL_TREE, build_chill_addr_expr (temp, (char *)0), tree_cons (NULL_TREE, length, tree_cons (NULL_TREE, force_addr_of (array), tree_cons (NULL_TREE, powersetlen (array), tree_cons (NULL_TREE, convert (integer_type_node, min_value), tree_cons (NULL_TREE, length, NULL_TREE))))))); expand_expr (func_call, const0_rtx, VOIDmode, 0); emit_queue (); return expand_expr (temp, ignore ? const0_rtx : target, VOIDmode, 0); } /* void __concatstring (char *out, char *left, unsigned left_len, char *right, unsigned right_len) */ case CONCAT_EXPR: { tree exp0 = TREE_OPERAND (exp, 0); tree exp1 = TREE_OPERAND (exp, 1); rtx size0, size1; rtx targetx; if (TREE_CODE (exp1) == UNDEFINED_EXPR) { if (TYPE_MODE (TREE_TYPE (exp0)) == BLKmode && TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { rtx temp = expand_expr (exp0, target, tmode, modifier); if (temp == target || target == NULL_RTX) return temp; emit_block_move (target, temp, expr_size (exp0), TYPE_ALIGN (TREE_TYPE(exp0)) / BITS_PER_UNIT); return target; } else { exp0 = force_addr_of (exp0); exp0 = convert (build_pointer_type (TREE_TYPE (exp)), exp0); exp0 = build1 (INDIRECT_REF, TREE_TYPE (exp), exp0); return expand_expr (exp0, NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); } } if (TREE_CODE (type) == ARRAY_TYPE) { /* No need to handle scalars or varying strings here, since that was done in convert or build_concat_expr. */ size0 = expand_expr (size_in_bytes (TREE_TYPE (exp0)), NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); size1 = expand_expr (size_in_bytes (TREE_TYPE (exp1)), NULL_RTX, Pmode, EXPAND_CONST_ADDRESS); /* build a temp for the result, target is its address */ if (target == NULL_RTX) { tree type0 = TREE_TYPE (exp0); tree type1 = TREE_TYPE (exp1); int len0 = int_size_in_bytes (type0); int len1 = int_size_in_bytes (type1); if (len0 < 0 && TYPE_ARRAY_MAX_SIZE (type0) && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type0)) == INTEGER_CST) len0 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type0)); if (len1 < 0 && TYPE_ARRAY_MAX_SIZE (type1) && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type1)) == INTEGER_CST) len1 = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type1)); if (len0 < 0 || len1 < 0) fatal ("internal error - don't know how much space is needed for concatenation"); target = assign_stack_temp (mode, len0 + len1, 0); preserve_temp_slots (target); } } else if (TREE_CODE (type) == SET_TYPE) { if (target == NULL_RTX) { target = assign_stack_temp (mode, int_size_in_bytes (type), 0); preserve_temp_slots (target); } } else abort (); if (GET_CODE (target) == MEM) targetx = target; else targetx = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0); /* expand 1st operand to a pointer to the array */ op0 = expand_expr (force_addr_of (exp0), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* expand 2nd operand to a pointer to the array */ op1 = expand_expr (force_addr_of (exp1), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); if (TREE_CODE (type) == SET_TYPE) { size0 = expand_expr (powersetlen (exp0), NULL_RTX, VOIDmode, 0); size1 = expand_expr (powersetlen (exp1), NULL_RTX, VOIDmode, 0); emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatps"), 0, Pmode, 5, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), convert_to_mode (TYPE_MODE (sizetype), size0, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype), op1, GET_MODE (op1), convert_to_mode (TYPE_MODE (sizetype), size1, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype)); } else { /* copy left, then right array to target */ emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__concatstring"), 0, Pmode, 5, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), convert_to_mode (TYPE_MODE (sizetype), size0, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype), op1, GET_MODE (op1), convert_to_mode (TYPE_MODE (sizetype), size1, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype)); } if (targetx != target) emit_move_insn (target, targetx); return target; } /* FIXME: the set_length computed below is a compile-time constant; you'll need to re-write that part for VARYING bit arrays, and possibly the set pointer will need to be adjusted to point past the word containing its dynamic length. */ /* void __notpowerset (char *out, char *src, unsigned long bitlength) */ case SET_NOT_EXPR: { tree expr = TREE_OPERAND (exp, 0); tree tsize = powersetlen (expr); rtx targetx; if (TREE_CODE (TREE_TYPE (expr)) != SET_TYPE) tsize = fold (build (MULT_EXPR, sizetype, tsize, size_int (BITS_PER_UNIT))); /* expand 1st operand to a pointer to the set */ op0 = expand_expr (force_addr_of (expr), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* build a temp for the result, target is its address */ if (target == NULL_RTX) { target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), int_size_in_bytes (TREE_TYPE (exp)), 0); preserve_temp_slots (target); } if (GET_CODE (target) == MEM) targetx = target; else targetx = assign_stack_temp (GET_MODE (target), GET_MODE_SIZE (GET_MODE (target)), 0); emit_library_call (gen_rtx(SYMBOL_REF, Pmode, "__notpowerset"), 0, VOIDmode, 3, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), expand_expr (tsize, NULL_RTX, MEM, EXPAND_CONST_ADDRESS), TYPE_MODE (long_unsigned_type_node)); if (targetx != target) emit_move_insn (target, targetx); return target; } case SET_DIFF_EXPR: lib_func = "__diffpowerset"; goto format_2; case SET_IOR_EXPR: lib_func = "__orpowerset"; goto format_2; case SET_XOR_EXPR: lib_func = "__xorpowerset"; goto format_2; /* void __diffpowerset (char *out, char *left, char *right, unsigned bitlength) */ case SET_AND_EXPR: lib_func = "__andpowerset"; format_2: { tree expr = TREE_OPERAND (exp, 0); tree tsize = powersetlen (expr); rtx targetx; if (TREE_CODE (TREE_TYPE (expr)) != SET_TYPE) tsize = fold (build (MULT_EXPR, long_unsigned_type_node, tsize, size_int (BITS_PER_UNIT))); /* expand 1st operand to a pointer to the set */ op0 = expand_expr (force_addr_of (expr), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* expand 2nd operand to a pointer to the set */ op1 = expand_expr (force_addr_of (TREE_OPERAND (exp, 1)), NULL_RTX, MEM, EXPAND_CONST_ADDRESS); /* FIXME: re-examine this code - the unary operator code above has recently (93/03/12) been changed a lot. Should this code also change? */ /* build a temp for the result, target is its address */ if (target == NULL_RTX) { target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), int_size_in_bytes (TREE_TYPE (exp)), 0); preserve_temp_slots (target); } if (GET_CODE (target) == MEM) targetx = target; else targetx = assign_stack_temp (GET_MODE (target), GET_MODE_SIZE (GET_MODE (target)), 0); emit_library_call (gen_rtx(SYMBOL_REF, Pmode, lib_func), 0, VOIDmode, 4, XEXP (targetx, 0), Pmode, op0, GET_MODE (op0), op1, GET_MODE (op1), expand_expr (tsize, NULL_RTX, MEM, EXPAND_CONST_ADDRESS), TYPE_MODE (long_unsigned_type_node)); if (target != targetx) emit_move_insn (target, targetx); return target; } case SET_IN_EXPR: { extern tree lookup_name PROTO((tree)); tree set = TREE_OPERAND (exp, 1); tree pos = convert (long_unsigned_type_node, TREE_OPERAND (exp, 0)); tree set_type = TREE_TYPE (set); tree set_length = discrete_count (TYPE_DOMAIN (set_type)); tree min_val = convert (long_integer_type_node, TYPE_MIN_VALUE (TYPE_DOMAIN (set_type))); tree fcall; /* FIXME: Function-call not needed if pos and width are constant! */ if (! mark_addressable (set)) { error ("powerset is not addressable"); return const0_rtx; } /* we use different functions for bitstrings and powersets */ if (CH_BOOLS_TYPE_P (set_type)) fcall = build_chill_function_call ( lookup_name (get_identifier ("__inbitstring")), tree_cons (NULL_TREE, convert (long_unsigned_type_node, pos), tree_cons (NULL_TREE, build1 (ADDR_EXPR, build_pointer_type (set_type), set), tree_cons (NULL_TREE, convert (long_unsigned_type_node, set_length), tree_cons (NULL_TREE, min_val, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), build_tree_list (NULL_TREE, get_chill_linenumber ()))))))); else fcall = build_chill_function_call ( lookup_name (get_identifier ("__inpowerset")), tree_cons (NULL_TREE, convert (long_unsigned_type_node, pos), tree_cons (NULL_TREE, build1 (ADDR_EXPR, build_pointer_type (set_type), set), tree_cons (NULL_TREE, convert (long_unsigned_type_node, set_length), build_tree_list (NULL_TREE, min_val))))); return expand_expr (fcall, NULL_RTX, VOIDmode, 0); } case PACKED_ARRAY_REF: { extern tree lookup_name PROTO((tree)); tree array = TREE_OPERAND (exp, 0); tree pos = save_expr (TREE_OPERAND (exp, 1)); tree array_type = TREE_TYPE (array); tree array_length = discrete_count (TYPE_DOMAIN (array_type)); tree min_val = convert (long_integer_type_node, TYPE_MIN_VALUE (TYPE_DOMAIN (array_type))); tree fcall; /* FIXME: Function-call not needed if pos and width are constant! */ /* TODO: make sure this makes sense. */ if (! mark_addressable (array)) { error ("array is not addressable"); return const0_rtx; } fcall = build_chill_function_call ( lookup_name (get_identifier ("__inpowerset")), tree_cons (NULL_TREE, convert (long_unsigned_type_node, pos), tree_cons (NULL_TREE, build1 (ADDR_EXPR, build_pointer_type (array_type), array), tree_cons (NULL_TREE, convert (long_unsigned_type_node, array_length), build_tree_list (NULL_TREE, min_val))))); return expand_expr (fcall, NULL_RTX, VOIDmode, 0); } case UNDEFINED_EXPR: if (target == 0) { target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), int_size_in_bytes (TREE_TYPE (exp)), 0); preserve_temp_slots (target); } /* We don't actually need to *do* anything ... */ return target; default: break; } /* NOTREACHED */ return NULL; } /* Check that the argument list has a length in [min_length .. max_length]. (max_length == -1 means "infinite".) If so return the actual length. Otherwise, return an error message and return -1. */ static int check_arglist_length (args, min_length, max_length, name) tree args; int min_length; int max_length; tree name; { int length = list_length (args); if (length < min_length) error ("Too few arguments in call to `%s'", IDENTIFIER_POINTER (name)); else if (max_length != -1 && length > max_length) error ("Too many arguments in call to `%s'", IDENTIFIER_POINTER (name)); else return length; return -1; } /* * This is the code from c-typeck.c, with the C-specific cruft * removed (possibly I just didn't understand it, but it was * apparently simply discarding part of my LIST). */ static tree internal_build_compound_expr (list, first_p) tree list; int first_p; { register tree rest; if (TREE_CHAIN (list) == 0) return TREE_VALUE (list); rest = internal_build_compound_expr (TREE_CHAIN (list), FALSE); if (! TREE_SIDE_EFFECTS (TREE_VALUE (list))) return rest; return build (COMPOUND_EXPR, TREE_TYPE (rest), TREE_VALUE (list), rest); } /* Given a list of expressions, return a compound expression that performs them all and returns the value of the last of them. */ /* FIXME: this should be merged with the C version */ tree build_chill_compound_expr (list) tree list; { return internal_build_compound_expr (list, TRUE); } /* Given an expression PTR for a pointer, return an expression for the value pointed to. do_empty_check is 0, don't perform a NULL pointer check, else do it. */ tree build_chill_indirect_ref (ptr, mode, do_empty_check) tree ptr; tree mode; int do_empty_check; { register tree type; if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK) return ptr; if (mode != NULL_TREE && TREE_CODE (mode) == ERROR_MARK) return error_mark_node; type = TREE_TYPE (ptr); if (TREE_CODE (type) == REFERENCE_TYPE) { type = TREE_TYPE (type); ptr = convert (type, ptr); } /* check for ptr is really a POINTER */ if (TREE_CODE (type) != POINTER_TYPE) { error ("cannot dereference, not a pointer."); return error_mark_node; } if (mode && TREE_CODE (mode) == IDENTIFIER_NODE) { tree decl = lookup_name (mode); if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL) { if (pass == 2) error ("missing '.' operator or undefined mode name `%s'.", IDENTIFIER_POINTER (mode)); #if 0 error ("You have forgotten the '.' operator which must"); error (" precede a STRUCT field reference, or `%s' is an undefined mode", IDENTIFIER_POINTER (mode)); #endif return error_mark_node; } } if (mode) { mode = get_type_of (mode); ptr = convert (build_pointer_type (mode), ptr); } else if (type == ptr_type_node) { error ("Can't dereference PTR value using unary `->'."); return error_mark_node; } if (do_empty_check) ptr = check_non_null (ptr); type = TREE_TYPE (ptr); if (TREE_CODE (type) == POINTER_TYPE) { if (TREE_CODE (ptr) == ADDR_EXPR && !flag_volatile && (TREE_TYPE (TREE_OPERAND (ptr, 0)) == TREE_TYPE (type))) return TREE_OPERAND (ptr, 0); else { tree t = TREE_TYPE (type); register tree ref = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (t), ptr); if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE) { error ("dereferencing pointer to incomplete type"); return error_mark_node; } if (TREE_CODE (t) == VOID_TYPE) warning ("dereferencing `void *' pointer"); /* We *must* set TREE_READONLY when dereferencing a pointer to const, so that we get the proper error message if the result is used to assign to. Also, &* is supposed to be a no-op. And ANSI C seems to specify that the type of the result should be the const type. */ /* A de-reference of a pointer to const is not a const. It is valid to change it via some other pointer. */ TREE_READONLY (ref) = TYPE_READONLY (t); TREE_SIDE_EFFECTS (ref) = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (ptr) || flag_volatile; TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t) || flag_volatile; return ref; } } else if (TREE_CODE (ptr) != ERROR_MARK) error ("invalid type argument of `->'"); return error_mark_node; } /* NODE is a COMPONENT_REF whose mode is an IDENTIFIER, which is replaced by the proper FIELD_DECL. Also do the right thing for variant records. */ tree resolve_component_ref (node) tree node; { tree datum = TREE_OPERAND (node, 0); tree field_name = TREE_OPERAND (node, 1); tree type = TREE_TYPE (datum); tree field; if (TREE_CODE (datum) == ERROR_MARK) return error_mark_node; if (TREE_CODE (type) == REFERENCE_TYPE) { type = TREE_TYPE (type); TREE_OPERAND (node, 0) = datum = convert (type, datum); } if (TREE_CODE (type) != RECORD_TYPE) { error ("operand of '.' is not a STRUCT"); return error_mark_node; } TREE_READONLY (node) = TREE_READONLY (datum); TREE_SIDE_EFFECTS (node) = TREE_SIDE_EFFECTS (datum); for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { if (TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) { tree variant; for (variant = TYPE_FIELDS (TREE_TYPE (field)); variant; variant = TREE_CHAIN (variant)) { tree vfield; for (vfield = TYPE_FIELDS (TREE_TYPE (variant)); vfield; vfield = TREE_CHAIN (vfield)) { if (DECL_NAME (vfield) == field_name) { /* Found a variant field */ datum = build (COMPONENT_REF, TREE_TYPE (field), datum, field); datum = build (COMPONENT_REF, TREE_TYPE (variant), datum, variant); TREE_OPERAND (node, 0) = datum; TREE_OPERAND (node, 1) = vfield; TREE_TYPE (node) = TREE_TYPE (vfield); TREE_READONLY (node) |= TYPE_READONLY (TREE_TYPE (node)); #if 0 if (flag_testing_tags) { tree tagtest = NOT IMPLEMENTED; tree tagf = ridpointers[(int) RID_RANGEFAIL]; node = check_expression (node, tagtest, tagf); } #endif return node; } } } } if (DECL_NAME (field) == field_name) { /* Found a fixed field */ TREE_OPERAND (node, 1) = field; TREE_TYPE (node) = TREE_TYPE (field); TREE_READONLY (node) |= TYPE_READONLY (TREE_TYPE (node)); return fold (node); } } error ("No field named `%s'", IDENTIFIER_POINTER (field_name)); return error_mark_node; } tree build_component_ref (datum, field_name) tree datum, field_name; { tree node = build_nt (COMPONENT_REF, datum, field_name); if (pass != 1) node = resolve_component_ref (node); return node; } /* function checks (for build_chill_component_ref) if a given type is really an instance type. CH_IS_INSTANCE_MODE is not strict enough in this case, i.e. SYNMODE foo = STRUCT (a, b UINT) is compatible to INSTANCE. */ static int is_really_instance (type) tree type; { tree decl = TYPE_NAME (type); if (decl == NULL_TREE) /* this is not an instance */ return 0; if (DECL_NAME (decl) == ridpointers[(int)RID_INSTANCE]) /* this is an instance */ return 1; if (TYPE_FIELDS (type) == TYPE_FIELDS (instance_type_node)) /* we have a NEWMODE'd instance */ return 1; return 0; } /* This function is called by the parse. Here we check if the user tries to access a field in a type which is layouted as a structure but isn't like INSTANCE, BUFFER, EVENT, ASSOCIATION, ACCESS, TEXT, or VARYING array or character string. We don't do this in build_component_ref cause this function gets called from the compiler to access fields in one of the above mentioned modes. */ tree build_chill_component_ref (datum, field_name) tree datum, field_name; { tree type = TREE_TYPE (datum); if ((type != NULL_TREE && TREE_CODE (type) == RECORD_TYPE) && ((CH_IS_INSTANCE_MODE (type) && is_really_instance (type)) || CH_IS_BUFFER_MODE (type) || CH_IS_EVENT_MODE (type) || CH_IS_ASSOCIATION_MODE (type) || CH_IS_ACCESS_MODE (type) || CH_IS_TEXT_MODE (type) || chill_varying_type_p (type))) { error ("operand of '.' is not a STRUCT"); return error_mark_node; } return build_component_ref (datum, field_name); } /* * Check for invalid binary operands & unary operands * RIGHT is 1 if checking right operand or unary operand; * it is 0 if checking left operand. * * return 1 if the given operand is NOT compatible as the * operand of the given operator * * return 0 if they might be compatible */ static int invalid_operand (code, type, right) enum chill_tree_code code; tree type; int right; /* 1 if right operand */ { switch ((int)code) { case ADDR_EXPR: break; case BIT_AND_EXPR: case BIT_IOR_EXPR: case BIT_NOT_EXPR: case BIT_XOR_EXPR: goto relationals; case CASE_EXPR: break; case CEIL_MOD_EXPR: goto numerics; case CONCAT_EXPR: /* must be static or varying char array */ if (TREE_CODE (type) == CHAR_TYPE) return 0; if (TREE_CODE (type) == ARRAY_TYPE && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) return 0; if (!chill_varying_type_p (type)) return 1; if (TREE_CODE (TREE_TYPE (CH_VARYING_ARRAY_TYPE (type))) == CHAR_TYPE) return 0; else return 1; /* note: CHILL conditional expressions (COND_EXPR) won't come * through here; they're routed straight to C-specific code */ case EQ_EXPR: return 0; /* ANYTHING can be compared equal */ case FLOOR_MOD_EXPR: if (TREE_CODE (type) == REAL_TYPE) return 1; goto numerics; case GE_EXPR: case GT_EXPR: goto relatables; case SET_IN_EXPR: if (TREE_CODE (type) == SET_TYPE) return 0; else return 1; case PACKED_ARRAY_REF: if (TREE_CODE (type) == ARRAY_TYPE) return 0; else return 1; case LE_EXPR: case LT_EXPR: relatables: switch ((int)TREE_CODE(type)) /* right operand must be set/bitarray type */ { case ARRAY_TYPE: if (TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE) return 0; else return 1; case BOOLEAN_TYPE: case CHAR_TYPE: case COMPLEX_TYPE: case ENUMERAL_TYPE: case INTEGER_TYPE: case OFFSET_TYPE: case POINTER_TYPE: case REAL_TYPE: case SET_TYPE: return 0; case FILE_TYPE: case FUNCTION_TYPE: case GRANT_TYPE: case LANG_TYPE: case METHOD_TYPE: return 1; case RECORD_TYPE: if (chill_varying_type_p (type) && TREE_CODE (TREE_TYPE (CH_VARYING_ARRAY_TYPE (type))) == CHAR_TYPE) return 0; else return 1; case REFERENCE_TYPE: case SEIZE_TYPE: case UNION_TYPE: case VOID_TYPE: return 1; } break; case MINUS_EXPR: case MULT_EXPR: goto numerics; case NEGATE_EXPR: if (TREE_CODE (type) == BOOLEAN_TYPE) return 0; else goto numerics; case NE_EXPR: return 0; /* ANYTHING can be compared unequal */ case NOP_EXPR: return 0; /* ANYTHING can be converted */ case PLUS_EXPR: numerics: switch ((int)TREE_CODE(type)) /* left operand must be discrete type */ { case ARRAY_TYPE: if (right || TREE_CODE (TREE_TYPE (type)) != BOOLEAN_TYPE) return 1; else return 0; case CHAR_TYPE: return right; case BOOLEAN_TYPE: case COMPLEX_TYPE: case FILE_TYPE: case FUNCTION_TYPE: case GRANT_TYPE: case LANG_TYPE: case METHOD_TYPE: case RECORD_TYPE: case REFERENCE_TYPE: case SEIZE_TYPE: case UNION_TYPE: case VOID_TYPE: return 1; case ENUMERAL_TYPE: case INTEGER_TYPE: case OFFSET_TYPE: case POINTER_TYPE: case REAL_TYPE: case SET_TYPE: return 0; } break; case RANGE_EXPR: break; case REPLICATE_EXPR: switch ((int)TREE_CODE(type)) /* right operand must be set/bitarray type */ { case COMPLEX_TYPE: case FILE_TYPE: case FUNCTION_TYPE: case GRANT_TYPE: case LANG_TYPE: case METHOD_TYPE: case OFFSET_TYPE: case POINTER_TYPE: case RECORD_TYPE: case REAL_TYPE: case SEIZE_TYPE: case UNION_TYPE: case VOID_TYPE: return 1; case ARRAY_TYPE: case BOOLEAN_TYPE: case CHAR_TYPE: case ENUMERAL_TYPE: case INTEGER_TYPE: case REFERENCE_TYPE: case SET_TYPE: return 0; } case TRUNC_DIV_EXPR: goto numerics; case TRUNC_MOD_EXPR: if (TREE_CODE (type) == REAL_TYPE) return 1; goto numerics; case TRUTH_ANDIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_NOT_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_OR_EXPR: relationals: switch ((int)TREE_CODE(type)) /* left operand must be discrete type */ { case ARRAY_TYPE: case CHAR_TYPE: case COMPLEX_TYPE: case ENUMERAL_TYPE: case FILE_TYPE: case FUNCTION_TYPE: case GRANT_TYPE: case INTEGER_TYPE: case LANG_TYPE: case METHOD_TYPE: case OFFSET_TYPE: case POINTER_TYPE: case REAL_TYPE: case RECORD_TYPE: case REFERENCE_TYPE: case SEIZE_TYPE: case UNION_TYPE: case VOID_TYPE: return 1; case BOOLEAN_TYPE: case SET_TYPE: return 0; } break; default: return 1; /* perhaps you forgot to add a new DEFTREECODE? */ } return 1; } static int invalid_right_operand (code, type) enum chill_tree_code code; tree type; { return invalid_operand (code, type, 1); } tree build_chill_abs (expr) tree expr; { tree temp; if (TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE || discrete_type_p (TREE_TYPE (expr))) temp = fold (build1 (ABS_EXPR, TREE_TYPE (expr), expr)); else { error("ABS argument must be discrete or real mode"); return error_mark_node; } /* FIXME: should call * cond_type_range_exception (temp); */ return temp; } tree build_chill_abstime (exprlist) tree exprlist; { int mask = 0, i, numargs; tree args = NULL_TREE; tree filename, lineno; int had_errors = 0; tree tmp; if (exprlist != NULL_TREE && TREE_CODE (exprlist) == ERROR_MARK) return error_mark_node; /* check for integer expressions */ i = 1; tmp = exprlist; while (tmp != NULL_TREE) { tree exp = TREE_VALUE (tmp); if (exp == NULL_TREE || TREE_CODE (exp) == ERROR_MARK) had_errors = 1; else if (TREE_CODE (TREE_TYPE (exp)) != INTEGER_TYPE) { error ("argument %d to ABSTIME must be of integer type.", i); had_errors = 1; } tmp = TREE_CHAIN (tmp); i++; } if (had_errors) return error_mark_node; numargs = list_length (exprlist); for (i = 0; i < numargs; i++) mask |= (1 << i); /* make it all arguments */ for (i = numargs; i < 6; i++) exprlist = tree_cons (NULL_TREE, integer_zero_node, exprlist); args = tree_cons (NULL_TREE, build_int_2 (mask, 0), exprlist); filename = force_addr_of (get_chill_filename ()); lineno = get_chill_linenumber (); args = chainon (args, tree_cons (NULL_TREE, filename, tree_cons (NULL_TREE, lineno, NULL_TREE))); return build_chill_function_call ( lookup_name (get_identifier ("_abstime")), args); } tree build_allocate_memory_call (ptr, size) tree ptr, size; { int err = 0; /* check for ptr is referable */ if (! CH_REFERABLE (ptr)) { error ("parameter 1 must be referable."); err++; } /* check for pointer */ else if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE) { error ("mode mismatch in parameter 1."); err++; } /* check for size > 0 if it is a constant */ if (TREE_CODE (size) == INTEGER_CST && TREE_INT_CST_LOW (size) <= 0) { error ("parameter 2 must be a positive integer."); err++; } if (err) return error_mark_node; if (TREE_TYPE (ptr) != ptr_type_node) ptr = build_chill_cast (ptr_type_node, ptr); return build_chill_function_call ( lookup_name (get_identifier ("_allocate_memory")), tree_cons (NULL_TREE, ptr, tree_cons (NULL_TREE, size, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))); } tree build_allocate_global_memory_call (ptr, size) tree ptr, size; { int err = 0; /* check for ptr is referable */ if (! CH_REFERABLE (ptr)) { error ("parameter 1 must be referable."); err++; } /* check for pointer */ else if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE) { error ("mode mismatch in parameter 1."); err++; } /* check for size > 0 if it is a constant */ if (TREE_CODE (size) == INTEGER_CST && TREE_INT_CST_LOW (size) <= 0) { error ("parameter 2 must be a positive integer."); err++; } if (err) return error_mark_node; if (TREE_TYPE (ptr) != ptr_type_node) ptr = build_chill_cast (ptr_type_node, ptr); return build_chill_function_call ( lookup_name (get_identifier ("_allocate_global_memory")), tree_cons (NULL_TREE, ptr, tree_cons (NULL_TREE, size, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))); } tree build_return_memory (ptr) tree ptr; { /* check input */ if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK) return error_mark_node; /* check for pointer */ if (TREE_CODE (TREE_TYPE (ptr)) != POINTER_TYPE) { error ("mode mismatch in parameter 1."); return error_mark_node; } if (TREE_TYPE (ptr) != ptr_type_node) ptr = build_chill_cast (ptr_type_node, ptr); return build_chill_function_call ( lookup_name (get_identifier ("_return_memory")), tree_cons (NULL_TREE, ptr, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); } /* Compute the number of runtime members of the * given powerset. */ tree build_chill_card (powerset) tree powerset; { if (pass == 2) { tree temp; tree card_func = lookup_name (get_identifier ("__cardpowerset")); if (powerset == NULL_TREE || TREE_CODE (powerset) == ERROR_MARK) return error_mark_node; if (TREE_CODE (powerset) == IDENTIFIER_NODE) powerset = lookup_name (powerset); if (TREE_CODE (TREE_TYPE(powerset)) == SET_TYPE) { int size; /* Do constant folding, if possible. */ if (TREE_CODE (powerset) == CONSTRUCTOR & TREE_CONSTANT (powerset) && (size = int_size_in_bytes (TREE_TYPE (powerset))) >= 0) { int bit_size = size * BITS_PER_UNIT; char* buffer = (char*) alloca (bit_size); temp = get_set_constructor_bits (powerset, buffer, bit_size); if (!temp) { int i; int count = 0; for (i = 0; i < bit_size; i++) if (buffer[i]) count++; temp = build_int_2 (count, 0); TREE_TYPE (temp) = TREE_TYPE (TREE_TYPE (card_func)); return temp; } } temp = build_chill_function_call (card_func, tree_cons (NULL_TREE, force_addr_of (powerset), tree_cons (NULL_TREE, powersetlen (powerset), NULL_TREE))); /* FIXME: should call * cond_type_range_exception (op0); */ return temp; } error("CARD argument must be powerset mode"); return error_mark_node; } return NULL_TREE; } /* function to build the type needed for the DESCR-built-in */ void build_chill_descr_type () { tree decl1, decl2; if (descr_type != NULL_TREE) /* already done */ return; decl1 = build_decl (FIELD_DECL, get_identifier ("datap"), ptr_type_node); decl2 = build_decl (FIELD_DECL, get_identifier ("len"), TREE_TYPE (lookup_name ( get_identifier ((ignore_case || ! special_UC) ? "ulong" : "ULONG")))); TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; decl2 = build_chill_struct_type (decl1); descr_type = build_decl (TYPE_DECL, get_identifier ("__tmp_DESCR_type"), decl2); pushdecl (descr_type); DECL_SOURCE_LINE (descr_type) = 0; satisfy_decl (descr_type, 0); } /* build a pointer to a descriptor. * descriptor = STRUCT (datap PTR, * len ULONG); * This descriptor is build in variable descr_type. */ tree build_chill_descr (expr) tree expr; { if (pass == 2) { tree tuple, decl, descr_var, datap, len, tmp; int is_static; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; /* check for expression is referable */ if (! CH_REFERABLE (expr)) { error ("expression for DESCR-builtin must be referable."); return error_mark_node; } mark_addressable (expr); #if 0 datap = build1 (ADDR_EXPR, build_chill_pointer_type (descr_type), expr); #else datap = build_chill_arrow_expr (expr, 1); #endif len = size_in_bytes (TREE_TYPE (expr)); descr_var = get_unique_identifier ("DESCR"); tuple = build_nt (CONSTRUCTOR, NULL_TREE, tree_cons (NULL_TREE, datap, tree_cons (NULL_TREE, len, NULL_TREE))); is_static = (current_function_decl == global_function_decl) && TREE_STATIC (expr); decl = decl_temp1 (descr_var, TREE_TYPE (descr_type), is_static, tuple, 0, 0); #if 0 tmp = force_addr_of (decl); #else tmp = build_chill_arrow_expr (decl, 1); #endif return tmp; } return NULL_TREE; } /* this function process the builtin's MILLISECS, SECS, MINUTES, HOURS and DAYS. The built duration value is in milliseconds. */ tree build_chill_duration (expr, multiplier, fnname, maxvalue) tree expr; unsigned long multiplier; tree fnname; unsigned long maxvalue; { tree temp; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE) { error ("argument to `%s' must be of integer type.", IDENTIFIER_POINTER (fnname)); return error_mark_node; } temp = convert (duration_timing_type_node, expr); temp = fold (build (MULT_EXPR, duration_timing_type_node, temp, build_int_2 (multiplier, 0))); if (range_checking) temp = check_range (temp, expr, integer_zero_node, build_int_2 (maxvalue, 0)); return temp; } /* build function call to one of the floating point functions */ static tree build_chill_floatcall (expr, chillname, funcname) tree expr; char *chillname; char *funcname; { tree result; tree type; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; /* look if expr is a REAL_TYPE */ type = TREE_TYPE (expr); if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) return error_mark_node; if (TREE_CODE (type) != REAL_TYPE) { error ("argument 1 to `%s' must be of floating point mode", chillname); return error_mark_node; } result = build_chill_function_call ( lookup_name (get_identifier (funcname)), tree_cons (NULL_TREE, expr, NULL_TREE)); return result; } /* common function for ALLOCATE and GETSTACK */ static tree build_allocate_getstack (mode, value, chill_name, fnname, filename, linenumber) tree mode; tree value; char *chill_name; char *fnname; tree filename; tree linenumber; { tree type, result; tree expr = NULL_TREE; tree args, tmpvar, fncall, ptr, init, outlist = NULL_TREE; if (mode == NULL_TREE || TREE_CODE (mode) == ERROR_MARK) return error_mark_node; if (TREE_CODE (mode) == TYPE_DECL) type = TREE_TYPE (mode); else type = mode; /* check if we have a mode */ if (TREE_CODE_CLASS (TREE_CODE (type)) != 't') { error ("First argument to `%s' must be a mode", chill_name); return error_mark_node; } /* check if we have a value if type is READonly */ if (TYPE_READONLY_PROPERTY (type) && value == NULL_TREE) { error ("READonly modes for %s must have a value", chill_name); return error_mark_node; } if (value != NULL_TREE) { if (TREE_CODE (value) == ERROR_MARK) return error_mark_node; expr = chill_convert_for_assignment (type, value, "assignment"); } /* build function arguments */ if (filename == NULL_TREE) args = tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE); else args = tree_cons (NULL_TREE, size_in_bytes (type), tree_cons (NULL_TREE, force_addr_of (filename), tree_cons (NULL_TREE, linenumber, NULL_TREE))); ptr = build_chill_pointer_type (type); tmpvar = decl_temp1 (get_unique_identifier (chill_name), ptr, 0, NULL_TREE, 0, 0); fncall = build_chill_function_call ( lookup_name (get_identifier (fnname)), args); outlist = tree_cons (NULL_TREE, build_chill_modify_expr (tmpvar, fncall), outlist); if (expr == NULL_TREE) { /* set allocated memory to 0 */ fncall = build_chill_function_call ( lookup_name (get_identifier ("memset")), tree_cons (NULL_TREE, convert (ptr_type_node, tmpvar), tree_cons (NULL_TREE, integer_zero_node, tree_cons (NULL_TREE, size_in_bytes (type), NULL_TREE)))); outlist = tree_cons (NULL_TREE, fncall, outlist); } else { /* write the init value to allocated memory */ outlist = tree_cons (NULL_TREE, build_chill_modify_expr (build_chill_indirect_ref (tmpvar, NULL_TREE, 0), expr), outlist); } outlist = tree_cons (NULL_TREE, tmpvar, outlist); result = build_chill_compound_expr (nreverse (outlist)); return result; } /* process the ALLOCATE built-in */ tree build_chill_allocate (mode, value) tree mode; tree value; { return build_allocate_getstack (mode, value, "ALLOCATE", "__allocate", get_chill_filename (), get_chill_linenumber ()); } /* process the GETSTACK built-in */ tree build_chill_getstack (mode, value) tree mode; tree value; { return build_allocate_getstack (mode, value, "GETSTACK", "__builtin_alloca", NULL_TREE, NULL_TREE); } /* process the TERMINATE built-in */ tree build_chill_terminate (ptr) tree ptr; { tree result; tree type; if (ptr == NULL_TREE || TREE_CODE (ptr) == ERROR_MARK) return error_mark_node; type = TREE_TYPE (ptr); if (type == NULL_TREE || TREE_CODE (type) != POINTER_TYPE) { error ("argument to TERMINATE must be a reference primitive value"); return error_mark_node; } result = build_chill_function_call ( lookup_name (get_identifier ("__terminate")), tree_cons (NULL_TREE, convert (ptr_type_node, ptr), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); return result; } /* build the type passed to _inttime function */ void build_chill_inttime_type () { tree idxlist; tree arrtype; tree decl; idxlist = build_tree_list (NULL_TREE, build_chill_range_type (NULL_TREE, integer_zero_node, build_int_2 (5, 0))); arrtype = build_chill_array_type (ptr_type_node, idxlist, 0, NULL_TREE); decl = build_decl (TYPE_DECL, get_identifier ("__tmp_INTTIME_type"), arrtype); pushdecl (decl); DECL_SOURCE_LINE (decl) = 0; satisfy_decl (decl, 0); } tree build_chill_inttime (t, loclist) tree t, loclist; { int had_errors = 0, cnt; tree tmp; tree init = NULL_TREE; int numargs; tree tuple, var; if (t == NULL_TREE || TREE_CODE (t) == ERROR_MARK) return error_mark_node; if (loclist == NULL_TREE || TREE_CODE (loclist) == ERROR_MARK) return error_mark_node; /* check first argument to be NEWMODE TIME */ if (TREE_TYPE (t) != abs_timing_type_node) { error ("argument 1 to INTTIME must be of mode TIME."); had_errors = 1; } cnt = 2; tmp = loclist; while (tmp != NULL_TREE) { tree loc = TREE_VALUE (tmp); char errmsg[200]; char *p, *p1; int write_error = 0; sprintf (errmsg, "argument %d to INTTIME must be ", cnt); p = errmsg + strlen (errmsg); p1 = p; if (loc == NULL_TREE || TREE_CODE (loc) == ERROR_MARK) had_errors = 1; else { if (! CH_REFERABLE (loc)) { strcpy (p, "referable"); p += strlen (p); write_error = 1; had_errors = 1; } if (TREE_CODE (TREE_TYPE (loc)) != INTEGER_TYPE) { if (p != p1) { strcpy (p, " and "); p += strlen (p); } strcpy (p, "of integer type"); write_error = 1; had_errors = 1; } /* FIXME: what's about ranges can't hold the result ?? */ if (write_error) error ("%s.", errmsg); } /* next location */ tmp = TREE_CHAIN (tmp); cnt++; } if (had_errors) return error_mark_node; /* make it always 6 arguments */ numargs = list_length (loclist); for (cnt = numargs; cnt < 6; cnt++) init = tree_cons (NULL_TREE, null_pointer_node, init); /* append the given one's */ tmp = loclist; while (tmp != NULL_TREE) { init = chainon (init, build_tree_list (NULL_TREE, build_chill_descr (TREE_VALUE (tmp)))); tmp = TREE_CHAIN (tmp); } tuple = build_nt (CONSTRUCTOR, NULL_TREE, init); var = decl_temp1 (get_unique_identifier ("INTTIME"), TREE_TYPE (lookup_name (get_identifier ("__tmp_INTTIME_type"))), 0, tuple, 0, 0); return build_chill_function_call ( lookup_name (get_identifier ("_inttime")), tree_cons (NULL_TREE, t, tree_cons (NULL_TREE, force_addr_of (var), NULL_TREE))); } /* Compute the runtime length of the given string variable * or expression. */ tree build_chill_length (expr) tree expr; { if (pass == 2) { tree type; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; if (TREE_CODE (expr) == IDENTIFIER_NODE) expr = lookup_name (expr); type = TREE_TYPE (expr); if (TREE_CODE(type) == ERROR_MARK) return type; if (chill_varying_type_p (type)) { tree temp = convert (integer_type_node, build_component_ref (expr, var_length_id)); /* FIXME: should call * cond_type_range_exception (temp); */ return temp; } if ((TREE_CODE (type) == ARRAY_TYPE || /* should work for a bitstring too */ (TREE_CODE (type) == SET_TYPE && TREE_CODE (TREE_TYPE (type)) == BOOLEAN_TYPE)) && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (type)))) { tree temp = fold (build (PLUS_EXPR, chill_integer_type_node, integer_one_node, TYPE_MAX_VALUE (TYPE_DOMAIN (type)))); return convert (chill_integer_type_node, temp); } if (CH_IS_BUFFER_MODE (type) || CH_IS_EVENT_MODE (type)) { tree len = max_queue_size (type); if (len == NULL_TREE) len = integer_minus_one_node; return len; } if (CH_IS_TEXT_MODE (type)) { if (TREE_CODE (expr) == TYPE_DECL) { /* text mode name */ return text_length (type); } else { /* text location */ tree temp = build_component_ref ( build_component_ref (expr, get_identifier ("tloc")), var_length_id); return convert (integer_type_node, temp); } } error("LENGTH argument must be string, buffer, event mode, text location or mode"); return error_mark_node; } return NULL_TREE; } /* Compute the declared minimum/maximum value of the variable, * expression or declared type */ static tree build_chill_lower_or_upper (what, is_upper) tree what; int is_upper; /* o -> LOWER; 1 -> UPPER */ { if (pass == 2) { tree type; struct ch_class class; if (what == NULL_TREE || TREE_CODE (what) == ERROR_MARK) return error_mark_node; if (TREE_CODE_CLASS (TREE_CODE (what)) == 't') type = what; else type = TREE_TYPE (what); if (type == NULL_TREE) { if (is_upper) error ("UPPER argument must have a mode, or be a mode"); else error ("LOWER argument must have a mode, or be a mode"); return error_mark_node; } while (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); if (chill_varying_type_p (type)) type = CH_VARYING_ARRAY_TYPE (type); if (discrete_type_p (type)) { tree val = is_upper ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type); class.kind = CH_VALUE_CLASS; class.mode = type; return convert_to_class (class, val); } else if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == SET_TYPE) { if (TYPE_STRING_FLAG (type)) { class.kind = CH_DERIVED_CLASS; class.mode = integer_type_node; } else { class.kind = CH_VALUE_CLASS; class.mode = TYPE_DOMAIN (type); } type = TYPE_DOMAIN (type); return convert_to_class (class, is_upper ? TYPE_MAX_VALUE (type) : TYPE_MIN_VALUE (type)); } if (is_upper) error("UPPER argument must be string, array, mode or integer"); else error("LOWER argument must be string, array, mode or integer"); return error_mark_node; } return NULL_TREE; } tree build_chill_lower (what) tree what; { return build_chill_lower_or_upper (what, 0); } static tree build_max_min (expr, max_min) tree expr; int max_min; /* 0: calculate MIN; 1: calculate MAX */ { if (pass == 2) { tree type, temp, setminval; tree set_base_type; int size_in_bytes; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; if (TREE_CODE (expr) == IDENTIFIER_NODE) expr = lookup_name (expr); type = TREE_TYPE (expr); set_base_type = TYPE_DOMAIN (type); setminval = TYPE_MIN_VALUE (set_base_type); if (TREE_CODE (type) != SET_TYPE) { error("%s argument must be POWERSET mode", max_min ? "MAX" : "MIN"); return error_mark_node; } /* find max/min of constant powerset at compile time */ if (TREE_CODE (expr) == CONSTRUCTOR && TREE_CONSTANT (expr) && (size_in_bytes = int_size_in_bytes (type)) >= 0) { HOST_WIDE_INT min_val = -1, max_val = -1; HOST_WIDE_INT i, i_hi = 0; HOST_WIDE_INT size_in_bits = size_in_bytes * BITS_PER_UNIT; char *buffer = (char*) alloca (size_in_bits); if (buffer == NULL || get_set_constructor_bits (expr, buffer, size_in_bits)) abort (); for (i = 0; i < size_in_bits; i++) { if (buffer[i]) { if (min_val < 0) min_val = i; max_val = i; } } if (min_val < 0) error ("%s called for empty POWERSET", max_min ? "MAX" : "MIN"); i = max_min ? max_val : min_val; temp = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (expr))); add_double (i, i_hi, TREE_INT_CST_LOW (temp), TREE_INT_CST_HIGH (temp), &i, &i_hi); temp = build_int_2 (i, i_hi); TREE_TYPE (temp) = set_base_type; return temp; } else { tree parmlist, filename, lineno; char *funcname; /* set up to call appropriate runtime function */ if (max_min) funcname = "__flsetpowerset"; else funcname = "__ffsetpowerset"; setminval = convert (long_integer_type_node, setminval); filename = force_addr_of (get_chill_filename()); lineno = get_chill_linenumber(); parmlist = tree_cons (NULL_TREE, force_addr_of (expr), tree_cons (NULL_TREE, powersetlen (expr), tree_cons (NULL_TREE, setminval, tree_cons (NULL_TREE, filename, build_tree_list (NULL_TREE, lineno))))); temp = lookup_name (get_identifier (funcname)); temp = build_chill_function_call (temp, parmlist); TREE_TYPE (temp) = set_base_type; return temp; } } return NULL_TREE; } /* Compute the current runtime maximum value of the powerset */ tree build_chill_max (expr) tree expr; { return build_max_min (expr, 1); } /* Compute the current runtime minimum value of the powerset */ tree build_chill_min (expr) tree expr; { return build_max_min (expr, 0); } /* Build a conversion from the given expression to an INT, * but only when the expression's type is the same size as * an INT. */ tree build_chill_num (expr) tree expr; { if (pass == 2) { tree temp; int need_unsigned; if (expr == NULL_TREE || TREE_CODE(expr) == ERROR_MARK) return error_mark_node; if (TREE_CODE (expr) == IDENTIFIER_NODE) expr = lookup_name (expr); expr = convert_to_discrete (expr); if (expr == NULL_TREE) { error ("argument to NUM is not discrete"); return error_mark_node; } /* enumeral types and string slices of length 1 must be kept unsigned */ need_unsigned = (TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE) || TREE_UNSIGNED (TREE_TYPE (expr)); temp = type_for_size (TYPE_PRECISION (TREE_TYPE (expr)), need_unsigned); if (temp == NULL_TREE) { error ("No integer mode which matches expression's mode"); return integer_zero_node; } temp = convert (temp, expr); if (TREE_CONSTANT (temp)) { if (tree_int_cst_lt (temp, TYPE_MIN_VALUE (TREE_TYPE (temp)))) error ("NUM's parameter is below its mode range"); if (tree_int_cst_lt (TYPE_MAX_VALUE (TREE_TYPE (temp)), temp)) error ("NUM's parameter is above its mode range"); } #if 0 else { if (range_checking) cond_overflow_exception (temp, TYPE_MIN_VALUE (TREE_TYPE (temp)), TYPE_MAX_VALUE (TREE_TYPE (temp))); } #endif /* NUM delivers the INT derived class */ CH_DERIVED_FLAG (temp) = 1; return temp; } return NULL_TREE; } static tree build_chill_pred_or_succ (expr, op) tree expr; enum tree_code op; /* PLUS_EXPR for SUCC; MINUS_EXPR for PRED. */ { struct ch_class class; tree etype, cond; tree limit; if (pass == 1) return NULL_TREE; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; /* disallow numbered SETs */ if (TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE && CH_ENUM_IS_NUMBERED (TREE_TYPE (expr))) { error ("Cannot take SUCC or PRED of a numbered SET"); return error_mark_node; } if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE) { if (TREE_TYPE (TREE_TYPE (expr)) == void_type_node) { error ("SUCC or PRED must not be done on a PTR."); return error_mark_node; } pedwarn ("SUCC or PRED for a reference type is not standard."); return fold (build (op, TREE_TYPE (expr), expr, size_in_bytes (TREE_TYPE (TREE_TYPE (expr))))); } expr = convert_to_discrete (expr); if (expr == NULL_TREE) { error ("SUCC or PRED argument must be a discrete mode"); return error_mark_node; } class = chill_expr_class (expr); if (class.mode) class.mode = CH_ROOT_MODE (class.mode); etype = class.mode; expr = convert (etype, expr); /* Exception if expression is already at the min (PRED)/max(SUCC) valid value for its type. */ cond = fold (build (op == PLUS_EXPR ? GE_EXPR : LE_EXPR, boolean_type_node, expr, convert (etype, op == PLUS_EXPR ? TYPE_MAX_VALUE (etype) : TYPE_MIN_VALUE (etype)))); if (TREE_CODE (cond) == INTEGER_CST && tree_int_cst_equal (cond, integer_one_node)) { error ("Taking the %s of a value already at its %s value", op == PLUS_EXPR ? "SUCC" : "PRED", op == PLUS_EXPR ? "maximum" : "minimum"); return error_mark_node; } if (range_checking) expr = check_expression (expr, cond, ridpointers[(int) RID_OVERFLOW]); expr = fold (build (op, etype, expr, convert (etype, integer_one_node))); return convert_to_class (class, expr); } /* Compute the value of the CHILL `size' operator just * like the C 'sizeof' operator (code stolen from c-typeck.c) * TYPE may be a location or mode tree. In pass 1, we build * a function-call syntax tree; in pass 2, we evaluate it. */ tree build_chill_sizeof (type) tree type; { if (pass == 2) { tree temp; struct ch_class class; enum tree_code code; tree signame = NULL_TREE; if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) return error_mark_node; if (TREE_CODE (type) == IDENTIFIER_NODE) type = lookup_name (type); code = TREE_CODE (type); if (code == ERROR_MARK) return error_mark_node; if (TREE_CODE_CLASS (TREE_CODE (type)) != 't') { if (TREE_CODE (type) == TYPE_DECL && CH_DECL_SIGNAL (type)) signame = DECL_NAME (type); type = TREE_TYPE (type); } if (code == FUNCTION_TYPE) { if (pedantic || warn_pointer_arith) pedwarn ("size applied to a function mode"); return error_mark_node; } if (code == VOID_TYPE) { if (pedantic || warn_pointer_arith) pedwarn ("sizeof applied to a void mode"); return error_mark_node; } if (TYPE_SIZE (type) == 0) { error ("sizeof applied to an incomplete mode"); return error_mark_node; } temp = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (TYPE_PRECISION (char_type_node))); if (signame != NULL_TREE) { /* we have a signal definition. This signal may have no data items specified. The definition however says that there are data, cause we cannot build a structure without fields. In this case return 0. */ if (IDENTIFIER_SIGNAL_DATA (signame) == 0) temp = integer_zero_node; } /* FIXME: should call * cond_type_range_exception (temp); */ class.kind = CH_DERIVED_CLASS; class.mode = integer_type_node; return convert_to_class (class, temp); } return NULL_TREE; } /* Compute the declared maximum value of the variable, * expression or declared type */ tree build_chill_upper (what) tree what; { return build_chill_lower_or_upper (what, 1); } /* * Here at the site of a function/procedure call.. We need to build * temps for the INOUT and OUT parameters, and copy the actual parameters * into the temps. After the call, we 'copy back' the values from the * temps to the actual parameter variables. This somewhat verbose pol- * icy meets the requirement that the actual parameters are undisturbed * if the function/procedure causes an exception. They are updated only * upon a normal return from the function. * * Note: the expr_list, which collects all of the above assignments, etc, * is built in REVERSE execution order. The list is corrected by nreverse * inside the build_chill_compound_expr call. */ tree build_chill_function_call (function, expr) tree function, expr; { register tree typetail, valtail, typelist; register tree temp, actual_args = NULL_TREE; tree name = NULL_TREE; tree function_call; tree fntype; int parmno = 1; /* parameter number for error message */ int callee_raise_exception = 0; /* list of assignments to run after the actual call, copying from the temps back to the user's variables. */ tree copy_back = NULL_TREE; /* list of expressions to run before the call, copying from the user's variable to the temps that are passed to the function */ tree expr_list = NULL_TREE; if (function == NULL_TREE || TREE_CODE (function) == ERROR_MARK) return error_mark_node; if (expr != NULL_TREE && TREE_CODE (expr) == ERROR_MARK) return error_mark_node; if (pass < 2) return error_mark_node; fntype = TREE_TYPE (function); if (TREE_CODE (function) == FUNCTION_DECL) { callee_raise_exception = TYPE_RAISES_EXCEPTIONS (fntype) != NULL_TREE; /* Differs from default_conversion by not setting TREE_ADDRESSABLE (because calling an inline function does not mean the function needs to be separately compiled). */ fntype = build_type_variant (fntype, TREE_READONLY (function), TREE_THIS_VOLATILE (function)); name = DECL_NAME (function); /* check that function is not a PROCESS */ if (CH_DECL_PROCESS (function)) { error ("cannot call a PROCESS, you START a PROCESS"); return error_mark_node; } function = build1 (ADDR_EXPR, build_pointer_type (fntype), function); } else if (TREE_CODE (fntype) == POINTER_TYPE) { fntype = TREE_TYPE (fntype); callee_raise_exception = TYPE_RAISES_EXCEPTIONS (fntype) != NULL_TREE; /* Z.200 6.7 Call Action: "A procedure call causes the EMPTY exception if the procedure primitive value delivers NULL. */ if (TREE_CODE (function) != ADDR_EXPR || TREE_CODE (TREE_OPERAND (function, 0)) != FUNCTION_DECL) function = check_non_null (function); } typelist = TYPE_ARG_TYPES (fntype); if (callee_raise_exception) { /* remove last two arguments from list for subsequent checking. They will get added automatically after checking */ int len = list_length (typelist); int i; tree newtypelist = NULL_TREE; tree wrk = typelist; for (i = 0; i < len - 3; i++) { newtypelist = tree_cons (TREE_PURPOSE (wrk), TREE_VALUE (wrk), newtypelist); wrk = TREE_CHAIN (wrk); } /* add the void_type_node */ newtypelist = tree_cons (NULL_TREE, void_type_node, newtypelist); typelist = nreverse (newtypelist); } /* Scan the given expressions and types, producing individual converted arguments and pushing them on ACTUAL_ARGS in reverse order. */ for (valtail = expr, typetail = typelist; valtail != NULL_TREE && typetail != NULL_TREE; parmno++, valtail = TREE_CHAIN (valtail), typetail = TREE_CHAIN (typetail)) { register tree actual = TREE_VALUE (valtail); register tree attr = TREE_PURPOSE (typetail) ? TREE_PURPOSE (typetail) : ridpointers[(int) RID_IN]; register tree type = TREE_VALUE (typetail); char place[30]; sprintf (place, "parameter %d", parmno); /* if we have reached void_type_node in typelist we are at the end of formal parameters and then we have too many actual parameters */ if (type == void_type_node) break; /* check if actual is a TYPE_DECL. FIXME: what else ? */ if (TREE_CODE (actual) == TYPE_DECL) { error ("invalid %s", place); actual = error_mark_node; } /* INOUT or OUT param to handle? */ else if (attr == ridpointers[(int) RID_OUT] || attr == ridpointers[(int)RID_INOUT]) { char temp_name[20]; tree parmtmp; tree in_actual = NULL_TREE, out_actual; /* actual parameter must be a location so we can build a reference to it */ if (!CH_LOCATION_P (actual)) { error ("%s parameter %d must be a location", (attr == ridpointers[(int) RID_OUT]) ? "OUT" : "INOUT", parmno); continue; } if (TYPE_READONLY_PROPERTY (TREE_TYPE (actual)) || TREE_READONLY (actual)) { error ("%s parameter %d is READ-only", (attr == ridpointers[(int) RID_OUT]) ? "OUT" : "INOUT", parmno); continue; } sprintf (temp_name, "PARM_%d_%s", parmno, (attr == ridpointers[(int)RID_OUT]) ? "OUT" : "INOUT"); parmtmp = decl_temp1 (get_unique_identifier (temp_name), TREE_TYPE (type), 0, NULL_TREE, 0, 0); /* this temp *must not* be optimized into a register */ mark_addressable (parmtmp); if (attr == ridpointers[(int)RID_INOUT]) { tree in_actual = chill_convert_for_assignment (TREE_TYPE (type), actual, place); tree tmp = build_chill_modify_expr (parmtmp, in_actual); expr_list = tree_cons (NULL_TREE, tmp, expr_list); } if (in_actual != error_mark_node) { /* list of copy back assignments to perform, from the temp back to the actual parameter */ out_actual = chill_convert_for_assignment (TREE_TYPE (actual), parmtmp, place); copy_back = tree_cons (NULL_TREE, build_chill_modify_expr (actual, out_actual), copy_back); } /* we can do this because build_chill_function_type turned these parameters into REFERENCE_TYPEs. */ actual = build1 (ADDR_EXPR, type, parmtmp); } else if (attr == ridpointers[(int) RID_LOC]) { int is_location = chill_location (actual); if (is_location) { if (is_location == 1) { error ("LOC actual parameter %d is a non-referable location", parmno); actual = error_mark_node; } else if (! CH_READ_COMPATIBLE (type, TREE_TYPE (actual))) { error ("mode mismatch in parameter %d", parmno); actual = error_mark_node; } else actual = convert (type, actual); } else { actual = chill_convert_for_assignment (TREE_TYPE (type), actual, place); sprintf (place, "parameter_%d", parmno); actual = decl_temp1 (get_identifier (place), TREE_TYPE (type), 0, actual, 0, 0); actual = convert (type, actual); } mark_addressable (actual); } else actual = chill_convert_for_assignment (type, actual, place); actual_args = tree_cons (NULL_TREE, actual, actual_args); } if (valtail != 0 && TREE_VALUE (valtail) != void_type_node) { char *errstr = "too many arguments to procedure"; if (name) error ("%s `%s'", errstr, IDENTIFIER_POINTER (name)); else error (errstr); return error_mark_node; } else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) { char *errstr = "too few arguments to procedure"; if (name) error ("%s `%s'", errstr, IDENTIFIER_POINTER (name)); else error (errstr); return error_mark_node; } if (callee_raise_exception) { /* add linenumber and filename of the caller as arguments */ actual_args = tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), actual_args); actual_args = tree_cons (NULL_TREE, get_chill_linenumber (), actual_args); } function_call = build (CALL_EXPR, TREE_TYPE (fntype), function, nreverse (actual_args), NULL_TREE); TREE_SIDE_EFFECTS (function_call) = 1; if (copy_back == NULL_TREE && expr_list == NULL_TREE) return function_call; /* no copying to do, either way */ else { tree result_type = TREE_TYPE (fntype); tree result_tmp = NULL_TREE; /* no result wanted from procedure call */ if (result_type == NULL_TREE || result_type == void_type_node) expr_list = tree_cons (NULL_TREE, function_call, expr_list); else { /* create a temp for the function's result. this is so that we can evaluate this temp as the last expression in the list, which will make the function's return value the value of the whole list of expressions (by the C rules for compound expressions) */ result_tmp = decl_temp1 (get_unique_identifier ("FUNC_RESULT"), result_type, 0, NULL_TREE, 0, 0); expr_list = tree_cons (NULL_TREE, build_chill_modify_expr (result_tmp, function_call), expr_list); } expr_list = chainon (copy_back, expr_list); /* last, but not least, the function's result */ if (result_tmp != NULL_TREE) expr_list = tree_cons (NULL_TREE, result_tmp, expr_list); temp = build_chill_compound_expr (nreverse (expr_list)); return temp; } } /* We saw something that looks like a function call, but if it's pass 1, we're not sure. */ tree build_generalized_call (func, args) tree func, args; { tree type = TREE_TYPE (func); if (pass == 1) return build (CALL_EXPR, NULL_TREE, func, args, NULL_TREE); /* Handle string repetition */ if (TREE_CODE (func) == INTEGER_CST) { if (args == NULL_TREE || TREE_CHAIN (args) != NULL_TREE) { error ("syntax error (integer used as function)"); return error_mark_node; } if (TREE_CODE (args) == TREE_LIST) args = TREE_VALUE (args); return build_chill_repetition_op (func, args); } if (args != NULL_TREE) { if (TREE_CODE (args) == RANGE_EXPR) { tree lo = TREE_OPERAND (args, 0), hi = TREE_OPERAND (args, 1); if (TREE_CODE_CLASS (TREE_CODE (func)) == 't') return build_chill_range_type (func, lo, hi); else return build_chill_slice_with_range (func, lo, hi); } else if (TREE_CODE (args) != TREE_LIST) { error ("syntax error - missing operator, comma, or '('?"); return error_mark_node; } } if (TREE_CODE (func) == TYPE_DECL) { if (CH_DECL_SIGNAL (func)) return build_signal_descriptor (func, args); func = TREE_TYPE (func); } if (TREE_CODE_CLASS (TREE_CODE (func)) == 't' && args != NULL_TREE && TREE_CHAIN (args) == NULL_TREE) return build_chill_cast (func, TREE_VALUE (args)); if (TREE_CODE (type) == FUNCTION_TYPE || (TREE_CODE (type) == POINTER_TYPE && TREE_TYPE (type) != NULL_TREE && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)) { /* Check for a built-in Chill function. */ if (TREE_CODE (func) == FUNCTION_DECL && DECL_BUILT_IN (func) && DECL_FUNCTION_CODE (func) > END_BUILTINS) { tree fnname = DECL_NAME (func); switch ((enum chill_built_in_function)DECL_FUNCTION_CODE (func)) { case BUILT_IN_CH_ABS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_abs (TREE_VALUE (args)); case BUILT_IN_ABSTIME: if (check_arglist_length (args, 0, 6, fnname) < 0) return error_mark_node; return build_chill_abstime (args); case BUILT_IN_ADDR: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; #if 0 return build_chill_addr_expr (TREE_VALUE (args), (char *)0); #else return build_chill_arrow_expr (TREE_VALUE (args), 0); #endif case BUILT_IN_ALLOCATE_GLOBAL_MEMORY: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_allocate_global_memory_call (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_ALLOCATE: if (check_arglist_length (args, 1, 2, fnname) < 0) return error_mark_node; return build_chill_allocate (TREE_VALUE (args), TREE_CHAIN (args) == NULL_TREE ? NULL_TREE : TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_ALLOCATE_MEMORY: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_allocate_memory_call (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_ASSOCIATE: if (check_arglist_length (args, 2, 3, fnname) < 0) return error_mark_node; return build_chill_associate (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args)), TREE_CHAIN (TREE_CHAIN (args))); case BUILT_IN_ARCCOS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__acos"); case BUILT_IN_ARCSIN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__asin"); case BUILT_IN_ARCTAN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__atan"); case BUILT_IN_CARD: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_card (TREE_VALUE (args)); case BUILT_IN_CONNECT: if (check_arglist_length (args, 3, 5, fnname) < 0) return error_mark_node; return build_chill_connect (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args)), TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))), TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args)))); case BUILT_IN_COPY_NUMBER: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_copy_number (TREE_VALUE (args)); case BUILT_IN_CH_COS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__cos"); case BUILT_IN_CREATE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_create (TREE_VALUE (args)); case BUILT_IN_DAYS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_duration (TREE_VALUE (args), DAYS_MULTIPLIER, fnname, DAYS_MAX); case BUILT_IN_CH_DELETE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_delete (TREE_VALUE (args)); case BUILT_IN_DESCR: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_descr (TREE_VALUE (args)); case BUILT_IN_DISCONNECT: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_disconnect (TREE_VALUE (args)); case BUILT_IN_DISSOCIATE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_dissociate (TREE_VALUE (args)); case BUILT_IN_EOLN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_eoln (TREE_VALUE (args)); case BUILT_IN_EXISTING: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_existing (TREE_VALUE (args)); case BUILT_IN_EXP: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__exp"); case BUILT_IN_GEN_CODE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_gen_code (TREE_VALUE (args)); case BUILT_IN_GEN_INST: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_gen_inst (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_GEN_PTYPE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_gen_ptype (TREE_VALUE (args)); case BUILT_IN_GETASSOCIATION: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_getassociation (TREE_VALUE (args)); case BUILT_IN_GETSTACK: if (check_arglist_length (args, 1, 2, fnname) < 0) return error_mark_node; return build_chill_getstack (TREE_VALUE (args), TREE_CHAIN (args) == NULL_TREE ? NULL_TREE : TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_GETTEXTACCESS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_gettextaccess (TREE_VALUE (args)); case BUILT_IN_GETTEXTINDEX: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_gettextindex (TREE_VALUE (args)); case BUILT_IN_GETTEXTRECORD: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_gettextrecord (TREE_VALUE (args)); case BUILT_IN_GETUSAGE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_getusage (TREE_VALUE (args)); case BUILT_IN_HOURS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_duration (TREE_VALUE (args), HOURS_MULTIPLIER, fnname, HOURS_MAX); case BUILT_IN_INDEXABLE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_indexable (TREE_VALUE (args)); case BUILT_IN_INTTIME: if (check_arglist_length (args, 2, 7, fnname) < 0) return error_mark_node; return build_chill_inttime (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_ISASSOCIATED: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_isassociated (TREE_VALUE (args)); case BUILT_IN_LENGTH: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_length (TREE_VALUE (args)); case BUILT_IN_LN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__log"); case BUILT_IN_LOG: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__log10"); case BUILT_IN_LOWER: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_lower (TREE_VALUE (args)); case BUILT_IN_MAX: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_max (TREE_VALUE (args)); case BUILT_IN_MILLISECS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_duration (TREE_VALUE (args), MILLISECS_MULTIPLIER, fnname, MILLISECS_MAX); case BUILT_IN_MIN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_min (TREE_VALUE (args)); case BUILT_IN_MINUTES: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_duration (TREE_VALUE (args), MINUTES_MULTIPLIER, fnname, MINUTES_MAX); case BUILT_IN_MODIFY: if (check_arglist_length (args, 1, -1, fnname) < 0) return error_mark_node; return build_chill_modify (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_NUM: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_num (TREE_VALUE (args)); case BUILT_IN_OUTOFFILE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_outoffile (TREE_VALUE (args)); case BUILT_IN_PRED: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_pred_or_succ (TREE_VALUE (args), MINUS_EXPR); case BUILT_IN_PROC_TYPE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_proc_type (TREE_VALUE (args)); case BUILT_IN_QUEUE_LENGTH: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_queue_length (TREE_VALUE (args)); case BUILT_IN_READABLE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_readable (TREE_VALUE (args)); case BUILT_IN_READRECORD: if (check_arglist_length (args, 1, 3, fnname) < 0) return error_mark_node; return build_chill_readrecord (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_READTEXT: if (check_arglist_length (args, 2, -1, fnname) < 0) return error_mark_node; return build_chill_readtext (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_RETURN_MEMORY: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_return_memory (TREE_VALUE (args)); case BUILT_IN_SECS: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_duration (TREE_VALUE (args), SECS_MULTIPLIER, fnname, SECS_MAX); case BUILT_IN_SEQUENCIBLE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_sequencible (TREE_VALUE (args)); case BUILT_IN_SETTEXTACCESS: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_chill_settextaccess (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_SETTEXTINDEX: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_chill_settextindex (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_SETTEXTRECORD: if (check_arglist_length (args, 2, 2, fnname) < 0) return error_mark_node; return build_chill_settextrecord (TREE_VALUE (args), TREE_VALUE (TREE_CHAIN (args))); case BUILT_IN_CH_SIN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__sin"); case BUILT_IN_SIZE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_sizeof (TREE_VALUE (args)); case BUILT_IN_SQRT: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__sqrt"); case BUILT_IN_SUCC: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_pred_or_succ (TREE_VALUE (args), PLUS_EXPR); case BUILT_IN_TAN: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_floatcall (TREE_VALUE (args), IDENTIFIER_POINTER (fnname), "__tan"); case BUILT_IN_TERMINATE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_terminate (TREE_VALUE (args)); case BUILT_IN_UPPER: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_upper (TREE_VALUE (args)); case BUILT_IN_VARIABLE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_variable (TREE_VALUE (args)); case BUILT_IN_WRITEABLE: if (check_arglist_length (args, 1, 1, fnname) < 0) return error_mark_node; return build_chill_writeable (TREE_VALUE (args)); case BUILT_IN_WRITERECORD: if (check_arglist_length (args, 2, 3, fnname) < 0) return error_mark_node; return build_chill_writerecord (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_WRITETEXT: if (check_arglist_length (args, 2, -1, fnname) < 0) return error_mark_node; return build_chill_writetext (TREE_VALUE (args), TREE_CHAIN (args)); case BUILT_IN_EXPIRED: case BUILT_IN_WAIT: sorry ("unimplemented builtin function `%s'", IDENTIFIER_POINTER (fnname)); break; default: error ("internal error - bad builtin function `%s'", IDENTIFIER_POINTER (fnname)); } } return build_chill_function_call (func, args); } if (chill_varying_type_p (TREE_TYPE (func))) type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (type))); if (CH_STRING_TYPE_P (type)) { if (args == NULL_TREE) { error ("empty expression in string index"); return error_mark_node; } if (TREE_CHAIN (args) != NULL) { error ("only one expression allowed in string index"); return error_mark_node; } if (flag_old_strings) return build_chill_slice_with_length (func, TREE_VALUE (args), integer_one_node); else if (CH_BOOLS_TYPE_P (type)) return build_chill_bitref (func, args); else return build_chill_array_ref (func, args); } else if (TREE_CODE (type) == ARRAY_TYPE) return build_chill_array_ref (func, args); if (TREE_CODE (func) != ERROR_MARK) error ("invalid: primval ( untyped_exprlist )"); return error_mark_node; } /* Given a set stored as one bit per char (in BUFFER[0 .. BIT_SIZE-1]), return a CONTRUCTOR, of type TYPE (a SET_TYPE). */ tree expand_packed_set (buffer, bit_size, type) char *buffer; int bit_size; tree type; { /* The ordinal number corresponding to the first stored bit. */ HOST_WIDE_INT first_bit_no = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))); tree list = NULL_TREE; int i; for (i = 0; i < bit_size; i++) if (buffer[i]) { int next_0; for (next_0 = i + 1; next_0 < bit_size && buffer[next_0]; next_0++) ; if (next_0 == i + 1) list = tree_cons (NULL_TREE, build_int_2 (i + first_bit_no, 0), list); else { list = tree_cons (build_int_2 (i + first_bit_no, 0), build_int_2 (next_0 - 1 + first_bit_no, 0), list); /* advance i past the range of 1-bits */ i = next_0; } } list = build (CONSTRUCTOR, type, NULL_TREE, nreverse (list)); TREE_CONSTANT (list) = 1; return list; } /* * fold a set represented as a CONSTRUCTOR list. * An empty set has a NULL_TREE in its TREE_OPERAND (set, 1) slot. */ static tree fold_set_expr (code, op0, op1) enum chill_tree_code code; tree op0, op1; { tree temp; char *buffer0, *buffer1, *bufferr; int i, size0, size1, first_unused_bit; if (! TREE_CONSTANT (op0) || TREE_CODE (op0) != CONSTRUCTOR) return NULL_TREE; if (op1 && (! TREE_CONSTANT (op1) || TREE_CODE (op1) != CONSTRUCTOR)) return NULL_TREE; size0 = int_size_in_bytes (TREE_TYPE (op0)) * BITS_PER_UNIT; if (size0 < 0) { error ("operand is variable-size bitstring/power-set"); return error_mark_node; } buffer0 = (char*) alloca (size0); temp = get_set_constructor_bits (op0, buffer0, size0); if (temp) return NULL_TREE; if (op0 && op1) { size1 = int_size_in_bytes (TREE_TYPE (op1)) * BITS_PER_UNIT; if (size1 < 0) { error ("operand is variable-size bitstring/power-set"); return error_mark_node; } if (size0 != size1) return NULL_TREE; buffer1 = (char*) alloca (size1); temp = get_set_constructor_bits (op1, buffer1, size1); if (temp) return NULL_TREE; } bufferr = (char*) alloca (size0); /* result buffer */ switch ((int)code) { case SET_NOT_EXPR: case BIT_NOT_EXPR: for (i = 0; i < size0; i++) bufferr[i] = 1 & ~buffer0[i]; goto build_result; case SET_AND_EXPR: case BIT_AND_EXPR: for (i = 0; i < size0; i++) bufferr[i] = buffer0[i] & buffer1[i]; goto build_result; case SET_IOR_EXPR: case BIT_IOR_EXPR: for (i = 0; i < size0; i++) bufferr[i] = buffer0[i] | buffer1[i]; goto build_result; case SET_XOR_EXPR: case BIT_XOR_EXPR: for (i = 0; i < size0; i++) bufferr[i] = (buffer0[i] ^ buffer1[i]) & 1; goto build_result; case SET_DIFF_EXPR: case MINUS_EXPR: for (i = 0; i < size0; i++) bufferr[i] = buffer0[i] & ~buffer1[i]; goto build_result; build_result: /* mask out unused bits. Same as runtime library does. */ first_unused_bit = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (op0)))) - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (op0)))) + 1; for (i = first_unused_bit; i < size0 ; i++) bufferr[i] = 0; return expand_packed_set (bufferr, size0, TREE_TYPE (op0)); case EQ_EXPR: for (i = 0; i < size0; i++) if (buffer0[i] != buffer1[i]) return boolean_false_node; return boolean_true_node; case NE_EXPR: for (i = 0; i < size0; i++) if (buffer0[i] != buffer1[i]) return boolean_true_node; return boolean_false_node; default: return NULL_TREE; } } /* * build a set or bit-array expression. Type-checking is * done elsewhere. */ static tree build_compare_set_expr (code, op0, op1) enum chill_tree_code code; tree op0, op1; { tree result_type = NULL_TREE; char *fnname; tree x; /* These conversions are needed if -fold-strings. */ if (TREE_CODE (TREE_TYPE (op0)) == BOOLEAN_TYPE) { if (CH_BOOLS_ONE_P (TREE_TYPE (op1))) return build_compare_discrete_expr (code, op0, convert (boolean_type_node, op1)); else op0 = convert (bitstring_one_type_node, op0); } if (TREE_CODE (TREE_TYPE (op1)) == BOOLEAN_TYPE) { if (CH_BOOLS_ONE_P (TREE_TYPE (op0))) return build_compare_discrete_expr (code, convert (boolean_type_node, op0), op1); else op1 = convert (bitstring_one_type_node, op1); } switch ((int)code) { case EQ_EXPR: { tree temp = fold_set_expr (EQ_EXPR, op0, op1); if (temp) return temp; fnname = "__eqpowerset"; goto compare_powerset; } break; case GE_EXPR: /* switch operands and fall thru */ x = op0; op0 = op1; op1 = x; case LE_EXPR: fnname = "__lepowerset"; goto compare_powerset; case GT_EXPR: /* switch operands and fall thru */ x = op0; op0 = op1; op1 = x; case LT_EXPR: fnname = "__ltpowerset"; goto compare_powerset; case NE_EXPR: return invert_truthvalue (build_compare_set_expr (EQ_EXPR, op0, op1)); compare_powerset: { tree tsize = powersetlen (op0); if (TREE_CODE (TREE_TYPE (op0)) != SET_TYPE) tsize = fold (build (MULT_EXPR, sizetype, tsize, size_int (BITS_PER_UNIT))); return build_chill_function_call (lookup_name (get_identifier (fnname)), tree_cons (NULL_TREE, force_addr_of (op0), tree_cons (NULL_TREE, force_addr_of (op1), tree_cons (NULL_TREE, tsize, NULL_TREE)))); } break; default: if ((int) code >= (int)LAST_AND_UNUSED_TREE_CODE) { error ("tree code `%s' unhandled in build_compare_set_expr", tree_code_name[(int)code]); return error_mark_node; } break; } return build ((enum tree_code)code, result_type, op0, op1); } /* Convert a varying string (or array) to dynamic non-varying string: EXP becomes EXP.var_data(0 UP EXP.var_length). */ tree varying_to_slice (exp) tree exp; { if (!chill_varying_type_p (TREE_TYPE (exp))) return exp; else { tree size, data, data_domain, doamin, min; tree novelty = CH_NOVELTY (TREE_TYPE (exp)); exp = save_if_needed (exp); size = build_component_ref (exp, var_length_id); data = build_component_ref (exp, var_data_id); TREE_TYPE (data) = copy_novelty (novelty, TREE_TYPE (data)); data_domain = TYPE_DOMAIN (TREE_TYPE (data)); if (data_domain != NULL_TREE && TYPE_MIN_VALUE (data_domain) != NULL_TREE) min = TYPE_MIN_VALUE (data_domain); else min = integer_zero_node; return build_chill_slice (data, min, size); } } /* Convert a scalar argument to a string or array type. This is a subroutine of `build_concat_expr'. */ static tree scalar_to_string (exp) tree exp; { tree type = TREE_TYPE (exp); if (SCALAR_P (type)) { int was_const = TREE_CONSTANT (exp); if (TREE_TYPE (exp) == char_type_node) exp = convert (string_one_type_node, exp); else if (TREE_TYPE (exp) == boolean_type_node) exp = convert (bitstring_one_type_node, exp); else exp = convert (build_array_type_for_scalar (type), exp); TREE_CONSTANT (exp) = was_const; return exp; } return varying_to_slice (exp); } /* FIXME: Generalize this to general arrays (not just strings), at least for the compiler-generated case of padding fixed-length arrays. */ static tree build_concat_expr (op0, op1) tree op0, op1; { tree orig_op0 = op0, orig_op1 = op1; tree type0, type1, size0, size1, res; op0 = scalar_to_string (op0); type0 = TREE_TYPE (op0); op1 = scalar_to_string (op1); type1 = TREE_TYPE (op1); size1 = size_in_bytes (type1); /* try to fold constant string literals */ if (TREE_CODE (op0) == STRING_CST && (TREE_CODE (op1) == STRING_CST || TREE_CODE (op1) == UNDEFINED_EXPR) && TREE_CODE (size1) == INTEGER_CST) { int len0 = TREE_STRING_LENGTH (op0); int len1 = TREE_INT_CST_LOW (size1); char *result = xmalloc (len0 + len1 + 1); memcpy (result, TREE_STRING_POINTER (op0), len0); if (TREE_CODE (op1) == UNDEFINED_EXPR) memset (&result[len0], '\0', len1); else memcpy (&result[len0], TREE_STRING_POINTER (op1), len1); return build_chill_string (len0 + len1, result); } else if (TREE_CODE (type0) == TREE_CODE (type1)) { tree result_size; struct ch_class result_class; struct ch_class class0; struct ch_class class1; class0 = chill_expr_class (orig_op0); class1 = chill_expr_class (orig_op1); if (TREE_CODE (type0) == SET_TYPE) { result_size = size_binop (PLUS_EXPR, discrete_count (TYPE_DOMAIN (type0)), discrete_count (TYPE_DOMAIN (type1))); result_class.mode = build_bitstring_type (result_size); } else { tree max0 = TYPE_MAX_VALUE (type0); tree max1 = TYPE_MAX_VALUE (type1); /* new array's dynamic size (in bytes). */ size0 = size_in_bytes (type0); /* size1 was computed above. */ result_size = size_binop (PLUS_EXPR, size0, size1); /* new array's type. */ result_class.mode = build_string_type (char_type_node, result_size); if (max0 || max1) { max0 = max0 == 0 ? size0 : convert (sizetype, max0); max1 = max1 == 0 ? size1 : convert (sizetype, max1); TYPE_MAX_VALUE (result_class.mode) = size_binop (PLUS_EXPR, max0, max1); } } if (class0.kind == CH_VALUE_CLASS || class1.kind == CH_VALUE_CLASS) { tree novelty0 = CH_NOVELTY (TREE_TYPE (orig_op0)); result_class.kind = CH_VALUE_CLASS; if (class0.kind == CH_VALUE_CLASS && novelty0 != NULL_TREE) SET_CH_NOVELTY_NONNIL (result_class.mode, novelty0); else if (class1.kind == CH_VALUE_CLASS) SET_CH_NOVELTY (result_class.mode, CH_NOVELTY (TREE_TYPE (orig_op1))); } else result_class.kind = CH_DERIVED_CLASS; if (TREE_CODE (result_class.mode) == SET_TYPE && TREE_CONSTANT (op0) && TREE_CONSTANT (op1) && TREE_CODE (op0) == CONSTRUCTOR && TREE_CODE (op1) == CONSTRUCTOR) { HOST_WIDE_INT size0, size1; char *buffer; size0 = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type0))) + 1; size1 = TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type1))) + 1; buffer = (char*) alloca (size0 + size1); if (size0 < 0 || size1 < 0 || get_set_constructor_bits (op0, buffer, size0) || get_set_constructor_bits (op1, buffer + size0, size1)) abort (); res = expand_packed_set (buffer, size0 + size1, result_class.mode); } else res = build (CONCAT_EXPR, result_class.mode, op0, op1); return convert_to_class (result_class, res); } else { error ("incompatible modes in concat expression"); return error_mark_node; } } /* * handle varying and fixed array compare operations */ static tree build_compare_string_expr (code, op0, op1) enum chill_tree_code code; tree op0, op1; { if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK) return error_mark_node; if (op1 == NULL_TREE || TREE_CODE (op1) == ERROR_MARK) return error_mark_node; if (tree_int_cst_equal (TYPE_SIZE (TREE_TYPE (op0)), TYPE_SIZE (TREE_TYPE (op1))) && ! chill_varying_type_p (TREE_TYPE (op0)) && ! chill_varying_type_p (TREE_TYPE (op1))) { tree size = size_in_bytes (TREE_TYPE (op0)); tree temp = lookup_name (get_identifier ("memcmp")); temp = build_chill_function_call (temp, tree_cons (NULL_TREE, force_addr_of (op0), tree_cons (NULL_TREE, force_addr_of (op1), tree_cons (NULL_TREE, size, NULL_TREE)))); return build_compare_discrete_expr (code, temp, integer_zero_node); } switch ((int)code) { case EQ_EXPR: code = STRING_EQ_EXPR; break; case GE_EXPR: return invert_truthvalue (build_compare_string_expr (LT_EXPR, op0, op1)); case LE_EXPR: return invert_truthvalue (build_compare_string_expr (LT_EXPR, op1, op0)); case GT_EXPR: return build_compare_string_expr (LT_EXPR, op1, op0); case LT_EXPR: code = STRING_LT_EXPR; break; case NE_EXPR: return invert_truthvalue (build_compare_string_expr (EQ_EXPR, op0, op1)); default: error ("Invalid operation on array of chars"); return error_mark_node; } return build (code, boolean_type_node, op0, op1); } tree compare_records (exp0, exp1) tree exp0, exp1; { tree type = TREE_TYPE (exp0); tree field; int have_variants = 0; tree result = boolean_true_node; extern int maximum_field_alignment; if (TREE_CODE (type) != RECORD_TYPE) abort (); exp0 = save_if_needed (exp0); exp1 = save_if_needed (exp1); for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { if (DECL_NAME (field) == NULL_TREE) { have_variants = 1; break; } } /* in case of -fpack we always do a memcmp */ if (maximum_field_alignment != 0) { tree memcmp_func = lookup_name (get_identifier ("memcmp")); tree arg1 = force_addr_of (exp0); tree arg2 = force_addr_of (exp1); tree arg3 = size_in_bytes (type); tree fcall = build_chill_function_call (memcmp_func, tree_cons (NULL_TREE, arg1, tree_cons (NULL_TREE, arg2, tree_cons (NULL_TREE, arg3, NULL_TREE)))); if (have_variants) warning ("comparison of variant structures is unsafe"); result = build_chill_binary_op (EQ_EXPR, fcall, integer_zero_node); return result; } if (have_variants) { sorry ("compare with variant records"); return error_mark_node; } for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { tree exp0fld = build_component_ref (exp0, DECL_NAME (field)); tree exp1fld = build_component_ref (exp1, DECL_NAME (field)); tree eq_flds = build_chill_binary_op (EQ_EXPR, exp0fld, exp1fld); result = build_chill_binary_op (TRUTH_AND_EXPR, result, eq_flds); } return result; } int compare_int_csts (op, val1, val2) enum tree_code op; tree val1, val2; { int result; tree tmp; tree type1 = TREE_TYPE (val1); tree type2 = TREE_TYPE (val2); switch (op) { case GT_EXPR: case GE_EXPR: tmp = val1; val1 = val2; val2 = tmp; tmp = type1; type1 = type2; type2 = tmp; op = (op == GT_EXPR) ? LT_EXPR : LE_EXPR; /* ... fall through ... */ case LT_EXPR: case LE_EXPR: if (!TREE_UNSIGNED (type1)) { if (!TREE_UNSIGNED (type2)) result = INT_CST_LT (val1, val2); else if (TREE_INT_CST_HIGH (val1) < 0) result = 1; else result = INT_CST_LT_UNSIGNED (val1, val2); } else { if (!TREE_UNSIGNED (type2) && TREE_INT_CST_HIGH (val2) < 0) result = 0; else result = INT_CST_LT_UNSIGNED (val1, val2); } if (op == LT_EXPR || result == 1) break; /* else fall through ... */ case NE_EXPR: case EQ_EXPR: if (TREE_INT_CST_LOW (val1) == TREE_INT_CST_LOW (val2) && TREE_INT_CST_HIGH (val1) == TREE_INT_CST_HIGH (val2) /* They're bitwise equal. Check for one being negative and the other unsigned. */ && (TREE_INT_CST_HIGH (val2) >= 0 || TREE_UNSIGNED (TREE_TYPE (val1)) == TREE_UNSIGNED (TREE_TYPE (val2)))) result = 1; else result = 0; if (op == NE_EXPR) result = !result; break; } return result; } /* Build an expression to compare discrete values VAL1 and VAL2. This does not check that they are discrete, nor that they are compatible; if you need such checks use build_compare_expr. */ tree build_compare_discrete_expr (op, val1, val2) enum chill_tree_code op; tree val1, val2; { tree type1 = TREE_TYPE (val1); tree type2 = TREE_TYPE (val2); tree tmp; if (TREE_CODE (val1) == INTEGER_CST && TREE_CODE (val2) == INTEGER_CST) { if (compare_int_csts (op, val1, val2)) return boolean_true_node; else return boolean_false_node; } if (TREE_UNSIGNED (type1) != TREE_UNSIGNED (type2)) { switch (op) { case GT_EXPR: case GE_EXPR: tmp = val1; val1 = val2; val2 = tmp; tmp = type1; type1 = type2; type2 = tmp; op = (op == GT_EXPR) ? LT_EXPR : LE_EXPR; /* ... fall through ... */ case LT_EXPR: case LE_EXPR: if (TREE_UNSIGNED (type2)) { tmp = build_int_2_wide (0, 0); TREE_TYPE (tmp) = type1; val1 = save_expr (val1); tmp = fold (build (LT_EXPR, boolean_type_node, val1, tmp)); if (TYPE_PRECISION (type2) < TYPE_PRECISION (type1)) { type2 = unsigned_type (type1); val2 = convert_to_integer (type2, val2); } val1 = convert_to_integer (type2, val1); return fold (build (TRUTH_OR_EXPR, boolean_type_node, tmp, fold (build (op, boolean_type_node, val1, val2)))); } unsigned_vs_signed: /* val1 is unsigned, val2 is signed */ tmp = build_int_2_wide (0, 0); TREE_TYPE (tmp) = type2; val2 = save_expr (val2); tmp = fold (build (GE_EXPR, boolean_type_node, val2, tmp)); if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2)) { type1 = unsigned_type (type2); val1 = convert_to_integer (type1, val1); } val2 = convert_to_integer (type1, val2); return fold (build (TRUTH_AND_EXPR, boolean_type_node, tmp, fold (build (op, boolean_type_node, val1, val2)))); case EQ_EXPR: if (TREE_UNSIGNED (val2)) { tmp = val1; val1 = val2; val2 = tmp; tmp = type1; type1 = type2; type2 = tmp; } goto unsigned_vs_signed; case NE_EXPR: tmp = build_compare_expr (EQ_EXPR, val1, val2); return build_chill_unary_op (TRUTH_NOT_EXPR, tmp); } } if (TYPE_PRECISION (type1) > TYPE_PRECISION (type2)) val2 = convert (type1, val2); else if (TYPE_PRECISION (type1) < TYPE_PRECISION (type2)) val1 = convert (type2, val1); return fold (build (op, boolean_type_node, val1, val2)); } tree build_compare_expr (op, val1, val2) enum chill_tree_code op; tree val1, val2; { tree tmp; tree type1, type2; val1 = check_have_mode (val1, "relational expression"); val2 = check_have_mode (val2, "relational expression"); if (val1 == NULL_TREE || TREE_CODE (val1) == ERROR_MARK) return error_mark_node; if (val2 == NULL_TREE || TREE_CODE (val2) == ERROR_MARK) return error_mark_node; if (pass == 1) return build (op, NULL_TREE, val1, val2); if (!CH_COMPATIBLE_CLASSES (val1, val2)) { error ("incompatible operands to %s", boolean_code_name [op]); return error_mark_node; } tmp = CH_ROOT_MODE (TREE_TYPE (val1)); if (tmp != TREE_TYPE (val1)) val1 = convert (tmp, val1); tmp = CH_ROOT_MODE (TREE_TYPE (val2)); if (tmp != TREE_TYPE (val2)) val2 = convert (tmp, val2); type1 = TREE_TYPE (val1); type2 = TREE_TYPE (val2); if (TREE_CODE (type1) == SET_TYPE) tmp = build_compare_set_expr (op, val1, val2); else if (discrete_type_p (type1)) tmp = build_compare_discrete_expr (op, val1, val2); else if (chill_varying_type_p (type1) || chill_varying_type_p (type2) || (TREE_CODE (type1) == ARRAY_TYPE && TREE_CODE (TREE_TYPE (type1)) == CHAR_TYPE) || (TREE_CODE (type2) == ARRAY_TYPE && TREE_CODE (TREE_TYPE (type2)) == CHAR_TYPE) ) tmp = build_compare_string_expr (op, val1, val2); else if ((TREE_CODE (type1) == RECORD_TYPE || TREE_CODE (type2) == RECORD_TYPE) && (op == EQ_EXPR || op == NE_EXPR)) { /* This is for handling INSTANCEs being compared against NULL. */ if (val1 == null_pointer_node) val1 = convert (type2, val1); if (val2 == null_pointer_node) val2 = convert (type1, val2); tmp = compare_records (val1, val2); if (op == NE_EXPR) tmp = build_chill_unary_op (TRUTH_NOT_EXPR, tmp); } else if (TREE_CODE (type1) == REAL_TYPE || TREE_CODE (type2) == REAL_TYPE || (op == EQ_EXPR || op == NE_EXPR)) { tmp = build (op, boolean_type_node, val1, val2); CH_DERIVED_FLAG (tmp) = 1; /* Optimization to avoid copy_node. */ tmp = fold (tmp); } else { error ("relational operator not allowed for this mode"); return error_mark_node; } if (!CH_DERIVED_FLAG (tmp)) { tmp = copy_node (tmp); CH_DERIVED_FLAG (tmp) = 1; } return tmp; } tree finish_chill_binary_op (node) tree node; { tree op0 = check_have_mode (TREE_OPERAND (node, 0), "binary expression"); tree op1 = check_have_mode (TREE_OPERAND (node, 1), "binary expression"); tree type0 = TREE_TYPE (op0); tree type1 = TREE_TYPE (op1); enum tree_code code0; enum tree_code code1; tree folded; if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK) return error_mark_node; if (UNSATISFIED (op0) || UNSATISFIED (op1)) { UNSATISFIED_FLAG (node) = 1; return node; } #if 0 /* assure that both operands have a type */ if (! type0 && type1) { op0 = convert (type1, op0); type0 = TREE_TYPE (op0); } if (! type1 && type0) { op1 = convert (type0, op1); type1 = TREE_TYPE (op1); } #endif UNSATISFIED_FLAG (node) = 0; #if 0 { int op0f = TREE_CODE (op0) == FUNCTION_DECL; int op1f = TREE_CODE (op1) == FUNCTION_DECL; if (op0f) op0 = convert (build_pointer_type (TREE_TYPE (op0)), op0); if (op1f) op1 = convert (build_pointer_type (TREE_TYPE (op1)), op1); if ((op0f || op1f) && code != EQ_EXPR && code != NE_EXPR) error ("Cannot use %s operator on PROC mode variable", tree_code_name[(int)code]); } if (invalid_left_operand (type0, code)) { error ("invalid left operand of %s", tree_code_name[(int)code]); return error_mark_node; } if (invalid_right_operand (code, type1)) { error ("invalid right operand of %s", tree_code_name[(int)code]); return error_mark_node; } #endif switch (TREE_CODE (node)) { case CONCAT_EXPR: return build_concat_expr (op0, op1); case REPLICATE_EXPR: op0 = fold (op0); if (!TREE_CONSTANT (op0) || !TREE_CONSTANT (op1)) { error ("repetition expression must be constant"); return error_mark_node; } else return build_chill_repetition_op (op0, op1); case FLOOR_MOD_EXPR: case TRUNC_MOD_EXPR: if (TREE_CODE (type0) != INTEGER_TYPE) { error ("left argument to MOD/REM operator must be integral"); return error_mark_node; } if (TREE_CODE (type1) != INTEGER_TYPE) { error ("right argument to MOD/REM operator must be integral"); return error_mark_node; } break; case MINUS_EXPR: if (TREE_CODE (type1) == SET_TYPE) { tree temp = fold_set_expr (MINUS_EXPR, op0, op1); if (temp) return temp; if (TYPE_MODE (type1) == BLKmode) TREE_SET_CODE (node, SET_DIFF_EXPR); else { op1 = build_chill_unary_op (BIT_NOT_EXPR, op1); TREE_OPERAND (node, 1) = op1; TREE_SET_CODE (node, BIT_AND_EXPR); } } break; case TRUNC_DIV_EXPR: if (TREE_CODE (type0) == REAL_TYPE || TREE_CODE (type1) == REAL_TYPE) TREE_SET_CODE (node, RDIV_EXPR); break; case BIT_AND_EXPR: if (TYPE_MODE (type1) == BLKmode) TREE_SET_CODE (node, SET_AND_EXPR); goto fold_set_binop; case BIT_IOR_EXPR: if (TYPE_MODE (type1) == BLKmode) TREE_SET_CODE (node, SET_IOR_EXPR); goto fold_set_binop; case BIT_XOR_EXPR: if (TYPE_MODE (type1) == BLKmode) TREE_SET_CODE (node, SET_XOR_EXPR); goto fold_set_binop; case SET_AND_EXPR: case SET_IOR_EXPR: case SET_XOR_EXPR: case SET_DIFF_EXPR: fold_set_binop: if (TREE_CODE (type0) == SET_TYPE) { tree temp = fold_set_expr (TREE_CODE (node), op0, op1); if (temp) return temp; } break; case SET_IN_EXPR: if (TREE_CODE (type1) != SET_TYPE || CH_BOOLS_TYPE_P (type1)) { error ("right operand of IN is not a powerset"); return error_mark_node; } if (!CH_COMPATIBLE (op0, TYPE_DOMAIN (type1))) { error ("left operand of IN incompatible with right operand"); return error_mark_node; } type0 = CH_ROOT_MODE (type0); if (type0 != TREE_TYPE (op0)) TREE_OPERAND (node, 0) = op0 = convert (type0, op0); TREE_TYPE (node) = boolean_type_node; CH_DERIVED_FLAG (node) = 1; node = fold (node); if (!CH_DERIVED_FLAG (node)) { node = copy_node (node); CH_DERIVED_FLAG (node) = 1; } return node; case NE_EXPR: case EQ_EXPR: case GE_EXPR: case GT_EXPR: case LE_EXPR: case LT_EXPR: return build_compare_expr (TREE_CODE (node), op0, op1); default: ; } if (!CH_COMPATIBLE_CLASSES (op0, op1)) { error ("incompatible operands to %s", tree_code_name[(int) TREE_CODE (node)]); return error_mark_node; } finish: if (TREE_TYPE (node) == NULL_TREE) { struct ch_class class; class = CH_ROOT_RESULTING_CLASS (op0, op1); TREE_OPERAND (node, 0) = op0 = convert_to_class (class, op0); type0 = TREE_TYPE (op0); TREE_OPERAND (node, 1) = op1 = convert_to_class (class, op1); type1 = TREE_TYPE (op1); TREE_TYPE (node) = class.mode; folded = convert_to_class (class, fold (node)); } else folded = fold (node); #if 0 if (folded == node) TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1); #endif if (TREE_CODE (node) == TRUNC_DIV_EXPR) if (TREE_CONSTANT (op1)) { if (tree_int_cst_equal (op1, integer_zero_node)) { error ("division by zero"); return integer_zero_node; } } else if (range_checking) { #if 0 tree test = build (EQ_EXPR, boolean_type_node, op1, integer_zero_node); /* Should this be overflow? */ folded = check_expression (folded, test, ridpointers[(int) RID_RANGEFAIL]); #endif } return folded; } /* * This implements the '->' operator, which, like the '&' in C, * returns a pointer to an object, which has the type of * pointer-to-that-object. * * FORCE is 0 when we're evaluating a user-level syntactic construct, * and 1 when we're calling from inside the compiler. */ tree build_chill_arrow_expr (ref, force) tree ref; int force; { tree addr_type; tree result; if (pass == 1) { error ("-> operator not allow in constant expression"); return error_mark_node; } if (ref == NULL_TREE || TREE_CODE (ref) == ERROR_MARK) return ref; while (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE) ref = convert (TREE_TYPE (TREE_TYPE (ref)), ref); if (!force && ! CH_LOCATION_P (ref)) { if (TREE_CODE (ref) == STRING_CST) pedwarn ("taking the address of a string literal is non-standard"); else if (TREE_CODE (TREE_TYPE (ref)) == FUNCTION_TYPE) pedwarn ("taking the address of a function is non-standard"); else { error ("ADDR requires a LOCATION argument"); return error_mark_node; } /* FIXME: Should we be sure that ref isn't a function if we're being pedantic? */ } addr_type = build_pointer_type (TREE_TYPE (ref)); #if 0 /* This transformation makes chill_expr_class return CH_VALUE_CLASS when it should return CH_REFERENCE_CLASS. That could be fixed, but we probably don't want this transformation anyway. */ if (TREE_CODE (ref) == NOP_EXPR) /* RETYPE_EXPR */ { tree addr; while (TREE_CODE (ref) == NOP_EXPR) /* RETYPE_EXPR */ ref = TREE_OPERAND (ref, 0); mark_addressable (ref); addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (ref)), ref); return build1 (NOP_EXPR, /* RETYPE_EXPR */ addr_type, addr); } else #endif { if (! mark_addressable (ref)) { error ("-> expression is not addressable"); return error_mark_node; } result = build1 (ADDR_EXPR, addr_type, ref); if (staticp (ref) && ! (TREE_CODE (ref) == FUNCTION_DECL && DECL_CONTEXT (ref) != 0)) TREE_CONSTANT (result) = 1; return result; } } /* * This implements the ADDR builtin function, which returns a * free reference, analogous to the C 'void *'. */ tree build_chill_addr_expr (ref, errormsg) tree ref; char *errormsg; { if (ref == error_mark_node) return ref; if (! CH_LOCATION_P (ref) && TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE) { error ("ADDR parameter must be a LOCATION", errormsg); return error_mark_node; } ref = build_chill_arrow_expr (ref, 1); if (ref != NULL_TREE && TREE_CODE (ref) != ERROR_MARK) TREE_TYPE (ref) = ptr_type_node; else if (errormsg == NULL) { error ("possible internal error in build_chill_arrow_expr"); return error_mark_node; } else { error ("%s is not addressable", errormsg); return error_mark_node; } return ref; } tree build_chill_binary_op (code, op0, op1) enum chill_tree_code code; tree op0, op1; { register tree result; if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK) return error_mark_node; if (op1 == NULL_TREE || TREE_CODE (op1) == ERROR_MARK) return error_mark_node; result = build (code, NULL_TREE, op0, op1); if (pass != 1) result = finish_chill_binary_op (result); return result; } /* * process a string repetition phrase '(' COUNT ')' STRING */ tree string_char_rep (count, string) int count; tree string; { int slen, charindx, repcnt; char ch; char *temp; char *inp; char *outp; tree type; if (string == NULL_TREE || TREE_CODE (string) == ERROR_MARK) return error_mark_node; type = TREE_TYPE (string); slen = int_size_in_bytes (type); temp = xmalloc (slen * count); inp = &ch; outp = temp; if (TREE_CODE (string) == STRING_CST) inp = TREE_STRING_POINTER (string); else /* single character */ ch = (char)TREE_INT_CST_LOW (string); /* copy the string/char COUNT times into the output buffer */ for (outp = temp, repcnt = 0; repcnt < count; repcnt++) for (charindx = 0; charindx < slen; charindx++) *outp++ = inp[charindx]; return build_chill_string (slen * count, temp); } /* Build a bit-string constant containing with the given LENGTH containing all ones (if VALUE is true), or all zeros (if VALUE is false). */ tree build_boring_bitstring (length, value) long length; int value; { tree result; tree list; /* Value of CONSTRUCTOR_ELTS in the result. */ if (value && length > 0) list = tree_cons (integer_zero_node, size_int (length - 1), NULL_TREE); else list = NULL_TREE; result = build (CONSTRUCTOR, build_bitstring_type (size_int (length)), NULL_TREE, list); TREE_CONSTANT (result) = 1; CH_DERIVED_FLAG (result) = 1; return result; } /* * handle a string repetition, with the syntax: * ( COUNT ) 'STRING' * COUNT is required to be constant, positive and folded. */ tree build_chill_repetition_op (count_op, string) tree count_op; tree string; { int count; tree type = TREE_TYPE (string); if (TREE_CODE (count_op) != INTEGER_CST) { error ("repetition count is not an integer constant"); return error_mark_node; } count = TREE_INT_CST_LOW (count_op); if (count < 0) { error ("repetition count < 0"); return error_mark_node; } if (! TREE_CONSTANT (string)) { error ("repetition value not constant"); return error_mark_node; } if (TREE_CODE (string) == STRING_CST) return string_char_rep (count, string); switch ((int)TREE_CODE (type)) { case BOOLEAN_TYPE: if (TREE_CODE (string) == INTEGER_CST) return build_boring_bitstring (count, TREE_INT_CST_LOW (string)); error ("bitstring repetition of non-constant boolean"); return error_mark_node; case CHAR_TYPE: return string_char_rep (count, string); case SET_TYPE: { int i, tree_const = 1; tree new_list = NULL_TREE; tree vallist; tree result; tree domain = TYPE_DOMAIN (type); tree orig_length; HOST_WIDE_INT orig_len; if (!CH_BOOLS_TYPE_P (type)) /* cannot replicate a powerset */ break; orig_length = discrete_count (domain); if (TREE_CODE (string) != CONSTRUCTOR || !TREE_CONSTANT (string) || TREE_CODE (orig_length) != INTEGER_CST) { error ("string repetition operand is non-constant bitstring"); return error_mark_node; } orig_len = TREE_INT_CST_LOW (orig_length); /* if the set is empty, this is NULL */ vallist = TREE_OPERAND (string, 1); if (vallist == NULL_TREE) /* No bits are set. */ return build_boring_bitstring (count * orig_len, 0); else if (TREE_CHAIN (vallist) == NULL_TREE && (TREE_PURPOSE (vallist) == NULL_TREE ? (orig_len == 1 && tree_int_cst_equal (TYPE_MIN_VALUE (domain), TREE_VALUE (vallist))) : (tree_int_cst_equal (TYPE_MIN_VALUE (domain), TREE_PURPOSE (vallist)) && tree_int_cst_equal (TYPE_MAX_VALUE (domain), TREE_VALUE (vallist))))) return build_boring_bitstring (count * orig_len, 1); for (i = 0; i < count; i++) { tree origin = build_int_2 (i * orig_len, 0); tree temp; /* scan down the given value list, building new bit-positions */ for (temp = vallist; temp; temp = TREE_CHAIN (temp)) { tree new_value = fold (size_binop (PLUS_EXPR, origin, TREE_VALUE (temp))); tree new_purpose = NULL_TREE; if (! TREE_CONSTANT (TREE_VALUE (temp))) tree_const = 0; if (TREE_PURPOSE (temp)) { new_purpose = fold (size_binop (PLUS_EXPR, origin, TREE_PURPOSE (temp))); if (! TREE_CONSTANT (TREE_PURPOSE (temp))) tree_const = 0; } new_list = tree_cons (new_purpose, new_value, new_list); } } result = build (CONSTRUCTOR, build_bitstring_type (size_int (count * orig_len)), NULL_TREE, nreverse (new_list)); TREE_CONSTANT (result) = tree_const; CH_DERIVED_FLAG (result) = CH_DERIVED_FLAG (string); return result; } default: error ("non-char, non-bit string repetition"); return error_mark_node; } return error_mark_node; } tree finish_chill_unary_op (node) tree node; { enum chill_tree_code code = TREE_CODE (node); tree op0 = check_have_mode (TREE_OPERAND (node, 0), "unary expression"); tree type0 = TREE_TYPE (op0); struct ch_class class; if (TREE_CODE (op0) == ERROR_MARK) return error_mark_node; /* The expression codes of the data types of the arguments tell us whether the arguments are integers, floating, pointers, etc. */ if (TREE_CODE (type0) == REFERENCE_TYPE) { op0 = convert (TREE_TYPE (type0), op0); type0 = TREE_TYPE (op0); } if (invalid_right_operand (code, type0)) { error ("invalid operand of %s", tree_code_name[(int)code]); return error_mark_node; } switch ((int)TREE_CODE (type0)) { case ARRAY_TYPE: if (TREE_CODE ( TREE_TYPE (type0)) == BOOLEAN_TYPE) code = SET_NOT_EXPR; else { error ("right operand of %s is not array of boolean", tree_code_name[(int)code]); return error_mark_node; } break; case BOOLEAN_TYPE: switch ((int)code) { case BIT_NOT_EXPR: case TRUTH_NOT_EXPR: return invert_truthvalue (truthvalue_conversion (op0)); default: error ("%s operator applied to boolean variable", tree_code_name[(int)code]); return error_mark_node; } break; case SET_TYPE: switch ((int)code) { case BIT_NOT_EXPR: case NEGATE_EXPR: { tree temp = fold_set_expr (BIT_NOT_EXPR, op0, NULL_TREE); if (temp) return temp; code = SET_NOT_EXPR; } break; default: error ("invalid right operand of %s", tree_code_name[(int)code]); return error_mark_node; } } class = chill_expr_class (op0); if (class.mode) class.mode = CH_ROOT_MODE (class.mode); TREE_SET_CODE (node, code); TREE_OPERAND (node, 0) = op0 = convert_to_class (class, op0); TREE_TYPE (node) = TREE_TYPE (op0); node = convert_to_class (class, fold (node)); /* FIXME: should call * cond_type_range_exception (op0); */ return node; } /* op is TRUTH_NOT_EXPR, BIT_NOT_EXPR, or NEGATE_EXPR */ tree build_chill_unary_op (code, op0) enum chill_tree_code code; tree op0; { register tree result = NULL_TREE; struct ch_class class; tree type0 = TREE_TYPE (op0); if (op0 == NULL_TREE || TREE_CODE (op0) == ERROR_MARK) return error_mark_node; result = build1 (code, NULL_TREE, op0); if (pass != 1) result = finish_chill_unary_op (result); return result; } tree truthvalue_conversion (expr) tree expr; { if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; #if 0 /* what about a LE_EXPR (integer_type, integer_type ) */ if (TREE_CODE (TREE_TYPE (expr)) != BOOLEAN_TYPE) error ("non-boolean mode in conditional expression"); #endif switch ((int)TREE_CODE (expr)) { /* It is simpler and generates better code to have only TRUTH_*_EXPR or comparison expressions as truth values at this level. */ #if 0 case COMPONENT_REF: /* A one-bit unsigned bit-field is already acceptable. */ if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1))) && TREE_UNSIGNED (TREE_OPERAND (expr, 1))) return expr; break; #endif case EQ_EXPR: /* It is simpler and generates better code to have only TRUTH_*_EXPR or comparison expressions as truth values at this level. */ case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case TRUTH_AND_EXPR: case TRUTH_OR_EXPR: case ERROR_MARK: return expr; case INTEGER_CST: return integer_zerop (expr) ? boolean_false_node : boolean_true_node; case REAL_CST: return real_zerop (expr) ? boolean_false_node : boolean_true_node; case ADDR_EXPR: if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0))) return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), boolean_true_node); else return boolean_true_node; case NEGATE_EXPR: case ABS_EXPR: case FLOAT_EXPR: case FFS_EXPR: /* These don't change whether an object is non-zero or zero. */ return truthvalue_conversion (TREE_OPERAND (expr, 0)); case LROTATE_EXPR: case RROTATE_EXPR: /* These don't change whether an object is zero or non-zero, but we can't ignore them if their second arg has side-effects. */ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))) return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1), truthvalue_conversion (TREE_OPERAND (expr, 0))); else return truthvalue_conversion (TREE_OPERAND (expr, 0)); case COND_EXPR: /* Distribute the conversion into the arms of a COND_EXPR. */ return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), truthvalue_conversion (TREE_OPERAND (expr, 1)), truthvalue_conversion (TREE_OPERAND (expr, 2)))); case CONVERT_EXPR: /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE, since that affects how `default_conversion' will behave. */ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE) break; /* fall through... */ case NOP_EXPR: /* If this is widening the argument, we can ignore it. */ if (TYPE_PRECISION (TREE_TYPE (expr)) >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) return truthvalue_conversion (TREE_OPERAND (expr, 0)); break; case BIT_XOR_EXPR: case MINUS_EXPR: /* These can be changed into a comparison of the two objects. */ if (TREE_TYPE (TREE_OPERAND (expr, 0)) == TREE_TYPE (TREE_OPERAND (expr, 1))) return build_chill_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1)); return build_chill_binary_op (NE_EXPR, TREE_OPERAND (expr, 0), fold (build1 (NOP_EXPR, TREE_TYPE (TREE_OPERAND (expr, 0)), TREE_OPERAND (expr, 1)))); } return build_chill_binary_op (NE_EXPR, expr, boolean_false_node); } /* * return a folded tree for the powerset's length in bits. If a * non-set is passed, we assume it's an array or boolean bytes. */ tree powersetlen (powerset) tree powerset; { tree domain, temp; if (powerset == NULL_TREE || TREE_CODE (powerset) == ERROR_MARK) return error_mark_node; return discrete_count (TYPE_DOMAIN (TREE_TYPE (powerset))); }