blob: 59371e820db468bee86f4673c6efbe36e1c5d51c [file] [log] [blame]
/* Convert language-specific tree expression to rtl instructions,
for GNU CHILL compiler.
Copyright (C) 1992, 1993, 1994, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.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"
#include "toplev.h"
extern char **boolean_code_name;
extern int flag_old_strings;
extern int ignore_case;
extern int special_UC;
/* 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 declarations */
static rtx chill_expand_expr PARAMS ((tree, rtx, enum machine_mode,
enum expand_modifier));
static tree chill_expand_case_expr PARAMS ((tree));
static int check_arglist_length PARAMS ((tree, int, int, tree));
static tree internal_build_compound_expr PARAMS ((tree, int));
static int is_really_instance PARAMS ((tree));
static int invalid_operand PARAMS ((enum chill_tree_code,
tree, int));
static int invalid_right_operand PARAMS ((enum chill_tree_code, tree));
static tree build_chill_abstime PARAMS ((tree));
static tree build_allocate_memory_call PARAMS ((tree, tree));
static tree build_allocate_global_memory_call PARAMS ((tree, tree));
static tree build_return_memory PARAMS ((tree));
static tree build_chill_duration PARAMS ((tree, unsigned long,
tree, unsigned long));
static tree build_chill_floatcall PARAMS ((tree, const char *,
const char *));
static tree build_allocate_getstack PARAMS ((tree, tree, const char *,
const char *, tree, tree));
static tree build_chill_allocate PARAMS ((tree, tree));
static tree build_chill_getstack PARAMS ((tree, tree));
static tree build_chill_terminate PARAMS ((tree));
static tree build_chill_inttime PARAMS ((tree, tree));
static tree build_chill_lower_or_upper PARAMS ((tree, int));
static tree build_max_min PARAMS ((tree, int));
static tree build_chill_pred_or_succ PARAMS ((tree, enum tree_code));
static tree expand_packed_set PARAMS ((const char *, int, tree));
static tree fold_set_expr PARAMS ((enum chill_tree_code,
tree, tree));
static tree build_compare_set_expr PARAMS ((enum tree_code, tree, tree));
static tree scalar_to_string PARAMS ((tree));
static tree build_concat_expr PARAMS ((tree, tree));
static tree build_compare_string_expr PARAMS ((enum tree_code, tree, tree));
static tree compare_records PARAMS ((tree, tree));
static tree string_char_rep PARAMS ((int, tree));
static tree build_boring_bitstring PARAMS ((long, int));
/* 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;
const 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);
}
static 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. */
static 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;
const 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 = NULL_RTX, size1 = NULL_RTX;
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)));
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);
HOST_WIDE_INT len0 = int_size_in_bytes (type0);
HOST_WIDE_INT len1 = int_size_in_bytes (type1);
if (len0 < 0 && TYPE_ARRAY_MAX_SIZE (type0)
&& host_integerp (TYPE_ARRAY_MAX_SIZE (type0), 1))
len0 = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type0), 1);
if (len1 < 0 && TYPE_ARRAY_MAX_SIZE (type1)
&& host_integerp (TYPE_ARRAY_MAX_SIZE (type1), 1))
len1 = tree_low_cst (TYPE_ARRAY_MAX_SIZE (type1), 1);
if (len0 < 0 || len1 < 0)
abort ();
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:
{
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:
{
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 ATTRIBUTE_UNUSED;
{
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;
}
static 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);
}
static 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)))));
}
static 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)))));
}
static 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. */
static 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;
const char *chillname;
const 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;
const char *chill_name;
const char *fnname;
tree filename;
tree linenumber;
{
tree type, result;
tree expr = NULL_TREE;
tree args, tmpvar, fncall, ptr, 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 */
static 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 */
static 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 */
static 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);
}
static 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;
const 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;
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_UNIT (type),
size_int (TYPE_PRECISION (char_type_node)
/ BITS_PER_UNIT));
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
{
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)
{
if (name)
error ("too many arguments to procedure `%s'",
IDENTIFIER_POINTER (name));
else
error ("too many arguments to procedure");
return error_mark_node;
}
else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
{
if (name)
error ("too few arguments to procedure `%s'",
IDENTIFIER_POINTER (name));
else
error ("too few arguments to procedure");
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). */
static tree
expand_packed_set (buffer, bit_size, type)
const 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 = NULL, *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 tree_code code;
tree op0, op1;
{
tree result_type = NULL_TREE;
const 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, 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 = fold (build (PLUS_EXPR, integer_type_node,
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 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);
}
static tree
compare_records (exp0, exp1)
tree exp0, exp1;
{
tree type = TREE_TYPE (exp0);
tree field;
int have_variants = 0;
tree result = boolean_true_node;
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;
default:
abort();
}
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 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);
default:
abort();
}
}
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 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);
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;
}
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;
const 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");
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
*/
static tree
string_char_rep (count, string)
int count;
tree string;
{
int slen, charindx, repcnt;
char ch;
char *temp;
const 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). */
static 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 (build (PLUS_EXPR, TREE_TYPE (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 (build (PLUS_EXPR, TREE_TYPE (origin),
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;
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;
{
if (powerset == NULL_TREE || TREE_CODE (powerset) == ERROR_MARK)
return error_mark_node;
return discrete_count (TYPE_DOMAIN (TREE_TYPE (powerset)));
}