aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2020-07-19 15:18:08 +0200
committerGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-17 13:20:17 -0300
commit5a467bb74a261df22772e60d9ab2ea22439d6d27 (patch)
tree715ba053befde079ca7dc10844e72b8bca92a4ef /gcc
parentaa68ce4e740c2c579fb778d6c2f39ca7307fc1d1 (diff)
downloadgcc-5a467bb74a261df22772e60d9ab2ea22439d6d27.zip
gcc-5a467bb74a261df22772e60d9ab2ea22439d6d27.tar.gz
gcc-5a467bb74a261df22772e60d9ab2ea22439d6d27.tar.bz2
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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/d/expr.cc45
-rw-r--r--gcc/testsuite/gdc.dg/array1.d14
2 files changed, 53 insertions, 6 deletions
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 58d4943..355561a 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -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)
diff --git a/gcc/testsuite/gdc.dg/array1.d b/gcc/testsuite/gdc.dg/array1.d
new file mode 100644
index 0000000..af81813
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/array1.d
@@ -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[];
+}