Commit e8e0acba by Iain Buclaw

d: Use memset to fill alignment holes with zeroes.

This patch removes the manual insertion of padding for fields in
constructed struct literals, and instead uses memset() on the
declaration being initialized.

When compiling optimized builds, the intent is usually missed, and
alignment holes end up with non-zero values in them anyway.

gcc/d/ChangeLog:

	PR d/94424
	* d-codegen.cc (build_alignment_field): Remove.
	(build_struct_literal): Don't insert alignment padding.
	* expr.cc (ExprVisitor::visit (AssignExp *)): Call memset before
	assigning struct literals.

gcc/testsuite/ChangeLog:

	PR d/94424
	* gdc.dg/pr94424.d: New test.
parent f14b41d2
2020-03-31 Iain Buclaw <ibuclaw@gdcproject.org> 2020-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
PR d/94424
* d-codegen.cc (build_alignment_field): Remove.
(build_struct_literal): Don't insert alignment padding.
* expr.cc (ExprVisitor::visit (AssignExp *)): Call memset before
assigning struct literals.
2020-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
* typeinfo.cc (TypeInfoVisitor::internal_reference): Call * typeinfo.cc (TypeInfoVisitor::internal_reference): Call
d_comdat_linkage on generated decl. d_comdat_linkage on generated decl.
......
...@@ -1076,26 +1076,6 @@ build_array_struct_comparison (tree_code code, StructDeclaration *sd, ...@@ -1076,26 +1076,6 @@ build_array_struct_comparison (tree_code code, StructDeclaration *sd,
return compound_expr (body, result); return compound_expr (body, result);
} }
/* Create an anonymous field of type ubyte[T] at OFFSET to fill
the alignment hole between OFFSET and FIELDPOS. */
static tree
build_alignment_field (tree type, HOST_WIDE_INT offset, HOST_WIDE_INT fieldpos)
{
tree atype = make_array_type (Type::tuns8, fieldpos - offset);
tree field = create_field_decl (atype, NULL, 1, 1);
SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (atype));
DECL_FIELD_OFFSET (field) = size_int (offset);
DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
DECL_FIELD_CONTEXT (field) = type;
DECL_PADDING_P (field) = 1;
layout_decl (field, 0);
return field;
}
/* Build a constructor for a variable of aggregate type TYPE using the /* Build a constructor for a variable of aggregate type TYPE using the
initializer INIT, an ordered flat list of fields and values provided initializer INIT, an ordered flat list of fields and values provided
by the frontend. The returned constructor should be a value that by the frontend. The returned constructor should be a value that
...@@ -1111,14 +1091,8 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init) ...@@ -1111,14 +1091,8 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
vec<constructor_elt, va_gc> *ve = NULL; vec<constructor_elt, va_gc> *ve = NULL;
HOST_WIDE_INT offset = 0; HOST_WIDE_INT offset = 0;
bool constant_p = true; bool constant_p = true;
bool fillholes = true;
bool finished = false; bool finished = false;
/* Filling alignment holes this only applies to structs. */
if (TREE_CODE (type) != RECORD_TYPE
|| CLASS_TYPE_P (type) || TYPE_PACKED (type))
fillholes = false;
/* Walk through each field, matching our initializer list. */ /* Walk through each field, matching our initializer list. */
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{ {
...@@ -1163,15 +1137,6 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init) ...@@ -1163,15 +1137,6 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
HOST_WIDE_INT fieldpos = int_byte_position (field); HOST_WIDE_INT fieldpos = int_byte_position (field);
gcc_assert (value != NULL_TREE); gcc_assert (value != NULL_TREE);
/* Insert anonymous fields in the constructor for padding out
alignment holes in-place between fields. */
if (fillholes && offset < fieldpos)
{
tree pfield = build_alignment_field (type, offset, fieldpos);
tree pvalue = build_zero_cst (TREE_TYPE (pfield));
CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
}
/* Must not initialize fields that overlap. */ /* Must not initialize fields that overlap. */
if (fieldpos < offset) if (fieldpos < offset)
{ {
...@@ -1214,15 +1179,6 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init) ...@@ -1214,15 +1179,6 @@ build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
break; break;
} }
/* Finally pad out the end of the record. */
if (fillholes && offset < int_size_in_bytes (type))
{
tree pfield = build_alignment_field (type, offset,
int_size_in_bytes (type));
tree pvalue = build_zero_cst (TREE_TYPE (pfield));
CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
}
/* Ensure that we have consumed all values. */ /* Ensure that we have consumed all values. */
gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type)); gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type));
......
...@@ -1054,14 +1054,13 @@ public: ...@@ -1054,14 +1054,13 @@ public:
tree t1 = build_expr (e->e1); tree t1 = build_expr (e->e1);
tree t2 = convert_for_assignment (build_expr (e->e2), tree t2 = convert_for_assignment (build_expr (e->e2),
e->e2->type, e->e1->type); e->e2->type, e->e1->type);
StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
/* Look for struct = 0. */ /* Look for struct = 0. */
if (e->e2->op == TOKint64) if (e->e2->op == TOKint64)
{ {
/* Use memset to fill struct. */ /* Use memset to fill struct. */
gcc_assert (e->op == TOKblit); gcc_assert (e->op == TOKblit);
StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET); tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
tree result = build_call_expr (tmemset, 3, build_address (t1), tree result = build_call_expr (tmemset, 3, build_address (t1),
t2, size_int (sd->structsize)); t2, size_int (sd->structsize));
...@@ -1079,7 +1078,22 @@ public: ...@@ -1079,7 +1078,22 @@ public:
this->result_ = compound_expr (result, t1); this->result_ = compound_expr (result, t1);
} }
else else
this->result_ = build_assign (modifycode, t1, t2); {
/* Simple struct literal assignment. */
tree init = NULL_TREE;
/* Fill any alignment holes in the struct using memset. */
if (e->op == TOKconstruct && !identity_compare_p (sd))
{
tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
init = build_call_expr (tmemset, 3, build_address (t1),
integer_zero_node,
size_int (sd->structsize));
}
tree result = build_assign (modifycode, t1, t2);
this->result_ = compound_expr (init, result);
}
return; return;
} }
......
2020-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
PR d/94424
* gdc.dg/pr94424.d: New test.
2020-03-31 Felix Yang <felix.yang@huawei.com> 2020-03-31 Felix Yang <felix.yang@huawei.com>
PR tree-optimization/94398 PR tree-optimization/94398
......
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94424
// { dg-additional-options "-fmain -funittest" }
// { dg-do run { target hw } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
@safe unittest
{
struct C
{
ubyte i;
this(ubyte i) { this.i = i; }
}
auto c1 = C(1);
auto c2 = C(2);
assert(__cmp([c1, c1][], [c2, c2][]) < 0);
assert(__cmp([c2, c2], [c1, c1]) > 0);
assert(__cmp([c2, c2], [c2, c1]) > 0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment