summaryrefslogtreecommitdiff
path: root/gcc/ch/tasking.c
diff options
context:
space:
mode:
authorbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-27 20:51:39 +0000
committerbothner <bothner@138bc75d-0d04-0410-961f-82ee72b054a4>1998-08-27 20:51:39 +0000
commitdd201ca1f8b531e5b83221b21b987dea2e71696b (patch)
tree3e221460a1bf1a44a2e3a008fead9cd61b440bc6 /gcc/ch/tasking.c
parent43ccffb6fd159b6ec48fdaa7f280a84450c0f2b3 (diff)
downloadgcc-dd201ca1f8b531e5b83221b21b987dea2e71696b.tar.gz
Migrate from devo/gcc/ch. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@22038 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/ch/tasking.c')
-rw-r--r--gcc/ch/tasking.c3423
1 files changed, 3423 insertions, 0 deletions
diff --git a/gcc/ch/tasking.c b/gcc/ch/tasking.c
new file mode 100644
index 00000000000..95c81c6fd2e
--- /dev/null
+++ b/gcc/ch/tasking.c
@@ -0,0 +1,3423 @@
+/* Implement tasking-related actions for CHILL.
+ Copyright (C) 1992, 93, 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include "config.h"
+#include "tree.h"
+#include "rtl.h"
+#include "ch-tree.h"
+#include "flags.h"
+#include "input.h"
+#include "obstack.h"
+#include "assert.h"
+#include "tasking.h"
+#include "lex.h"
+
+/* external functions */
+extern void emit_jump PROTO((rtx));
+extern void error PROTO((char *, ...));
+extern void error_with_decl PVPROTO ((tree, char *, ...));
+extern void push_obstacks PROTO((struct obstack *, struct obstack *));
+extern void warning PROTO((char *, ...));
+
+/* from ch-lex.l, from compiler directives */
+extern tree process_type;
+extern tree send_signal_prio;
+extern tree send_buffer_prio;
+
+tree tasking_message_type;
+tree instance_type_node;
+tree generic_signal_type_node;
+
+/* the type a tasking code variable has */
+tree chill_taskingcode_type_node;
+
+/* forward declarations */
+void validate_process_parameters PROTO((tree));
+tree make_process_struct PROTO((tree, tree));
+
+/* list of this module's process, buffer, etc. decls.
+ This is a list of TREE_VECs, chain by their TREE_CHAINs. */
+tree tasking_list = NULL_TREE;
+/* The parts of a tasking_list element. */
+#define TASK_INFO_PDECL(NODE) TREE_VEC_ELT(NODE,0)
+#define TASK_INFO_ENTRY(NODE) TREE_VEC_ELT(NODE,1)
+#define TASK_INFO_CODE_DECL(NODE) TREE_VEC_ELT(NODE,2)
+#define TASK_INFO_STUFF_NUM(NODE) TREE_VEC_ELT(NODE,3)
+#define TASK_INFO_STUFF_TYPE(NODE) TREE_VEC_ELT(NODE,4)
+
+/* name template for process argument type */
+static char * struct_name = "__tmp_%s_arg_type";
+
+/* name template for process arguments for debugging type */
+static char * struct_debug_name = "__tmp_%s_debug_type";
+
+/* name template for process argument variable */
+static char * data_name = "__tmp_%s_arg_variable";
+
+/* name template for process wrapper */
+static char * wrapper_name = "__tmp_%s_wrapper";
+
+extern int ignoring;
+static tree void_ftype_void;
+static tree pointer_to_instance;
+static tree infinite_buffer_event_length_node;
+
+tree
+get_struct_type_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (struct_name) + 1);
+
+ sprintf (tmpname, struct_name, idp);
+ return get_identifier (tmpname);
+}
+
+tree
+get_struct_debug_type_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (struct_debug_name) + 1);
+
+ sprintf (tmpname, struct_debug_name, idp);
+ return get_identifier (tmpname);
+}
+
+
+tree
+get_tasking_code_name (name)
+ tree name;
+{
+ char *skelname = "__tmp_%s_code";
+ char *name_str = IDENTIFIER_POINTER (name);
+ char *tmpname = (char *)alloca (IDENTIFIER_LENGTH (name) +
+ strlen (skelname) + 1);
+
+ sprintf (tmpname, skelname, name_str);
+ return get_identifier (tmpname);
+}
+
+
+static tree
+get_struct_variable_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name); /* process name */
+ char *tmpname = xmalloc (strlen (idp) + strlen (data_name) + 1);
+
+ sprintf (tmpname, data_name, idp);
+ return get_identifier (tmpname);
+}
+
+static tree
+get_process_wrapper_name (name)
+ tree name;
+{
+ char *idp = IDENTIFIER_POINTER (name);
+ char *tmpname = xmalloc (strlen (idp) + strlen (wrapper_name) + 1);
+
+ sprintf (tmpname, wrapper_name, idp);
+ return get_identifier (tmpname);
+}
+
+/*
+ * If this is a quasi declaration - parsed within a SPEC MODULE,
+ * QUASI_FLAG is TRUE, to indicate that the variable should not
+ * be initialized. The other module will do that.
+ */
+tree
+generate_tasking_code_variable (name, tasking_code_ptr, quasi_flag)
+ tree name, *tasking_code_ptr;
+ int quasi_flag;
+{
+
+ tree decl;
+ tree tasking_code_name = get_tasking_code_name (name);
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ {
+ /* check for value should be assigned is out of range */
+ if (TREE_INT_CST_LOW (*tasking_code_ptr) >
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (chill_taskingcode_type_node)))
+ error ("Tasking code %d out of range for `%s'.",
+ TREE_INT_CST_LOW (*tasking_code_ptr),
+ IDENTIFIER_POINTER (name));
+ }
+
+ decl = do_decl (tasking_code_name,
+ chill_taskingcode_type_node, 1, 1,
+ quasi_flag ? NULL_TREE : *tasking_code_ptr,
+ 0);
+
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ *tasking_code_ptr = fold (build (PLUS_EXPR, chill_taskingcode_type_node,
+ integer_one_node,
+ *tasking_code_ptr));
+ return decl;
+}
+
+
+/*
+ * If this is a quasi declaration - parsed within a SPEC MODULE,
+ * QUASI_FLAG is TRUE, to indicate that the variable should not
+ * be initialized. The other module will do that. This is just
+ * for BUFFERs and EVENTs.
+ */
+tree
+decl_tasking_code_variable (name, tasking_code_ptr, quasi_flag)
+ tree name, *tasking_code_ptr;
+ int quasi_flag;
+{
+ extern struct obstack permanent_obstack;
+ tree tasking_code_name = get_tasking_code_name (name);
+ tree decl;
+
+ /* guarantee that RTL for the code_variable resides in
+ the permanent obstack. The BUFFER or EVENT may be
+ declared in a PROC, not at global scope... */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ push_obstacks_nochange ();
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ {
+ /* check for value should be assigned is out of range */
+ if (TREE_INT_CST_LOW (*tasking_code_ptr) >
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (chill_taskingcode_type_node)))
+ error ("Tasking code %d out of range for `%s'.",
+ TREE_INT_CST_LOW (*tasking_code_ptr),
+ IDENTIFIER_POINTER (name));
+ }
+
+ decl = decl_temp1 (tasking_code_name,
+ chill_taskingcode_type_node, 1,
+ quasi_flag ? NULL_TREE : *tasking_code_ptr,
+ 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ /* Return to the ambient context. */
+ pop_obstacks ();
+
+ if (pass == 2 && ! quasi_flag && *tasking_code_ptr != NULL_TREE)
+ *tasking_code_ptr = fold (build (PLUS_EXPR, chill_taskingcode_type_node,
+ integer_one_node,
+ *tasking_code_ptr));
+ return decl;
+}
+
+/*
+ * Transmute a process parameter list into an argument structure
+ * TYPE_DECL for the start_process call to reference. Create a
+ * proc_type variable for later. Returns the new struct type.
+ */
+tree
+make_process_struct (name, processparlist)
+ tree name, processparlist;
+{
+ tree temp;
+ tree a_parm;
+ tree field_decls = NULL_TREE;
+
+ if (name == NULL_TREE || TREE_CODE (name) == ERROR_MARK)
+ return error_mark_node;
+
+ if (processparlist == NULL_TREE)
+ return tree_cons (NULL_TREE, NULL_TREE, void_list_node);
+
+ if (TREE_CODE (processparlist) == ERROR_MARK)
+ return error_mark_node;
+
+ /* build list of field decls for build_chill_struct_type */
+ for (a_parm = processparlist; a_parm != NULL_TREE;
+ a_parm = TREE_CHAIN (a_parm))
+ {
+ tree parnamelist = TREE_VALUE (a_parm);
+ tree purpose = TREE_PURPOSE (a_parm);
+ tree mode = TREE_VALUE (purpose);
+ tree parm_attr = TREE_PURPOSE (purpose);
+ tree field;
+
+ /* build a FIELD_DECL node */
+ if (parm_attr != NULL_TREE)
+ {
+ if (parm_attr == ridpointers[(int)RID_LOC])
+ mode = build_chill_reference_type (mode);
+ else if (parm_attr == ridpointers[(int)RID_IN])
+ ;
+ else if (pass == 1)
+ {
+ for (field = parnamelist; field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ error ("invalid attribute for argument `%s' (only IN or LOC allowed).",
+ IDENTIFIER_POINTER (TREE_VALUE (field)));
+ }
+ }
+
+ field = grok_chill_fixedfields (parnamelist, mode, NULL_TREE);
+
+ /* chain the fields in reverse */
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+
+ temp = build_chill_struct_type (field_decls);
+ return temp;
+}
+
+/* Build a function for a PROCESS and define some
+ types for the process arguments.
+ After the PROCESS a wrapper function will be
+ generated which gets the PROCESS arguments via a pointer
+ to a structure having the same layout as the arguments.
+ This wrapper function then will call the PROCESS.
+ The advantage in doing it this way is, that PROCESS
+ arguments may be displayed by gdb without any change
+ to gdb.
+*/
+tree
+build_process_header (plabel, paramlist)
+ tree plabel, paramlist;
+{
+ tree struct_ptr_type = NULL_TREE;
+ tree new_param_list = NULL_TREE;
+ tree struct_decl = NULL_TREE;
+ tree process_struct = NULL_TREE;
+ tree struct_debug_type = NULL_TREE;
+ tree code_decl;
+
+ if (! global_bindings_p ())
+ {
+ error ("PROCESS may only be declared at module level");
+ return error_mark_node;
+ }
+
+ if (paramlist)
+ {
+ /* must make the structure OUTSIDE the parameter scope */
+ if (pass == 1)
+ {
+ process_struct = make_process_struct (plabel, paramlist);
+ struct_ptr_type = build_chill_pointer_type (process_struct);
+ }
+ else
+ {
+ process_struct = NULL_TREE;
+ struct_ptr_type = NULL_TREE;
+ }
+
+ struct_decl = push_modedef (get_struct_type_name (plabel),
+ struct_ptr_type, -1);
+ DECL_SOURCE_LINE (struct_decl) = 0;
+ struct_debug_type = push_modedef (get_struct_debug_type_name (plabel),
+ process_struct, -1);
+ DECL_SOURCE_LINE (struct_debug_type) = 0;
+
+ if (pass == 2)
+ {
+ /* build a list of PARM_DECL's */
+ tree wrk = paramlist;
+ tree tmp, list = NULL_TREE;
+
+ while (wrk != NULL_TREE)
+ {
+ tree wrk1 = TREE_VALUE (wrk);
+
+ while (wrk1 != NULL_TREE)
+ {
+ tmp = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (tmp) = DECL_NAME (tmp) = TREE_VALUE (wrk1);
+ if (list == NULL_TREE)
+ new_param_list = list = tmp;
+ else
+ {
+ TREE_CHAIN (list) = tmp;
+ list = tmp;
+ }
+ wrk1 = TREE_CHAIN (wrk1);
+ }
+ wrk = TREE_CHAIN (wrk);
+ }
+ }
+ else
+ {
+ /* build a list of modes */
+ tree wrk = paramlist;
+
+ while (wrk != NULL_TREE)
+ {
+ tree wrk1 = TREE_VALUE (wrk);
+
+ while (wrk1 != NULL_TREE)
+ {
+ new_param_list = tree_cons (TREE_PURPOSE (TREE_PURPOSE (wrk)),
+ TREE_VALUE (TREE_PURPOSE (wrk)),
+ new_param_list);
+ wrk1 = TREE_CHAIN (wrk1);
+ }
+ wrk = TREE_CHAIN (wrk);
+ }
+ new_param_list = nreverse (new_param_list);
+ }
+ }
+
+ /* declare the code variable outside the process */
+ code_decl = generate_tasking_code_variable (plabel,
+ &process_type, 0);
+
+ /* start the parameter scope */
+ push_chill_function_context ();
+
+ if (! start_chill_function (plabel, void_type_node,
+ new_param_list, NULL_TREE, NULL_TREE))
+ return error_mark_node;
+
+ current_module->procedure_seen = 1;
+ CH_DECL_PROCESS (current_function_decl) = 1;
+ /* remember the code variable in the function decl */
+ DECL_TASKING_CODE_DECL (current_function_decl) =
+ (struct lang_decl *)code_decl;
+ if (paramlist == NULL_TREE)
+ /* do it here, cause we don't have a wrapper */
+ add_taskstuff_to_list (code_decl, "_TT_Process", process_type,
+ current_function_decl, NULL_TREE);
+
+ return perm_tree_cons (code_decl, struct_decl, NULL_TREE);
+}
+
+/* Generate a function which gets a pointer
+ to an argument block and call the corresponding
+ PROCESS
+*/
+void
+build_process_wrapper (plabel, processdata)
+ tree plabel;
+ tree processdata;
+{
+ tree args = NULL_TREE;
+ tree wrapper = NULL_TREE;
+ tree parammode = TREE_VALUE (processdata);
+ tree code_decl = TREE_PURPOSE (processdata);
+ tree func = lookup_name (plabel);
+
+ /* check the mode. If it is an ERROR_MARK there was an error
+ in build_process_header, if it is a NULL_TREE the process
+ don't have parameters, so we must not generate a wrapper */
+ if (parammode == NULL_TREE ||
+ TREE_CODE (parammode) == ERROR_MARK)
+ return;
+
+ /* get the function name */
+ wrapper = get_process_wrapper_name (plabel);
+
+ /* build the argument */
+ if (pass == 2)
+ {
+ /* build a PARM_DECL */
+ args = make_node (PARM_DECL);
+ DECL_ASSEMBLER_NAME (args) = DECL_NAME (args) = get_identifier ("x");
+ }
+ else
+ {
+ /* build a tree list with the mode */
+ args = tree_cons (NULL_TREE,
+ TREE_TYPE (parammode),
+ NULL_TREE);
+ }
+
+ /* start the function */
+ push_chill_function_context ();
+
+ if (! start_chill_function (wrapper, void_type_node,
+ args, NULL_TREE, NULL_TREE))
+ return;
+
+ /* to avoid granting */
+ DECL_SOURCE_LINE (current_function_decl) = 0;
+
+ if (! ignoring)
+ {
+ /* make the call to the PROCESS */
+ tree wrk;
+ tree x = lookup_name (get_identifier ("x"));
+ /* no need to check this pointer to be NULL */
+ tree indref = build_chill_indirect_ref (x, NULL_TREE, 0);
+
+ args = NULL_TREE;
+ wrk = TYPE_FIELDS (TREE_TYPE (TREE_TYPE (x)));
+ while (wrk != NULL_TREE)
+ {
+ args = tree_cons (NULL_TREE,
+ build_component_ref (indref, DECL_NAME (wrk)),
+ args);
+ wrk = TREE_CHAIN (wrk);
+ }
+ CH_DECL_PROCESS (func) = 0;
+ expand_expr_stmt (
+ build_chill_function_call (func, nreverse (args)));
+ CH_DECL_PROCESS (func) = 1;
+ }
+
+ add_taskstuff_to_list (code_decl, "_TT_Process", process_type,
+ func, current_function_decl);
+
+ /* finish the function */
+ finish_chill_function ();
+ pop_chill_function_context ();
+}
+
+/* Generate errors for INOUT, OUT parameters.
+
+ "Only if LOC is specified may the mode have the non-value
+ property"
+ */
+
+void
+validate_process_parameters (parms)
+ tree parms;
+{
+}
+
+/*
+ * build the tree for a start process action. Loop through the
+ * actual parameters, making a constructor list, which we use to
+ * initialize the argument structure. NAME is the process' name.
+ * COPYNUM is its copy number, whatever that is. EXPRLIST is the
+ * list of actual parameters passed by the start call. They must
+ * match. EXPRLIST must still be in reverse order; we'll reverse it here.
+ *
+ * Note: the OPTSET name is not now used - it's here for
+ * possible future support for the optional 'SET instance-var'
+ * clause.
+ */
+void
+build_start_process (process_name, copynum,
+ exprlist, optset)
+ tree process_name, copynum, exprlist, optset;
+{
+ tree process_decl, struct_type_node;
+ tree result;
+ tree valtail, typetail;
+ tree tuple, actuallist = NULL_TREE;
+ tree typelist;
+ int parmno = 2;
+ tree args;
+ tree filename, linenumber;
+
+ if (exprlist != NULL_TREE && TREE_CODE (exprlist) == ERROR_MARK)
+ process_decl = NULL_TREE;
+ else if (! ignoring)
+ {
+ process_decl = lookup_name (process_name);
+ if (process_decl == NULL_TREE)
+ error ("process name %s never declared",
+ IDENTIFIER_POINTER (process_name));
+ else if (TREE_CODE (process_decl) != FUNCTION_DECL
+ || ! CH_DECL_PROCESS (process_decl))
+ {
+ error ("You may only START a process, not a proc");
+ process_decl = NULL_TREE;
+ }
+ else if (DECL_EXTERNAL (process_decl))
+ {
+ args = TYPE_ARG_TYPES (TREE_TYPE (process_decl));
+ if (TREE_VALUE (args) != void_type_node)
+ struct_type_node = TREE_TYPE (TREE_VALUE (args));
+ else
+ struct_type_node = NULL_TREE;
+ }
+ else
+ {
+ tree debug_type = lookup_name (
+ get_struct_debug_type_name (DECL_NAME (process_decl)));
+
+ if (debug_type == NULL_TREE)
+ /* no debug type, no arguments */
+ struct_type_node = NULL_TREE;
+ else
+ struct_type_node = TREE_TYPE (debug_type);
+ }
+ }
+
+ /* begin a new name scope */
+ pushlevel (1);
+ clear_last_expr ();
+ push_momentary ();
+ if (pass == 2)
+ expand_start_bindings (0);
+
+ if (! ignoring && process_decl != NULL_TREE)
+ {
+ if (optset == NULL_TREE) ;
+ else if (!CH_REFERABLE (optset))
+ {
+ error ("SET expression not a location.");
+ optset = NULL_TREE;
+ }
+ else if (!CH_IS_INSTANCE_MODE (TREE_TYPE (optset)))
+ {
+ error ("SET location must be INSTANCE mode");
+ optset = NULL_TREE;
+ }
+ if (optset)
+ optset = force_addr_of (optset);
+ else
+ optset = convert (ptr_type_node, integer_zero_node);
+
+ if (struct_type_node != NULL_TREE)
+ {
+ typelist = TYPE_FIELDS (struct_type_node);
+
+ for (valtail = nreverse (exprlist), typetail = typelist;
+ valtail != NULL_TREE && typetail != NULL_TREE; parmno++,
+ valtail = TREE_CHAIN (valtail), typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+ actual = chill_convert_for_assignment (type, actual, place);
+ actuallist = tree_cons (NULL_TREE, actual,
+ actuallist);
+ }
+
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (actuallist));
+ }
+ else
+ {
+ valtail = NULL_TREE;
+ typetail = NULL_TREE;
+ }
+
+ if (valtail != 0 && TREE_VALUE (valtail) != void_type_node)
+ {
+ char *errstr = "too many arguments to process";
+ if (process_name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (process_name));
+ else
+ error (errstr);
+ }
+ else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
+ {
+ char *errstr = "too few arguments to process";
+ if (process_name)
+ error ("%s `%s'", errstr, IDENTIFIER_POINTER (process_name));
+ else
+ error (errstr);
+ }
+ else
+ {
+ tree process_decl = lookup_name (process_name);
+ tree process_type = (tree)DECL_TASKING_CODE_DECL (process_decl);
+ tree struct_size, struct_pointer;
+
+ if (struct_type_node != NULL_TREE)
+ {
+ result =
+ decl_temp1 (get_unique_identifier ("START_ARG"),
+ struct_type_node, 0, tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (result) = 0;
+
+ mark_addressable (result);
+ struct_pointer
+ = build1 (ADDR_EXPR,
+ build_chill_pointer_type (struct_type_node),
+ result);
+ struct_size = size_in_bytes (struct_type_node);
+ }
+ else
+ {
+ struct_size = integer_zero_node;
+ struct_pointer = null_pointer_node;
+ }
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__start_process")),
+ tree_cons (NULL_TREE, process_type,
+ tree_cons (NULL_TREE, convert (integer_type_node, copynum),
+ tree_cons (NULL_TREE, struct_size,
+ tree_cons (NULL_TREE, struct_pointer,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, filename,
+ build_tree_list (NULL_TREE, linenumber)))))))));
+ }
+ }
+ /* end of scope */
+
+ if (pass == 2)
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ poplevel (kept_level_p (), 0, 0);
+ pop_momentary ();
+}
+
+/*
+ * A CHILL SET which represents all of the possible tasking
+ * elements.
+ */
+static tree
+build_tasking_enum ()
+{
+ tree result, decl1;
+ tree enum1;
+ tree list = NULL_TREE;
+ tree value = integer_zero_node;
+
+ enum1 = start_enum (NULL_TREE);
+ result = build_enumerator (get_identifier ("_TT_UNUSED"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Process"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Signal"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Buffer"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Event"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Synonym"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = build_enumerator (get_identifier ("_TT_Exception"),
+ value);
+ list = chainon (result, list);
+ value = fold (build (PLUS_EXPR, integer_type_node,
+ value, integer_one_node));
+
+ result = finish_enum (enum1, list);
+
+ decl1 = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_TaskingEnum"),
+ result);
+ pushdecl (decl1);
+ satisfy_decl (decl1, 0);
+ return decl1;
+}
+
+tree
+build_tasking_struct ()
+{
+ tree listbase, decl1, decl2, result;
+ tree enum_type = TREE_TYPE (build_tasking_enum ());
+ /* We temporarily reset the maximum_field_alignment to zero so the
+ compiler's init data structures can be compatible with the
+ run-time system, even when we're compiling with -fpack. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+ maximum_field_alignment = 0;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier ("TaskName"),
+ build_chill_pointer_type (char_type_node));
+ DECL_INITIAL (decl1) = NULL_TREE;
+ listbase = decl1;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskValue"),
+ build_chill_pointer_type (chill_taskingcode_type_node));
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskValueDefined"),
+ integer_type_node);
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskEntry"),
+ build_chill_pointer_type (void_ftype_void));
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ decl2 = build_decl (FIELD_DECL, get_identifier ("TaskType"),
+ enum_type);
+ TREE_CHAIN (decl1) = decl2;
+ DECL_INITIAL (decl2) = NULL_TREE;
+ decl1 = decl2;
+
+ TREE_CHAIN (decl2) = NULL_TREE;
+ result = build_chill_struct_type (listbase);
+ satisfy_decl (result, 0);
+ maximum_field_alignment = save_maximum_field_alignment;
+ return result;
+}
+
+/*
+ * build data structures describing each task/signal, etc.
+ * in current module.
+ */
+void
+tasking_setup ()
+{
+ tree tasknode;
+ tree struct_type;
+
+ if (pass == 1)
+ return;
+
+ struct_type = TREE_TYPE (lookup_name (
+ get_identifier ("__tmp_TaskingStruct")));
+
+ for (tasknode = tasking_list; tasknode != NULL_TREE;
+ tasknode = TREE_CHAIN (tasknode))
+ {
+ /* This is the tasking_code_variable's decl */
+ tree stuffnumber = TASK_INFO_STUFF_NUM (tasknode);
+ tree code_decl = TASK_INFO_CODE_DECL (tasknode);
+ tree proc_decl = TASK_INFO_PDECL (tasknode);
+ tree entry = TASK_INFO_ENTRY (tasknode);
+ tree name = DECL_NAME (proc_decl);
+ char *init_struct = (char *) alloca (IDENTIFIER_LENGTH(name) + 20);
+ /* take care of zero termination */
+ tree task_name;
+ /* these are the fields of the struct, in declaration order */
+ tree init_flag = (stuffnumber == NULL_TREE) ?
+ integer_zero_node : integer_one_node;
+ tree type = DECL_INITIAL (TASK_INFO_STUFF_TYPE (tasknode));
+ tree int_addr;
+ tree entry_point;
+ tree name_ptr;
+ tree decl;
+ tree struct_id;
+ tree initializer;
+
+ if (TREE_CODE (proc_decl) == FUNCTION_DECL
+ && CH_DECL_PROCESS (proc_decl)
+ && ! DECL_EXTERNAL (proc_decl))
+ {
+ if (entry == NULL_TREE)
+ entry = proc_decl;
+ mark_addressable (entry);
+ entry_point = build1 (ADDR_EXPR,
+ build_chill_pointer_type (void_ftype_void),
+ entry);
+ }
+ else
+ entry_point = build1 (NOP_EXPR,
+ build_chill_pointer_type (void_ftype_void),
+ null_pointer_node);
+
+ /* take care of zero termination */
+ task_name =
+ build_chill_string (IDENTIFIER_LENGTH (name) + 1,
+ IDENTIFIER_POINTER (name));
+
+ mark_addressable (code_decl);
+ int_addr = build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ code_decl);
+
+ mark_addressable (task_name);
+ name_ptr = build1 (ADDR_EXPR,
+ build_chill_pointer_type (char_type_node),
+ task_name);
+
+ sprintf (init_struct, "__tmp_%s_struct",
+ IDENTIFIER_POINTER (name));
+
+ struct_id = get_identifier (init_struct);
+ initializer = build (CONSTRUCTOR, struct_type, NULL_TREE,
+ tree_cons (NULL_TREE, name_ptr,
+ tree_cons (NULL_TREE, int_addr,
+ tree_cons (NULL_TREE, init_flag,
+ tree_cons (NULL_TREE, entry_point,
+ tree_cons (NULL_TREE, type, NULL_TREE))))));
+ TREE_CONSTANT (initializer) = 1;
+ decl = decl_temp1 (struct_id, struct_type, 1, initializer, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ /* pass the decl to tasking_registry() in the symbol table */
+ IDENTIFIER_LOCAL_VALUE (struct_id) = decl;
+ }
+}
+
+
+/*
+ * Generate code to register the tasking-related stuff
+ * with the runtime. Only in pass 2.
+ */
+void
+tasking_registry ()
+{
+ tree tasknode, fn_decl;
+
+ if (pass == 1)
+ return;
+
+ fn_decl = lookup_name (get_identifier ("__register_tasking"));
+
+ for (tasknode = tasking_list; tasknode != NULL_TREE;
+ tasknode = TREE_CHAIN (tasknode))
+ {
+ tree proc_decl = TASK_INFO_PDECL (tasknode);
+ tree name = DECL_NAME (proc_decl);
+ tree arg_decl;
+ char *init_struct = (char *) alloca (IDENTIFIER_LENGTH (name) + 20);
+
+ sprintf (init_struct, "__tmp_%s_struct",
+ IDENTIFIER_POINTER (name));
+ arg_decl = lookup_name (get_identifier (init_struct));
+
+ expand_expr_stmt (
+ build_chill_function_call (fn_decl,
+ build_tree_list (NULL_TREE, force_addr_of (arg_decl))));
+ }
+}
+
+/*
+ * Put a tasking entity (a PROCESS, or SIGNAL) onto
+ * the list for tasking_setup (). CODE_DECL is the integer code
+ * variable's DECL, which describes the shadow integer which
+ * accompanies each tasking entity. STUFFTYPE is a string
+ * representing the sort of tasking entity we have here (i.e.
+ * process, signal, etc.). STUFFNUMBER is an enumeration
+ * value saying the same thing. PROC_DECL is the declaration of
+ * the entity. It's a FUNCTION_DECL if the entity is a PROCESS, it's
+ * a TYPE_DECL if the entity is a SIGNAL.
+ */
+void
+add_taskstuff_to_list (code_decl, stufftype, stuffnumber,
+ proc_decl, entry)
+ tree code_decl;
+ char *stufftype;
+ tree stuffnumber, proc_decl, entry;
+{
+ if (pass == 1)
+ /* tell chill_finish_compile that there's
+ task-level code to be processed. */
+ tasking_list = integer_one_node;
+
+ /* do only in pass 2 so we know in chill_finish_compile whether
+ to generate a constructor function, and to avoid double the
+ correct number of entries. */
+ else /* pass == 2 */
+ {
+ tree task_node = make_tree_vec (5);
+ TASK_INFO_PDECL (task_node) = proc_decl;
+ TASK_INFO_ENTRY (task_node) = entry;
+ TASK_INFO_CODE_DECL (task_node) = code_decl;
+ TASK_INFO_STUFF_NUM (task_node) = stuffnumber;
+ TASK_INFO_STUFF_TYPE (task_node)
+ = lookup_name (get_identifier (stufftype));
+ TREE_CHAIN (task_node) = tasking_list;
+ tasking_list = task_node;
+ }
+}
+
+/*
+ * These next routines are called out of build_generalized_call
+ */
+tree
+build_copy_number (instance_expr)
+ tree instance_expr;
+{
+ tree result;
+
+ if (instance_expr == NULL_TREE
+ || TREE_CODE (instance_expr) == ERROR_MARK)
+ return error_mark_node;
+ if (! CH_IS_INSTANCE_MODE (TREE_TYPE (instance_expr)))
+ {
+ error ("COPY_NUMBER argument must be INSTANCE expression");
+ return error_mark_node;
+ }
+ result = build_component_ref (instance_expr,
+ get_identifier (INS_COPY));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_gen_code (decl)
+ tree decl;
+{
+ tree result;
+
+ if (decl == NULL_TREE || TREE_CODE (decl) == ERROR_MARK)
+ return error_mark_node;
+
+ if ((TREE_CODE (decl) == FUNCTION_DECL && CH_DECL_PROCESS (decl))
+ || (TREE_CODE (decl) == TYPE_DECL && CH_DECL_SIGNAL (decl)))
+ result = (tree)(DECL_TASKING_CODE_DECL (decl));
+ else
+ {
+ error ("GEN_CODE argument must be a process or signal name.");
+ return error_mark_node;
+ }
+ CH_DERIVED_FLAG (result) = 1;
+ return (result);
+}
+
+
+tree
+build_gen_inst (process, copyn)
+ tree process, copyn;
+{
+ tree ptype;
+ tree result;
+
+ if (copyn == NULL_TREE || TREE_CODE (copyn) == ERROR_MARK)
+ return error_mark_node;
+ if (process == NULL_TREE || TREE_CODE (process) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_TYPE (copyn)) != INTEGER_TYPE)
+ {
+ error ("GEN_INST parameter 2 must be an integer mode");
+ copyn = integer_zero_node;
+ }
+
+ copyn = check_range (copyn, copyn,
+ TYPE_MIN_VALUE (chill_taskingcode_type_node),
+ TYPE_MAX_VALUE (chill_taskingcode_type_node));
+
+ if (TREE_CODE (process) == FUNCTION_DECL
+ && CH_DECL_PROCESS (process))
+ ptype = (tree)DECL_TASKING_CODE_DECL (process);
+ else if (TREE_TYPE (process) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (process)) == INTEGER_TYPE)
+ {
+ process = check_range (process, process,
+ TYPE_MIN_VALUE (chill_taskingcode_type_node),
+ TYPE_MAX_VALUE (chill_taskingcode_type_node));
+ ptype = convert (chill_taskingcode_type_node, process);
+ }
+ else
+ {
+ error ("GEN_INST parameter 1 must be a PROCESS or an integer expression");
+ return (error_mark_node);
+ }
+
+ result = convert (instance_type_node,
+ build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, ptype,
+ tree_cons (NULL_TREE,
+ convert (chill_taskingcode_type_node, copyn), NULL_TREE))));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_gen_ptype (process_decl)
+ tree process_decl;
+{
+ tree result;
+
+ if (process_decl == NULL_TREE || TREE_CODE (process_decl) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (process_decl) != FUNCTION_DECL
+ || ! CH_DECL_PROCESS (process_decl))
+ {
+ error_with_decl (process_decl, "%s is not a declared process");
+ return error_mark_node;
+ }
+
+ result = (tree)DECL_TASKING_CODE_DECL (process_decl);
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+
+tree
+build_proc_type (instance_expr)
+ tree instance_expr;
+{
+ tree result;
+
+ if (instance_expr == NULL_TREE || TREE_CODE (instance_expr) == ERROR_MARK)
+ return error_mark_node;
+
+ if (! CH_IS_INSTANCE_MODE (TREE_TYPE (instance_expr)))
+ {
+ error ("PROC_TYPE argument must be INSTANCE expression");
+ return error_mark_node;
+ }
+ result = build_component_ref (instance_expr,
+ get_identifier (INS_PTYPE));
+ CH_DERIVED_FLAG (result) = 1;
+ return result;
+}
+
+tree
+build_queue_length (buf_ev)
+ tree buf_ev;
+{
+ if (buf_ev == NULL_TREE || TREE_CODE (buf_ev) == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_TYPE (buf_ev) == NULL_TREE ||
+ TREE_CODE (TREE_TYPE (buf_ev)) == ERROR_MARK)
+ return error_mark_node;
+
+ if (CH_IS_BUFFER_MODE (TREE_TYPE (buf_ev)) ||
+ CH_IS_EVENT_MODE (TREE_TYPE (buf_ev)))
+ {
+ char *field_name;
+ tree arg1, arg2;
+
+ if (CH_IS_EVENT_MODE (TREE_TYPE (buf_ev)))
+ {
+ field_name = "__event_data";
+ arg2 = integer_one_node;
+ }
+ else
+ {
+ field_name = "__buffer_data";
+ arg2 = integer_zero_node;
+ }
+ arg1 = build_component_ref (buf_ev, get_identifier (field_name));
+ return build_chill_function_call (
+ lookup_name (get_identifier ("__queue_length")),
+ tree_cons (NULL_TREE, arg1,
+ tree_cons (NULL_TREE, arg2, NULL_TREE)));
+ }
+
+ error ("QUEUE_LENGTH argument must be a BUFFER/EVENT location.");
+ return error_mark_node;
+}
+
+tree
+build_signal_struct_type (signame, sigmodelist, optsigdest)
+ tree signame, sigmodelist, optsigdest;
+{
+ tree decl, temp;
+
+ if (pass == 1)
+ {
+ int fldcnt = 0;
+ tree mode, field_decls = NULL_TREE;
+
+ for (mode = sigmodelist; mode != NULL_TREE; mode = TREE_CHAIN (mode))
+ {
+ tree field;
+ char fldname[20];
+
+ if (TREE_VALUE (mode) == NULL_TREE)
+ continue;
+ sprintf (fldname, "fld%03d", fldcnt++);
+ field = build_decl (FIELD_DECL,
+ get_identifier (fldname),
+ TREE_VALUE (mode));
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+ if (field_decls == NULL_TREE)
+ field_decls = build_decl (FIELD_DECL,
+ get_identifier ("__tmp_empty"),
+ boolean_type_node);
+ temp = build_chill_struct_type (field_decls);
+
+ /* save the destination process name of the signal */
+ IDENTIFIER_SIGNAL_DEST (signame) = optsigdest;
+ IDENTIFIER_SIGNAL_DATA (signame) = fldcnt;
+ }
+ else
+ {
+ /* optsigset is only valid in pass 2, so we have to save it now */
+ IDENTIFIER_SIGNAL_DEST (signame) = optsigdest;
+ temp = NULL_TREE; /* Actually, don't care. */
+ }
+
+ decl = push_modedef (signame, temp, -1);
+ if (decl != NULL_TREE)
+ CH_DECL_SIGNAL (decl) = 1;
+ return decl;
+}
+
+/*
+ * An instance type is a unique process identifier in the CHILL
+ * tasking arena. It consists of a process type and a copy number.
+ */
+void
+build_instance_type ()
+{
+ tree decl1, decl2, tdecl;
+
+ decl1 = build_decl (FIELD_DECL, get_identifier (INS_PTYPE),
+ chill_taskingcode_type_node);
+
+ TREE_CHAIN (decl1) = decl2 =
+ build_decl (FIELD_DECL, get_identifier (INS_COPY),
+ chill_taskingcode_type_node);
+ TREE_CHAIN (decl2) = NULL_TREE;
+
+ instance_type_node = build_chill_struct_type (decl1);
+ tdecl = build_decl (TYPE_DECL, ridpointers[(int) RID_INSTANCE],
+ instance_type_node);
+ TYPE_NAME (instance_type_node) = tdecl;
+ CH_NOVELTY (instance_type_node) = tdecl;
+ DECL_SOURCE_LINE (tdecl) = 0;
+ pushdecl (tdecl);
+
+ pointer_to_instance = build_chill_pointer_type (instance_type_node);
+}
+
+#if 0
+ *
+ * The tasking message descriptor looks like this C structure:
+ *
+ * typedef struct
+ * {
+ * short *sc; /* ptr to code integer */
+ * int data_len; /* length of signal/buffer data msg */
+ * void *data; /* ptr to signal/buffer data */
+ * } SignalDescr;
+ *
+ *
+#endif
+
+void
+build_tasking_message_type ()
+{
+ tree type_name;
+ tree temp;
+ /* We temporarily reset maximum_field_alignment to deal with
+ the runtime system. */
+ extern int maximum_field_alignment;
+ int save_maximum_field_alignment = maximum_field_alignment;
+ tree field1, field2, field3;
+
+ maximum_field_alignment = 0;
+ field1 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_code_ptr"),
+ build_pointer_type (chill_integer_type_node));
+ field2 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_data_len"),
+ integer_type_node);
+ field3 = build_decl (FIELD_DECL,
+ get_identifier ("_SD_data_ptr"),
+ ptr_type_node);
+ TREE_CHAIN (field1) = field2;
+ TREE_CHAIN (field2) = field3;
+ temp = build_chill_struct_type (field1);
+
+ type_name = get_identifier ("__tmp_SD_struct");
+ tasking_message_type = build_decl (TYPE_DECL, type_name, temp);
+
+ /* This won't get seen in pass 2, so lay it out now. */
+ layout_chill_struct_type (temp);
+ pushdecl (tasking_message_type);
+ maximum_field_alignment = save_maximum_field_alignment;
+}
+
+tree
+build_signal_descriptor (sigdef, exprlist)
+ tree sigdef, exprlist;
+{
+ tree fieldlist, typetail, valtail;
+ tree actuallist = NULL_TREE;
+ tree signame = DECL_NAME (sigdef);
+ tree dataptr, datalen;
+ int parmno = 1;
+
+ if (sigdef == NULL_TREE
+ || TREE_CODE (sigdef) == ERROR_MARK)
+ return error_mark_node;
+
+ if (exprlist != NULL_TREE
+ && TREE_CODE (exprlist) == ERROR_MARK)
+ return error_mark_node;
+
+ if (TREE_CODE (sigdef) != TYPE_DECL
+ || ! CH_DECL_SIGNAL (sigdef))
+ {
+ error ("SEND requires a SIGNAL; %s is not a SIGNAL name",
+ signame);
+ return error_mark_node;
+ }
+ if (CH_TYPE_NONVALUE_P (TREE_TYPE (sigdef)))
+ return error_mark_node;
+
+ fieldlist = TYPE_FIELDS (TREE_TYPE (sigdef));
+ if (IDENTIFIER_SIGNAL_DATA (signame) == 0)
+ fieldlist = TREE_CHAIN (fieldlist);
+
+ for (valtail = exprlist, typetail = fieldlist;
+ valtail != NULL_TREE && typetail != NULL_TREE;
+ parmno++, valtail = TREE_CHAIN (valtail),
+ typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+ actual = chill_convert_for_assignment (type, actual, place);
+ actuallist = tree_cons (NULL_TREE, actual, actuallist);
+ }
+ if (valtail != 0 && TREE_VALUE (valtail) != void_type_node)
+ {
+ error ("too many values for SIGNAL `%s'",
+ IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+ else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node)
+ {
+ error ("too few values for SIGNAL `%s'",
+ IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+
+ {
+ /* build signal data structure */
+ tree sigdataname = get_unique_identifier (
+ IDENTIFIER_POINTER (signame));
+ if (exprlist == NULL_TREE)
+ {
+ dataptr = null_pointer_node;
+ datalen = integer_zero_node;
+ }
+ else
+ {
+ tree tuple = build_nt (CONSTRUCTOR,
+ NULL_TREE, nreverse (actuallist));
+ tree decl = decl_temp1 (sigdataname, TREE_TYPE (sigdef),
+ 0, tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ dataptr = force_addr_of (decl);
+ datalen = size_in_bytes (TREE_TYPE (decl));
+ }
+
+ /* build descriptor pointing to signal data */
+ {
+ tree decl, tuple;
+ tree tasking_message_var = get_unique_identifier (
+ IDENTIFIER_POINTER (signame));
+
+ tree tasking_code =
+ (tree)DECL_TASKING_CODE_DECL (lookup_name (signame));
+
+ mark_addressable (tasking_code);
+ tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ tasking_code),
+ tree_cons (NULL_TREE, datalen,
+ tree_cons (NULL_TREE, dataptr, NULL_TREE))));
+
+ decl = decl_temp1 (tasking_message_var,
+ TREE_TYPE (tasking_message_type), 0,
+ tuple, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ tuple = force_addr_of (decl);
+ return tuple;
+ }
+ }
+}
+
+void
+expand_send_signal (sigmsgbuffer, optroutinginfo, optsendto,
+ optpriority, signame)
+ tree sigmsgbuffer;
+ tree optroutinginfo;
+ tree optsendto;
+ tree optpriority;
+ tree signame;
+{
+ tree routing_size, routing_addr;
+ tree filename, linenumber;
+ tree sigdest = IDENTIFIER_SIGNAL_DEST (signame);
+
+ /* check the presence of priority */
+ if (optpriority == NULL_TREE)
+ {
+ if (send_signal_prio == NULL_TREE)
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("Signal sent without priority");
+ warning (" and no default priority was set.");
+ warning (" PRIORITY defaulted to 0");
+ }
+ optpriority = integer_zero_node;
+ }
+ else
+ optpriority = send_signal_prio;
+ }
+
+ /* check the presence of a destination.
+ optdest either may be an instance location
+ or a process declaration */
+ if (optsendto == NULL_TREE)
+ {
+ if (sigdest == NULL_TREE)
+ {
+ error ("SEND without a destination instance");
+ error (" and no destination process specified");
+ error (" for the signal");
+ optsendto = convert (instance_type_node,
+ null_pointer_node);
+ }
+ else
+ {
+ /* build an instance [sigdest; -1] */
+ tree process_name = DECL_NAME (sigdest);
+ tree copy_number = fold (build (MINUS_EXPR, integer_type_node,
+ integer_zero_node,
+ integer_one_node));
+ tree tasking_code = (tree)DECL_TASKING_CODE_DECL (
+ lookup_name (process_name));
+
+ optsendto = build (CONSTRUCTOR, instance_type_node, NULL_TREE,
+ tree_cons (NULL_TREE, tasking_code,
+ tree_cons (NULL_TREE, copy_number, NULL_TREE)));
+ /* as our system doesn't allow that and Z.200 specifies it,
+ we issue a warning */
+ warning ("SEND to ANY copy of process `%s'.", IDENTIFIER_POINTER (process_name));
+ }
+ }
+ else if (! CH_IS_INSTANCE_MODE (TREE_TYPE (optsendto)))
+ {
+ error ("SEND TO must be an INSTANCE mode");
+ optsendto = convert (instance_type_node, null_pointer_node);
+ }
+ else
+ optsendto = check_non_null (convert (instance_type_node, optsendto));
+
+ /* check the routing stuff */
+ if (optroutinginfo != NULL_TREE)
+ {
+ tree routing_name;
+ tree decl;
+
+ if (TREE_TYPE (optroutinginfo) == NULL_TREE)
+ {
+ error ("SEND WITH must have a mode");
+ optroutinginfo = integer_zero_node;
+ }
+ routing_name = get_unique_identifier ("RI");
+ decl = decl_temp1 (routing_name,
+ TREE_TYPE (optroutinginfo), 0,
+ optroutinginfo, 0, 0);
+ /* prevent granting of this type */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ routing_addr = force_addr_of (decl);
+ routing_size = size_in_bytes (TREE_TYPE (decl));
+ }
+ else
+ {
+ routing_size = integer_zero_node;
+ routing_addr = null_pointer_node;
+ }
+ /* get filename and linenumber */
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Now (at last!) we can call the runtime */
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__send_signal")),
+ tree_cons (NULL_TREE, sigmsgbuffer,
+ tree_cons (NULL_TREE, optsendto,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, routing_size,
+ tree_cons (NULL_TREE, routing_addr,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))))))));
+}
+
+#if 0
+ * The following code builds a RECEIVE CASE action, which actually
+ * has 2 different functionalities:
+ *
+ * 1) RECEIVE signal CASE action
+ * which looks like this:
+ *
+ * SIGNAL advance;
+ * SIGNAL terminate = (CHAR);
+ * SIGNAL sig1 = (CHAR);
+ *
+ * DCL user, system INSTANCE;
+ * DCL count INT, char_code CHAR;
+ * DCL instance_loc INSTANCE;
+ *
+ * workloop:
+ * RECEIVE CASE SET instance_loc;
+ * (advance):
+ * count + := 1;
+ * (terminate IN char_code):
+ * SEND sig1(char_code) TO system;
+ * EXIT workloop;
+ * ELSE
+ * STOP;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many signals need processing, we generate the following
+ * C-equivalent code:
+ *
+ * /* define the codes for the signals */
+ * static short __tmp_advance_code;
+ * static short __tmp_terminate_code;
+ * static short __tmp_sig1_code;
+ *
+ * /* define the types of the signals */
+ * typedef struct
+ * {
+ * char fld0;
+ * } __tmp_terminate_struct;
+ *
+ * typedef struct
+ * {
+ * char fld0;
+ * } __tmp_sig1_struct;
+ *
+ * static INSTANCE user, system, instance_loc;
+ * static short count;
+ * static char char_code;
+ *
+ * { /* start a new symbol context */
+ * int number_of_sigs;
+ * short *sig_code [];
+ * void *sigdatabuf;
+ * int sigdatalen;
+ * short sigcode;
+ *
+ * goto __rcsetup;
+ *
+ * __rcdoit: ;
+ * int timedout = __wait_signal (&sigcode
+ * number_of_sigs,
+ * sig_code,
+ * sigdatabuf,
+ * sigdatalen,
+ * &instance_loc);
+ * if (sigcode == __tmp_advance_code)
+ * {
+ * /* code for advance alternative's action_statement_list */
+ * count++;
+ * }
+ * else if (sigcode == __tmp_terminate_code)
+ * {
+ * /* copy signal's data to where they belong,
+ * with range-check, if enabled */
+ * char_code = ((__tmp_terminate_struct *)sigdatabuf)->fld0;
+ *
+ * /* code for terminate alternative's action_statement_list */
+ * __send_signal (sig1 ..... );
+ * goto __workloop_end;
+ * }
+ * else
+ * {
+ * /* code here for the ELSE action_statement_list */
+ * __stop_process ();
+ * }
+ * goto __rc_done;
+ *
+ * __rcsetup:
+ * union { __tmp_terminate_struct terminate;
+ * __tmp_sig1_struct } databuf;
+ * short *sig_code_ptr [2] = { &__tmp_advance_code,
+ * &__tmp_terminate_code };
+ * sigdatabuf = &databuf;
+ * sigdatalen = sizeof (databuf);
+ * sig_code = &sig_code_ptr[0];
+ * number_of_sigs = 2;
+ * goto __rcdoit;
+ *
+ * __rc_done: ;
+ * } /* end the new symbol context */
+ * __workloop_end: ;
+ *
+ *
+ * 2) RECEIVE buffer CASE action:
+ * which looks like this:
+ *
+ * NEWMODE m_s = STRUCT (mini INT, maxi INT);
+ * DCL b1 BUFFER INT;
+ * DCL b2 BUFFER (30) s;
+ *
+ * DCL i INT, s m_s, ins INSTANCE;
+ * DCL count INT;
+ *
+ * workloop:
+ * RECEIVE CASE SET ins;
+ * (b1 IN i):
+ * count +:= i;
+ * (b2 in s):
+ * IF count < s.mini OR count > s.maxi THEN
+ * EXIT workloop;
+ * FI;
+ * ELSE
+ * STOP;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many buffers need processing, we generate the following
+ * C-equivalent code:
+ *
+ * typedef struct
+ * {
+ * short mini;
+ * short maxi;
+ * } m_s;
+ *
+ * static void *b1;
+ * static void *b2;
+ * static short i;
+ * static m_s s;
+ * static INSTANCE ins;
+ * static short count;
+ *
+ * workloop:
+ * { /* start a new symbol context */
+ * int number_of_sigs;
+ * void *sig_code [];
+ * void *sigdatabuf;
+ * int sigdatalen;
+ * void *buflocation;
+ * int timedout;
+ *
+ * goto __rcsetup;
+ *
+ * __rcdoit:
+ * timedout = __wait_buffer (&buflocation,
+ * number_of_sigs,
+ * sig_code,
+ * sigdatabuf,
+ * sigdatalen,
+ * &ins, ...);
+ * if (buflocation == &b1)
+ * {
+ * i = ((short *)sigdatabuf)->fld0;
+ * count += i;
+ * }
+ * else if (buflocation == &b2)
+ * {
+ * s = ((m_s)*sigdatabuf)->fld1;
+ * if (count < s.mini || count > s.maxi)
+ * goto __workloop_end;
+ * }
+ * else
+ * __stop_process ();
+ * goto __rc_done;
+ *
+ * __rcsetup:
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned maxqueuesize;
+ * } Buffer_Descr;
+ * union { short b1,
+ * m_s b2 } databuf;
+ * Buffer_Descr bufptr [2] =
+ * {
+ * { &b1, -1 },
+ * { &b2, 30 },
+ * };
+ * void * bufarray[2] = { &bufptr[0],
+ * &bufptr[1] };
+ * sigdatabuf = &databuf;
+ * sigdatalen = sizeof (databuf);
+ * sig_code = &bufarray[0];
+ * number_of_sigs = 2;
+ * goto __rcdoit;
+ *
+ * __rc_done;
+ * } /* end of symbol context */
+ * __workloop_end:
+ *
+#endif
+
+struct rc_state_type
+{
+ struct rc_state_type *enclosing;
+ rtx rcdoit;
+ rtx rcsetup;
+ tree n_sigs;
+ tree sig_code;
+ tree databufp;
+ tree datalen;
+ tree else_clause;
+ tree received_signal;
+ tree received_buffer;
+ tree to_loc;
+ int sigseen;
+ int bufseen;
+ tree actuallist;
+ int call_generated;
+ int if_generated;
+ int bufcnt;
+};
+
+struct rc_state_type *current_rc_state = NULL;
+
+/*
+ * this function tells if there is an if to terminate
+ * or not
+ */
+int
+build_receive_case_if_generated()
+{
+ if (!current_rc_state)
+ {
+ error ("internal error: RECEIVE CASE stack invalid.");
+ abort ();
+ }
+ return current_rc_state->if_generated;
+}
+
+/* build_receive_case_start returns an INTEGER_CST node
+ containing the case-label number to be used by
+ build_receive_case_end to generate correct labels */
+tree
+build_receive_case_start (optset)
+ tree optset;
+{
+ /* counter to generate unique receive_case labels */
+ static int rc_lbl_count = 0;
+ tree current_label_value =
+ build_int_2 ((HOST_WIDE_INT)rc_lbl_count, 0);
+ tree sigcodename, filename, linenumber;
+
+ struct rc_state_type *rc_state
+ = (struct rc_state_type*) xmalloc (sizeof (struct rc_state_type));
+ rc_state->rcdoit = gen_label_rtx ();
+ rc_state->rcsetup = gen_label_rtx ();
+ rc_state->enclosing = current_rc_state;
+ current_rc_state = rc_state;
+ rc_state->sigseen = 0;
+ rc_state->bufseen = 0;
+ rc_state->call_generated = 0;
+ rc_state->if_generated = 0;
+ rc_state->bufcnt = 0;
+
+ rc_lbl_count++;
+ if (optset == NULL_TREE || TREE_CODE (optset) == ERROR_MARK)
+ optset = null_pointer_node;
+ else
+ {
+ if (CH_IS_INSTANCE_MODE (TREE_TYPE (optset)) && CH_LOCATION_P (optset))
+ optset = force_addr_of (optset);
+ else
+ {
+ error ("SET requires INSTANCE location");
+ optset = null_pointer_node;
+ }
+ }
+
+ rc_state->to_loc = build_timeout_preface ();
+
+ rc_state->n_sigs =
+ decl_temp1 (get_identifier ("number_of_sigs"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ rc_state->sig_code =
+ decl_temp1 (get_identifier ("sig_codep"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ rc_state->databufp =
+ decl_temp1 (get_identifier ("databufp"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ rc_state->datalen =
+ decl_temp1 (get_identifier ("datalen"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ rc_state->else_clause =
+ decl_temp1 (get_identifier ("else_clause"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ /* wait_signal will store the signal number in here */
+ sigcodename = get_identifier ("received_signal");
+ rc_state->received_signal =
+ decl_temp1 (sigcodename, chill_integer_type_node, 0,
+ NULL_TREE, 0, 0);
+
+ /* wait_buffer will store the buffer address in here */
+ sigcodename = get_unique_identifier ("received_buffer");
+ rc_state->received_buffer =
+ decl_temp1 (sigcodename, ptr_type_node, 0,
+ NULL_TREE, 0, 0);
+
+ /* now jump to the end of RECEIVE CASE actions, to
+ set up variables for them. */
+ emit_jump (rc_state->rcsetup);
+
+ /* define the __rcdoit label. We come here after
+ initialization of all variables, to execute the
+ actions. */
+ emit_label (rc_state->rcdoit);
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Argument list for calling the runtime routine. We'll call it
+ the first time we call build_receive_case_label, when we know
+ whether to call wait_signal or wait_buffer. NOTE: at this time
+ the first argument will be set. */
+ rc_state->actuallist =
+ tree_cons (NULL_TREE, NULL_TREE,
+ tree_cons (NULL_TREE, rc_state->n_sigs,
+ tree_cons (NULL_TREE, rc_state->sig_code,
+ tree_cons (NULL_TREE, rc_state->databufp,
+ tree_cons (NULL_TREE, rc_state->datalen,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, rc_state->else_clause,
+ tree_cons (NULL_TREE, rc_state->to_loc,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))))));
+ return current_label_value;
+}
+
+static tree
+build_receive_signal_case_label (sigdecl, loclist)
+ tree sigdecl, loclist;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree signame = DECL_NAME (sigdecl);
+ tree expr;
+
+ if (rc_state->bufseen != 0)
+ {
+ error ("SIGNAL in RECEIVE CASE alternative follows");
+ error (" a BUFFER name on line %d", rc_state->bufseen);
+ return error_mark_node;
+ }
+ rc_state->sigseen = lineno;
+ rc_state->bufseen = 0;
+
+ if (!IDENTIFIER_SIGNAL_DATA (signame) && loclist != NULL_TREE)
+ {
+ error ("SIGNAL `%s' has no data fields", IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+ if (IDENTIFIER_SIGNAL_DATA (signame) && loclist == NULL_TREE)
+ {
+ error ("SIGNAL `%s' requires data fields", IDENTIFIER_POINTER (signame));
+ return error_mark_node;
+ }
+
+ if (!rc_state->call_generated)
+ {
+ tree wait_call;
+
+ TREE_VALUE (rc_state->actuallist) = force_addr_of (rc_state->received_signal);
+ wait_call = build_chill_function_call (lookup_name
+ (get_identifier ("__wait_signal_timed")),
+ rc_state->actuallist);
+#if 0
+ chill_expand_assignment (rc_state->received_signal,
+ NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, rc_state->to_loc);
+
+ rc_state->call_generated = 1;
+ }
+
+ /* build the conditional expression */
+ expr = build (EQ_EXPR, boolean_type_node,
+ rc_state->received_signal,
+ (tree)DECL_TASKING_CODE_DECL (sigdecl));
+
+ if (!rc_state->if_generated)
+ {
+ expand_start_cond (expr, 0);
+ rc_state->if_generated = 1;
+ }
+ else
+ expand_start_elseif (expr);
+
+ if (IDENTIFIER_SIGNAL_DATA (signame))
+ {
+ /* copy data from signal buffer to user's variables */
+ tree typelist = TYPE_FIELDS (TREE_TYPE (sigdecl));
+ tree valtail, typetail;
+ int parmno = 1;
+ tree pointer_type = build_chill_pointer_type (TREE_TYPE (sigdecl));
+ tree pointer = convert (pointer_type, rc_state->databufp);
+
+ for (valtail = nreverse (loclist), typetail = typelist;
+ valtail != NULL_TREE && typetail != NULL_TREE;
+ parmno++, valtail = TREE_CHAIN (valtail),
+ typetail = TREE_CHAIN (typetail))
+ {
+ register tree actual = valtail ? TREE_VALUE (valtail) : 0;
+ register tree type = typetail ? TREE_TYPE (typetail) : 0;
+ register tree assgn;
+ char place[30];
+ sprintf (place, "signal field %d", parmno);
+
+ assgn = build_component_ref (build1 (INDIRECT_REF,
+ TREE_TYPE (sigdecl),
+ pointer),
+ DECL_NAME (typetail));
+ if (!CH_TYPE_NONVALUE_P (type))
+ /* don't assign to non-value type. Error printed at signal definition */
+ chill_expand_assignment (actual, NOP_EXPR, assgn);
+ }
+
+ if (valtail == NULL_TREE && typetail != NULL_TREE)
+ error ("too few data fields provided for `%s'",
+ IDENTIFIER_POINTER (signame));
+ if (valtail != NULL_TREE && typetail == NULL_TREE)
+ error ("too many data fields provided for `%s'",
+ IDENTIFIER_POINTER (signame));
+ }
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+
+ return build_tree_list (loclist, signame);
+}
+
+static tree
+build_receive_buffer_case_label (buffer, loclist)
+ tree buffer, loclist;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree buftype = buffer_element_mode (TREE_TYPE (buffer));
+ tree expr, var;
+ tree pointer_type, pointer, assgn;
+ int had_errors = 0;
+ tree x, y, z, bufaddr;
+
+ if (rc_state->sigseen != 0)
+ {
+ error ("BUFFER in RECEIVE CASE alternative follows");
+ error (" a SIGNAL name on line %d", rc_state->sigseen);
+ return error_mark_node;
+ }
+ rc_state->bufseen = lineno;
+ rc_state->sigseen = 0;
+
+ if (! CH_REFERABLE (buffer))
+ {
+ error ("BUFFER in RECEIVE CASE alternative must be a location.");
+ return error_mark_node;
+ }
+
+ if (TREE_CHAIN (loclist) != NULL_TREE)
+ {
+ error ("buffer receive alternative requires only 1 defining occurence.");
+ return error_mark_node;
+ }
+
+ if (!rc_state->call_generated)
+ {
+ tree wait_call;
+
+ /* here we change the mode of rc_state->sig_code to
+ REF ARRAY (0:65535) REF __tmp_DESCR_type.
+ This is neccesary, cause we cannot evaluate the buffer twice
+ (once here where we compare against the address of the buffer
+ and second in build_receive_buffer_case_end, where we use the
+ address build the descriptor, which gets passed to __wait_buffer).
+ So we change the comparison from
+ if (rc_state->received_buffer == &buffer)
+ to
+ if (rc_state->received_buffer ==
+ rc_state->sig_codep->[rc_state->bufcnt]->datap).
+
+ This will evaluate the buffer location only once
+ (in build_receive_buffer_case_end) and therefore doesn't confuse
+ our machinery. */
+
+ tree reftmpdescr = build_chill_pointer_type (
+ TREE_TYPE (lookup_name (
+ get_identifier ("__tmp_DESCR_type"))));
+ tree idxtype = build_chill_range_type (NULL_TREE,
+ integer_zero_node,
+ build_int_2 (65535, 0)); /* should be enough, probably use ULONG */
+ tree arrtype = build_chill_array_type (reftmpdescr,
+ tree_cons (NULL_TREE, idxtype, NULL_TREE),
+ 0, NULL_TREE);
+ tree refarrtype = build_chill_pointer_type (arrtype);
+
+ TREE_VALUE (rc_state->actuallist) = force_addr_of (rc_state->received_buffer);
+ wait_call = build_chill_function_call (
+ lookup_name (get_identifier ("__wait_buffer")),
+ rc_state->actuallist);
+#if 0
+ chill_expand_assignment (rc_state->received_buffer,
+ NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, rc_state->to_loc);
+
+ /* do this after the call, otherwise there will be a mode mismatch */
+ TREE_TYPE (rc_state->sig_code) = refarrtype;
+
+ /* now we are ready to generate the call */
+ rc_state->call_generated = 1;
+ }
+
+ x = build_chill_indirect_ref (rc_state->sig_code, NULL_TREE, 0);
+ y = build_chill_array_ref (x,
+ tree_cons (NULL_TREE, build_int_2 (rc_state->bufcnt, 0), NULL_TREE));
+ z = build_chill_indirect_ref (y, NULL_TREE, 0);
+ bufaddr = build_chill_component_ref (z, get_identifier ("datap"));
+
+ /* build the conditional expression */
+ expr = build (EQ_EXPR, boolean_type_node,
+ rc_state->received_buffer,
+ bufaddr);
+
+ /* next buffer in list */
+ rc_state->bufcnt++;
+
+ if (!rc_state->if_generated)
+ {
+ expand_start_cond (expr, 0);
+ rc_state->if_generated = 1;
+ }
+ else
+ expand_start_elseif (expr);
+
+ /* copy buffer's data to destination */
+ var = TREE_VALUE (loclist);
+
+ if (buftype != NULL_TREE && TREE_CODE (buftype) == ERROR_MARK)
+ had_errors = 1;
+ else if (! CH_COMPATIBLE (var, buftype))
+ {
+ error ("incompatible modes in receive buffer alternative.");
+ had_errors = 1;
+ }
+
+ if (! CH_LOCATION_P (var))
+ {
+ error ("defining occurence in receive buffer alternative must be a location.");
+ had_errors = 1;
+ }
+
+ if (! had_errors)
+ {
+ pointer_type = build_chill_pointer_type (TREE_TYPE (var));
+ pointer = convert (pointer_type,
+ rc_state->databufp);
+ /* no need to check this pointer being NULL */
+ assgn = build_chill_indirect_ref (pointer, NULL_TREE, 0);
+
+ chill_expand_assignment (var, NOP_EXPR, assgn);
+ }
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+
+ return build_tree_list (loclist, buffer);
+}
+/*
+ * SIGNAME is the signal name or buffer location,
+ * LOCLIST is a list of possible locations to store data in
+ */
+tree
+build_receive_case_label (signame, loclist)
+ tree signame, loclist;
+{
+ /* now see what we have got and do some checks */
+ if (TREE_CODE (signame) == TYPE_DECL && CH_DECL_SIGNAL (signame))
+ return build_receive_signal_case_label (signame, loclist);
+
+ if (TREE_TYPE (signame) != NULL_TREE
+ && CH_IS_BUFFER_MODE (TREE_TYPE (signame)))
+ {
+ if (loclist == NULL_TREE)
+ {
+ error ("buffer receive alternative without `IN location'.");
+ return error_mark_node;
+ }
+ return build_receive_buffer_case_label (signame, loclist);
+ }
+
+ error ("RECEIVE CASE alternative must specify a SIGNAL name or BUFFER location.");
+ return error_mark_node;
+}
+
+/*
+ * LABEL_CNT is the case-label counter passed from build_receive_case_start.
+ * ELSE_CLAUSE defines if the RECEIVE CASE action had an ELSE(1) or not(0).
+ * BUF_LIST is a tree-list of tree-lists, where TREE_VALUE defines the
+ * BUFFER location and TREE_PURPOSE defines the defining occurence.
+ */
+static void
+build_receive_buffer_case_end (label_cnt, buf_list, else_clause)
+ tree label_cnt, buf_list, else_clause;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree alist;
+ tree field_decls = NULL_TREE; /* list of all buffer types, for the union */
+ int buffer_cnt = 0;
+ tree descr_type = lookup_name (get_identifier ("__tmp_DESCR_type"));
+ tree tuple = NULL_TREE; /* constructors for array of ptrs */
+ tree union_type_node = NULL_TREE;
+
+ /* walk thru all the buffers */
+ for (alist = buf_list; alist != NULL_TREE;
+ buffer_cnt++, alist = TREE_CHAIN (alist))
+ {
+ tree value = TREE_VALUE (alist);
+ tree buffer = TREE_VALUE (value); /* this is the buffer */
+ tree data = TREE_VALUE (TREE_PURPOSE (value)); /* the location to receive in */
+ tree buffer_descr;
+ tree buffer_descr_init;
+ tree buffer_length;
+ tree buffer_ptr;
+ tree field;
+ char fldname[20];
+
+ /* build descriptor for buffer */
+ buffer_length = max_queue_size (TREE_TYPE (buffer));
+ if (buffer_length == NULL_TREE)
+ buffer_length = infinite_buffer_event_length_node;
+ buffer_descr_init = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, force_addr_of (buffer),
+ tree_cons (NULL_TREE, buffer_length, NULL_TREE)));
+ buffer_descr = decl_temp1 (get_unique_identifier ("RCbuffer"),
+ TREE_TYPE (descr_type), 0,
+ buffer_descr_init, 0, 0);
+ tuple = tree_cons (NULL_TREE,
+ force_addr_of (buffer_descr),
+ tuple);
+
+ /* make a field for the union */
+ sprintf (fldname, "fld%03d", buffer_cnt);
+ field = grok_chill_fixedfields (
+ tree_cons (NULL_TREE, get_identifier (fldname), NULL_TREE),
+ TREE_TYPE (data), NULL_TREE);
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+ }
+
+ /* generate the union */
+ if (field_decls != NULL_TREE)
+ {
+ tree data_id = get_identifier ("databuffer");
+ tree data_decl;
+
+ union_type_node = finish_struct (
+ start_struct (UNION_TYPE, NULL_TREE),
+ field_decls);
+ data_decl = decl_temp1 (data_id, union_type_node, 0, NULL_TREE, 0, 0);
+
+ chill_expand_assignment (rc_state->databufp, NOP_EXPR,
+ force_addr_of (data_decl));
+
+ chill_expand_assignment (rc_state->datalen, NOP_EXPR,
+ size_in_bytes (TREE_TYPE (data_decl)));
+ }
+
+ /* tell runtime system if we had an else or not */
+ chill_expand_assignment (rc_state->else_clause, NOP_EXPR, else_clause);
+
+ /* generate the array of pointers to all buffers */
+ {
+ tree array_id = get_identifier ("buf_ptr_array");
+ tree array_type_node =
+ build_chill_array_type (ptr_type_node,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (buffer_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE, nreverse (tuple));
+ tree array_decl = decl_temp1 (array_id, array_type_node, 0,
+ constr, 0, 0);
+
+ chill_expand_assignment (build_chill_cast (ptr_type_node, rc_state->sig_code),
+ NOP_EXPR,
+ force_addr_of (array_decl));
+ chill_expand_assignment (rc_state->n_sigs, NOP_EXPR,
+ build_int_2 (buffer_cnt, 0));
+ }
+}
+
+/*
+ * SIG_LIST is a tree list. The TREE_VALUEs are VAR_DECLs of
+ * __tmp_%s_code variables, and the TREE_PURPOSEs are the
+ * TYPE_DECLs of the __tmp_%s_struct types. LABEL_CNT is the
+ * case-label counter passed from build_receive_case_start.
+ */
+static void
+build_receive_signal_case_end (label_cnt, sig_list, else_clause)
+ tree label_cnt, sig_list, else_clause;
+{
+ struct rc_state_type *rc_state = current_rc_state;
+ tree alist, temp1;
+ tree union_type_node = NULL_TREE;
+ tree field_decls = NULL_TREE; /* list of signal
+ structure, for the union */
+ tree tuple = NULL_TREE; /* constructor for array of ptrs */
+ int signal_cnt = 0;
+ int fldcnt = 0;
+
+ /* for each list of locations, validate it against the
+ corresponding signal's list of fields. */
+ {
+ for (alist = sig_list; alist != NULL_TREE;
+ signal_cnt++, alist = TREE_CHAIN (alist))
+ {
+ tree value = TREE_VALUE (alist);
+ tree signame = TREE_VALUE (value); /* signal's ID node */
+ tree sigdecl = lookup_name (signame);
+ tree sigtype = TREE_TYPE (sigdecl);
+ tree field;
+ char fldname[20];
+
+ if (IDENTIFIER_SIGNAL_DATA (signame))
+ {
+ sprintf (fldname, "fld%03d", fldcnt++);
+ field = grok_chill_fixedfields (
+ tree_cons (NULL_TREE,
+ get_identifier (fldname),
+ NULL_TREE),
+ sigtype, NULL_TREE);
+ if (field_decls == NULL_TREE)
+ field_decls = field;
+ else
+ chainon (field_decls, field);
+
+ }
+
+ temp1 = (tree)DECL_TASKING_CODE_DECL (sigdecl);
+ mark_addressable (temp1);
+ tuple = tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ temp1),
+ tuple);
+ }
+ }
+
+ /* generate the union of all of the signal data types */
+ if (field_decls != NULL_TREE)
+ {
+ tree data_id = get_identifier ("databuffer");
+ tree data_decl;
+ union_type_node = finish_struct (start_struct (UNION_TYPE,
+ NULL_TREE),
+ field_decls);
+ data_decl =
+ decl_temp1 (data_id, union_type_node, 0, NULL_TREE, 0, 0);
+
+ chill_expand_assignment (rc_state->databufp, NOP_EXPR,
+ force_addr_of (data_decl));
+
+ chill_expand_assignment (rc_state->datalen, NOP_EXPR,
+ size_in_bytes (TREE_TYPE (data_decl)));
+ }
+
+ /* tell runtime system if we had an else or not */
+ chill_expand_assignment (rc_state->else_clause, NOP_EXPR, else_clause);
+
+ /* generate the array of all signal codes */
+ {
+ tree array_id = get_identifier ("sig_code_array");
+ tree array_type_node
+ = build_chill_array_type (
+ build_chill_pointer_type (chill_integer_type_node),
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (signal_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (tuple));
+ tree array_decl =
+ decl_temp1 (array_id, array_type_node, 0, constr, 0, 0);
+
+ chill_expand_assignment (rc_state->sig_code, NOP_EXPR,
+ force_addr_of (array_decl));
+
+ /* give number of signals to runtime system */
+ chill_expand_assignment (rc_state->n_sigs, NOP_EXPR,
+ build_int_2 (signal_cnt, 0));
+ }
+}
+
+/* General function for the end of a RECEIVE CASE action */
+
+void
+build_receive_case_end (label_cnt, alist, else_clause)
+ tree label_cnt, alist, else_clause;
+{
+ rtx rcdone = gen_label_rtx ();
+ struct rc_state_type *rc_state = current_rc_state;
+ tree tmp;
+ int had_errors = 0;
+
+ /* finish the if's, if generated */
+ if (rc_state->if_generated)
+ expand_end_cond ();
+
+ /* check alist for errors */
+ for (tmp = alist; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp))
+ {
+ if (TREE_CODE (TREE_VALUE (tmp)) == ERROR_MARK)
+ had_errors++;
+ }
+
+ /* jump to the end of RECEIVE CASE processing */
+ emit_jump (rcdone);
+
+ /* define the __rcsetup label. We come here to initialize
+ all variables */
+ emit_label (rc_state->rcsetup);
+
+ if (alist == NULL_TREE && !had_errors)
+ {
+ error ("RECEIVE CASE without alternatives");
+ goto gen_rcdoit;
+ }
+
+ if (TREE_CODE (alist) == ERROR_MARK || had_errors)
+ goto gen_rcdoit;
+
+ /* now call the actual end function */
+ if (rc_state->bufseen)
+ build_receive_buffer_case_end (label_cnt, alist, else_clause);
+ else
+ build_receive_signal_case_end (label_cnt, alist, else_clause);
+
+ /* now jump to the beginning of RECEIVE CASE processing */
+gen_rcdoit: ;
+ emit_jump (rc_state->rcdoit);
+
+ /* define the __rcdone label. We come here when the whole
+ receive case is done. */
+ emit_label (rcdone);
+
+ current_rc_state = rc_state->enclosing;
+ free(rc_state);
+}
+
+/* build a CONTINUE action */
+
+void expand_continue_event (evloc)
+ tree evloc;
+{
+ tree filename, linenumber, evaddr;
+
+ /* do some checks */
+ if (evloc == NULL_TREE || TREE_CODE (evloc) == ERROR_MARK)
+ return;
+
+ if (! CH_REFERABLE (evloc) || ! CH_IS_EVENT_MODE (TREE_TYPE (evloc)))
+ {
+ error ("CONTINUE requires an event location.");
+ return;
+ }
+
+ evaddr = force_addr_of (evloc);
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ expand_expr_stmt (
+ build_chill_function_call (lookup_name (get_identifier ("__continue")),
+ tree_cons (NULL_TREE, evaddr,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))));
+}
+
+#if 0
+ * The following code builds a DELAY CASE statement,
+ * which looks like this in CHILL:
+ *
+ * DCL ev1, ev2 EVENT, ins INSTANCE;
+ * DCL ev3 EVENT (10);
+ * DCL count1 INT := 0, count2 INT := 0;
+ *
+ * DELAY CASE SET ins;
+ * (ev1): count1 +:= 1;
+ * (ev2, ev3): count2 +:= 1;
+ * ESAC;
+ *
+ * Because we don''t know until we get to the ESAC how
+ * many events need processing, we generate the following
+ * C-equivalent code:
+ *
+ *
+ * { /* start a new symbol context */
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned long len;
+ * } Descr;
+ * int number_of_events;
+ * Descr *event_codes;
+ *
+ * goto __dlsetup;
+ *
+ * __dldoit:
+ * void *whatevent = __delay_event (number_of_events,
+ * event_codes,
+ * priority,
+ * &instance_loc,
+ * filename,
+ * linenumber);
+ * if (whatevent == &ev1)
+ * {
+ * /* code for ev1 alternative's action_statement_list */
+ * count1 += 1;
+ * }
+ * else if (whatevent == &ev2 || whatevent == &ev3)
+ * {
+ * /* code for ev2 and ev3 alternative's action_statement_list */
+ * count2 += 1;
+ * }
+ * goto __dl_done;
+ *
+ * __dlsetup:
+ * Descr event_code_ptr [3] = {
+ * { &ev1, -1 },
+ * { &ev2, -1 },
+ * { &ev3, 10 } };
+ * event_codes = &event_code_ptr[0];
+ * number_of_events = 3;
+ * goto __dldoit;
+ *
+ * __dl_done:
+ * ;
+ * } /* end the new symbol context */
+ *
+#endif
+
+struct dl_state_type
+{
+ struct dl_state_type *enclosing;
+ rtx dldoit;
+ rtx dlsetup;
+ tree n_events;
+ tree event_codes;
+ tree received_event;
+};
+
+struct dl_state_type *current_dl_state = NULL;
+
+/* build_receive_case_start returns an INTEGER_CST node
+ containing the case-label number to be used by
+ build_receive_case_end to generate correct labels */
+tree
+build_delay_case_start (optset, optpriority)
+ tree optset, optpriority;
+{
+ /* counter to generate unique delay case labels */
+ static int dl_lbl_count = 0;
+ tree current_label_value =
+ build_int_2 ((HOST_WIDE_INT)dl_lbl_count, 0);
+ tree wait_call;
+ tree actuallist = NULL_TREE;
+ tree filename, linenumber;
+ tree to_loc;
+
+ struct dl_state_type *dl_state
+ = (struct dl_state_type*) xmalloc (sizeof (struct dl_state_type));
+ dl_state->enclosing = current_dl_state;
+ current_dl_state = dl_state;
+ dl_state->dldoit = gen_label_rtx ();
+ dl_state->dlsetup = gen_label_rtx ();
+
+ dl_lbl_count++;
+
+ /* check the optional SET location */
+ if (optset == NULL_TREE
+ || TREE_CODE (optset) == ERROR_MARK)
+ optset = null_pointer_node;
+ else if (CH_IS_INSTANCE_MODE (TREE_TYPE (optset)) && CH_LOCATION_P (optset))
+ optset = force_addr_of (optset);
+ else
+ {
+ error ("SET requires INSTANCE location");
+ optset = null_pointer_node;
+ }
+
+ /* check the presence of the PRIORITY expression */
+ if (optpriority == NULL_TREE)
+ optpriority = integer_zero_node;
+ else if (TREE_CODE (optpriority) == ERROR_MARK)
+ optpriority = integer_zero_node;
+ else if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY must be of integer type.");
+ optpriority = integer_zero_node;
+ }
+
+ /* check for time supervised */
+ to_loc = build_timeout_preface ();
+
+ dl_state->n_events =
+ decl_temp1 (get_identifier ("number_of_events"),
+ integer_type_node, 0, integer_zero_node, 0, 0);
+
+ dl_state->event_codes =
+ decl_temp1 (get_identifier ("event_codes"),
+ ptr_type_node, 0, null_pointer_node, 0, 0);
+
+ /* wait_event will store the signal number in here */
+ dl_state->received_event =
+ decl_temp1 (get_identifier ("received_event"),
+ ptr_type_node, 0, NULL_TREE, 0, 0);
+
+ /* now jump to the end of RECEIVE CASE actions, to
+ set up variables for them. */
+ emit_jump (dl_state->dlsetup);
+
+ /* define the __rcdoit label. We come here after
+ initialization of all variables, to execute the
+ actions. */
+ emit_label (dl_state->dldoit);
+
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* here we go, call the runtime routine */
+ actuallist = tree_cons (NULL_TREE, force_addr_of (dl_state->received_event),
+ tree_cons (NULL_TREE, dl_state->n_events,
+ tree_cons (NULL_TREE, dl_state->event_codes,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, to_loc,
+ tree_cons (NULL_TREE, optset,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))));
+
+ wait_call = build_chill_function_call (
+ lookup_name (get_identifier ("__delay_event")),
+ actuallist);
+
+#if 0
+ chill_expand_assignment (dl_state->received_event, NOP_EXPR, wait_call);
+#endif
+ build_timesupervised_call (wait_call, to_loc);
+ return current_label_value;
+}
+
+/*
+ EVENTLIST is the list of this alternative's events
+ and IF_OR_ELSEIF indicates what action (1 for if and
+ 0 for else if) should be generated.
+*/
+void
+build_delay_case_label (eventlist, if_or_elseif)
+ tree eventlist;
+ int if_or_elseif;
+{
+ tree eventp, expr = NULL_TREE;
+
+ if (eventlist == NULL_TREE || TREE_CODE (eventlist) == ERROR_MARK)
+ return;
+
+ for (eventp = eventlist; eventp != NULL_TREE;
+ eventp = TREE_CHAIN (eventp))
+ {
+ tree event = TREE_VALUE (eventp);
+ tree temp1;
+
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ temp1 = null_pointer_node;
+ else if (! CH_IS_EVENT_MODE (TREE_TYPE (event)) || ! CH_REFERABLE (event))
+ {
+ error ("delay alternative must be an EVENT location.");
+ temp1 = null_pointer_node;
+ }
+ else
+ temp1 = force_addr_of (event);
+
+ /* build the conditional expression */
+ if (expr == NULL_TREE)
+ expr = build (EQ_EXPR, boolean_type_node,
+ current_dl_state->received_event, temp1);
+ else
+ expr =
+ build (TRUTH_ORIF_EXPR, boolean_type_node, expr,
+ build (EQ_EXPR, boolean_type_node,
+ current_dl_state->received_event, temp1));
+ }
+ if (if_or_elseif)
+ expand_start_cond (expr, 0);
+ else
+ expand_start_elseif (expr);
+
+ /* last action here */
+ emit_line_note (input_filename, lineno);
+}
+
+/*
+ * EVENT_LIST is a tree list. The TREE_VALUEs are VAR_DECLs of
+ * EVENT variables. LABEL_CNT is the case-label counter
+ * passed from build_delay_case_start.
+ */
+void
+build_delay_case_end (label_cnt, event_list)
+ tree label_cnt, event_list;
+{
+ struct dl_state_type *dl_state = current_dl_state;
+ rtx dldone = gen_label_rtx ();
+ tree tuple = NULL_TREE; /* constructor for array of descrs */
+ tree acode;
+ int event_cnt = 0;
+
+ /* if we have an empty event_list, there was no alternatives and we
+ havn't started an if therefor don't run expand_end_cond */
+ if (event_list != NULL_TREE)
+ /* finish the if's */
+ expand_end_cond ();
+
+ /* jump to the end of RECEIVE CASE processing */
+ emit_jump (dldone);
+
+ /* define the __dlsetup label. We come here to initialize
+ all variables */
+ emit_label (dl_state->dlsetup);
+
+ if (event_list == NULL_TREE)
+ {
+ error ("DELAY CASE without alternatives");
+ goto gen_dldoit;
+ }
+
+ if (event_list == NULL_TREE
+ || TREE_CODE (event_list) == ERROR_MARK)
+ goto gen_dldoit;
+
+ /* make a list of pointers (in reverse order)
+ to the event code variables */
+ for (acode = event_list; acode != NULL_TREE;
+ acode = TREE_CHAIN (acode))
+ {
+ tree event = TREE_VALUE (acode);
+ tree event_length;
+ tree descr_init;
+
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ {
+ descr_init =
+ tree_cons (NULL_TREE, null_pointer_node,
+ tree_cons (NULL_TREE, integer_zero_node, NULL_TREE));
+ }
+ else
+ {
+ event_length = max_queue_size (TREE_TYPE (event));
+ if (event_length == NULL_TREE)
+ event_length = infinite_buffer_event_length_node;
+ descr_init =
+ tree_cons (NULL_TREE, force_addr_of (event),
+ tree_cons (NULL_TREE, event_length, NULL_TREE));
+ }
+ tuple = tree_cons (NULL_TREE,
+ build_nt (CONSTRUCTOR, NULL_TREE, descr_init),
+ tuple);
+ event_cnt++;
+ }
+
+ /* generate the array of all event code pointers */
+ {
+ tree descr_type = TREE_TYPE (lookup_name (get_identifier ("__tmp_DESCR_type")));
+ tree array_id = get_identifier ("event_code_array");
+ tree array_type_node
+ = build_chill_array_type (descr_type,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE,
+ integer_one_node,
+ build_int_2 (event_cnt, 0)),
+ NULL_TREE),
+ 0, NULL_TREE);
+ tree constr = build_nt (CONSTRUCTOR, NULL_TREE,
+ nreverse (tuple));
+ tree array_decl =
+ decl_temp1 (array_id, array_type_node, 0, constr, 0, 0);
+
+ chill_expand_assignment (dl_state->event_codes, NOP_EXPR,
+ force_addr_of (array_decl));
+
+ /* give number of signals to runtime system */
+ chill_expand_assignment (dl_state->n_events, NOP_EXPR,
+ build_int_2 (event_cnt, 0));
+ }
+
+ /* now jump to the beginning of DELAY CASE processing */
+gen_dldoit:
+ emit_jump (dl_state->dldoit);
+
+ /* define the __dldone label. We come here when the whole
+ DELAY CASE is done. */
+ emit_label (dldone);
+
+ current_dl_state = dl_state->enclosing;
+ free(dl_state);
+}
+
+#if 0
+ * The following code builds a simple delay statement,
+ * which looks like this in CHILL:
+ *
+ * DCL ev1 EVENT(5), ins INSTANCE;
+ *
+ * DELAY ev1 PRIORITY 7;
+ *
+ * This statement unconditionally delays the current
+ * PROCESS, until some other process CONTINUEs it.
+ *
+ * Here is the generated C code:
+ *
+ * typedef struct
+ * {
+ * void *p;
+ * unsigned long len;
+ * } Descr;
+ *
+ * static short __tmp_ev1_code;
+ *
+ * { /* start a new symbol context */
+ *
+ * Descr __delay_array[1] = { { ev1, 5 } };
+ *
+ * __delay_event (1, &__delay_array, 7, NULL,
+ * filename, linenumber);
+ *
+ * } /* end of symbol scope */
+ */
+#endif
+void
+build_delay_action (event, optpriority)
+ tree event, optpriority;
+{
+ int had_errors = 0;
+ tree to_loc = NULL_TREE;
+ /* we discard the return value of __delay_event, cause in
+ a normal DELAY action no selections have to be made */
+ tree ev_got = null_pointer_node;
+
+ /* check the event */
+ if (event == NULL_TREE || TREE_CODE (event) == ERROR_MARK)
+ had_errors = 1;
+ else if (! CH_IS_EVENT_MODE (TREE_TYPE (event)) || ! CH_REFERABLE (event))
+ {
+ error ("DELAY action requires an event location.");
+ had_errors = 1;
+ }
+
+ /* check the presence of priority */
+ if (optpriority != NULL_TREE)
+ {
+ if (TREE_CODE (optpriority) == ERROR_MARK)
+ return;
+ if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY in DELAY action must be of integer type.");
+ return;
+ }
+ }
+ else
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("DELAY action without priority.");
+ warning (" PRIORITY defaulted to 0.");
+ }
+ optpriority = integer_zero_node;
+ }
+ if (had_errors)
+ return;
+
+ {
+ tree descr_type;
+ tree array_type_node;
+ tree array_decl;
+ tree descr_init;
+ tree array_init;
+ tree event_length = max_queue_size (TREE_TYPE (event));
+ tree event_codes;
+ tree filename = force_addr_of (get_chill_filename ());
+ tree linenumber = get_chill_linenumber ();
+ tree actuallist;
+
+ to_loc = build_timeout_preface ();
+
+ descr_type = TREE_TYPE (lookup_name (get_identifier ("__tmp_DESCR_type")));
+
+ array_type_node =
+ build_chill_array_type (descr_type,
+ tree_cons (NULL_TREE,
+ build_chill_range_type (NULL_TREE, integer_one_node,
+ integer_one_node),
+ NULL_TREE),
+ 0, NULL_TREE);
+ if (event_length == NULL_TREE)
+ event_length = infinite_buffer_event_length_node;
+
+ descr_init =
+ tree_cons (NULL_TREE, force_addr_of (event),
+ tree_cons (NULL_TREE, event_length, NULL_TREE));
+ array_init =
+ tree_cons (NULL_TREE,
+ build_nt (CONSTRUCTOR, NULL_TREE, descr_init),
+ NULL_TREE);
+ array_decl =
+ decl_temp1 (get_unique_identifier ("event_codes_array"),
+ array_type_node, 0,
+ build_nt (CONSTRUCTOR, NULL_TREE, array_init),
+ 0, 0);
+
+ event_codes =
+ decl_temp1 (get_unique_identifier ("event_ptr"),
+ ptr_type_node, 0,
+ force_addr_of (array_decl),
+ 0, 0);
+
+ actuallist =
+ tree_cons (NULL_TREE, ev_got,
+ tree_cons (NULL_TREE, integer_one_node,
+ tree_cons (NULL_TREE, event_codes,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, to_loc,
+ tree_cons (NULL_TREE, null_pointer_node,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE))))))));
+
+
+ build_timesupervised_call (
+ build_chill_function_call (
+ lookup_name (get_identifier ("__delay_event")),
+ actuallist), to_loc);
+ }
+}
+
+void
+expand_send_buffer (buffer, value, optpriority, optwith, optto)
+ tree buffer, value, optpriority, optwith, optto;
+{
+ tree filename, linenumber;
+ tree buffer_mode_decl = NULL_TREE;
+ tree buffer_ptr, value_ptr;
+ int had_errors = 0;
+ tree timeout_value, fcall;
+
+ /* check buffer location */
+ if (buffer == NULL_TREE || TREE_CODE (buffer) == ERROR_MARK)
+ {
+ buffer = NULL_TREE;
+ had_errors = 1;
+ }
+ if (buffer != NULL_TREE)
+ {
+ if (! CH_IS_BUFFER_MODE (TREE_TYPE (buffer)) || ! CH_REFERABLE (buffer))
+ {
+ error ("send buffer action requires a BUFFER location.");
+ had_errors = 1;
+ }
+ else
+ buffer_mode_decl = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (buffer)));
+ }
+
+ /* check value and type */
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ had_errors = 1;
+ value = NULL_TREE;
+ }
+ if (value != NULL_TREE)
+ {
+ if (TREE_CHAIN (value) != NULL_TREE)
+ {
+ error ("there must be only 1 value for send buffer action.");
+ had_errors = 1;
+ }
+ else
+ {
+ value = TREE_VALUE (value);
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ had_errors = 1;
+ value = NULL_TREE;
+ }
+ if (value != NULL_TREE && buffer_mode_decl != NULL_TREE)
+ {
+ if (TREE_TYPE (buffer_mode_decl) != NULL_TREE &&
+ TREE_CODE (TREE_TYPE (buffer_mode_decl)) == ERROR_MARK)
+ had_errors = 1;
+ else if (CH_COMPATIBLE (value, TREE_TYPE (buffer_mode_decl)))
+ {
+ value = convert (TREE_TYPE (buffer_mode_decl), value);
+ if (value == NULL_TREE || TREE_CODE (value) == ERROR_MARK)
+ {
+ error ("convert failed for send buffer action.");
+ had_errors = 1;
+ }
+ }
+ else
+ {
+ error ("incompatible modes in send buffer action.");
+ had_errors = 1;
+ }
+ }
+ }
+ }
+
+ /* check the presence of priority */
+ if (optpriority == NULL_TREE)
+ {
+ if (send_buffer_prio == NULL_TREE)
+ {
+ /* issue a warning in case of -Wall */
+ if (extra_warnings)
+ {
+ warning ("Buffer sent without priority");
+ warning (" and no default priority was set.");
+ warning (" PRIORITY defaulted to 0.");
+ }
+ optpriority = integer_zero_node;
+ }
+ else
+ optpriority = send_buffer_prio;
+ }
+ else if (TREE_CODE (optpriority) == ERROR_MARK)
+ had_errors = 1;
+ else if (TREE_CODE (TREE_TYPE (optpriority)) != INTEGER_TYPE)
+ {
+ error ("PRIORITY must be of integer type.");
+ had_errors = 1;
+ }
+
+ if (optwith != NULL_TREE)
+ {
+ error ("WITH not allowed for send buffer action.");
+ had_errors = 1;
+ }
+ if (optto != NULL_TREE)
+ {
+ error ("TO not allowed for send buffer action.");
+ had_errors = 1;
+ }
+ if (had_errors)
+ return;
+
+ {
+ tree descr_type;
+ tree buffer_descr, buffer_init, buffer_length;
+ tree val;
+
+ /* process timeout */
+ timeout_value = build_timeout_preface ();
+
+ descr_type = lookup_name (get_identifier ("__tmp_DESCR_type"));
+
+ /* build descr for buffer */
+ buffer_length = max_queue_size (TREE_TYPE (buffer));
+ if (buffer_length == NULL_TREE)
+ buffer_length = infinite_buffer_event_length_node;
+ buffer_init = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE, force_addr_of (buffer),
+ tree_cons (NULL_TREE, buffer_length, NULL_TREE)));
+ buffer_descr = decl_temp1 (get_unique_identifier ("buffer_descr"),
+ TREE_TYPE (descr_type), 0, buffer_init,
+ 0, 0);
+ buffer_ptr = decl_temp1 (get_unique_identifier ("buffer_ptr"),
+ ptr_type_node, 0,
+ force_addr_of (buffer_descr),
+ 0, 0);
+
+ /* build descr for value */
+ if (! CH_REFERABLE (value))
+ val = decl_temp1 (get_identifier ("buffer_value"),
+ TREE_TYPE (value), 0,
+ value, 0, 0);
+ else
+ val = value;
+
+ value_ptr = build_chill_descr (val);
+
+ }
+
+ /* get filename and linenumber */
+ filename = force_addr_of (get_chill_filename ());
+ linenumber = get_chill_linenumber ();
+
+ /* Now, we can call the runtime */
+ fcall = build_chill_function_call (
+ lookup_name (get_identifier ("__send_buffer")),
+ tree_cons (NULL_TREE, buffer_ptr,
+ tree_cons (NULL_TREE, value_ptr,
+ tree_cons (NULL_TREE, optpriority,
+ tree_cons (NULL_TREE, timeout_value,
+ tree_cons (NULL_TREE, filename,
+ tree_cons (NULL_TREE, linenumber, NULL_TREE)))))));
+ build_timesupervised_call (fcall, timeout_value);
+}
+# if 0
+
+void
+process_buffer_decls (namelist, mode, optstatic)
+ tree namelist, mode;
+ int optstatic;
+{
+ tree names;
+ int quasi_flag = current_module->is_spec_module;
+
+ if (pass < 2)
+ return;
+
+ for (names = namelist; names != NULL_TREE; names = TREE_CHAIN (names))
+ {
+ tree name = TREE_VALUE (names);
+ tree bufdecl = lookup_name (name);
+ tree code_decl =
+ decl_tasking_code_variable (name, &buffer_code, quasi_flag);
+
+ /* remember the code variable in the buffer decl */
+ DECL_TASKING_CODE_DECL (bufdecl) = (struct lang_decl *)code_decl;
+
+ add_taskstuff_to_list (code_decl, "_TT_Buffer",
+ quasi_flag ? NULL_TREE : buffer_code,
+ bufdecl);
+ }
+}
+#endif
+
+/*
+ * if no queue size was specified, QUEUESIZE is integer_zero_node.
+ */
+tree
+build_buffer_type (element_type, queuesize)
+ tree element_type, queuesize;
+{
+ tree type, field;
+ if (element_type == NULL_TREE || TREE_CODE (element_type) == ERROR_MARK)
+ return error_mark_node;
+ if (queuesize != NULL_TREE && TREE_CODE (queuesize) == ERROR_MARK)
+ return error_mark_node;
+
+ type = make_node (RECORD_TYPE);
+ field = build_decl (FIELD_DECL, get_identifier("__buffer_data"),
+ ptr_type_node);
+ TYPE_FIELDS (type) = field;
+ TREE_CHAIN (field)
+ = build_lang_decl (TYPE_DECL, get_identifier ("__element_mode"),
+ element_type);
+ field = TREE_CHAIN (field);
+ if (queuesize)
+ {
+ tree size_field = build_decl (CONST_DECL, get_identifier("__queue_max"),
+ integer_type_node);
+ DECL_INITIAL (size_field) = queuesize;
+ TREE_CHAIN (field) = size_field;
+ }
+ CH_IS_BUFFER_MODE (type) = 1;
+ CH_TYPE_NONVALUE_P (type) = 1;
+ if (pass == 2)
+ type = layout_chill_struct_type (type);
+ return type;
+}
+
+#if 0
+tree
+build_buffer_descriptor (bufname, expr, optpriority)
+ tree bufname, expr, optpriority;
+{
+ tree bufdecl;
+
+ if (bufname == NULL_TREE
+ || TREE_CODE (bufname) == ERROR_MARK)
+ return error_mark_node;
+
+ if (expr != NULL_TREE
+ && TREE_CODE (expr) == ERROR_MARK)
+ return error_mark_node;
+#if 0
+/* FIXME: is this what we really want to test? */
+ bufdecl = lookup_name (bufname);
+ if (TREE_CODE (bufdecl) != TYPE_DECL
+ || ! CH_IS_BUFFER_MODE (TREE_TYPE (bufdecl)))
+ {
+ error ("SEND requires a BUFFER; `%s' is not a BUFFER name",
+ bufname);
+ return error_mark_node;
+ }
+#endif
+ {
+ /* build buffer/signal data structure */
+ tree bufdataname = get_unique_identifier (IDENTIFIER_POINTER (bufname));
+ tree dataptr;
+
+ if (expr == NULL_TREE)
+ dataptr = null_pointer_node;
+ else
+ {
+ tree decl =
+ decl_temp1 (bufdataname, TREE_TYPE (bufdecl), 0,
+ expr, 0, 0);
+ /* prevent granting of this variable */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ dataptr = force_addr_of (decl);
+ }
+
+ /* build descriptor pointing to buffer data */
+ {
+ tree tasking_message_var = get_unique_identifier (IDENTIFIER_POINTER (bufname));
+ tree data_len = (expr == NULL_TREE) ? integer_zero_node :
+ size_in_bytes (TREE_TYPE (bufdecl));
+ tree tasking_code = (tree)DECL_TASKING_CODE_DECL (bufdecl);
+ tree tuple = build_nt (CONSTRUCTOR, NULL_TREE,
+ tree_cons (NULL_TREE,
+ build1 (ADDR_EXPR,
+ build_chill_pointer_type (chill_integer_type_node),
+ tasking_code),
+ tree_cons (NULL_TREE, data_len,
+ tree_cons (NULL_TREE, dataptr, NULL_TREE))));
+
+ tree decl = decl_temp1 (tasking_message_var,
+ TREE_TYPE (tasking_message_type), 0,
+ tuple, 0, 0);
+ mark_addressable (tasking_code);
+ /* prevent granting of this variable */
+ DECL_SOURCE_LINE (decl) = 0;
+
+ tuple = force_addr_of (decl);
+ return tuple;
+ }
+ }
+}
+#endif
+
+#if 0
+void
+process_event_decls (namelist, mode, optstatic)
+ tree namelist, mode;
+ int optstatic;
+{
+ tree names;
+ int quasi_flag = current_module->is_spec_module;
+
+ if (pass < 2)
+ return;
+
+ for (names = namelist; names != NULL_TREE; names = TREE_CHAIN (names))
+ {
+ tree name = TREE_VALUE (names);
+ tree eventdecl = lookup_name (name);
+ tree code_decl =
+ decl_tasking_code_variable (name, &event_code, quasi_flag);
+
+ /* remember the code variable in the event decl */
+ DECL_TASKING_CODE_DECL (eventdecl) = (struct lang_decl *)code_decl;
+
+ add_taskstuff_to_list (code_decl, "_TT_Event",
+ quasi_flag ? NULL_TREE : event_code,
+ eventdecl);
+ }
+}
+#endif
+
+/* Return the buffer or event length of a buffer or event mode.
+ (NULL_TREE means unlimited.) */
+
+tree
+max_queue_size (mode)
+ tree mode;
+{
+ tree field = TYPE_FIELDS (mode);
+ for ( ; field != NULL_TREE ; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == CONST_DECL)
+ return DECL_INITIAL (field);
+ }
+ return NULL_TREE;
+}
+
+/* Return the buffer element mode of a buffer mode. */
+
+tree
+buffer_element_mode (bufmode)
+ tree bufmode;
+{
+ tree field = TYPE_FIELDS (bufmode);
+ for ( ; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == TYPE_DECL)
+ return TREE_TYPE (field);
+ }
+ return NULL_TREE;
+}
+
+/* invalidate buffer element mode in case we detect, that the
+ elelment mode has the non-value property */
+
+void
+invalidate_buffer_element_mode (bufmode)
+ tree bufmode;
+{
+ tree field = TYPE_FIELDS (bufmode);
+ for ( ; field != NULL_TREE; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == TYPE_DECL)
+ {
+ TREE_TYPE (field) = error_mark_node;
+ return;
+ }
+ }
+}
+
+/* For an EVENT or BUFFER mode TYPE, with a give maximum queue size QSIZE,
+ perform various error checks. Return a new queue size. */
+
+tree
+check_queue_size (type, qsize)
+ tree type, qsize;
+{
+ if (qsize == NULL_TREE || TREE_CODE (qsize) == ERROR_MARK)
+ return qsize;
+ if (TREE_TYPE (qsize) == NULL_TREE
+ || !CH_SIMILAR (TREE_TYPE (qsize), integer_type_node))
+ {
+ error ("non-integral max queue size for EVENT/BUFFER mode");
+ return integer_one_node;
+ }
+ if (TREE_CODE (qsize) != INTEGER_CST)
+ {
+ error ("non-constant max queue size for EVENT/BUFFER mode");
+ return integer_one_node;
+ }
+ if (compare_int_csts (pedantic ? LE_EXPR : LT_EXPR,
+ qsize,
+ integer_zero_node))
+ {
+ error ("max queue_size for EVENT/BUFFER is not positive");
+ return integer_one_node;
+ }
+ return qsize;
+}
+
+/*
+ * An EVENT type is modelled as a boolean type, which should
+ * allocate the minimum amount of space.
+ */
+tree
+build_event_type (queuesize)
+ tree queuesize;
+{
+ tree type = make_node (RECORD_TYPE);
+ tree field = build_decl (FIELD_DECL, get_identifier("__event_data"),
+ ptr_type_node);
+ TYPE_FIELDS (type) = field;
+ if (queuesize)
+ {
+ tree size_field = build_decl (CONST_DECL, get_identifier("__queue_max"),
+ integer_type_node);
+ DECL_INITIAL (size_field) = queuesize;
+ TREE_CHAIN (field) = size_field;
+ }
+ CH_IS_EVENT_MODE (type) = 1;
+ CH_TYPE_NONVALUE_P (type) = 1;
+ if (pass == 2)
+ type = layout_chill_struct_type (type);
+ return type;
+}
+
+/*
+ * Initialize the various types of tasking data.
+ */
+void
+tasking_init ()
+{
+ extern int ignore_case;
+ extern int special_UC;
+ extern tree chill_predefined_function_type;
+ tree temp, ins_ftype_void;
+ tree endlink = void_list_node;
+ tree int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int;
+ tree void_ftype_ptr;
+ tree void_ftype_ptr_ins_int_int_ptr_ptr_int;
+ tree int_ftype_ptr_ptr_int_ptr_ptr_int;
+ tree void_ftype_int_int_int_ptr_ptr_ptr_int;
+ tree int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int;
+ tree int_ftype_ptr_int;
+
+ /* type of tasking code variables */
+ chill_taskingcode_type_node = short_unsigned_type_node;
+
+ void_ftype_void =
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE, void_type_node, NULL_TREE));
+
+ build_instance_type ();
+ ins_ftype_void
+ = build_function_type (instance_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ build_tree_list (NULL_TREE, void_type_node)));
+
+ builtin_function ("__whoami", ins_ftype_void,
+ NOT_BUILT_IN, NULL_PTR);
+
+ build_tasking_message_type ();
+
+ temp = build_decl (TYPE_DECL,
+ get_identifier ("__tmp_TaskingStruct"),
+ build_tasking_struct ());
+ pushdecl (temp);
+ DECL_SOURCE_LINE (temp) = 0;
+
+ /* any SIGNAL will be compatible with this one */
+ generic_signal_type_node = copy_node (boolean_type_node);
+
+ builtin_function ((ignore_case || ! special_UC) ? "copy_number" : "COPY_NUMBER",
+ chill_predefined_function_type,
+ BUILT_IN_COPY_NUMBER, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_code" : "GEN_CODE",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_CODE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_inst" : "GEN_INST",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_INST, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "gen_ptype" : "GEN_PTYPE",
+ chill_predefined_function_type,
+ BUILT_IN_GEN_PTYPE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "proc_type" : "PROC_TYPE",
+ chill_predefined_function_type,
+ BUILT_IN_PROC_TYPE, NULL_PTR);
+ builtin_function ((ignore_case || ! special_UC) ? "queue_length" : "QUEUE_LENGTH",
+ chill_predefined_function_type,
+ BUILT_IN_QUEUE_LENGTH, NULL_PTR);
+
+ int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))))))));
+ void_ftype_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, endlink));
+
+ int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))))));
+
+ void_ftype_ptr_ins_int_int_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, instance_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))));
+ int_ftype_ptr_ptr_int_ptr_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)))))));
+
+ void_ftype_int_int_int_ptr_ptr_ptr_int
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink))))))));
+
+ int_ftype_ptr_int
+ = build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ endlink)));
+
+ builtin_function ("__delay_event", int_ftype_ptr_int_ptr_int_ptr_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__queue_length", int_ftype_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__register_tasking", void_ftype_ptr,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__send_signal", void_ftype_ptr_ins_int_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__send_buffer", int_ftype_ptr_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__start_process", void_ftype_int_int_int_ptr_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__stop_process", void_ftype_void, NOT_BUILT_IN,
+ NULL_PTR);
+ builtin_function ("__wait_buffer", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+ builtin_function ("__wait_signal_timed", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int,
+ NOT_BUILT_IN, NULL_PTR);
+
+ infinite_buffer_event_length_node = build_int_2 (-1, 0);
+ TREE_TYPE (infinite_buffer_event_length_node) = long_integer_type_node;
+ TREE_UNSIGNED (infinite_buffer_event_length_node) = 1;
+}