| /* Implement tasking-related actions for CHILL. |
| Copyright (C) 1992, 1993, 1994, 1998, 1999, 2000 |
| Free Software Foundation, Inc. |
| |
| This file is part of GNU CC. |
| |
| GNU CC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU CC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU CC; see the file COPYING. If not, write to |
| the Free Software Foundation, 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. */ |
| |
| #include "config.h" |
| #include "system.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" |
| #include "toplev.h" |
| |
| /* 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 */ |
| #if 0 |
| static void validate_process_parameters PARAMS ((tree)); |
| static tree get_struct_variable_name PARAMS ((tree)); |
| static tree decl_tasking_code_variable PARAMS ((tree, tree *, int)); |
| #endif |
| static tree get_struct_debug_type_name PARAMS ((tree)); |
| static tree get_process_wrapper_name PARAMS ((tree)); |
| static tree build_tasking_enum PARAMS ((void)); |
| static void build_tasking_message_type PARAMS ((void)); |
| static tree build_receive_signal_case_label PARAMS ((tree, tree)); |
| static tree build_receive_buffer_case_label PARAMS ((tree, tree)); |
| static void build_receive_buffer_case_end PARAMS ((tree, tree)); |
| static void build_receive_signal_case_end PARAMS ((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 */ |
| #define STRUCT_NAME "__tmp_%s_arg_type" |
| |
| /* name template for process arguments for debugging type */ |
| #define STRUCT_DEBUG_NAME "__tmp_%s_debug_type" |
| |
| /* name template for process argument variable */ |
| #define DATA_NAME "__tmp_%s_arg_variable" |
| |
| /* name template for process wrapper */ |
| #define WRAPPER_NAME "__tmp_%s_wrapper" |
| |
| /* name template for process code */ |
| #define SKELNAME "__tmp_%s_code" |
| |
| 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; |
| { |
| const char *idp = IDENTIFIER_POINTER (name); /* process name */ |
| char *tmpname = xmalloc (strlen (idp) + sizeof (STRUCT_NAME)); |
| |
| sprintf (tmpname, STRUCT_NAME, idp); |
| return get_identifier (tmpname); |
| } |
| |
| static tree |
| get_struct_debug_type_name (name) |
| tree name; |
| { |
| const char *idp = IDENTIFIER_POINTER (name); /* process name */ |
| char *tmpname = xmalloc (strlen (idp) + sizeof (STRUCT_DEBUG_NAME)); |
| |
| sprintf (tmpname, STRUCT_DEBUG_NAME, idp); |
| return get_identifier (tmpname); |
| } |
| |
| |
| tree |
| get_tasking_code_name (name) |
| tree name; |
| { |
| const char *name_str = IDENTIFIER_POINTER (name); |
| char *tmpname = (char *) alloca (IDENTIFIER_LENGTH (name) + |
| sizeof (SKELNAME)); |
| |
| sprintf (tmpname, SKELNAME, name_str); |
| return get_identifier (tmpname); |
| } |
| |
| #if 0 |
| static tree |
| get_struct_variable_name (name) |
| tree name; |
| { |
| const char *idp = IDENTIFIER_POINTER (name); /* process name */ |
| char *tmpname = xmalloc (strlen (idp) + sizeof (DATA_NAME)); |
| |
| sprintf (tmpname, DATA_NAME, idp); |
| return get_identifier (tmpname); |
| } |
| #endif |
| |
| static tree |
| get_process_wrapper_name (name) |
| tree name; |
| { |
| const char *idp = IDENTIFIER_POINTER (name); |
| char *tmpname = xmalloc (strlen (idp) + sizeof (WRAPPER_NAME)); |
| |
| 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 %ld out of range for `%s'", |
| (long) 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. |
| */ |
| #if 0 |
| static 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 %ld out of range for `%s'", |
| (long) 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; |
| } |
| #endif |
| |
| /* |
| * 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" |
| */ |
| |
| #if 0 |
| static void |
| validate_process_parameters (parms) |
| tree parms ATTRIBUTE_UNUSED; |
| { |
| } |
| #endif |
| |
| /* |
| * 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 = NULL_TREE, struct_type_node = NULL_TREE; |
| tree result; |
| tree valtail, typetail; |
| tree tuple = NULL_TREE, 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) |
| { |
| if (process_name) |
| error ("too many arguments to process `%s'", |
| IDENTIFIER_POINTER (process_name)); |
| else |
| error ("too many arguments to process"); |
| } |
| else if (typetail != 0 && TREE_VALUE (typetail) != void_type_node) |
| { |
| if (process_name) |
| error ("too few arguments to process `%s'", |
| IDENTIFIER_POINTER (process_name)); |
| else |
| error ("too few arguments to process"); |
| } |
| 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. */ |
| unsigned 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; |
| const 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))) |
| { |
| const 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); |
| } |
| |
| /* |
| * |
| * 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; |
| * |
| * |
| */ |
| |
| static void |
| build_tasking_message_type () |
| { |
| tree type_name; |
| tree temp; |
| /* We temporarily reset maximum_field_alignment to deal with |
| the runtime system. */ |
| unsigned 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", |
| IDENTIFIER_POINTER (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))))))))); |
| } |
| |
| /* |
| * 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: |
| * |
| */ |
| |
| 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 occurrence"); |
| 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 necessary, 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 occurrence 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 occurrence. |
| */ |
| static void |
| build_receive_buffer_case_end (buf_list, else_clause) |
| tree 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 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 (sig_list, else_clause) |
| tree 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 (alist, else_clause) |
| tree 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 (alist, else_clause); |
| else |
| build_receive_signal_case_end (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))))); |
| } |
| |
| /* |
| * 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 |
| * |
| */ |
| |
| 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 (event_list) |
| tree 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); |
| } |
| |
| /* |
| * 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 |
| */ |
| 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 (qsize) |
| tree 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, |
| 0, 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, BUILT_IN_NORMAL, NULL_PTR); |
| builtin_function ((ignore_case || ! special_UC) ? "gen_code" : "GEN_CODE", |
| chill_predefined_function_type, |
| BUILT_IN_GEN_CODE, BUILT_IN_NORMAL, NULL_PTR); |
| builtin_function ((ignore_case || ! special_UC) ? "gen_inst" : "GEN_INST", |
| chill_predefined_function_type, |
| BUILT_IN_GEN_INST, BUILT_IN_NORMAL, NULL_PTR); |
| builtin_function ((ignore_case || ! special_UC) ? "gen_ptype" : "GEN_PTYPE", |
| chill_predefined_function_type, |
| BUILT_IN_GEN_PTYPE, BUILT_IN_NORMAL, NULL_PTR); |
| builtin_function ((ignore_case || ! special_UC) ? "proc_type" : "PROC_TYPE", |
| chill_predefined_function_type, |
| BUILT_IN_PROC_TYPE, BUILT_IN_NORMAL, NULL_PTR); |
| builtin_function ((ignore_case || ! special_UC) ? "queue_length" : "QUEUE_LENGTH", |
| chill_predefined_function_type, |
| BUILT_IN_QUEUE_LENGTH, BUILT_IN_NORMAL, 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, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__queue_length", int_ftype_ptr_int, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__register_tasking", void_ftype_ptr, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__send_signal", void_ftype_ptr_ins_int_int_ptr_ptr_int, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__send_buffer", int_ftype_ptr_ptr_int_ptr_ptr_int, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__start_process", void_ftype_int_int_int_ptr_ptr_ptr_int, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__stop_process", void_ftype_void, 0, NOT_BUILT_IN, |
| NULL_PTR); |
| builtin_function ("__wait_buffer", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int, |
| 0, NOT_BUILT_IN, NULL_PTR); |
| builtin_function ("__wait_signal_timed", int_ftype_ptr_int_ptr_ptr_int_ptr_int_ptr_ptr_int, |
| 0, 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; |
| } |