d: Inline bounds checking for simple array assignments.

This optimizes the code generation of simple array assignments, inlining
the array bounds checking code so there is no reliance on the library
routine _d_arraycopy(), which also deals with postblit and copy
constructors for non-trivial arrays.

gcc/d/ChangeLog:

	* expr.cc (ExprVisitor::visit (AssignExp *)): Inline bounds checking
	for simple array assignments.

gcc/testsuite/ChangeLog:

	* gdc.dg/array1.d: New test.
This commit is contained in:
Iain Buclaw 2020-07-19 15:18:08 +02:00
parent ab0edbcb37
commit febd7c43bc
2 changed files with 53 additions and 6 deletions

View File

@ -962,14 +962,47 @@ public:
/* Perform a memcpy operation. */
gcc_assert (e->e2->type->ty != Tpointer);
if (!postblit && !destructor && !array_bounds_check ())
if (!postblit && !destructor)
{
tree t1 = d_save_expr (d_array_convert (e->e1));
tree t2 = d_array_convert (e->e2);
tree size = size_mult_expr (d_array_length (t1),
size_int (etype->size ()));
tree result = build_memcpy_call (d_array_ptr (t1),
d_array_ptr (t2), size);
tree t2 = d_save_expr (d_array_convert (e->e2));
/* References to array data. */
tree t1ptr = d_array_ptr (t1);
tree t1len = d_array_length (t1);
tree t2ptr = d_array_ptr (t2);
/* Generate: memcpy(to, from, size) */
tree size = size_mult_expr (t1len, size_int (etype->size ()));
tree result = build_memcpy_call (t1ptr, t2ptr, size);
/* Insert check that array lengths match and do not overlap. */
if (array_bounds_check ())
{
/* tlencmp = (t1len == t2len) */
tree t2len = d_array_length (t2);
tree tlencmp = build_boolop (EQ_EXPR, t1len, t2len);
/* toverlap = (t1ptr + size <= t2ptr
|| t2ptr + size <= t1ptr) */
tree t1ptrcmp = build_boolop (LE_EXPR,
build_offset (t1ptr, size),
t2ptr);
tree t2ptrcmp = build_boolop (LE_EXPR,
build_offset (t2ptr, size),
t1ptr);
tree toverlap = build_boolop (TRUTH_ORIF_EXPR, t1ptrcmp,
t2ptrcmp);
/* (tlencmp && toverlap) ? memcpy() : _d_arraybounds() */
tree tassert = build_array_bounds_call (e->loc);
tree tboundscheck = build_boolop (TRUTH_ANDIF_EXPR,
tlencmp, toverlap);
result = build_condition (void_type_node, tboundscheck,
result, tassert);
}
this->result_ = compound_expr (result, t1);
}
else if ((postblit || destructor) && e->op != TOKblit)

View File

@ -0,0 +1,14 @@
// { dg-do compile }
// { dg-final { scan-assembler-not "_d_arraycopy" } }
void test1()
{
int[10] a1 = void;
int[10] a2 = void;
a1[] = a2[];
}
void test2(int[] a1, int[] a2)
{
a1[] = a2[];
}