diff options
Diffstat (limited to 'gcc/d/d-codegen.cc')
-rw-r--r-- | gcc/d/d-codegen.cc | 145 |
1 files changed, 104 insertions, 41 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2b3089b..e35f75a 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -1,5 +1,5 @@ /* d-codegen.cc -- Code generation and routines for manipulation of GCC trees. - Copyright (C) 2006-2024 Free Software Foundation, Inc. + Copyright (C) 2006-2025 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 @@ -43,24 +43,33 @@ along with GCC; see the file COPYING3. If not see #include "d-tree.h" -/* Return the GCC location for the D frontend location LOC. */ +/* Return the GCC location for the D frontend source location LOC. */ location_t -make_location_t (const Loc &loc) +make_location_t (const SourceLoc &loc) { location_t gcc_location = input_location; - if (const char *filename = loc.filename ()) + if (loc.filename.length != 0) { - linemap_add (line_table, LC_ENTER, 0, filename, loc.linnum ()); - linemap_line_start (line_table, loc.linnum (), 0); - gcc_location = linemap_position_for_column (line_table, loc.charnum ()); + linemap_add (line_table, LC_ENTER, 0, loc.filename.ptr, loc.line); + linemap_line_start (line_table, loc.line, 0); + gcc_location = linemap_position_for_column (line_table, loc.column); linemap_add (line_table, LC_LEAVE, 0, NULL, 0); } return gcc_location; } +/* Likewise, but converts LOC from a compact opaque location. */ + +location_t +make_location_t (const Loc loc) +{ + const SourceLoc sloc = loc.toSourceLoc (); + return make_location_t (sloc); +} + /* Return the DECL_CONTEXT for symbol DSYM. */ tree @@ -246,15 +255,15 @@ build_integer_cst (dinteger_t value, tree type) tree build_float_cst (const real_t &value, Type *totype) { - real_t new_value; + real_value new_value; TypeBasic *tb = totype->isTypeBasic (); gcc_assert (tb != NULL); tree type_node = build_ctype (tb); - real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ()); + real_convert (&new_value, TYPE_MODE (type_node), &value.rv ()); - return build_real (type_node, new_value.rv ()); + return build_real (type_node, new_value); } /* Returns the .length component from the D dynamic array EXP. */ @@ -308,7 +317,7 @@ d_array_value (tree type, tree len, tree data) CONSTRUCTOR_APPEND_ELT (ce, len_field, len); CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data); - return build_constructor (type, ce); + return build_padded_constructor (type, ce); } /* Returns value representing the array length of expression EXP. @@ -631,6 +640,37 @@ force_target_expr (tree exp) return build_target_expr (decl, exp); } +/* Determine whether expression EXP can have a copy of its value elided. */ + +static bool +can_elide_copy_p (Expression *exp) +{ + /* Explicit `__rvalue(exp)'. */ + if (exp->rvalue ()) + return true; + + /* Look for variable expression. */ + Expression *last = exp; + while (CommaExp *ce = last->isCommaExp ()) + last = ce->e2; + + if (VarExp *ve = last->isVarExp ()) + { + if (VarDeclaration *vd = ve->var->isVarDeclaration ()) + { + /* Variable is an implicit copy of an lvalue. */ + if (vd->storage_class & STCrvalue) + return true; + + /* The destructor is going to run on the variable. */ + if (vd->isArgDtorVar ()) + return true; + } + } + + return false; +} + /* Returns the address of the expression EXP. */ tree @@ -677,10 +717,11 @@ build_address (tree exp) if (AGGREGATE_TYPE_P (TREE_TYPE (exp)) && !aggregate_value_p (TREE_TYPE (exp), exp)) { - tree tmp = build_local_temp (TREE_TYPE (exp)); - init = compound_expr (init, build_memset_call (tmp)); - init = compound_expr (init, modify_expr (tmp, exp)); - exp = tmp; + tree target = force_target_expr (exp); + tree ptr = build_address (TARGET_EXPR_SLOT (target)); + init = compound_expr (init, target); + init = compound_expr (init, build_clear_padding_call (ptr)); + exp = TARGET_EXPR_SLOT (target); } else exp = force_target_expr (exp); @@ -851,14 +892,13 @@ build_memset_call (tree ptr, tree num) } /* Use a zero constant to fill the destination if setting the entire object. - For CONSTRUCTORs, the memcpy() is lowered to a ref-all pointer assignment, - which can then be merged with other stores to the object. */ + For CONSTRUCTORs, also set CONSTRUCTOR_ZERO_PADDING_BITS. */ tree valtype = TREE_TYPE (TREE_TYPE (ptr)); if (tree_int_cst_equal (TYPE_SIZE_UNIT (valtype), num)) { tree cst = build_zero_cst (valtype); if (TREE_CODE (cst) == CONSTRUCTOR) - return build_memcpy_call (ptr, build_address (cst), num); + CONSTRUCTOR_ZERO_PADDING_BITS (cst) = 1; return modify_expr (build_deref (ptr), cst); } @@ -867,6 +907,18 @@ build_memset_call (tree ptr, tree num) ptr, integer_zero_node, num); } +/* Build a call to built-in clear_padding(), clears padding bits inside of the + object representation of object pointed by PTR. */ + +tree +build_clear_padding_call (tree ptr) +{ + gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr))); + + return build_call_expr (builtin_decl_explicit (BUILT_IN_CLEAR_PADDING), 1, + ptr); +} + /* Return TRUE if the struct SD is suitable for comparison using memcmp. This is because we don't guarantee that padding is zero-initialized for a stack variable, so we can't use memcmp to compare struct values. */ @@ -904,7 +956,7 @@ identity_compare_p (StructDeclaration *sd) if (offset != vd->offset) return false; - offset += vd->type->size (); + offset += dmd::size (vd->type); } } @@ -972,15 +1024,15 @@ lower_struct_comparison (tree_code code, StructDeclaration *sd, /* Compare inner data structures. */ tcmp = lower_struct_comparison (code, ts->sym, t1ref, t2ref); } - else if (type->ty != TY::Tvector && type->isintegral ()) + else if (type->ty != TY::Tvector && type->isIntegral ()) { /* Integer comparison, no special handling required. */ tcmp = build_boolop (code, t1ref, t2ref); } - else if (type->ty != TY::Tvector && type->isfloating ()) + else if (type->ty != TY::Tvector && type->isFloating ()) { /* Floating-point comparison, don't compare padding in type. */ - if (!type->iscomplex ()) + if (!type->isComplex ()) tcmp = build_float_identity (code, t1ref, t2ref); else { @@ -1165,7 +1217,7 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) { /* If the initializer was empty, use default zero initialization. */ if (vec_safe_is_empty (init)) - return build_constructor (type, NULL); + return build_padded_constructor (type, NULL); /* Struct literals can be seen for special enums representing `_Complex', make sure to reinterpret the literal as the correct type. */ @@ -1266,7 +1318,7 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) /* Ensure that we have consumed all values. */ gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type)); - tree ctor = build_constructor (type, ve); + tree ctor = build_padded_constructor (type, ve); if (constant_p) TREE_CONSTANT (ctor) = 1; @@ -1274,6 +1326,17 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) return ctor; } +/* Return a new zero padded CONSTRUCTOR node whose type is TYPE and values are + in the vec pointed to by VALS. */ + +tree +build_padded_constructor (tree type, vec<constructor_elt, va_gc> *vals) +{ + tree ctor = build_constructor (type, vals); + CONSTRUCTOR_ZERO_PADDING_BITS (ctor) = 1; + return ctor; +} + /* Given the TYPE of an anonymous field inside T, return the FIELD_DECL for the field. If not found return NULL_TREE. Because anonymous types can nest, we must also search all @@ -1607,7 +1670,7 @@ underlying_complex_expr (tree type, tree expr) real_part (expr)); CONSTRUCTOR_APPEND_ELT (ve, TREE_CHAIN (TYPE_FIELDS (type)), imaginary_part (expr)); - return build_constructor (type, ve); + return build_padded_constructor (type, ve); } /* Replace type in the reinterpret cast with a cast to the record type. */ @@ -1812,7 +1875,7 @@ build_array_from_val (Type *type, tree val) for (size_t i = 0; i < dims; i++) CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val); - return build_constructor (build_ctype (type), elms); + return build_padded_constructor (build_ctype (type), elms); } /* Build a static array of type TYPE from an array of EXPS. @@ -1839,15 +1902,13 @@ build_array_from_exprs (Type *type, Expressions *exps, bool const_p) /* Create a new temporary to store the array. */ tree var = build_local_temp (satype); + /* Initialize the temporary. */ + tree assign = modify_expr (var, build_padded_constructor (satype, elms)); + /* Fill any alignment holes with zeroes. */ - TypeStruct *ts = etype->baseElemOf ()->isTypeStruct (); - tree init = NULL; - if (ts && (!identity_compare_p (ts->sym) || ts->sym->isUnionDeclaration ())) - init = build_memset_call (var); + tree clear_padding = build_clear_padding_call (build_address (var)); - /* Initialize the temporary. */ - tree assign = modify_expr (var, build_constructor (satype, elms)); - return compound_expr (compound_expr (init, assign), var); + return compound_expr (compound_expr (assign, clear_padding), var); } @@ -2119,7 +2180,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type) /* Must be a `nothrow' function. */ TypeFunction *tf = func->type->toTypeFunction (); - if (!tf->isnothrow ()) + if (!tf->isNothrow ()) return false; /* Return type can't be `void' or `noreturn', as that implies all work is @@ -2128,7 +2189,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type) return false; /* Only consider it as `pure' if it can't modify its arguments. */ - if (func->isPure () == PURE::const_) + if (dmd::isPure (func) == PURE::const_) return true; } @@ -2137,7 +2198,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type) TypeFunction *tf = get_function_type (type); /* Must be a `nothrow` function type. */ - if (tf == NULL || !tf->isnothrow ()) + if (tf == NULL || !tf->isNothrow ()) return false; /* Return type can't be `void' or `noreturn', as that implies all work is @@ -2261,7 +2322,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object, if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ) && TREE_CODE (targ) != CONSTRUCTOR) { - tree t = build_constructor (TREE_TYPE (targ), NULL); + tree t = build_padded_constructor (TREE_TYPE (targ), NULL); targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t); } @@ -2280,8 +2341,10 @@ d_build_call (TypeFunction *tf, tree callable, tree object, - The ABI of the function expects the callee to destroy its arguments; when the caller is handles destruction, then `targ' has already been made into a temporary. */ - if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor) - || target.isCalleeDestroyingArgs (tf)) + if (!can_elide_copy_p (arg) + && (arg->op == EXP::structLiteral + || (!sd->postblit && !sd->dtor) + || target.isCalleeDestroyingArgs (tf))) targ = force_target_expr (targ); targ = convert (build_reference_type (TREE_TYPE (targ)), @@ -2571,7 +2634,7 @@ get_frame_for_symbol (Dsymbol *sym) framefields = DECL_CHAIN (framefields); } - frame_ref = build_address (build_constructor (type, ve)); + frame_ref = build_address (build_padded_constructor (type, ve)); } } @@ -2915,7 +2978,7 @@ get_frameinfo (FuncDeclaration *fd) symbols, give it a decent error for now. */ if (requiresClosure != fd->requiresClosure && (fd->nrvo_var || !global.params.useGC)) - fd->checkClosure (); + dmd::checkClosure (fd); /* Set-up a closure frame, this will be allocated on the heap. */ FRAMEINFO_CREATES_FRAME (ffi) = 1; |