aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/d-codegen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/d-codegen.cc')
-rw-r--r--gcc/d/d-codegen.cc145
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;