aboutsummaryrefslogtreecommitdiff
path: root/gcc/ch/expr.c
diff options
context:
space:
mode:
authorPer Bothner <bothner@gcc.gnu.org>1998-08-27 13:51:39 -0700
committerPer Bothner <bothner@gcc.gnu.org>1998-08-27 13:51:39 -0700
commit3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93 (patch)
tree3e221460a1bf1a44a2e3a008fead9cd61b440bc6 /gcc/ch/expr.c
parent360c5f1547ccd947d760a18f59817b38e0a47fd3 (diff)
downloadgcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.zip
gcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.tar.gz
gcc-3c79b2da6ba52fe9ae2ec45f9ed6774f3366db93.tar.bz2
Migrate from devo/gcc/ch. From-SVN: r22038
Diffstat (limited to 'gcc/ch/expr.c')
-rw-r--r--gcc/ch/expr.c4493
1 files changed, 4493 insertions, 0 deletions
diff --git a/gcc/ch/expr.c b/gcc/ch/expr.c
new file mode 100644
index 0000000..16b1e3c
--- /dev/null
+++ b/gcc/ch/expr.c
@@ -0,0 +1,4493 @@
+/* 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 <stdio.h>
+#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)));
+}