/* D-specific tree lowering bits; see also gimple.c. Copyright (C) 2020 Free Software Foundation, Inc. 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 3, 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 COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "dmd/globals.h" #include "tree.h" #include "gimple-expr.h" #include "gimplify.h" #include "d-tree.h" /* Return TRUE if an operand OP of a given TYPE being copied has no data. The middle-end does a similar check with zero sized types. */ static bool empty_modify_p (tree type, tree op) { tree_code code = TREE_CODE (op); switch (code) { case COMPOUND_EXPR: return empty_modify_p (type, TREE_OPERAND (op, 1)); case CONSTRUCTOR: /* Non-empty construcors are valid. */ if (CONSTRUCTOR_NELTS (op) != 0 || TREE_CLOBBER_P (op)) return false; break; case CALL_EXPR: /* Leave nrvo alone because it isn't a copy. */ if (CALL_EXPR_RETURN_SLOT_OPT (op)) return false; break; default: /* If the operand doesn't have a simple form. */ if (!is_gimple_lvalue (op) && !INDIRECT_REF_P (op)) return false; break; } return empty_aggregate_p (type); } /* Gimplify assignment from an INIT_EXPR or MODIFY_EXPR. */ static gimplify_status d_gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { tree op0 = TREE_OPERAND (*expr_p, 0); tree op1 = TREE_OPERAND (*expr_p, 1); if (error_operand_p (op0) || error_operand_p (op1)) return GS_UNHANDLED; /* Remove any copies of empty aggregates. */ if (empty_modify_p (TREE_TYPE (op0), op1)) { gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p, is_gimple_lvalue, fb_lvalue); if (TREE_SIDE_EFFECTS (op1)) gimplify_and_add (op1, pre_p); *expr_p = TREE_OPERAND (*expr_p, 0); return GS_OK; } /* If the back end isn't clever enough to know that the lhs and rhs types are the same, add an explicit conversion. */ if ((AGGREGATE_TYPE_P (TREE_TYPE (op0)) || AGGREGATE_TYPE_P (TREE_TYPE (op1))) && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0))) { TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (op0), op1); return GS_OK; } return GS_UNHANDLED; } /* Gimplify an ADDR_EXPR node. */ static gimplify_status d_gimplify_addr_expr (tree *expr_p) { tree op0 = TREE_OPERAND (*expr_p, 0); /* Constructors are not lvalues, so make them one. */ if (TREE_CODE (op0) == CONSTRUCTOR) { TREE_OPERAND (*expr_p, 0) = force_target_expr (op0); return GS_OK; } return GS_UNHANDLED; } /* Gimplify a CALL_EXPR node. */ static gimplify_status d_gimplify_call_expr (tree *expr_p, gimple_seq *pre_p) { if (CALL_EXPR_ARGS_ORDERED (*expr_p)) { /* Strictly evaluate all arguments from left to right. */ int nargs = call_expr_nargs (*expr_p); location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location); /* No need to enforce evaluation order if only one argument. */ if (nargs < 2) return GS_UNHANDLED; /* Or if all arguments are already free of side-effects. */ bool has_side_effects = false; for (int i = 0; i < nargs; i++) { if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i))) { has_side_effects = true; break; } } if (!has_side_effects) return GS_UNHANDLED; /* Leave the last argument for gimplify_call_expr. */ for (int i = 0; i < nargs - 1; i++) { tree new_arg = CALL_EXPR_ARG (*expr_p, i); /* If argument has a side-effect, gimplify_arg will handle it. */ if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR) return GS_ERROR; /* Even if an argument itself doesn't have any side-effects, it might be altered by another argument in the list. */ if (new_arg == CALL_EXPR_ARG (*expr_p, i) && !really_constant_p (new_arg)) new_arg = get_formal_tmp_var (new_arg, pre_p); CALL_EXPR_ARG (*expr_p, i) = new_arg; } return GS_OK; } return GS_UNHANDLED; } /* Gimplify an UNSIGNED_RSHIFT_EXPR node. */ static gimplify_status d_gimplify_unsigned_rshift_expr (tree *expr_p) { /* Convert op0 to an unsigned type. */ tree op0 = TREE_OPERAND (*expr_p, 0); tree op1 = TREE_OPERAND (*expr_p, 1); tree type = d_unsigned_type (TREE_TYPE (op0)); *expr_p = convert (TREE_TYPE (*expr_p), build2 (RSHIFT_EXPR, type, convert (type, op0), op1)); return GS_OK; } /* Implements the lang_hooks.gimplify_expr routine for language D. Do gimplification of D specific expression trees in EXPR_P. */ int d_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) { switch (TREE_CODE (*expr_p)) { case INIT_EXPR: case MODIFY_EXPR: return d_gimplify_modify_expr (expr_p, pre_p, post_p); case ADDR_EXPR: return d_gimplify_addr_expr (expr_p); case CALL_EXPR: return d_gimplify_call_expr (expr_p, pre_p); case UNSIGNED_RSHIFT_EXPR: return d_gimplify_unsigned_rshift_expr (expr_p); case FLOAT_MOD_EXPR: gcc_unreachable (); default: break; } return GS_UNHANDLED; }