diff options
Diffstat (limited to 'gcc/config/cil32/gen-cil.c')
-rw-r--r-- | gcc/config/cil32/gen-cil.c | 3562 |
1 files changed, 3562 insertions, 0 deletions
diff --git a/gcc/config/cil32/gen-cil.c b/gcc/config/cil32/gen-cil.c new file mode 100644 index 00000000000..0f74ce6ac88 --- /dev/null +++ b/gcc/config/cil32/gen-cil.c @@ -0,0 +1,3562 @@ +/* Dump of the GENERIC trees in CIL. + + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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. + +GCC 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 GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +Authors: + Andrea Bona + Andrea Ornstein + Erven Rohou + Roberto Costa + +Contact information at STMicroelectronics: +Roberto Costa <roberto.costa@st.com> */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "diagnostic.h" +#include "real.h" +#include "hashtab.h" +#include "tree-flow.h" +#include "langhooks.h" +#include "tree-iterator.h" +#include "tree-chrec.h" +#include "tree-pass.h" +#include "timevar.h" +#include "assert.h" +#include "toplev.h" +#include "pointer-set.h" +#include "output.h" +#include "varray.h" +#include "ggc.h" +#include "tree-simp-cil.h" +#include "gen-cil.h" + +/* Nonzero for a type which is at file scope. */ +#define TYPE_FILE_SCOPE_P(EXP) \ + (! TYPE_CONTEXT (EXP) \ + || TREE_CODE (TYPE_CONTEXT (EXP)) == TRANSLATION_UNIT_DECL) + +struct fnct_attr { + const char *assembly_name; + const char *cil_name; + const char *pinvoke_assembly; + const char *pinvoke_fname; +}; + +/* Local functions, macros and variables. */ +static void decode_function_attrs (tree, struct fnct_attr *); +static void mark_var_defs_uses (tree); +static void remove_stloc_ldloc (block_stmt_iterator, tree *, bool *); +static void mark_referenced_type (tree); +static void mark_referenced_string (tree); +static void dump_decl_name (FILE *, tree); +static void dump_string_name (FILE *, tree); +static void dump_label_name (FILE *, tree); +static void dump_fun_type (FILE *, tree, tree, const char *, bool); +static void dump_valuetype_name (FILE *, tree); +static void compute_addr_expr (FILE *, tree); +static void print_type_suffix (FILE *, tree, tree, bool); +static void gen_cil_modify_expr (FILE *, tree); +static char * append_string (char *, const char *, + unsigned int *, unsigned int *); +static char * append_coded_type (char *, tree, unsigned int *, unsigned int *); +static char * get_md5 (const char *, size_t, size_t *); +static tree make_valuetype_identifier (tree); +static void print_valuetype_decl (FILE *, tree); +static void dump_type (FILE *, tree, bool); +static void dump_type_promotion (FILE *, tree, bool); +static void dump_type_promoted_type_def (FILE *, tree, bool); +static void dump_type_for_builtin (FILE *, tree, bool); +static void dump_type_eval_mode (FILE *, tree, bool); + +static void stack_set (unsigned int) ATTRIBUTE_UNUSED; +static void stack_reset (void); +static void stack_push (unsigned int); +static void stack_pop (unsigned int); +static void gen_start_function (FILE *); +static unsigned int gen_cil (void); +static void gen_cil_1 (FILE *); +static void gen_cil_node (FILE *, tree); +static bool gen_cil_gate (void); +static void create_init_method(tree); + +static struct pointer_set_t *defd_vars; +static struct pointer_set_t *defd_more_than_once_vars; +static struct pointer_set_t *used_vars; +static struct pointer_set_t *used_more_than_once_vars; +static struct pointer_set_t *useless_vars; +static struct pointer_set_t *referenced_types; +static GTY(()) varray_type referenced_strings; +static struct pointer_set_t *referenced_string_ptrs; +static struct pointer_set_t *referenced_pinvoke; +static GTY(()) varray_type pending_ctors; +static unsigned int stack; +static unsigned int max_stack; + + +/* Recursively mark the definitions and the uses of the non-static + non-volatile local variables used in tree NODE. */ + +static void +mark_var_defs_uses (tree node) +{ + if (node == NULL_TREE) + return; /* ER: was spc */ + + switch (TREE_CODE (node)) + { + case COND_EXPR: + mark_var_defs_uses (COND_EXPR_COND (node)); + break; + + case SWITCH_EXPR: + mark_var_defs_uses (SWITCH_COND (node)); + break; + + case CALL_EXPR: + { + tree args = TREE_OPERAND (node, 1); + + mark_var_defs_uses (TREE_OPERAND (node, 0)); + + while (args) + { + mark_var_defs_uses (TREE_VALUE (args)); + args = TREE_CHAIN (args); + } + } + break; + + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case RDIV_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case LT_EXPR: + case GT_EXPR: + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case EXACT_DIV_EXPR: + case FLOOR_DIV_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case MAX_EXPR: + case MIN_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + mark_var_defs_uses (TREE_OPERAND (node, 0)); + mark_var_defs_uses (TREE_OPERAND (node, 1)); + break; + + case INIT_EXPR: + case MODIFY_EXPR: + { + tree lhs = TREE_OPERAND (node, 0); + tree rhs = TREE_OPERAND (node, 1); + + if (TREE_CODE (lhs) == VAR_DECL) + { + if (! TREE_ADDRESSABLE (lhs) + && ! TREE_STATIC (lhs) + && ! TREE_THIS_VOLATILE (lhs) + && ! DECL_FILE_SCOPE_P (lhs)) + { + if (!pointer_set_contains (defd_vars, lhs)) + pointer_set_insert (defd_vars, lhs); + else if (!pointer_set_contains (defd_more_than_once_vars, lhs)) + pointer_set_insert (defd_more_than_once_vars, lhs); + } + } + else + mark_var_defs_uses (lhs); + + mark_var_defs_uses (rhs); + gcc_assert (TREE_CODE (rhs) != CONSTRUCTOR + && TREE_CODE (rhs) != STRING_CST); + } + break; + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case CONVERT_EXPR: + case NOP_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case INDIRECT_REF: + case BIT_FIELD_REF: + case ADDR_EXPR: + case COMPONENT_REF: + case ABS_EXPR: + case RETURN_EXPR: + case WITH_SIZE_EXPR: + mark_var_defs_uses (TREE_OPERAND (node, 0)); + break; + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case VECTOR_CST: + case PARM_DECL: + case FUNCTION_DECL: + case LABEL_DECL: + case LABEL_EXPR: + case GOTO_EXPR: + case ASM_EXPR: + break; + + case VAR_DECL: + if (! TREE_ADDRESSABLE (node) + && ! TREE_STATIC (node) + && ! TREE_THIS_VOLATILE (node) + && ! DECL_FILE_SCOPE_P (node)) + { + if (! pointer_set_contains (used_vars, node)) + pointer_set_insert (used_vars, node); + else if (! pointer_set_contains (used_more_than_once_vars, node)) + pointer_set_insert (used_more_than_once_vars, node); + } + break; + + default: + fprintf (stderr, "mark_var_defs_uses: Cannot handle "); + debug_generic_expr (node); + gcc_assert (0); + } +} + +/* Avoids couple of useless stloc - ldloc from being emitted by removing + non-static non-volatile local variables used exactly once + throughout the entire function from tree NODE_PTR. + BSI is the statement iterator pointing to the statement containing NODE_PTR. + The bool pointed by MOD is set if the function changed anything, + otherwise its value is not modified. + This function works recursively, looking for VAR_DECLs corresponding + to local non-static non-volatile local variables used exactly once + in the function. + When such a variable is found, if its only definition is in + the statement immediately preceding BSI, then the use of the variable is + replaced by its definition (and that statement is removed). + By doing so, the code exits GIMPLE form; however, the CIL emission + mechanism is able to handle such a hybrid GIMPLE representation. */ + +static void +remove_stloc_ldloc (block_stmt_iterator bsi, tree *node_ptr, bool *mod) +{ + tree node = *node_ptr; + block_stmt_iterator prev_bsi; + + if (node == NULL_TREE) + return; /* ER: was spc */ + + /* Get iterator for the previous statememt */ + prev_bsi = bsi; + bsi_prev (&prev_bsi); + + /* No remotion is possible if the statement is the first in the block */ + if (bsi_end_p (prev_bsi)) + return; + + switch (TREE_CODE (node)) + { + case COND_EXPR: + remove_stloc_ldloc (bsi, &COND_EXPR_COND (node), mod); + break; + + case SWITCH_EXPR: + remove_stloc_ldloc (bsi, &SWITCH_COND (node), mod); + break; + + case CALL_EXPR: + { + tree args = TREE_OPERAND (node, 1); + + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); + + while (args) + { + remove_stloc_ldloc (bsi, &TREE_VALUE (args), mod); + args = TREE_CHAIN (args); + } + } + break; + + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case RDIV_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case LT_EXPR: + case GT_EXPR: + case EQ_EXPR: + case NE_EXPR: + case LE_EXPR: + case GE_EXPR: + case EXACT_DIV_EXPR: + case FLOOR_DIV_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case MAX_EXPR: + case MIN_EXPR: + case UNORDERED_EXPR: + case ORDERED_EXPR: + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 1), mod); + break; + + case INIT_EXPR: + case MODIFY_EXPR: + if (! AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0)))) + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 1), mod); + gcc_assert (TREE_CODE (TREE_OPERAND (node, 1)) != CONSTRUCTOR + && TREE_CODE (TREE_OPERAND (node, 1)) != STRING_CST); + break; + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case CONVERT_EXPR: + case NOP_EXPR: + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + case BIT_FIELD_REF: + case ABS_EXPR: + case RETURN_EXPR: + case WITH_SIZE_EXPR: + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); + break; + + case ADDR_EXPR: + case COMPONENT_REF: + if (! AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (node, 0)))) + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); + break; + + case INDIRECT_REF: + if (! AGGREGATE_TYPE_P (TREE_TYPE (node))) + remove_stloc_ldloc (bsi, &TREE_OPERAND (node, 0), mod); + break; + + case VAR_DECL: + if (! TREE_ADDRESSABLE (node) + && ! TREE_STATIC (node) + && ! TREE_THIS_VOLATILE (node) + && ! DECL_FILE_SCOPE_P (node)) + { + tree prev_stmt; + + /* Get the previous statement */ + prev_stmt = bsi_stmt (prev_bsi); + + /* If the variable is used exactly once and the definition + is in the previous statement, then remove it */ + if (TREE_CODE (prev_stmt) == MODIFY_EXPR + && TREE_OPERAND (prev_stmt, 0) == node + && pointer_set_contains (used_vars, node) + && ! pointer_set_contains (used_more_than_once_vars, node)) + { + /* If the definition is unique, set that + the variable has become useless. */ + if (! pointer_set_contains (defd_more_than_once_vars, node)) + pointer_set_insert (useless_vars, node); + + /* Replace variable's use with the definition */ + *node_ptr = TREE_OPERAND (prev_stmt, 1); + + /* Remove the previous statement */ + bsi_remove (&prev_bsi, true); + + /* Set that the function changed something */ + *mod = true; + } + } + break; + + default: + ; + } +} + + +/* stack_* functions are used to keep track of the number of elements + in the evaluation stack, in order to record the maximum number. + This is emitted in .maxstack directive for each function. */ + +/* Set that the evaluation stack contains n elements. */ + +static void +stack_set (unsigned int n) +{ + stack = n; + if (stack > max_stack) + max_stack = stack; +} + +/* Set that the evaluation stack is empty. */ + +static inline void +stack_reset (void) +{ + stack = 0; +} + +/* Add n elements to the evaluation stack. */ + +static void +stack_push (unsigned int n) +{ + stack += n; + if (stack > max_stack) + max_stack = stack; +} + +/* Remove n elements from the evaluation stack. */ + +static inline void +stack_pop (unsigned int n) +{ + gcc_assert (stack >= n); + stack -= n; +} + +/* Given the FUNCTION_DECL tree T, decode its CIL-specific function + attributes and record them in ATTRS. */ + +static void +decode_function_attrs (tree t, struct fnct_attr *attrs) +{ + tree tmp; + + gcc_assert (TREE_CODE (t) == FUNCTION_DECL); + + attrs->assembly_name = 0; + attrs->cil_name = 0; + attrs->pinvoke_assembly = 0; + attrs->pinvoke_fname = 0; + + tmp = DECL_ATTRIBUTES (t); + while (tmp) + { + const char *attr_name = IDENTIFIER_POINTER (TREE_PURPOSE (tmp)); + tree params = TREE_VALUE (tmp); + + if (strcmp (attr_name, "assembly_name") == 0) + attrs->assembly_name = TREE_STRING_POINTER (TREE_VALUE (params)); + else if (strcmp (attr_name, "cil_name") == 0) + attrs->cil_name = TREE_STRING_POINTER (TREE_VALUE (params)); + else if (strcmp (attr_name, "pinvoke") == 0) + { + attrs->pinvoke_assembly = TREE_STRING_POINTER (TREE_VALUE (params)); + if (TREE_CHAIN (params)) + attrs->pinvoke_fname = TREE_STRING_POINTER (TREE_VALUE (TREE_CHAIN (params))); + } + tmp = TREE_CHAIN (tmp); + } +} + +/* Mark the type represented by tree T as referenced. + This function works recursively, since types referenced by type T + itself are also marked as referenced. + Referenced types are emitted at the end of the compilation unit, + non-referenced types are not. + T must be a type node. */ + +static void +mark_referenced_type (tree t) +{ + t = TYPE_MAIN_VARIANT (t); + + /* If the type was already referenced, nothing else to do */ + if (pointer_set_contains (referenced_types, t)) + return; + + /* Give the aggregate a name unless it has it already */ + switch (TREE_CODE (t)) + { + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case ARRAY_TYPE: + if (TYPE_NAME (t) == 0) + { + tree type_decl = build0 (TYPE_DECL, t); + DECL_NAME (type_decl) = make_valuetype_identifier (t); + TYPE_NAME (t) = type_decl; + } + break; + + default: + /* Nothing to do for the other types */ + ; + } + + /* Transform local-scope types into global-scope types */ + if (!TYPE_FILE_SCOPE_P (t)) + { + tree type_name = TYPE_NAME (t); + const char *orig_name; + size_t tmp_name_max_len = 256; + size_t tmp_name_len = 0; + char *tmp_name; + char suffix[32]; + + gcc_assert (type_name != 0); + gcc_assert (DECL_P (type_name) + || TREE_CODE (type_name) == IDENTIFIER_NODE); + + if (TREE_CODE (type_name) == IDENTIFIER_NODE) + orig_name = IDENTIFIER_POINTER (type_name); + else + orig_name = IDENTIFIER_POINTER (DECL_NAME (type_name)); + + snprintf (suffix, 31, "?vt%lu", (unsigned long)t); + + tmp_name = (char *)xmalloc (tmp_name_max_len); + tmp_name = append_string (tmp_name, orig_name, + &tmp_name_len, &tmp_name_max_len); + tmp_name = append_string (tmp_name, suffix, + &tmp_name_len, &tmp_name_max_len); + + TYPE_NAME (t) = get_identifier_with_length (tmp_name, tmp_name_len); + TYPE_CONTEXT (t) = 0; + free (tmp_name); + } + + switch (TREE_CODE (t)) + { + case ENUMERAL_TYPE: + pointer_set_insert (referenced_types, t); + break; + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + tree tmp; + + pointer_set_insert (referenced_types, t); + tmp = TYPE_FIELDS (t); + + while (tmp) + { + mark_referenced_type (TREE_TYPE (tmp)); + tmp = TREE_CHAIN (tmp); + } + } + break; + + case POINTER_TYPE: + case REFERENCE_TYPE: + mark_referenced_type (TREE_TYPE (t)); + break; + + case ARRAY_TYPE: + pointer_set_insert (referenced_types, t); + mark_referenced_type (TREE_TYPE (t)); + break; + + case FUNCTION_TYPE: + { + tree args_type; + mark_referenced_type (TREE_TYPE (t)); + args_type = TYPE_ARG_TYPES (t); + while (args_type) + { + mark_referenced_type (TREE_VALUE (args_type)); + args_type = TREE_CHAIN (args_type); + } + } + break; + + default: + /* Nothing to do for the other types */ + ; + } +} + +/* Mark the string represented by tree T as referenced. + Referenced strings are emitted at the end of the compilation unit, + non-referenced strings are not. + T must be a STRING_CST node. */ + +static void +mark_referenced_string (tree t) +{ + gcc_assert (TREE_CODE (t) == STRING_CST); + if (!pointer_set_contains (referenced_string_ptrs, + (void *)(TREE_STRING_POINTER (t)))) + { + VARRAY_PUSH_TREE (referenced_strings, t); + pointer_set_insert (referenced_string_ptrs, + (void *)(TREE_STRING_POINTER (t))); + mark_referenced_type (TREE_TYPE (t)); + } +} + +/* Mark the function represented by tree T as a pinvoke. + T must be a FUNCTION_DECL node. */ + +void +cil_add_pinvoke (tree t) +{ + gcc_assert (TREE_CODE (t) == FUNCTION_DECL); + pointer_set_insert (referenced_pinvoke, t); + mark_referenced_type (TREE_TYPE (t)); +} + +/* Dump the name of a _DECL node. */ + +static void +dump_decl_name (FILE* file, tree node) +{ + gcc_assert (DECL_P (node) || TREE_CODE (node) == IDENTIFIER_NODE); + fputs ("'", file); + + if (DECL_ASSEMBLER_NAME_SET_P (node)) + { + fprintf (file, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node))); + } + else if (TREE_CODE (node) == IDENTIFIER_NODE) + fprintf (file, IDENTIFIER_POINTER (node)); + else if (DECL_NAME (node)) + { + mark_decl_referenced (node); + fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node))); + } + else + fprintf (file, "?UNNAMED%d", DECL_UID (node)); + + fputs ("'", file); +} + +/* Dump the name of a STRING_CST node. */ + +static void +dump_string_name (FILE* file, tree node) +{ + gcc_assert (TREE_CODE (node) == STRING_CST); + + fprintf (file, "'?string%lu'", (unsigned long)TREE_STRING_POINTER (node)); +} + +/* Dump the name of a label. */ + +static void +dump_label_name (FILE* file, tree node) +{ + /* Always print the label id. */ + fprintf (file, "?L" HOST_WIDE_INT_PRINT_DEC, LABEL_DECL_UID (node)); + + /* For convenience, also print the identifier when available. Note that the + identifier alone is incorrect: in case of inlining, several labels can + end up with the same id. */ + if (DECL_NAME (node)) + { + fputs ("_", file); + fprintf (file, IDENTIFIER_POINTER (DECL_NAME (node))); + } +} + +/* Dump the name of a valuetype. + T must be an aggregate type or an enumeral type, since these are + the types emitted as CIL valuetypes. */ + +static void +dump_valuetype_name (FILE *file, tree t) +{ + tree type_name; + + gcc_assert (AGGREGATE_TYPE_P (t) || TREE_CODE (t) == ENUMERAL_TYPE); + gcc_assert (TYPE_MAIN_VARIANT (t) == t); + gcc_assert (TYPE_FILE_SCOPE_P (t)); + gcc_assert (TYPE_NAME (t)); + + type_name = TYPE_NAME (t); + gcc_assert (DECL_P (type_name) || TREE_CODE (type_name) == IDENTIFIER_NODE); + + fputs ("'", file); + if (TREE_CODE (type_name) == IDENTIFIER_NODE) + fprintf (file, IDENTIFIER_POINTER (type_name)); + else if (DECL_NAME (type_name)) + fprintf (file, IDENTIFIER_POINTER (DECL_NAME (type_name))); + else + fprintf (file, "?UNNAMED%d", DECL_UID (type_name)); + fputs ("'", file); +} + +/* Dump the signature of function type FUN_TYPE. + The function name that is dumped is taken from function_decl FUN + or from NAME. Only and exactly one of the two must be non-null. + REF tells whether the function type (and the types of the return value + and of the incoming parameters) have to be marked as referenced. + FUN_TYPE must be a FUNCTION_TYPE. + FUN, if not null, must be a FUNCTION_DECL. */ + +static void +dump_fun_type (FILE *stream, tree fun_type, tree fun, const char *name, bool ref) +{ + tree args_type; + tree last_arg_type = NULL; + bool varargs = FALSE; + + gcc_assert (! (fun && name)); + + mark_referenced_type (fun_type); + + args_type = TYPE_ARG_TYPES (fun_type); + + if (args_type == NULL) + warning (0, + "Missing function %s prototype, guessing it, you should fix the code", + fun?IDENTIFIER_POINTER (DECL_NAME (fun)):""); + else + { + last_arg_type = args_type; + while (TREE_CHAIN (last_arg_type)) + last_arg_type = TREE_CHAIN (last_arg_type); + + if (TREE_VALUE (last_arg_type) != void_type_node) + { + last_arg_type = NULL; + varargs = TRUE; + } + } + + if (varargs) + fputs ("vararg ", stream); + + dump_type (stream, TREE_TYPE (fun_type), ref); + + fputs (" ", stream); + if (fun) + { + struct fnct_attr attrs; + + decode_function_attrs (fun, &attrs); + + if (attrs.assembly_name) + fprintf (stream, "[%s]", attrs.assembly_name); + else if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (fun)) + fputs ("[ExternalAssembly]ExternalAssembly::", stream); + + if (attrs.cil_name) + fprintf (stream, "%s", attrs.cil_name); + else + dump_decl_name (stream, fun); + } + + if (name) + fputs (name, stream); + + fputs ("(", stream); + + while (args_type != last_arg_type) + { + dump_type (stream, TREE_VALUE (args_type), ref); + args_type = TREE_CHAIN (args_type); + + if (args_type != last_arg_type) + fputs (", ", stream); + } + + if (varargs) + fputs (", ...", stream); + + fputs (")", stream); +} + +/* Dump type NODE. + REF tells whether the function type (and the types of the return value + and of the incoming parameters) have to be marked as referenced. + NODE must be a type node. */ + +static void +dump_type (FILE *file, tree node, bool ref) +{ +/* node = TYPE_MAIN_VARIANT (node); */ + + if (TYPE_MAIN_VARIANT (node) == va_list_type_node) { + fputs ("valuetype [mscorlib]System.ArgIterator", file); + return; + } + + switch (TREE_CODE (node)) + { + case ENUMERAL_TYPE: + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + node = TYPE_MAIN_VARIANT (node); + + /* Reference the type if told to do so */ + if (ref) + mark_referenced_type (node); + + /* Print the name of the structure. */ + fputs ("valuetype ", file); + dump_valuetype_name (file, node); + break; + + case VOID_TYPE: + fputs ("void", file); + break; + + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + if (TYPE_UNSIGNED (node)) + fputs ("unsigned ", file); + + switch (type_size) + { + case 8: fputs ("int8", file); break; + case 16: fputs ("int16", file); break; + case 32: fputs ("int32", file); break; + case 64: fputs ("int64", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + break; + + case REAL_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + switch (type_size) + { + case 32: fputs ("float32", file); break; + case 64: fputs ("float64", file); break; + default: + fprintf (stderr, "Unsupported floating point size %d\n", type_size); + gcc_assert (0); + } + } + break; + + case BOOLEAN_TYPE: + fputs ("int8", file); + break; + + case POINTER_TYPE: + if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE) + { + fputs ("method ", file); + dump_fun_type (file, TREE_TYPE (node), NULL, " * ", ref); + } + else + { + dump_type (file, TREE_TYPE (node), ref); + fputs (" *", file); + } + break; + + case FUNCTION_TYPE: +/* dump_fun_type (file, node, NULL, NULL, ref); */ + gcc_assert (0); + break; + + case VECTOR_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + tree innertype = TREE_TYPE (node); + enum machine_mode innermode = TYPE_MODE (innertype); + + /* Only expect integer vectors */ + gcc_assert (GET_MODE_CLASS (innermode) == MODE_INT); + + /* and emit as corresponding same-size integer mode */ + if (TYPE_UNSIGNED (node)) + fputs ("unsigned ", file); + + switch (type_size) + { + case 8: fputs ("int8", file); break; + case 16: fputs ("int16", file); break; + case 32: fputs ("int32", file); break; + case 64: fputs ("int64", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + break; + + case COMPLEX_TYPE: + case REFERENCE_TYPE: + + default: + fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]); + gcc_assert (0); + break; + } +} + +/* Dump type NODE, promoted following C conventions for var args. + REF tells whether the function type (and the types of the return value + and of the incoming parameters) have to be marked as referenced. + NODE must be a type node. */ + +static void +dump_type_promotion (FILE *file, tree node, bool ref) +{ + + switch (TREE_CODE (node)) + { + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + node = TYPE_MAIN_VARIANT (node); + + /* Reference the type if told to do so */ + if (ref) + mark_referenced_type (node); + + /* Print the name of the structure. */ + fputs ("valuetype ", file); + dump_valuetype_name (file, node); + break; + + case ENUMERAL_TYPE: + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + if (TYPE_UNSIGNED (node)) + { + switch (type_size) + { + case 8: + case 16: fputs ("int32", file); break; + case 32: fputs ("unsigned int32", file); break; + case 64: fputs ("unsigned int64", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + else + { + switch (type_size) + { + case 8: + case 16: + case 32: fputs ("int32", file); break; + case 64: fputs ("int64", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + } + break; + + case REAL_TYPE: + fputs ("float64", file); + break; + + case BOOLEAN_TYPE: + fputs ("int32", file); + break; + + case POINTER_TYPE: + fputs ("native int", file); + break; + + default: + fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]); + gcc_assert (0); + break; + } +} + +/* Dump the type def of type NODE, promoted following C conventions + for var args. + REF tells whether the function type (and the types of the return value + and of the incoming parameters) have to be marked as referenced. + NODE must be a type node. */ + +static void +dump_type_promoted_type_def (FILE *stream, tree node, bool ref) +{ + switch (TREE_CODE (node)) + { + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + node = TYPE_MAIN_VARIANT (node); + + /* Reference the type if told to do so */ + if (ref) + mark_referenced_type (node); + + /* Print the name of the structure. */ + fputs ("valuetype ", stream); + dump_valuetype_name (stream, node); + break; + + case ENUMERAL_TYPE: + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + if (TYPE_UNSIGNED (node)) + { + switch (type_size) + { + case 8: + case 16: fputs ("class [mscorlib]System.Int32", stream); break; + case 32: fputs ("class [mscorlib]System.UInt32", stream); break; + case 64: fputs ("class [mscorlib]System.UInt64", stream); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + else + { + switch (type_size) + { + case 8: + case 16: + case 32: fputs ("class [mscorlib]System.Int32", stream); break; + case 64: fputs ("class [mscorlib]System.Int64", stream); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + } + break; + + case REAL_TYPE: + fputs ("class [mscorlib]System.Double", stream); + break; + + case BOOLEAN_TYPE: + fputs ("class [mscorlib]System.Int32", stream); + break; + + case POINTER_TYPE: + fputs ("class [mscorlib]System.IntPtr", stream); + break; + + default: + fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]); + gcc_assert (0); + break; + } +} + +static void +dump_type_for_builtin (FILE *file, tree node, bool all_types) +{ +/* node = TYPE_MAIN_VARIANT (node); */ + + switch (TREE_CODE (node)) + { + case ENUMERAL_TYPE: + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + if (TYPE_UNSIGNED (node)) + fputs ("unsigned ", file); + + switch (type_size) + { + case 8: if (all_types) { fputs ("int8", file); return; } + case 16: if (all_types) { fputs ("int16", file); return; } + case 32: fputs ("int32", file); break; + case 64: fputs ("int64", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + break; + + case REAL_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + switch (type_size) + { + case 32: fputs ("float32", file); break; + case 64: fputs ("float64", file); break; + default: + fprintf (stderr, "Unsupported floating point size %d\n", type_size); + gcc_assert (0); + } + } + break; + + default: + fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]); + gcc_assert (0); + break; + } +} + +static void +dump_type_eval_mode (FILE *stream, tree node, bool all_types) +{ + switch (TREE_CODE (node)) + { + case ENUMERAL_TYPE: + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + switch (type_size) + { + case 8: if (all_types) { fputs ("qi", stream); break; } + case 16: if (all_types) { fputs ("hi", stream); break; } + case 32: fputs ("si", stream); break; + case 64: fputs ("ti", stream); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + } + } + break; + + case REAL_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (node)); + + switch (type_size) + { + case 32: fputs ("sf", stream); break; + case 64: fputs ("df", stream); break; + default: + fprintf (stderr, "Unsupported floating point size %d\n", + type_size); + gcc_assert (0); + } + } + break; + + default: + fprintf (stderr, "%s: %s\n", __func__, tree_code_name[TREE_CODE (node)]); + gcc_assert (0); + break; + } +} + +static void +compute_addr_expr (FILE *file, tree t) +{ + switch (TREE_CODE (t)) + { + case STRING_CST: + mark_referenced_string (t); + fputs ("\n\tldsflda\t", file); + dump_type (file, TREE_TYPE (t), true); + fputs (" ", file); + dump_string_name (file, t); + stack_push (1); + break; + + case VAR_DECL: + if (!DECL_FILE_SCOPE_P (t)) + fputs ("\n\tldloca\t", file); + else + { + fputs ("\n\tldsflda\t", file); + if (COMPLETE_TYPE_P (TREE_TYPE (t))) + dump_type (file, TREE_TYPE (t), true); + else + fputs ("native int", file); + fputs (" ", file); + if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (t)) + fputs ("[ExternalAssembly]ExternalAssembly::", file); + } + + dump_decl_name (file, t); + stack_push (1); + break; + + case PARM_DECL: + fputs ("\n\tldarga\t", file); + dump_decl_name (file, t); + stack_push (1); + break; + + case FUNCTION_DECL: + fputs ("\n\tldftn\t", file); + dump_fun_type (file, TREE_TYPE (t), t, NULL, true); + stack_push (1); + break; + + case INDIRECT_REF: + gen_cil_node (file, TREE_OPERAND (t, 0)); + break; + + case COMPONENT_REF: + { + tree obj = TREE_OPERAND (t, 0); + tree fld = TREE_OPERAND (t, 1); + tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj)); + + gcc_assert (! DECL_BIT_FIELD (fld)); + + compute_addr_expr (file, obj); + fputs ("\n\tldflda\t", file); + dump_type (file, TREE_TYPE (fld), true); + fputs (" ", file); + mark_referenced_type (obj_type); + dump_valuetype_name (file, obj_type); + fputs ("::", file); + dump_decl_name (file, fld); + } + break; + + case BIT_FIELD_REF: + { + tree obj = TREE_OPERAND (t, 0); + unsigned int off = TREE_INT_CST_LOW (TREE_OPERAND (t, 2)); + + gcc_assert (off % 8 == 0); + compute_addr_expr (file, obj); + if (off / 8 > 0) + { + fprintf (file, "\n\tldc.i4\t%d", off / 8); + fputs ("\n\tadd", file); + stack_push (1); + stack_pop (1); + } + } + break; + + default: + fprintf (stderr, "%s: [7m%s[m\n", + __func__, tree_code_name[TREE_CODE (t)]); + gcc_assert (0); + } + + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + fputs ("\n\tconv.i", file); +} + +static void +print_type_suffix (FILE *file, tree type_node, tree conv_in_type, bool unsign) +{ + int type_size = GET_MODE_BITSIZE (TYPE_MODE (type_node)); + + switch (TREE_CODE (type_node)) + { + case ENUMERAL_TYPE: + case INTEGER_TYPE: + { + bool uns = false; + + if (TYPE_UNSIGNED (type_node) + || (conv_in_type != NULL_TREE + && TYPE_UNSIGNED (conv_in_type) + && type_size > GET_MODE_BITSIZE (TYPE_MODE (conv_in_type)))) + uns = unsign; + + switch (type_size) + { + case 8: fputs ((uns)?"u1":"i1", file); break; + case 16: fputs ((uns)?"u2":"i2", file); break; + case 32: fputs ((uns)?"u4":"i4", file); break; + case 64: fputs ((uns)?"u8":"i8", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + break; + } + } + break; + + case REAL_TYPE: + switch (type_size) + { + case 32: fputs ("r4", file); break; + case 64: fputs ("r8", file); break; + default: + fprintf (stderr, "Unsupported floating point size %d\n", type_size); + gcc_assert (0); + break; + } + break; + + case POINTER_TYPE: + fputs ("i", file); + break; + + case VECTOR_TYPE: + { + bool uns = false; + tree innertype = TREE_TYPE (type_node); + enum machine_mode innermode = TYPE_MODE (innertype); + + /* Only expect integer vectors */ + gcc_assert (GET_MODE_CLASS (innermode) == MODE_INT); + + /* and then emit as corresponding same-size interger mode */ + if (TYPE_UNSIGNED (type_node) && unsign) + uns = true; + + switch (type_size) + { + case 8: fputs ((uns)?"u1":"i1", file); break; + case 16: fputs ((uns)?"u2":"i2", file); break; + case 32: fputs ((uns)?"u4":"i4", file); break; + case 64: fputs ((uns)?"u8":"i8", file); break; + default: + fprintf (stderr, "Unsupported integer size %d\n", type_size); + gcc_assert (0); + break; + } + break; + } + + default: + internal_error ("print_type_suffix %s\n", + tree_code_name[TREE_CODE (type_node)]); + gcc_assert (0); + break; + } +} + +/* Dump the node NODE in CIL on the file FILE. */ +static void +gen_cil_node (FILE *file, tree node) +{ + tree op0, op1; + + if (node == NULL_TREE) + return; /* ER: was spc */ + + if (TARGET_EMIT_GIMPLE_COMMENTS && EXPR_HAS_LOCATION (node)) + { + expanded_location xloc = expand_location (EXPR_LOCATION (node)); + if (xloc.file) + fprintf (file, "\n\t/* [file:%s,line:%d] */", xloc.file, xloc.line); + else + fprintf (file, "\n\t/* [line:%d] */", xloc.line); + } + + switch (TREE_CODE (node)) + { + case INTEGER_CST: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (node))); + + switch (type_size) + { + case 8: + case 16: + case 32: + fprintf (file, "\n\tldc.i4\t%ld", TREE_INT_CST_LOW (node)); + break; + + case 64: + fprintf (file, "\n\tldc.i8\t%ld", TREE_INT_CST_LOW (node)); + break; + + default: + internal_error ("\nldc: unsupported int size %d\n", type_size); + break; + } + if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) + fputs ("\n\tconv.i", file); + stack_push (1); + } + break; + + case REAL_CST: + { + REAL_VALUE_TYPE d; + tree type_tree; + int type_size; + enum machine_mode mode; + char string[100]; + /* we have 32 and 64 bit reals, real_to_format fills 32 bits per long */ + long buf[2]; + + d = TREE_REAL_CST (node); + type_tree = TREE_TYPE (node); + mode = TYPE_MODE (type_tree); + real_to_target (buf, &d, mode); + real_to_decimal (string, &d, sizeof (string), 5, 1); + type_size = GET_MODE_BITSIZE (TYPE_MODE (type_tree)); + + switch (type_size) + { + case 32: + fprintf (file, "\n\tldc.r4\tfloat32(%#08lx)", buf[0]); + break; + + case 64: + fprintf (file, "\n\tldc.r8\tfloat64(%#08lx%08lx)", buf[1], buf[0]); + break; + + default: + internal_error ("\nldc.r: unsupported float size %d\n", type_size); + break; + } + fprintf (file, " /* %s */", string); + stack_push (1); + break; + } + + case VECTOR_CST: + { + tree elt; + unsigned int val = 0; + tree vector_type = TREE_TYPE (node); + int vector_bitsize = GET_MODE_BITSIZE (TYPE_MODE (vector_type)); + tree unit_type = TREE_TYPE (vector_type); + int unit_bitsize = GET_MODE_BITSIZE (TYPE_MODE (unit_type)); + + /* At this time, support only 32 bit vectors */ + if (vector_bitsize != 32) + internal_error ("\nVECTOR_CST size %d\n", vector_bitsize); + + for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt)) + { + tree elt_val = TREE_VALUE (elt); + switch (TREE_CODE (elt_val)) + { + case INTEGER_CST: + val = (val << unit_bitsize) | TREE_INT_CST_LOW (elt_val); + break; + + default: + internal_error ("\nldc: unsupported VECTOR_CST type\n"); + break; + } + } + + fprintf (file, "\n\tldc.i4\t%#0x", val); + stack_push (1); + break; + } + + case LABEL_DECL: + internal_error ("use dump_label_name instead of gen_cil_node\n"); + break; + + case INIT_EXPR: + case MODIFY_EXPR: + gen_cil_modify_expr (file, node); + break; + + case GOTO_EXPR: + fputs ("\n\tbr ", file); + dump_label_name (file, GOTO_DESTINATION (node)); + gcc_assert (stack == 0); + break; + + case COND_EXPR: + /* At this point, both clauses of COND_EXPR must contain simple gotos */ + gcc_assert (TREE_CODE (COND_EXPR_THEN (node)) == GOTO_EXPR + && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR); + + op0 = COND_EXPR_COND (node); + if (TREE_CODE (op0) == LE_EXPR + || TREE_CODE (op0) == LT_EXPR + || TREE_CODE (op0) == GE_EXPR + || TREE_CODE (op0) == GT_EXPR + || TREE_CODE (op0) == EQ_EXPR + || TREE_CODE (op0) == NE_EXPR) + + { + tree op00 = TREE_OPERAND (op0, 0); + tree op01 = TREE_OPERAND (op0, 1); + bool is_unsigned = TYPE_UNSIGNED (TREE_TYPE (op00)); + gen_cil_node (file, op00); + gen_cil_node (file, op01); + switch (TREE_CODE (op0)) + { + case LE_EXPR: fputs ("\n\tble", file); break; + case LT_EXPR: fputs ("\n\tblt", file); break; + case GE_EXPR: fputs ("\n\tbge", file); break; + case GT_EXPR: fputs ("\n\tbgt", file); break; + case EQ_EXPR: fputs ("\n\tbeq", file); is_unsigned = FALSE; break; + case NE_EXPR: fputs ("\n\tbne", file); is_unsigned = TRUE; break; + default: + gcc_unreachable (); + } + + if (is_unsigned) + fputs (".un\t", file); + else + fputs ("\t", file); + dump_label_name (file, GOTO_DESTINATION (COND_EXPR_THEN (node))); + stack_pop (2); + } + else + { + gen_cil_node (file, op0); + fputs ("\n\tldc.i4.0" + "\n\tbne.un\t", file); + dump_label_name (file, GOTO_DESTINATION (COND_EXPR_THEN (node))); + stack_push (1); + stack_pop (2); + } + + fputs ("\n\tbr\t", file); + dump_label_name (file, GOTO_DESTINATION (COND_EXPR_ELSE (node))); + gcc_assert (stack == 0); + break; + + case SWITCH_EXPR: + { + tree vec = SWITCH_LABELS (node); + unsigned int vec_len, i; + bool first_case = true; + tree min_val = 0, max_val = 0; + double_int max_min_diff; + unsigned int switch_n; + tree default_label; + tree *labels; + + /* The switch body is lowered in gimplify.c, we should never have + switches with a non-NULL SWITCH_BODY here. */ + gcc_assert (vec && !SWITCH_BODY (node)); + vec_len = TREE_VEC_LENGTH (vec); + + /* Compute range of cases */ + for (i = 0; i < vec_len - 1 ; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + tree low = CASE_LOW (elt); + tree high = CASE_HIGH (elt); + + if (!high) + high = low; + + gcc_assert (low && high); + + /* Discard empty ranges. */ + if (INT_CST_LT (high, low)) + continue; + + if (first_case) + { + min_val = low; + max_val = high; + first_case = false; + } + else + { + if (INT_CST_LT (low, min_val)) + min_val = low; + + if (INT_CST_LT (max_val, high)) + max_val = high; + } + } + gcc_assert (!INT_CST_LT (max_val, min_val)); + + /* Get the default label */ + gcc_assert (!CASE_HIGH (TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec)- 1))); + gcc_assert (!CASE_LOW (TREE_VEC_ELT (vec, TREE_VEC_LENGTH (vec) - 1))); + default_label = CASE_LABEL (TREE_VEC_ELT (vec, + TREE_VEC_LENGTH (vec) - 1)); + + /* Prepare a table with the label for each value of the condition */ + max_min_diff = double_int_add (double_int_neg (TREE_INT_CST (min_val)), + TREE_INT_CST (max_val)); + gcc_assert (max_min_diff.high == 0 && max_min_diff.low < 8192); + switch_n = max_min_diff.low + 1; + gcc_assert (switch_n > 0); + labels = (tree*)xmalloc (switch_n * sizeof (tree)); + + for (i=0 ; i < switch_n; ++i) + labels[i] = default_label; + + for (i = 0; i < vec_len - 1 ; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + tree low = CASE_LOW (elt); + tree high = CASE_HIGH (elt); + double_int low_val, high_val, end, j; + double_int minus_min_val = double_int_neg (TREE_INT_CST (min_val)); + + if (!high) + high = low; + + gcc_assert (low && high); + + /* Discard empty ranges. */ + if (INT_CST_LT (high, low)) + continue; + + low_val = TREE_INT_CST (low); + high_val = TREE_INT_CST (high); + end = double_int_add (high_val, double_int_one); + + for (j = low_val; + !double_int_equal_p (j, end); + j = double_int_add (j, double_int_one) + ) + { + double_int norm_j = double_int_add (j, minus_min_val); + + gcc_assert (norm_j.high == 0 && norm_j.low < 8192); + labels[norm_j.low] = CASE_LABEL (elt); + } + } + + /* Emit switch condition */ + gen_cil_node (file, SWITCH_COND (node)); + + /* Emit subtraction to normalize the condition */ + if (!double_int_equal_p (TREE_INT_CST (min_val), double_int_zero)) + { + double_int min = TREE_INT_CST (min_val); + + fputs ("\n\tldc.i4\t", file); + + if (double_int_negative_p (min)) + { + dump_double_int (file, double_int_neg (min), false); + fputs ("\n\tadd", file); + } + else + { + dump_double_int (file, min, false); + fputs ("\n\tsub", file); + } + + stack_push (1); + stack_pop (1); + } + + /* Emit switch instruction */ + fputs ("\n\tswitch\t(", file); + for (i=0 ; i < switch_n; ++i) + { + dump_label_name (file, labels[i]); + if (i < switch_n - 1) + fputs (", ", file); + } + fputs (")", file); + stack_pop (1); + + /* Emit branch for default label */ + fputs ("\n\tbr\t", file); + dump_label_name (file, default_label); + gcc_assert (stack == 0); + } + break; + + case CALL_EXPR: + { + tree fun_expr = TREE_OPERAND (node, 0); + tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr)); + bool direct_call = (TREE_CODE (fun_expr) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (fun_expr, 0)) == FUNCTION_DECL); + tree args; + tree args_type; + tree last_arg_type; + bool varargs; + unsigned int nargs = 0; + tree dfun = 0; + + if (direct_call) + dfun = TREE_OPERAND (fun_expr, 0); + + /* Built-in functions must be handled in a special way */ + if (dfun && DECL_BUILT_IN (dfun)) + { + bool done = false; + gcc_assert (direct_call); + + if (DECL_BUILT_IN_CLASS (dfun) == BUILT_IN_MD) + { + switch (DECL_FUNCTION_CODE (dfun)) + { + case CIL32_BUILTIN_VA_ARG: + { + tree args = TREE_OPERAND (node, 1); + tree va = TREE_VALUE (args); + tree dummy = TREE_VALUE (TREE_CHAIN (args)); + tree type = TREE_TYPE (TREE_TYPE (dummy)); + + gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (va)) == va_list_type_node); + compute_addr_expr (file, va); + fputs ("\n\tcall\tinstance typedref [mscorlib]System.ArgIterator::GetNextArg()" + "\n\trefanyval ", + file); + + dump_type_promoted_type_def (file, type, true); + done = true; + } + break; + + default: + gcc_assert (0); + } + } + else + { + switch (DECL_FUNCTION_CODE (dfun)) + { + case BUILT_IN_VA_START: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); + + /* A lowering phase should have checked that va + has no side effects. */ + gcc_assert (! TREE_SIDE_EFFECTS (va)); + + gcc_assert (TREE_CODE (va) == ADDR_EXPR); + compute_addr_expr (file, TREE_OPERAND (va, 0)); + fputs ("\n\tinitobj\tvaluetype [mscorlib]System.ArgIterator", + file); + + stack_pop (1); + + compute_addr_expr (file, TREE_OPERAND (va, 0)); + fputs ("\n\targlist" + "\n\tcall\tinstance void " + "[mscorlib]System.ArgIterator::.ctor(valuetype " + "[mscorlib]System.RuntimeArgumentHandle)", + file); + + stack_push (1); + stack_pop (2); + done = true; + } + break; + + case BUILT_IN_VA_END: + { + tree va = TREE_VALUE (TREE_OPERAND (node, 1)); + + gcc_assert (TREE_CODE (va) == ADDR_EXPR); + compute_addr_expr (file, TREE_OPERAND (va, 0)); + fputs ("\n\tcall\tinstance void [mscorlib]System.ArgIterator::End()", + file); + + stack_pop (1); + done = true; + } + break; + + case BUILT_IN_VA_COPY: + { + tree args = TREE_OPERAND (node, 1); + tree va_dest = TREE_VALUE (args); + tree va_src = TREE_VALUE (TREE_CHAIN (args)); + + gen_cil_node (file, va_src); + + /* A lowering phase should have checked that the destination + in va_copy is a local variable. */ + gcc_assert (TREE_CODE (va_dest) == ADDR_EXPR); + gcc_assert (TREE_CODE (TREE_OPERAND (va_dest, 0)) == VAR_DECL + && !DECL_FILE_SCOPE_P (TREE_OPERAND (va_dest, 0))); + fputs ("\n\tstloc\t", file); + dump_decl_name (file, TREE_OPERAND (va_dest, 0)); + + stack_pop (1); + done = true; + } + break; + + case BUILT_IN_MEMSET: + { + tree args = TREE_OPERAND (node, 1); + + tree ptr = TREE_VALUE (args); + tree value = TREE_VALUE (TREE_CHAIN (args)); + tree size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + + gen_cil_node (file, ptr); + fputs ("\n\tdup", file); + stack_push (1); + + gen_cil_node (file, value); + gen_cil_node (file, size); + + fputs ("\n\tunaligned. 1" + "\n\tinitblk", file); + stack_pop (3); + done = true; + } + break; + + case BUILT_IN_MEMCPY: + { + tree args = TREE_OPERAND (node, 1); + + tree ptr_dst = TREE_VALUE (args); + tree ptr_src = TREE_VALUE (TREE_CHAIN (args)); + tree size = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))); + + gen_cil_node (file, ptr_dst); + fputs ("\n\tdup", file); + stack_push (1); + + gen_cil_node (file, ptr_src); + gen_cil_node (file, size); + + fputs ("\n\tunaligned. 1" + "\n\tcpblk", file); + stack_pop (3); + done = true; + } + break; + + case BUILT_IN_ALLOCA: + { + tree args = TREE_OPERAND (node, 1); + tree size = TREE_VALUE (args); + + gen_cil_node (file, size); + fputs ("\n\tlocalloc", file); + + done = true; + } + break; + + default: + if (DECL_ASSEMBLER_NAME_SET_P (node)) + { + /* Go Ahead as a normal function call */ + } +/* else */ +/* { */ +/* fprintf (stderr, */ +/* "unsupported builtin: %s\n", */ +/* IDENTIFIER_POINTER (DECL_NAME (dfun))); */ +/* gcc_assert (0); */ +/* } */ + } + } + + if (done) + break; + } + + /* Print parameters. */ + args = TREE_OPERAND (node, 1); + while (args) + { + gen_cil_node (file, TREE_VALUE (args)); + args = TREE_CHAIN (args); + } + + /* Print function pointer, in case of indirect call */ + if (!direct_call) + gen_cil_node (file, fun_expr); + +#if 0 + op1 = TREE_OPERAND (node, 2); + if (op1) + { + gcc_assert (0); + fprintf (file, " [static-chain: "); + gen_cil_node (file, op1); + fprintf (file, "%c", ']'); + } + + if (0 && CALL_EXPR_RETURN_SLOT_OPT (node)) + fprintf (file, " [return slot optimization]"); +#endif + + fprintf (file, "\n\t"); +#if 0 + if (CALL_EXPR_TAILCALL (node)) + fprintf (file, "tail."); +#endif + if (direct_call) + fputs ("call\t", file); + else + fputs ("calli\t", file); + + args_type = TYPE_ARG_TYPES (fun_type); + last_arg_type = 0; + varargs = FALSE; + + if (args_type == NULL) + { + if (direct_call) + warning (0, + "Missing function %s prototype, guessing it, " + "you should fix the code", + IDENTIFIER_POINTER (DECL_NAME (dfun))); + else + warning (0, + "Missing indirect function prototype, guessing it, " + "you should fix the code"); + } + + else + { + last_arg_type = args_type; + + while (TREE_CHAIN (last_arg_type)) + last_arg_type = TREE_CHAIN (last_arg_type); + + if (TREE_VALUE (last_arg_type) != void_type_node) + { + last_arg_type = 0; + varargs = TRUE; + } + } + + if (varargs) + fputs ("vararg ", file); + + dump_type (file, TREE_TYPE (fun_type), true); + + if (direct_call) + { + struct fnct_attr attrs; + decode_function_attrs (dfun, &attrs); + + fputs (" ", file); + + if (attrs.assembly_name) + fprintf (file, "[%s]", attrs.assembly_name); + else if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (dfun)) + fputs ("[ExternalAssembly]ExternalAssembly::", file); + + if (attrs.cil_name) + fprintf (file, "%s", attrs.cil_name); + else + dump_decl_name (file, dfun); + } + + fputs (" (", file); + args = TREE_OPERAND (node, 1); + + while (args_type != last_arg_type) + { + ++nargs; + dump_type (file, TREE_VALUE (args_type), true); + args = TREE_CHAIN (args); + args_type = TREE_CHAIN (args_type); + if (args_type != last_arg_type) + fputs (", ", file); + } + + if (varargs && args) + fputs (", ..., ", file); + + while (args) + { + ++nargs; + dump_type_promotion (file, TREE_TYPE (TREE_VALUE (args)), true); + args = TREE_CHAIN (args); + if (args) + fputs (", ", file); + } + + fputs (")", file); + + if (direct_call) + stack_pop (nargs); + else + stack_pop (nargs + 1); + + if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE) + stack_push (1); + + break; + } + + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case RDIV_EXPR: + case LSHIFT_EXPR: + case BIT_XOR_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + switch (TREE_CODE (node)) + { + case MULT_EXPR: fputs ("\n\tmul", file); break; + case PLUS_EXPR: fputs ("\n\tadd", file); break; + case MINUS_EXPR: fputs ("\n\tsub", file); break; + case RDIV_EXPR: fputs ("\n\tdiv", file); break; + case LSHIFT_EXPR: fputs ("\n\tshl", file); break; + case BIT_XOR_EXPR: fputs ("\n\txor", file); break; + default: + gcc_unreachable (); + } + + /* Values smaller than 32-bits are represented as 32-bit + on the evaluation stack, therefore an explicit conversion + is required. */ + if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) < 32) + { + fputs ("\n\tconv.", file); + print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true); + } + + stack_pop (1); + break; + + case BIT_IOR_EXPR: + case BIT_AND_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + switch (TREE_CODE (node)) + { + case BIT_IOR_EXPR: fputs ("\n\tor", file); break; + case BIT_AND_EXPR: fputs ("\n\tand", file); break; + default: + gcc_unreachable (); + } + + /* No need for conversions even in case of values smaller + than 32-bits, since for these operations the output is + always less or equal than both operands. */ + + stack_pop (1); + break; + + case LT_EXPR: + case GT_EXPR: + case EQ_EXPR: + case NE_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + switch (TREE_CODE (node)) + { + case LT_EXPR: + fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tclt.un":"\n\tclt", file); + break; + + case GT_EXPR: + fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tcgt.un":"\n\tcgt", file); + break; + + case EQ_EXPR: fputs ("\n\tceq", file); break; + case NE_EXPR: fputs ("\n\tceq" + "\n\tldc.i4.1" + "\n\txor", file); break; + + default: + gcc_unreachable (); + } + + if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) == 64) + fputs ("\n\tconv.i8", file); + + stack_pop (1); + break; + + + case LE_EXPR: + case GE_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + switch (TREE_CODE (node)) + { + case LE_EXPR: + fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tcgt.un":"\n\tcgt", file); + break; + + case GE_EXPR: + fputs (TYPE_UNSIGNED (TREE_TYPE (op0))?"\n\tclt.un":"\n\tclt", file); + break; + + default: + gcc_unreachable (); + } + + fputs ("\n\tldc.i4.1" + "\n\txor", file); + + if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) == 64) + fputs ("\n\tconv.i8", file); + + stack_pop (1); + break; + + case EXACT_DIV_EXPR: + case TRUNC_DIV_EXPR: + case TRUNC_MOD_EXPR: + case RSHIFT_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + switch (TREE_CODE (node)) + { + case EXACT_DIV_EXPR: + case TRUNC_DIV_EXPR: fputs ("\n\tdiv", file); break; + case TRUNC_MOD_EXPR: fputs ("\n\trem", file); break; + case RSHIFT_EXPR: fputs ("\n\tshr", file); break; + default: + gcc_unreachable (); + } + + if (TYPE_UNSIGNED (TREE_TYPE (node))) + fputs (".un", file); + + /* No need for conversions even in case of values smaller + than 32-bits, since for these operations the output is + always less or equal than both operands. */ + + stack_pop (1); + break; + + case FLOOR_DIV_EXPR: + { + bool is_signed0, is_signed1; + + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + is_signed0 = TYPE_UNSIGNED (TREE_TYPE (op0)); + is_signed1 = TYPE_UNSIGNED (TREE_TYPE (op1)); + /* If both operands are unsigned, the result is positive and thus + rounding towards zero is identical to towards -infinity. */ + if (is_signed0 && is_signed1) + { + fputs ("\n\tdiv.un", file); + } + else + { + fputs ("\n\tcall\t int32 [gcc4net]gcc4net.Crt::floordiv(", file); + dump_type_for_builtin (file, TREE_TYPE (op0), true); + fputs (", ", file); + dump_type_for_builtin (file, TREE_TYPE (op1), true); + fputs (")", file); + } + + /* No need for conversions even in case of values smaller + than 32-bits, since for this operation the output is + always less or equal than both operands. */ + + stack_pop (1); + break; + } + + case NEGATE_EXPR: + case BIT_NOT_EXPR: + gen_cil_node (file, TREE_OPERAND (node, 0)); + + switch (TREE_CODE (node)) + { + case NEGATE_EXPR: fputs ("\n\tneg", file); break; + case BIT_NOT_EXPR: fputs ("\n\tnot", file); break; + default: + gcc_unreachable (); + } + + /* Values smaller than 32-bits are represented as 32-bit + on the evaluation stack, therefore an explicit conversion + is required. + Unfortunately this is true for the negation as well just + for the case in which the operand is the smallest negative value. + Example: 8-bit negation of -128 gives 0 and not 128. */ + if (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (node))) < 32) + { + fputs ("\n\tconv.", file); + print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true); + } + + break; + + case INDIRECT_REF: + case BIT_FIELD_REF: + compute_addr_expr (file, node); + fputs ("\n\tldind.", file); + print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true); + break; + + case CONVERT_EXPR: + /* ER: if flag_trapv is set, we could generate the .ovf version? */ + /* TODO: */ + gen_cil_node (file, TREE_OPERAND (node, 0)); + fputs ("\n\tconv.", file); + print_type_suffix (file, TREE_TYPE (node), TREE_TYPE (TREE_OPERAND (node, 0)), true); + break; + + case NOP_EXPR: + { + enum tree_code out_type_code = TREE_CODE (TREE_TYPE (node)); + + gen_cil_node (file, TREE_OPERAND (node, 0)); + + if (out_type_code == INTEGER_TYPE + || out_type_code == ENUMERAL_TYPE + || out_type_code == REAL_TYPE + || out_type_code == POINTER_TYPE) + { + fputs ("\n\tconv.", file); + print_type_suffix (file, TREE_TYPE (node), + TREE_TYPE (TREE_OPERAND (node, 0)), true); + } + } + break; + + case LABEL_EXPR: + op0 = TREE_OPERAND (node, 0); + /* If this is for break or continue, don't bother printing it. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + break; + } + fprintf (file, "\n"); + dump_label_name (file, op0); + fprintf (file, ":"); + + if (DECL_NONLOCAL (op0)) + fprintf (file, " [non-local]"); + + break; + + case RETURN_EXPR: + op0 = TREE_OPERAND (node, 0); + if (op0) + { +/* dump_generic_node (file, op0); */ + if (TREE_CODE (op0) == MODIFY_EXPR) + gen_cil_node (file, TREE_OPERAND (op0, 1)); + else + gen_cil_node (file, op0); + } + + /* Pre-C99 code may contain void-returns for non-void functions, + but the simplification pass should already have avoided this. */ + gcc_assert (op0 + || TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) + == VOID_TYPE); + + fputs ("\n\tret", file); + stack_reset (); + break; + + case ASM_EXPR: + { + /* support just a simple string, no input/output/clober */ + tree asm_string = ASM_STRING (node); + const char *str = TREE_STRING_POINTER (asm_string); + + fputs ("\n\t", file); + fputs (str, file); + break; + } + + case MIN_EXPR: + case MAX_EXPR: + { + tree node_type = TREE_TYPE (node); + + gcc_assert (!TARGET_EXPAND_MINMAX); + + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + gen_cil_node (file, op1); + + /* emit a call */ + fputs ("\n\tcall\t", file); + dump_type_for_builtin (file, node_type, false); + fputs (" [gcc4net]gcc4net.Crt::__", file); + + if (TYPE_UNSIGNED (node_type)) + fputs ("u", file); + + if (TREE_CODE (node) == MIN_EXPR) + fputs ("min", file); + else + fputs ("max", file); + + dump_type_eval_mode (file, node_type, false); + fputs ("3(", file); + dump_type_for_builtin (file, TREE_TYPE (op0), false); + fputs (", ", file); + dump_type_for_builtin (file, TREE_TYPE (op1), false); + fputs (")", file); + stack_pop (1); + } + break; + + case ABS_EXPR: + { + tree node_type = TREE_TYPE (node); + + gcc_assert (!TARGET_EXPAND_ABS); + + op0 = TREE_OPERAND (node, 0); + gen_cil_node (file, op0); + + /* emit a call */ + fputs ("\n\tcall\t", file); + dump_type_for_builtin (file, node_type, false); + fputs (" [gcc4net]gcc4net.Crt::__abs", file); + dump_type_eval_mode (file, node_type, false); + fputs ("2(", file); + dump_type_for_builtin (file, TREE_TYPE (op0), false); + fputs (")", file); + } + break; + + case SSA_NAME: + gcc_assert (0); + break; + + case VAR_DECL: + mark_referenced_type (TREE_TYPE (node)); + + if (!DECL_FILE_SCOPE_P (node)) + fputs ("\n\tldloc\t", file); + else + { + fputs ("\n\tldsfld\t", file); + dump_type (file, TREE_TYPE (node), true); + fputs (" ", file); + if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (node)) + fputs ("[ExternalAssembly]ExternalAssembly::", file); + } + + dump_decl_name (file, node); + stack_push (1); + break; + + case PARM_DECL: + mark_referenced_type (TREE_TYPE (node)); + fputs ("\n\tldarg\t", file); + dump_decl_name (file, node); + stack_push (1); + break; + + case FIELD_DECL: + case NAMESPACE_DECL: + fprintf (stderr, "CIL: Cannot handle FIELD_DECL or NAMESPACE_DECL: "); + dump_decl_name (stderr, node); + gcc_assert (0); + break; + + case TREE_LIST: + gcc_assert (0); + break; + + case FUNCTION_DECL: + case CONST_DECL: + gcc_assert (0); + break; + + case ADDR_EXPR: + compute_addr_expr (file, TREE_OPERAND (node, 0)); + break; + + case COMPONENT_REF: + { + tree obj = TREE_OPERAND (node, 0); + tree fld = TREE_OPERAND (node, 1); + tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj)); + tree fld_type = TREE_TYPE (fld); + + gcc_assert (TREE_CODE (fld) == FIELD_DECL); + gcc_assert (! DECL_BIT_FIELD (fld)); + + compute_addr_expr (file, obj); + fputs ("\n\tldfld\t", file); + dump_type (file, fld_type, true); + fputs (" ", file); + mark_referenced_type (obj_type); + dump_valuetype_name (file, obj_type); + fputs ("::", file); + dump_decl_name (file, fld); + } + break; + + case FLOAT_EXPR: + case FIX_TRUNC_EXPR: + gen_cil_node (file, TREE_OPERAND (node, 0)); + fputs ("\n\tconv.", file); + print_type_suffix (file, TREE_TYPE (node), NULL_TREE, true); + break; + + case TRUTH_NOT_EXPR: + gen_cil_node (file, TREE_OPERAND (node, 0)); + fputs ("\n\tldc.i4.0" + "\n\tceq", file); + stack_push (1); + stack_pop (1); + break; + + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + gen_cil_node (file, op0); + if (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE) + { + fputs ("\n\tldc.i4.0" + "\n\tceq" + "\n\tldc.i4.1" + "\n\txor", file); + stack_push (1); + stack_pop (1); + } + + gen_cil_node (file, op1); + if (TREE_CODE (TREE_TYPE (op1)) == INTEGER_TYPE) + { + fputs ("\n\tldc.i4.0" + "\n\tceq" + "\n\tldc.i4.1" + "\n\txor", file); + stack_push (1); + stack_pop (1); + } + + if (TREE_CODE (node) == TRUTH_AND_EXPR) + fputs ("\n\tand", file); + else if (TREE_CODE (node) == TRUTH_OR_EXPR) + fputs ("\n\tor", file); + else + fputs ("\n\txor" + "\n\tldc.i4.1" + "\n\tand", file); + stack_pop (1); + break; + + case ENUMERAL_TYPE: + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case VECTOR_TYPE: + case BOOLEAN_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + internal_error ("gen_cil_node does not support TYPE nodes," + " to dump Type name use dump_type.\n"); + break; + + default: + internal_error ("\n\nUnsupported tree in CIL generation: '[7m%s[m'\n", + tree_code_name[TREE_CODE (node)]); + break; + } +} + +static void +gen_cil_modify_expr (FILE *file, tree node) +{ + tree lhs = TREE_OPERAND (node, 0); + tree rhs = TREE_OPERAND (node, 1); + + if (AGGREGATE_TYPE_P (TREE_TYPE (rhs)) + && (TREE_CODE (lhs) == INDIRECT_REF || TREE_CODE (rhs) == INDIRECT_REF)) + { + gcc_assert (AGGREGATE_TYPE_P (TREE_TYPE (lhs))); + compute_addr_expr (file, lhs); + compute_addr_expr (file, rhs); + fprintf (file, "\n\tldc.i4\t%lu", + TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (rhs)))); + fputs ("\n\tcall\tvoid [gcc4net]gcc4net.Crt::memcpy(void*, void*, int32)",file); + stack_push (1); + stack_pop (3); + return; + } + + switch (TREE_CODE (lhs)) + { + case SSA_NAME: + gcc_assert (0); + break; + + case INDIRECT_REF: + compute_addr_expr (file, lhs); + gen_cil_node (file, rhs); + fputs ("\n\tstind.", file); + print_type_suffix (file, TREE_TYPE (lhs), NULL_TREE, false); + stack_pop (2); + break; + + case VAR_DECL: + mark_referenced_type (TREE_TYPE (lhs)); + gen_cil_node (file, rhs); + + if (!DECL_FILE_SCOPE_P (lhs)) + fputs ("\n\tstloc\t", file); + else + { + fputs ("\n\tstsfld\t", file); + dump_type (file, TREE_TYPE (lhs), true); + fputs (" ", file); + if (TARGET_EMIT_EXTERNAL_ASSEMBLY && DECL_EXTERNAL (lhs)) + fputs ("[ExternalAssembly]ExternalAssembly::", file); + } + dump_decl_name (file, lhs); + + stack_pop (1); + break; + + case PARM_DECL: + gen_cil_node (file, rhs); + fputs ("\n\tstarg\t", file); + dump_decl_name (file, lhs); + stack_pop (1); + break; + + case COMPONENT_REF: + { + tree obj = TREE_OPERAND (lhs, 0); + tree fld = TREE_OPERAND (lhs, 1); + tree obj_type = TYPE_MAIN_VARIANT (TREE_TYPE (obj)); + tree fld_type = TREE_TYPE (fld); + + gcc_assert (TREE_CODE (fld) == FIELD_DECL); + gcc_assert (! DECL_BIT_FIELD (fld)); + + compute_addr_expr (file, obj); + gen_cil_node (file, rhs); + mark_referenced_type (obj_type); + fputs ("\n\tstfld\t", file); + dump_type (file, fld_type, true); + fputs (" ", file); + dump_valuetype_name (file, obj_type); + fputs ("::", file); + dump_decl_name (file, fld); + stack_pop (2); + } + break; + + default: +/* { */ +/* fprintf (stderr, " [7m LHS [m "); */ +/* gen_cil_node (file, lhs); */ +/* break; */ +/* } */ + fprintf (stderr, "CIL: Cannot handle lhs: "); + debug_generic_expr (lhs); + gcc_assert (0); + } +} + +/* Warning: these strings are not null-terminated */ +static char * +append_string (char *str, const char *to_append, + unsigned int *len, unsigned int *max_len) +{ + size_t i, orig_len = *len; + size_t append_len = strlen (to_append); + + *len += append_len; + + if (*len > *max_len) + { + while (*len > *max_len) + *max_len *= 2; + str = (char *)xrealloc (str, *max_len); + } + + for (i=0; i < append_len; ++i) + str[orig_len + i] = to_append[i]; + + return str; +} + +/* Warning: these strings are not null-terminated */ +static char * +append_coded_type (char *str, tree type, + unsigned int *len, unsigned int *max_len) +{ + encode_type: + type = TYPE_MAIN_VARIANT (type); + + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (type)); + char tmp_str[8] = "UI"; + char *tmp_str_ptr = tmp_str; + + snprintf (tmp_str_ptr + 2, 6, "%d", type_size); + + if (!TYPE_UNSIGNED (type)) + ++tmp_str_ptr; + + str = append_string (str, tmp_str_ptr, len, max_len); + } + break; + + case REAL_TYPE: + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (type)); + char tmp_str[4] = "F"; + + snprintf (tmp_str + 1, 3, "%d", type_size); + + str = append_string (str, tmp_str, len, max_len); + } + break; + + case POINTER_TYPE: + str = append_string (str, "*", len, max_len); + type = TREE_TYPE (type); + goto encode_type; + + case ARRAY_TYPE: + str = append_string (str, "[", len, max_len); + if (TYPE_DOMAIN (type)) + { + tree domain = TYPE_DOMAIN (type); + tree min = TYPE_MIN_VALUE (domain); + tree max = TYPE_MAX_VALUE (domain); + + if (min && max + && integer_zerop (min) + && host_integerp (max, 0)) + { + unsigned int size = TREE_INT_CST_LOW (max) + 1; + char tmp_str[32]; + + snprintf (tmp_str, 32, "%d", size); + str = append_string (str, tmp_str, len, max_len); + } + else + str = append_string (str, "unk", len, max_len); + } + str = append_string (str, "]", len, max_len); + type = TREE_TYPE (type); + goto encode_type; + + case ENUMERAL_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + const char *prefix; + const char *type_str; + tree type_name; + + /* Give the aggregate a name unless it has it already */ + if (TYPE_NAME (type) == 0) + { + tree type_decl = build0 (TYPE_DECL, type); + DECL_NAME (type_decl) = make_valuetype_identifier (type); + TYPE_NAME (type) = type_decl; + } + + type_name = TYPE_NAME (type); + + if (TREE_CODE (type_name) == IDENTIFIER_NODE) + type_str = IDENTIFIER_POINTER (type_name); + else + type_str = IDENTIFIER_POINTER (DECL_NAME (type_name)); + + switch (TREE_CODE (type)) + { + case ENUMERAL_TYPE: + prefix = "E"; + break; + + case RECORD_TYPE: + prefix = "S"; + break; + + case UNION_TYPE: + case QUAL_UNION_TYPE: + prefix = "UN"; + break; + + default: + gcc_assert (0); + prefix = "error"; + } + + str = append_string (str, prefix, len, max_len); + str = append_string (str, type_str, len, max_len); + } + break; + + default: + str = append_string (str, "unknown", len, max_len); + } + + return str; +} + +static char * +get_md5 (const char *str, size_t len, size_t *md5_len) +{ + char *md5_str; + + /* TODO: unimplemented */ + *md5_len = len; + md5_str = (char *)xmalloc (len); + memcpy (md5_str, str, len); + + return md5_str; +} + +static tree +make_valuetype_identifier (tree t) +{ + size_t tmp_name_max_len = 256; + size_t tmp_name_len = 0; + char *tmp_name; + size_t vt_name_len = 0; + char *vt_name; + tree ident; + + tmp_name = (char *)xmalloc (tmp_name_max_len); + + if (TREE_CODE (t) == ENUMERAL_TYPE) + { + tree tmp; + + tmp_name = append_string (tmp_name, "enum?", + &tmp_name_len, &tmp_name_max_len); + + tmp = TYPE_VALUES (t); + + while (tmp) + { + tmp_name = append_string (tmp_name, + IDENTIFIER_POINTER (TREE_PURPOSE (tmp)), + &tmp_name_len, &tmp_name_max_len); + tmp_name = append_string (tmp_name, "?", + &tmp_name_len, &tmp_name_max_len); + tmp = TREE_CHAIN (tmp); + } + } + else if (TREE_CODE (t) == ARRAY_TYPE) + { + tmp_name = append_string (tmp_name, "array?", + &tmp_name_len, &tmp_name_max_len); + tmp_name = append_coded_type (tmp_name, t, + &tmp_name_len, &tmp_name_max_len); + } + else + { + tree tmp; + + if (TREE_CODE (t) == RECORD_TYPE) + tmp_name = append_string (tmp_name, "struct?", + &tmp_name_len, &tmp_name_max_len); + else + tmp_name = append_string (tmp_name, "union?", + &tmp_name_len, &tmp_name_max_len); + + tmp = TYPE_FIELDS (t); + while (tmp) + { + tree ttype = TREE_TYPE (tmp); + + tmp_name = append_coded_type (tmp_name, ttype, + &tmp_name_len, &tmp_name_max_len); + tmp_name = append_string (tmp_name, "?", + &tmp_name_len, &tmp_name_max_len); + if (DECL_NAME (tmp) != 0) + tmp_name = append_string (tmp_name, + IDENTIFIER_POINTER (DECL_NAME (tmp)), + &tmp_name_len, &tmp_name_max_len); + else + /* Unnamed bitfields or unions */ + tmp_name = append_string (tmp_name, "?unnamed", + &tmp_name_len, &tmp_name_max_len); + tmp_name = append_string (tmp_name, "?", + &tmp_name_len, &tmp_name_max_len); + tmp = TREE_CHAIN (tmp); + } + } + + vt_name = get_md5 (tmp_name, tmp_name_len, &vt_name_len); + free (tmp_name); + + ident = get_identifier_with_length (vt_name, vt_name_len); + free (vt_name); + + return ident; +} + +static void +print_valuetype_decl (FILE *file, tree t) +{ + bool is_enum; + + if (!AGGREGATE_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE) + return; + + if (file == 0) + return; + + gcc_assert (TYPE_MAIN_VARIANT (t) == t); + gcc_assert (TYPE_NAME (t)); + + is_enum = (TREE_CODE (t) == ENUMERAL_TYPE); + + /* Print the name of the valuetype. */ + fputs ("\n.class ", file); + + if (TYPE_FILE_SCOPE_P (t)) + fputs ("public ", file); + else + fputs ("private ", file); + + if (!is_enum) + fputs ("explicit ", file); + + fputs ("sealed serializable ansi ", file); + dump_valuetype_name (file, t); + fputs (" extends ['mscorlib']System.", file); + + if (is_enum) + fputs ("Enum\n", file); + else + fputs ("ValueType\n", file); + + /* Print the contents of the valuetype. */ + fputs ("{\n", file); + + if (is_enum) + { + int type_size = GET_MODE_BITSIZE (TYPE_MODE (t)); + char tmp_str[8] = "int"; + char *base_type_str = tmp_str; + tree tmp; + + snprintf (base_type_str + 3, 5, "%d", type_size); + + fputs ("\t.field public specialname rtspecialname ", file); + + if (!TYPE_UNSIGNED (t)) + fputs ("unsigned ", file); + + fprintf (file, "%s 'value__'\n", base_type_str); + + tmp = TYPE_VALUES (t); + while (tmp) + { + fputs ("\t.field public static literal ", file); + dump_type (file, t, false); + fputs (" ", file); + dump_decl_name (file, TREE_PURPOSE (tmp)); + fprintf (file, " = %s(%ld)\n", + base_type_str, TREE_INT_CST_LOW (TREE_VALUE (tmp))); + tmp = TREE_CHAIN (tmp); + } + } + else if (TREE_CODE (t) == ARRAY_TYPE) + { + /* array */ + fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t))); + fprintf (file, "\t.pack %u\n", TYPE_ALIGN_UNIT (t)); + fputs ("\t.field [0] public specialname ", file); + dump_type (file, TREE_TYPE (t), false); + fputs (" 'elem__'\n", file); + } + else + { + /* struct and union */ + tree tmp; + + fprintf (file, "\t.size %ld\n", TREE_INT_CST_LOW (TYPE_SIZE_UNIT (t))); + fprintf (file, "\t.pack %u\n", TYPE_ALIGN_UNIT (t)); + + tmp = TYPE_FIELDS (t); + while (tmp) + { + tree type; + unsigned int bit_offset = + TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (tmp)); + unsigned int byte_offset = + TREE_INT_CST_LOW (DECL_FIELD_OFFSET (tmp)); + unsigned int offset; + + /* Skip unnamed bitfields */ + if (DECL_NAME (tmp) == 0 && DECL_BIT_FIELD (tmp)) + goto next; + + if (DECL_BIT_FIELD (tmp)) + { + unsigned int type_size; + + type = DECL_BIT_FIELD_TYPE (tmp); + + gcc_assert (TREE_CODE (TREE_TYPE (tmp)) == INTEGER_TYPE + || TREE_CODE (TREE_TYPE (tmp)) == BOOLEAN_TYPE); + gcc_assert (TREE_CODE (type) == INTEGER_TYPE + || TREE_CODE (type) == BOOLEAN_TYPE + || TREE_CODE (type) == ENUMERAL_TYPE); + + type_size = TREE_INT_CST_LOW (TYPE_SIZE (type)); + offset = byte_offset + (bit_offset & ~(type_size - 1)) / 8; + } + else + { + type = TREE_TYPE (tmp); + gcc_assert (bit_offset % 8 == 0); + offset = byte_offset + bit_offset / 8; + } + + fprintf (file, "\t.field [%d] public ", offset); + dump_type (file, type, false); + fputs (" ", file ); + dump_decl_name (file, tmp); + fputs ("\n", file); + next: + tmp = TREE_CHAIN (tmp); + } + } + + fputs ("}\n", file); +} + +static void +print_string_decl (FILE *file, tree t) +{ + const char *str; + int len, i; + + gcc_assert (TREE_CODE (t) == STRING_CST); + str = TREE_STRING_POINTER (t); + len = TREE_STRING_LENGTH (t); + + mark_referenced_type (TREE_TYPE (t)); + + /* Emit the string in readable form as a comment. */ + fputs ("// string: \"", file); + for (i=0; i < len-1; ++i) + { + switch (str[i]) { + case '\n': fputs ("\\n", file); break; + case '"': fputs ("\"", file); break; + default: fputc (str[i], file); break; + } + } + fputs ("\"\n", file); + + fprintf (file, ".data 'DataStr%lu' = bytearray(", + (unsigned long)TREE_STRING_POINTER (t)); + for (i=0; i < len; ++i) + fprintf (file, "%02x ", str[i]); + fputs (")\n", file); + + fputs (".field private static ", file); + dump_type (file, TREE_TYPE (t), true); + fputs (" ", file); + dump_string_name (file, t); + fprintf (file, " at 'DataStr%lu'\n", + (unsigned long)TREE_STRING_POINTER (t)); +} + +static void +gen_start_function (FILE *stream) +{ + int nargs; + tree args; + for (nargs=0,args = DECL_ARGUMENTS (current_function_decl); + args; + args = TREE_CHAIN (args),++nargs) + { + } + + fputs ("\n.method public static void '.start'(class [mscorlib]System.String[] 'args') cil managed", + stream); + fputs ("\n{" + "\n\t.entrypoint" + "\n\t.maxstack 2" + "\n\t.locals (int32 'argc', int8** 'argv')", stream); + /* TODO: add startup code*/ + switch (nargs) + { + case 0: + fputs ("\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()" + "\n\tcall\tint32 main()", stream); + break; + + case 1: + fputs ("\n\tldloca\t'argc'" + "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)" + "\n\tpop" + "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()" + "\n\tldloc\t'argc'" + "\n\tcall\tint32 main(int32)", stream); + break; + + case 2: + fputs ("\n\tldloca\t'argc'" + "\n\tcall\tnative int [gcc4net]gcc4net.StartupHelper::GetArgv(int32&)" + "\n\tstloc\t'argv'" + "\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Startup()" + "\n\tldloc\t'argc'" + "\n\tldloc\t'argv'" + "\n\tcall\tint32 main(int32, int8**)", stream); + break; + + default: + gcc_assert (0); + } + + /* TODO: add exit code*/ + fputs ("\n\tcall\tvoid [gcc4net]gcc4net.StartupHelper::Shutdown(int32)" + "\n\tret" + "\n} // .start" + "\n\n", stream); +} + +static void +gen_cil_1 (FILE *stream) +{ + basic_block bb; + block_stmt_iterator bsi; + bool varargs = FALSE; + tree args; + + /* Mark defs and uses of local non-static variables */ + defd_vars = pointer_set_create (); + defd_more_than_once_vars = pointer_set_create (); + used_vars = pointer_set_create (); + used_more_than_once_vars = pointer_set_create (); + FOR_EACH_BB (bb) + { + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + mark_var_defs_uses (bsi_stmt (bsi)); + } + } + pointer_set_destroy (defd_vars); + + /* Remove useless pairs of stloc - ldloc */ + useless_vars = pointer_set_create (); + FOR_EACH_BB (bb) + { + /* Start from the second statement, if any */ + bsi = bsi_start (bb); + if (! bsi_end_p (bsi)) + bsi_next (&bsi); + + for (; !bsi_end_p (bsi); bsi_next (&bsi)) + { + bool changed; + + /* Remove stloc - ldloc pairs until no change is done + to the current statement */ + do { + changed = false; + remove_stloc_ldloc (bsi, bsi_stmt_ptr (bsi), &changed); + } while (changed); + } + } + pointer_set_destroy (defd_more_than_once_vars); + pointer_set_destroy (used_vars); + pointer_set_destroy (used_more_than_once_vars); + + /* Remove useless vars (only used in removed stloc - ldloc pairs) */ + { + tree cell, prev_cell = NULL_TREE; + + for (cell = cfun->unexpanded_var_list; + cell; + cell = TREE_CHAIN (cell)) + { + tree var = TREE_VALUE (cell); + + if (pointer_set_contains (useless_vars, var)) + { + if (prev_cell == NULL_TREE) + cfun->unexpanded_var_list = TREE_CHAIN (cell); + else + TREE_CHAIN (prev_cell) = TREE_CHAIN (cell); + } + else + prev_cell = cell; + } + } + pointer_set_destroy (useless_vars); + + stack_reset (); + max_stack = 0; + + if (strcmp ("main", + lang_hooks.decl_printable_name (current_function_decl, 1)) == 0) + gen_start_function (stream); + + { + tree var, cell; + + for (cell = cfun->unexpanded_var_list; + cell; + cell = TREE_CHAIN (cell)) + { + var = TREE_VALUE (cell); + + if (TREE_STATIC (var) && TREE_ASM_WRITTEN (var) == 0) + make_decl_cil (stream, var); + } + } + + { + tree args_type = TYPE_ARG_TYPES (TREE_TYPE (current_function_decl)); + + if (args_type != NULL) + { + while (TREE_CHAIN (args_type)) + args_type = TREE_CHAIN (args_type); + + if (TREE_VALUE (args_type) != void_type_node) + varargs = TRUE; + } + } + + fputs ("\n.method ", stream); + + if (TREE_PUBLIC (current_function_decl)) + fputs ("public ", stream); + else + fputs ("private ", stream); + + fputs ("static ", stream); + if (varargs) + fputs ("vararg ", stream); + dump_type (stream, TREE_TYPE (TREE_TYPE (current_function_decl)), true); + fprintf (stream, " '%s' (", + lang_hooks.decl_printable_name (current_function_decl, 1)); + + args = DECL_ARGUMENTS (current_function_decl); + + while (args) + { + dump_type (stream, DECL_ARG_TYPE (args), true); + fputs (" ", stream); + dump_decl_name (stream, args); + args = TREE_CHAIN (args); + + if (args) + fputs (", ", stream); + else if (varargs) + fputs (", ...", stream); + } + + fputs (") cil managed" + "\n{" + "\n\t.locals init (", stream); + { + tree var, cell; + bool first = true; + + for (cell = cfun->unexpanded_var_list; + cell; + cell = TREE_CHAIN (cell)) + { + var = TREE_VALUE (cell); + if (!TREE_STATIC (var)) + { + if (!first) + fputs (", ", stream); + first = false; + dump_type (stream, TREE_TYPE (var), true); + fputs (" ", stream); + dump_decl_name (stream, var); + } + } + } + fputs (")\n", stream); + + if (DECL_STATIC_CONSTRUCTOR (current_function_decl)) + { + if (TARGET_OPENSYSTEMC) + fputs ("\n\t.custom instance " + "void ['OpenSystem.C']'OpenSystem.C'.InitializerAttribute::.ctor() " + "= (01 00 00 00)", stream); + } + + FOR_EACH_BB (bb) + { + tree stmt = NULL_TREE; + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + stmt = bsi_stmt (bsi); + if (TARGET_EMIT_GIMPLE_COMMENTS) + { + fprintf (stream, "\n\t/* [1m"); + print_generic_expr (stream, stmt, 0); + fprintf (stream, "[m */"); + } + gcc_assert (stack == 0); + + if (TREE_CODE (stmt) != NOP_EXPR + || TREE_CODE (TREE_OPERAND (stmt, 0)) != INTEGER_CST) + gen_cil_node (stream, stmt); + + if (TREE_CODE (stmt) == CALL_EXPR) + { + tree fun_expr = TREE_OPERAND (stmt, 0); + tree fun_type = TREE_TYPE (TREE_TYPE (fun_expr)); + + if (TREE_CODE (TREE_TYPE (fun_type)) != VOID_TYPE) + { + fputs ("\n\tpop", stream); + stack_pop (1); + } + } + } + + if ((!stmt || (TREE_CODE (stmt) != COND_EXPR)) && single_succ_p (bb)) + { + basic_block succ = single_succ (bb); + + /* The last part of the test (succ != bb->next_bb) is a HACK. It + avoids generating a branch to the successor in case of a + fallthrough. To be fixed when we have a proper layout of basic + blocks. Note that branches from COND_EXPR are still generated, + even to a fallthrough. */ + if ((succ->index != EXIT_BLOCK) && (succ != bb->next_bb)) + { + tree label = tree_block_label (succ); + fputs ("\n\tbr ", stream); + dump_label_name (stream, label); + gcc_assert (stack == 0); + } + } + } + + fprintf (stream, "\n\t.maxstack %d\n", max_stack); + fprintf (stream, "\n} // %s\n", + lang_hooks.decl_printable_name (current_function_decl, 1)); + TREE_ASM_WRITTEN (current_function_decl) = 1; +} + +static void +create_init_method (tree decl) +{ + static int init_counter = 0; + tree init; + char name[30]; + tree fun_type; + tree fun_decl; + tree init_expr = NULL; + tree result; + + ++init_counter; + sprintf (name, "?init-%d", init_counter); + + fun_type = build_function_type (void_type_node, void_list_node); + fun_decl = build_decl (FUNCTION_DECL, get_identifier (name), fun_type); + + result = build_decl (RESULT_DECL, NULL_TREE, void_type_node); + DECL_ARTIFICIAL (result) = 1; + DECL_IGNORED_P (result) = 1; + DECL_RESULT (fun_decl) = result; + + allocate_struct_function (fun_decl); + + + TREE_STATIC (fun_decl) = 1; + TREE_USED (fun_decl) = 1; + DECL_ARTIFICIAL (fun_decl) = 1; + DECL_IGNORED_P (fun_decl) = 0; + TREE_PUBLIC (fun_decl) = 0; + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fun_decl) = 1; + DECL_UNINLINABLE (fun_decl) = 1; + DECL_EXTERNAL (fun_decl) = 0; + DECL_STATIC_CONSTRUCTOR (fun_decl) = 1; + DECL_CONTEXT (fun_decl) = NULL_TREE; + DECL_INITIAL (fun_decl) = make_node (BLOCK); + + init = DECL_INITIAL (decl); + DECL_INITIAL (decl) = NULL_TREE; + + DECL_SOURCE_LOCATION (fun_decl) = EXPR_LOCATION (init); + + expand_init_to_stmt_list (decl, init, &init_expr, false); + + DECL_SAVED_TREE (fun_decl) = init_expr; + + gimplify_function_tree (fun_decl); + tree_lowering_passes (fun_decl); + tree_rest_of_compilation (fun_decl); +} + +void +make_decl_cil (FILE *stream, tree decl) +{ + if (TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || TREE_PUBLIC (decl))) + { + tree init = DECL_INITIAL (decl); + + fputs ("\n.field ", stream); + + if (TREE_PUBLIC (decl)) + fputs ("public ", stream); + else + fputs ("private ", stream); + + fputs ("static ", stream); + dump_type (stream, TREE_TYPE (decl), true); + fputs (" ", stream); + dump_decl_name (stream, decl); + fputs ("\n", stream); + + if (init && init != error_mark_node) + VARRAY_PUSH_TREE (pending_ctors, decl); + + TREE_ASM_WRITTEN (decl) = 1; + } +} + +void +gen_cil_init (void) +{ + FILE *stream = asm_out_file; + + fputs (".assembly extern gcc4net {}", stream); + if (TARGET_EMIT_EXTERNAL_ASSEMBLY) + fputs ("\n.assembly '_C_MONO_ASSEMBLY' {}", stream); + fputs ("\n.module '<Module>'", stream); + + if (TARGET_EMIT_EXTERNAL_ASSEMBLY) + fputs ("\n.class public '_C_MONO_MODULE'" + "\n{", stream); + + if (TARGET_OPENSYSTEMC) + fputs ("\n.custom instance " + "void ['OpenSystem.C']'OpenSystem.C'.ModuleAttribute::.ctor() " + "= (01 00 00 00)" + "\n", stream); + + referenced_types = pointer_set_create (); + VARRAY_TREE_INIT (referenced_strings, 32, "strings used in current unit"); + referenced_string_ptrs = pointer_set_create (); + referenced_pinvoke = pointer_set_create (); + VARRAY_TREE_INIT (pending_ctors, 32, "pending ctors"); +} + +void +gen_cil_fini (void) +{ + FILE *stream = asm_out_file; + struct pointer_set_iter_t it; + int i, n; + + + i = 0; + n = VARRAY_ACTIVE_SIZE (pending_ctors); + while (i<n) + { + for (; i < n; ++i) + { + tree decl = VARRAY_TREE (pending_ctors, i); + create_init_method (decl); + } + n = VARRAY_ACTIVE_SIZE (pending_ctors); + } + VARRAY_CLEAR (pending_ctors); + + i = 0; + n = VARRAY_ACTIVE_SIZE (referenced_strings); + for (; i < n; ++i) + { + tree type = VARRAY_TREE (referenced_strings, i); + print_string_decl (stream, type); + } + VARRAY_CLEAR (referenced_strings); + pointer_set_destroy (referenced_string_ptrs); + + if (TARGET_EMIT_EXTERNAL_ASSEMBLY) + fputs ("\n} // _C_MONO_MODULE\n", stream); + + /* There may be distinct tree types that correspond to identical types. + In order not to slow down mark_referenced_type(...) function (which + may typically be called several times for the same type), insertion + of types in the mark set makes only sure that the same tree type + pointer is not inserted twice. As a consequence, there may still be + distinct tree types that correspond to identical types in the + reference type set. + Hence, before emitting a type, make sure no type with the same name + has already been emitted. */ + + it = pointer_set_begin (referenced_types); + while (!POINTER_SET_ITER_IS_END (it)) + { + tree type = (tree)POINTER_SET_ITER_ELEM (it); + bool found = false; + struct pointer_set_iter_t it2; + tree type_name = TYPE_NAME (type); + const char* type_str; + + if (COMPLETE_TYPE_P (type)) + { + gcc_assert (DECL_P (type_name) + || TREE_CODE (type_name) == IDENTIFIER_NODE); + + if (TREE_CODE (type_name) == IDENTIFIER_NODE) + type_str = IDENTIFIER_POINTER (type_name); + else + type_str = IDENTIFIER_POINTER (DECL_NAME (type_name)); + + it2 = pointer_set_begin (referenced_types); + while (!found && POINTER_SET_ITER_ELEM (it2) != type) + { + tree type2 = (tree)POINTER_SET_ITER_ELEM (it2); + tree type2_name = TYPE_NAME (type2); + const char* type2_str; + + gcc_assert (DECL_P (type2_name) + || TREE_CODE (type2_name) == IDENTIFIER_NODE); + + if (TREE_CODE (type2_name) == IDENTIFIER_NODE) + type2_str = IDENTIFIER_POINTER (type2_name); + else + type2_str = IDENTIFIER_POINTER (DECL_NAME (type2_name)); + + found = strcmp (type2_str, type_str) == 0; + it2 = pointer_set_next (referenced_types, it2); + } + + if (!found) + print_valuetype_decl (stream, type); + } + + it = pointer_set_next (referenced_types, it); + } + pointer_set_destroy (referenced_types); + + it = pointer_set_begin (referenced_pinvoke); + while (!POINTER_SET_ITER_IS_END (it)) + { + tree fun = (tree)POINTER_SET_ITER_ELEM (it); + tree fun_type = TREE_TYPE (fun); + struct fnct_attr attributes; + + decode_function_attrs (fun, &attributes); + + fputs (".method ", stream); + + if (TREE_PUBLIC (fun)) + fputs ("public ", stream); + else + fputs ("private ", stream); + + fprintf (stream, "static pinvokeimpl(\"%s\"", attributes.pinvoke_assembly); + + if (attributes.pinvoke_fname) + fprintf (stream, " as \"%s\"", attributes.pinvoke_fname); + + fputs (") ", stream); + + dump_fun_type (stream, fun_type, fun, NULL, false); + + fputs (" cil managed {}\n", stream); + it = pointer_set_next (referenced_pinvoke, it); + } + pointer_set_destroy (referenced_pinvoke); +} + +static bool +gen_cil_gate (void) +{ + return current_function_decl != NULL; +} + +static unsigned int +gen_cil (void) +{ + gen_cil_1 (asm_out_file); + return 0; +} + +/* Define the parameters of the gen-CIL pass. */ + +struct tree_opt_pass pass_gen_cil = +{ + "cil", /* name */ + gen_cil_gate, /* gate */ + gen_cil, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_REST_OF_COMPILATION, /* tv_id */ + PROP_cfg, /* properties_required */ + 0, /* properties_provided */ + /* ??? If TER is enabled, we also kill gimple. */ + 0, /* properties_destroyed */ + 0, + 0, + 0 /* letter */ +}; + +#include "gt-gen-cil.h" + +/* + * Local variables: + * eval: (c-set-style "gnu") + * End: + */ |