| /* m2statement.cc provides an interface to GCC statement trees. |
| |
| Copyright (C) 2012-2026 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius@glam.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 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 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 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 Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "gcc-consolidation.h" |
| |
| #include "../gm2-lang.h" |
| #include "../m2-tree.h" |
| |
| /* Prototypes. */ |
| |
| #define m2statement_c |
| #include "m2assert.h" |
| #include "m2block.h" |
| #include "m2decl.h" |
| #include "m2expr.h" |
| #include "m2statement.h" |
| #include "m2tree.h" |
| #include "m2treelib.h" |
| #include "m2type.h" |
| #include "m2convert.h" |
| #include "m2builtins.h" |
| #include "m2pp.h" |
| |
| static GTY (()) tree param_list = NULL_TREE; /* Ready for the next time we |
| call/define a function. */ |
| static GTY (()) tree last_function = NULL_TREE; |
| |
| |
| /* BuildStartFunctionCode generate function entry code. */ |
| |
| void |
| m2statement_BuildStartFunctionCode (location_t location, tree fndecl, |
| bool isexported, bool isinline) |
| { |
| tree param_decl; |
| |
| ASSERT_BOOL (isexported); |
| ASSERT_BOOL (isinline); |
| /* Announce we are compiling this function. */ |
| announce_function (fndecl); |
| |
| /* Set up to compile the function and enter it. */ |
| |
| DECL_INITIAL (fndecl) = NULL_TREE; |
| |
| current_function_decl = fndecl; |
| m2block_pushFunctionScope (fndecl); |
| m2statement_SetBeginLocation (location); |
| |
| ASSERT_BOOL ((cfun != NULL)); |
| /* Initialize the RTL code for the function. */ |
| allocate_struct_function (fndecl, false); |
| /* Begin the statement tree for this function. */ |
| DECL_SAVED_TREE (fndecl) = NULL_TREE; |
| |
| /* Set the context of these parameters to this function. */ |
| for (param_decl = DECL_ARGUMENTS (fndecl); param_decl; |
| param_decl = TREE_CHAIN (param_decl)) |
| DECL_CONTEXT (param_decl) = fndecl; |
| |
| /* This function exists in static storage. (This does not mean |
| `static' in the C sense!) */ |
| TREE_STATIC (fndecl) = 1; |
| TREE_PUBLIC (fndecl) = isexported; |
| /* We could do better here by detecting ADR |
| or type PROC used on this function. --fixme-- */ |
| TREE_ADDRESSABLE (fndecl) = 1; |
| DECL_DECLARED_INLINE_P (fndecl) = 0; /* isinline; */ |
| } |
| |
| /* BuildEndFunctionCode generates the function epilogue. */ |
| |
| void |
| m2statement_BuildEndFunctionCode (location_t location, tree fndecl, bool nested) |
| { |
| tree block = DECL_INITIAL (fndecl); |
| |
| BLOCK_SUPERCONTEXT (block) = fndecl; |
| |
| /* Must mark the RESULT_DECL as being in this function. */ |
| DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; |
| |
| /* And attach it to the function. */ |
| DECL_INITIAL (fndecl) = block; |
| |
| m2block_finishFunctionCode (fndecl); |
| m2statement_SetEndLocation (location); |
| |
| m2pp_dump_gimple (M2PP_DUMP_PRE_GENERICIZE, fndecl); |
| gm2_genericize (fndecl); |
| if (nested) |
| (void)cgraph_node::get_create (fndecl); |
| else |
| { |
| m2pp_dump_gimple (M2PP_DUMP_POST_GENERICIZE, fndecl); |
| cgraph_node::finalize_function (fndecl, false); |
| } |
| |
| m2block_popFunctionScope (); |
| |
| /* We're leaving the context of this function, so zap cfun. It's |
| still in DECL_STRUCT_FUNCTION, and we'll restore it in |
| tree_rest_of_compilation. */ |
| set_cfun (NULL); |
| current_function_decl = NULL; |
| } |
| |
| /* BuildPushFunctionContext pushes the current function context. |
| Maps onto push_function_context in ../function.cc. */ |
| |
| void |
| m2statement_BuildPushFunctionContext (void) |
| { |
| push_function_context (); |
| } |
| |
| /* BuildPopFunctionContext pops the current function context. Maps |
| onto pop_function_context in ../function.cc. */ |
| |
| void |
| m2statement_BuildPopFunctionContext (void) |
| { |
| pop_function_context (); |
| } |
| |
| void |
| m2statement_SetBeginLocation (location_t location) |
| { |
| if (cfun != NULL) |
| cfun->function_start_locus = location; |
| } |
| |
| void |
| m2statement_SetEndLocation (location_t location) |
| { |
| if (cfun != NULL) |
| cfun->function_end_locus = location; |
| } |
| |
| /* copy_record_fields copy each record field from right to left. */ |
| |
| static |
| void |
| copy_record_fields (location_t location, tree left, tree right) |
| { |
| unsigned int i; |
| tree right_value; |
| tree left_type = TREE_TYPE (left); |
| vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right); |
| FOR_EACH_CONSTRUCTOR_VALUE (values, i, right_value) |
| { |
| tree left_field = m2treelib_get_field_no (left_type, NULL_TREE, false, i); |
| tree left_ref = m2expr_BuildComponentRef (location, left, left_field); |
| m2statement_CopyByField (location, left_ref, right_value); |
| } |
| } |
| |
| /* copy_array copy each element of an array from array right to array left. */ |
| |
| static |
| void |
| copy_array (location_t location, tree left, tree right) |
| { |
| unsigned int i; |
| tree value; |
| vec<constructor_elt, va_gc> *values = CONSTRUCTOR_ELTS (right); |
| tree array_type = TREE_TYPE (left); |
| tree index_type = TYPE_DOMAIN (array_type); |
| tree elt_type = TREE_TYPE (array_type); |
| tree low_indice = TYPE_MIN_VALUE (index_type); |
| low_indice |
| = m2convert_BuildConvert (location, index_type, low_indice, false); |
| FOR_EACH_CONSTRUCTOR_VALUE (values, i, value) |
| { |
| tree idx = m2decl_BuildIntegerConstant (i); |
| idx = m2convert_BuildConvert (location, index_type, idx, false); |
| tree array_ref = build4_loc (location, ARRAY_REF, elt_type, left, |
| idx, low_indice, NULL_TREE); |
| m2statement_CopyByField (location, array_ref, value); |
| } |
| } |
| |
| /* copy_array cst into left using strncpy. */ |
| |
| static |
| void |
| copy_strncpy (location_t location, tree left, tree cst) |
| { |
| tree result = m2builtins_BuiltinStrNCopy (location, |
| m2expr_BuildAddr (location, left, false), |
| m2expr_BuildAddr (location, cst, false), |
| m2decl_BuildIntegerConstant (m2expr_StringLength (cst))); |
| TREE_SIDE_EFFECTS (result) = true; |
| TREE_USED (left) = true; |
| TREE_USED (cst) = true; |
| add_stmt (location, result); |
| } |
| |
| /* CopyMemcpy copy bytes from src into dest using builtin_memcpy. */ |
| |
| void |
| m2statement_CopyMemcpy (location_t location, tree dest, tree src, tree bytes) |
| { |
| tree addr_dest = m2expr_BuildAddr (location, dest, false); |
| tree result = m2builtins_BuiltinMemCopy (location, |
| addr_dest, |
| m2expr_BuildAddr (location, src, false), |
| bytes); |
| TREE_SIDE_EFFECTS (result) = true; |
| TREE_USED (dest) = true; |
| TREE_USED (src) = true; |
| add_stmt (location, result); |
| } |
| |
| /* CopyByField_Lower copy right to left using memcpy for unions, |
| strncpy for string cst, field assignment for records, |
| array element assignment for array constructors. For all |
| other types it uses BuildAssignmentStatement. */ |
| |
| static |
| void |
| CopyByField_Lower (location_t location, |
| tree left, tree right) |
| { |
| tree left_type = TREE_TYPE (left); |
| enum tree_code right_code = TREE_CODE (right); |
| enum tree_code left_code = TREE_CODE (left_type); |
| |
| if (left_code == RECORD_TYPE && right_code == CONSTRUCTOR) |
| copy_record_fields (location, left, right); |
| else if (left_code == ARRAY_TYPE && right_code == CONSTRUCTOR) |
| copy_array (location, left, right); |
| else if (left_code == UNION_TYPE && right_code == CONSTRUCTOR) |
| m2statement_CopyMemcpy (location, left, right, |
| m2expr_GetSizeOf (location, left)); |
| else if (right_code == STRING_CST) |
| copy_strncpy (location, left, right); |
| else |
| m2statement_BuildAssignmentStatement (location, left, right); |
| } |
| |
| /* CopyByField recursively checks each field to ensure GCC |
| type equivalence and if so it uses assignment. |
| Otherwise use strncpy or memcpy depending upon type. */ |
| |
| void |
| m2statement_CopyByField (location_t location, tree des, tree expr) |
| { |
| if (m2type_IsGccStrictTypeEquivalent (des, expr)) |
| m2statement_BuildAssignmentStatement (location, des, expr); |
| else |
| CopyByField_Lower (location, des, expr); |
| } |
| |
| /* BuildAssignmentTree builds the assignment of des and expr. |
| It returns des. */ |
| |
| void |
| m2statement_BuildAssignmentTree (location_t location, tree des, tree expr) |
| { |
| tree result; |
| |
| m2assert_AssertLocation (location); |
| STRIP_TYPE_NOPS (expr); |
| |
| if (TREE_CODE (expr) == FUNCTION_DECL) |
| result = build2 (MODIFY_EXPR, TREE_TYPE (des), des, |
| m2expr_BuildAddr (location, expr, false)); |
| else |
| { |
| gcc_assert (TREE_CODE (TREE_TYPE (des)) != TYPE_DECL); |
| if ((TREE_CODE (expr) == CONSTRUCTOR) |
| && (TREE_CODE (TREE_TYPE (des)) == ARRAY_TYPE)) |
| { |
| m2statement_CopyMemcpy (location, des, expr, |
| m2expr_GetSizeOf (location, |
| m2type_GetTreeType (des))); |
| return; |
| } |
| else if (TREE_TYPE (expr) == TREE_TYPE (des)) |
| result = build2 (MODIFY_EXPR, TREE_TYPE (des), des, expr); |
| else |
| result = build2 ( |
| MODIFY_EXPR, TREE_TYPE (des), des, |
| m2convert_BuildConvert (location, TREE_TYPE (des), expr, false)); |
| } |
| |
| TREE_SIDE_EFFECTS (result) = true; |
| TREE_USED (des) = true; |
| TREE_USED (expr) = true; |
| add_stmt (location, result); |
| } |
| |
| /* BuildAssignmentStatement builds the assignment of des and expr. */ |
| |
| void |
| m2statement_BuildAssignmentStatement (location_t location, tree des, tree expr) |
| { |
| m2statement_BuildAssignmentTree (location, des, expr); |
| } |
| |
| /* BuildGoto builds a goto operation. */ |
| |
| void |
| m2statement_BuildGoto (location_t location, char *name) |
| { |
| tree label = m2block_getLabel (location, name); |
| |
| m2assert_AssertLocation (location); |
| TREE_USED (label) = true; |
| add_stmt (location, build1 (GOTO_EXPR, void_type_node, label)); |
| } |
| |
| /* DeclareLabel create a label, name. */ |
| |
| void |
| m2statement_DeclareLabel (location_t location, char *name) |
| { |
| tree label = m2block_getLabel (location, name); |
| |
| m2assert_AssertLocation (location); |
| add_stmt (location, build1 (LABEL_EXPR, void_type_node, label)); |
| } |
| |
| /* BuildParam build a list of parameters, ready for a subsequent |
| procedure call. */ |
| |
| void |
| m2statement_BuildParam (location_t location, tree param) |
| { |
| m2assert_AssertLocation (location); |
| |
| TREE_USED (param) = true; |
| if (TREE_CODE (param) == FUNCTION_DECL) |
| param = m2expr_BuildAddr (location, param, false); |
| |
| param_list = chainon (build_tree_list (NULL_TREE, param), param_list); |
| } |
| |
| /* nCount return the number of chained tree nodes in list, t. */ |
| |
| static int |
| nCount (tree t) |
| { |
| int i = 0; |
| |
| while (t != NULL) |
| { |
| i++; |
| t = TREE_CHAIN (t); |
| } |
| return i; |
| } |
| |
| /* BuildProcedureCallTree creates a procedure call from a procedure |
| and parameter list and the return type, rettype. */ |
| |
| tree |
| m2statement_BuildProcedureCallTree (location_t location, tree procedure, |
| tree rettype) |
| { |
| tree functype = TREE_TYPE (procedure); |
| tree funcptr = build1 (ADDR_EXPR, build_pointer_type (functype), procedure); |
| tree call; |
| int n = nCount (param_list); |
| tree *argarray = XALLOCAVEC (tree, n); |
| tree t = param_list; |
| int i; |
| |
| m2assert_AssertLocation (location); |
| ASSERT_CONDITION ( |
| last_function |
| == NULL_TREE); /* Previous function value has not been collected. */ |
| TREE_USED (procedure) = true; |
| |
| for (i = 0; i < n; i++) |
| { |
| argarray[i] = TREE_VALUE (t); |
| t = TREE_CHAIN (t); |
| } |
| |
| if (rettype == NULL_TREE) |
| { |
| rettype = void_type_node; |
| call = build_call_array_loc (location, rettype, funcptr, n, argarray); |
| TREE_USED (call) = true; |
| TREE_SIDE_EFFECTS (call) = true; |
| |
| #if defined(DEBUG_PROCEDURE_CALLS) |
| fprintf (stderr, "built the modula-2 call, here is the tree\n"); |
| fflush (stderr); |
| debug_tree (call); |
| #endif |
| |
| param_list |
| = NULL_TREE; /* Ready for the next time we call a procedure. */ |
| last_function = NULL_TREE; |
| return call; |
| } |
| else |
| { |
| last_function = build_call_array_loc ( |
| location, m2tree_skip_type_decl (rettype), funcptr, n, argarray); |
| TREE_USED (last_function) = true; |
| TREE_SIDE_EFFECTS (last_function) = true; |
| param_list |
| = NULL_TREE; /* Ready for the next time we call a procedure. */ |
| return last_function; |
| } |
| } |
| |
| /* BuildIndirectProcedureCallTree creates a procedure call from a |
| procedure and parameter list and the return type, rettype. */ |
| |
| tree |
| m2statement_BuildIndirectProcedureCallTree (location_t location, |
| tree procedure, tree rettype) |
| { |
| tree call; |
| int n = nCount (param_list); |
| tree *argarray = XALLOCAVEC (tree, n); |
| tree t = param_list; |
| int i; |
| |
| m2assert_AssertLocation (location); |
| TREE_USED (procedure) = true; |
| TREE_SIDE_EFFECTS (procedure) = true; |
| |
| for (i = 0; i < n; i++) |
| { |
| argarray[i] = TREE_VALUE (t); |
| t = TREE_CHAIN (t); |
| } |
| |
| if (rettype == NULL_TREE) |
| { |
| rettype = void_type_node; |
| call = build_call_array_loc (location, rettype, procedure, n, argarray); |
| TREE_USED (call) = true; |
| TREE_SIDE_EFFECTS (call) = true; |
| |
| #if defined(DEBUG_PROCEDURE_CALLS) |
| fprintf (stderr, "built the modula-2 call, here is the tree\n"); |
| fflush (stderr); |
| debug_tree (call); |
| #endif |
| |
| last_function = NULL_TREE; |
| param_list |
| = NULL_TREE; /* Ready for the next time we call a procedure. */ |
| return call; |
| } |
| else |
| { |
| last_function = build_call_array_loc ( |
| location, m2tree_skip_type_decl (rettype), procedure, n, argarray); |
| TREE_USED (last_function) = true; |
| TREE_SIDE_EFFECTS (last_function) = true; |
| param_list |
| = NULL_TREE; /* Ready for the next time we call a procedure. */ |
| return last_function; |
| } |
| } |
| |
| |
| /* BuildBuiltinCallTree calls the builtin procedure. */ |
| |
| tree |
| m2statement_BuildBuiltinCallTree (tree func) |
| { |
| TREE_USED (func) = true; |
| TREE_SIDE_EFFECTS (func) = true; |
| param_list |
| = NULL_TREE; /* Ready for the next time we call a procedure. */ |
| return func; |
| } |
| |
| |
| /* BuildFunctValue generates code for |
| value := last_function (foobar). */ |
| |
| tree |
| m2statement_BuildFunctValue (location_t location, tree value) |
| { |
| tree assign |
| = m2treelib_build_modify_expr (location, value, NOP_EXPR, last_function); |
| |
| m2assert_AssertLocation (location); |
| ASSERT_CONDITION ( |
| last_function |
| != NULL_TREE); /* No value available, possible used before. */ |
| |
| TREE_SIDE_EFFECTS (assign) = true; |
| TREE_USED (assign) = true; |
| TREE_USED (value) = true; |
| last_function = NULL_TREE; |
| return assign; |
| } |
| |
| /* BuildCall2 builds a tree representing: function (arg1, arg2). */ |
| |
| tree |
| m2statement_BuildCall2 (location_t location, tree function, tree rettype, |
| tree arg1, tree arg2) |
| { |
| m2assert_AssertLocation (location); |
| ASSERT_CONDITION (param_list == NULL_TREE); |
| |
| param_list = chainon (build_tree_list (NULL_TREE, arg2), param_list); |
| param_list = chainon (build_tree_list (NULL_TREE, arg1), param_list); |
| return m2statement_BuildProcedureCallTree (location, function, rettype); |
| } |
| |
| /* BuildCall3 builds a tree representing: function (arg1, arg2, arg3). */ |
| |
| tree |
| m2statement_BuildCall3 (location_t location, tree function, tree rettype, |
| tree arg1, tree arg2, tree arg3) |
| { |
| m2assert_AssertLocation (location); |
| ASSERT_CONDITION (param_list == NULL_TREE); |
| |
| param_list = chainon (build_tree_list (NULL_TREE, arg3), param_list); |
| param_list = chainon (build_tree_list (NULL_TREE, arg2), param_list); |
| param_list = chainon (build_tree_list (NULL_TREE, arg1), param_list); |
| return m2statement_BuildProcedureCallTree (location, function, rettype); |
| } |
| |
| /* BuildFunctionCallTree creates a procedure function call from |
| a procedure and parameter list and the return type, rettype. |
| No tree is returned as the tree is held in the last_function global |
| variable. It is expected the BuildFunctValue is to be called after |
| a call to BuildFunctionCallTree. */ |
| |
| void |
| m2statement_BuildFunctionCallTree (location_t location, tree procedure, |
| tree rettype) |
| { |
| m2statement_BuildProcedureCallTree (location, procedure, rettype); |
| } |
| |
| /* SetLastFunction assigns last_function to, t. */ |
| |
| void |
| m2statement_SetLastFunction (tree t) |
| { |
| last_function = t; |
| } |
| |
| /* SetParamList assigns param_list to, t. */ |
| |
| void |
| m2statement_SetParamList (tree t) |
| { |
| param_list = t; |
| } |
| |
| /* GetLastFunction returns, last_function. */ |
| |
| tree |
| m2statement_GetLastFunction (void) |
| { |
| return last_function; |
| } |
| |
| /* GetParamList returns, param_list. */ |
| |
| tree |
| m2statement_GetParamList (void) |
| { |
| return param_list; |
| } |
| |
| /* GetCurrentFunction returns the current_function. */ |
| |
| tree |
| m2statement_GetCurrentFunction (void) |
| { |
| return current_function_decl; |
| } |
| |
| /* GetParamTree return parameter, i. */ |
| |
| tree |
| m2statement_GetParamTree (tree call, unsigned int i) |
| { |
| return CALL_EXPR_ARG (call, i); |
| } |
| |
| /* BuildTryFinally returns a TRY_FINALL_EXPR with the call and |
| cleanups attached. */ |
| |
| tree |
| m2statement_BuildTryFinally (location_t location, tree call, tree cleanups) |
| { |
| return build_stmt (location, TRY_FINALLY_EXPR, call, cleanups); |
| } |
| |
| /* BuildCleanUp return a CLEANUP_POINT_EXPR which will clobber, |
| param. */ |
| |
| tree |
| m2statement_BuildCleanUp (tree param) |
| { |
| tree clobber = build_constructor (TREE_TYPE (param), NULL); |
| TREE_THIS_VOLATILE (clobber) = 1; |
| return build2 (MODIFY_EXPR, TREE_TYPE (param), param, clobber); |
| } |
| |
| /* BuildAsm generates an inline assembler instruction. */ |
| |
| void |
| m2statement_BuildAsm (location_t location, tree instr, bool isVolatile, |
| bool isSimple, tree inputs, tree outputs, tree trash, |
| tree labels) |
| { |
| tree string = resolve_asm_operand_names (instr, outputs, inputs, labels); |
| tree args = build_stmt (location, ASM_EXPR, string, outputs, inputs, trash, |
| labels); |
| |
| m2assert_AssertLocation (location); |
| |
| /* ASM statements without outputs, including simple ones, are treated |
| as volatile. */ |
| ASM_BASIC_P (args) = isSimple; |
| ASM_VOLATILE_P (args) = isVolatile; |
| |
| add_stmt (location, args); |
| } |
| |
| /* BuildStart creates a module initialization function. We make |
| this function public if it is not an inner module. The linker |
| will create a call list for all linked modules which determines |
| the initialization sequence for all modules. */ |
| |
| tree |
| m2statement_BuildStart (location_t location, char *name, bool inner_module) |
| { |
| tree fntype; |
| tree fndecl; |
| |
| m2assert_AssertLocation (location); |
| /* The function type depends on the return type and type of args. */ |
| fntype = build_function_type (integer_type_node, NULL_TREE); |
| fndecl = build_decl (location, FUNCTION_DECL, get_identifier (name), fntype); |
| |
| DECL_EXTERNAL (fndecl) = 0; |
| if (inner_module) |
| TREE_PUBLIC (fndecl) = 0; |
| else |
| TREE_PUBLIC (fndecl) = 1; |
| |
| TREE_STATIC (fndecl) = 1; |
| DECL_RESULT (fndecl) |
| = build_decl (location, RESULT_DECL, NULL_TREE, integer_type_node); |
| DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl; |
| |
| /* Prevent the optimizer from removing it if it is public. */ |
| if (TREE_PUBLIC (fndecl)) |
| gm2_mark_addressable (fndecl); |
| |
| m2statement_BuildStartFunctionCode (location, fndecl, !inner_module, |
| inner_module); |
| return fndecl; |
| } |
| |
| /* BuildEnd complete the initialization function for this module. */ |
| |
| void |
| m2statement_BuildEnd (location_t location, tree fndecl, bool nested) |
| { |
| m2statement_BuildEndFunctionCode (location, fndecl, nested); |
| current_function_decl = NULL; |
| set_cfun (NULL); |
| } |
| |
| /* BuildCallInner call the inner module function. It has no |
| parameters and no return value. */ |
| |
| void |
| m2statement_BuildCallInner (location_t location, tree fndecl) |
| { |
| m2assert_AssertLocation (location); |
| param_list = NULL_TREE; |
| add_stmt (location, |
| m2statement_BuildProcedureCallTree (location, fndecl, NULL_TREE)); |
| } |
| |
| |
| /* BuildIfThenDoEnd returns a tree which will only execute |
| statement, s, if, condition, is true. */ |
| |
| tree |
| m2statement_BuildIfThenDoEnd (tree condition, tree then_block) |
| { |
| if (then_block == NULL_TREE) |
| return NULL_TREE; |
| else |
| return fold_build3 (COND_EXPR, void_type_node, condition, then_block, |
| alloc_stmt_list ()); |
| } |
| |
| /* BuildIfThenElseEnd returns a tree which will execute then_block |
| or else_block depending upon, condition. */ |
| |
| tree |
| m2statement_BuildIfThenElseEnd (tree condition, tree then_block, |
| tree else_block) |
| { |
| if (then_block == NULL_TREE) |
| return NULL_TREE; |
| else |
| return fold_build3 (COND_EXPR, void_type_node, condition, then_block, |
| else_block); |
| } |
| |
| /* BuildReturnValueCode generates the code associated with: |
| RETURN ( value ). */ |
| |
| void |
| m2statement_BuildReturnValueCode (location_t location, tree fndecl, tree value) |
| { |
| tree ret_stmt; |
| tree t; |
| |
| m2assert_AssertLocation (location); |
| t = build2 ( |
| MODIFY_EXPR, TREE_TYPE (DECL_RESULT (fndecl)), DECL_RESULT (fndecl), |
| m2convert_BuildConvert ( |
| location, m2tree_skip_type_decl (TREE_TYPE (DECL_RESULT (fndecl))), |
| value, false)); |
| |
| ret_stmt = build_stmt (location, RETURN_EXPR, t); |
| add_stmt (location, ret_stmt); |
| } |
| |
| /* IfExprJump if expr then jump to the label. */ |
| |
| void |
| m2statement_IfExprJump (location_t location, tree exp, char *label) |
| { |
| tree if_jump; |
| |
| m2assert_AssertLocation (location); |
| if (TREE_CODE (TREE_TYPE (exp)) != BOOLEAN_TYPE) |
| exp = convert_loc (location, m2type_GetBooleanType (), exp); |
| |
| m2block_push_statement_list (m2block_begin_statement_list ()); |
| m2statement_BuildGoto (location, label); |
| if_jump = build3 (COND_EXPR, void_type_node, exp, |
| m2block_pop_statement_list (), |
| alloc_stmt_list ()); |
| add_stmt (location, if_jump); |
| } |
| |
| |
| /* IfBitInSetJump if bit in set jump to label. */ |
| |
| void |
| m2statement_IfBitInSetJump (location_t location, bool invertCondition, |
| tree setvalue, tree bit, char *label) |
| { |
| tree condition; |
| |
| condition = m2expr_BuildNotEqualTo (location, |
| m2expr_BuildLogicalAnd (location, |
| m2expr_BuildLSL (location, |
| m2expr_GetWordOne (location), |
| bit, false), |
| setvalue), |
| m2expr_GetWordZero (location)) ; |
| if (invertCondition) |
| condition = m2expr_BuildEqualTo (location, condition, |
| m2type_GetBooleanFalse ()); |
| m2statement_IfExprJump (location, condition, label); |
| } |
| |
| #include "gt-m2-m2statement.h" |