diff mbox series

Go patch committed: Eliminate bounds checks in append expression

Message ID CAOyqgcUpcaVMCt0ijv1x-knHmkQ3gWMxiEhoWfV2u2wVWWtJNw@mail.gmail.com
State New
Headers show
Series Go patch committed: Eliminate bounds checks in append expression | expand

Commit Message

Ian Lance Taylor March 15, 2019, 4:34 a.m. UTC
This patch by Cherry Zhang fixes the Go frontend to eliminate bound
checks in an append expression.  The compiler generates two array
index expressions when lowering an append expression.  Currently they
generate bound checks.  Bound checks are not necessary in this case,
as we know the slice has, or will grow to, enough length and capacity.
Eliminate them.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 269634)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-946aa5ab2e82d045a2a3b2f18ba2c5b00e957c4b
+80a7f6dae0861a06407a44c501b6346a4abd119c
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 269619)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -8008,8 +8008,8 @@  Builtin_call_expression::flatten_append(
   ref = Expression::make_temporary_reference(s1tmp, loc);
   Expression* zero = Expression::make_integer_ul(0, int_type, loc);
   Expression* ref2 = Expression::make_temporary_reference(ntmp, loc);
-  // FIXME: Mark this index as not requiring bounds checks.
-  ref = Expression::make_index(ref, zero, ref2, NULL, loc);
+  ref = Expression::make_array_index(ref, zero, ref2, NULL, loc);
+  ref->array_index_expression()->set_needs_bounds_check(false);
 
   if (assign_lhs == NULL)
     {
@@ -8058,8 +8058,8 @@  Builtin_call_expression::flatten_append(
       a1 = Expression::make_temporary_reference(s1tmp, loc);
       ref = Expression::make_temporary_reference(l1tmp, loc);
       Expression* nil = Expression::make_nil(loc);
-      // FIXME: Mark this index as not requiring bounds checks.
-      a1 = Expression::make_index(a1, ref, nil, NULL, loc);
+      a1 = Expression::make_array_index(a1, ref, nil, NULL, loc);
+      a1->array_index_expression()->set_needs_bounds_check(false);
 
       a2 = Expression::make_temporary_reference(s2tmp, loc);
 
@@ -8086,9 +8086,9 @@  Builtin_call_expression::flatten_append(
 	  ref2 = Expression::make_temporary_reference(l1tmp, loc);
 	  Expression* off = Expression::make_integer_ul(i, int_type, loc);
 	  ref2 = Expression::make_binary(OPERATOR_PLUS, ref2, off, loc);
-	  // FIXME: Mark this index as not requiring bounds checks.
-	  Expression* lhs = Expression::make_index(ref, ref2, NULL, NULL,
-						   loc);
+	  Expression* lhs = Expression::make_array_index(ref, ref2, NULL,
+                                                         NULL, loc);
+          lhs->array_index_expression()->set_needs_bounds_check(false);
 	  gogo->lower_expression(function, inserter, &lhs);
 	  gogo->flatten_expression(function, inserter, &lhs);
 	  // The flatten pass runs after the write barrier pass, so we
@@ -11328,15 +11328,6 @@  Array_index_expression::do_get_backend(T
   if (length == NULL)
     length = cap_arg;
 
-  int code = (array_type->length() != NULL
-	      ? (this->end_ == NULL
-		 ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS
-		 : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS)
-	      : (this->end_ == NULL
-		 ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
-		 : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
-  Bexpression* crash = gogo->runtime_error(code, loc)->get_backend(context);
-
   if (this->start_->type()->integer_type() == NULL
       && !Type::are_convertible(int_type, this->start_->type(), NULL))
     {
@@ -11344,31 +11335,46 @@  Array_index_expression::do_get_backend(T
       return context->backend()->error_expression();
     }
 
-  Bexpression* bad_index =
-    Expression::check_bounds(this->start_, loc)->get_backend(context);
-
   Bexpression* start = this->start_->get_backend(context);
   start = gogo->backend()->convert_expression(int_btype, start, loc);
-  Bexpression* start_too_large =
-    gogo->backend()->binary_expression((this->end_ == NULL
-					? OPERATOR_GE
-					: OPERATOR_GT),
-                                       start,
-				       (this->end_ == NULL
-					? length
-					: capacity),
-                                       loc);
-  bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large,
-						 bad_index, loc);
+
+  Bexpression* crash = NULL;
+  Bexpression* bad_index = NULL;
+  if (this->needs_bounds_check_)
+    {
+      int code = (array_type->length() != NULL
+                  ? (this->end_ == NULL
+                     ? RUNTIME_ERROR_ARRAY_INDEX_OUT_OF_BOUNDS
+                     : RUNTIME_ERROR_ARRAY_SLICE_OUT_OF_BOUNDS)
+                  : (this->end_ == NULL
+                     ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
+                     : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
+      crash = gogo->runtime_error(code, loc)->get_backend(context);
+      bad_index = Expression::check_bounds(this->start_, loc)->get_backend(context);
+      Bexpression* start_too_large =
+        gogo->backend()->binary_expression((this->end_ == NULL
+                                            ? OPERATOR_GE
+                                            : OPERATOR_GT),
+                                           start,
+                                           (this->end_ == NULL
+                                            ? length
+                                            : capacity),
+                                           loc);
+      bad_index = gogo->backend()->binary_expression(OPERATOR_OROR,
+                                                     start_too_large,
+                                                     bad_index, loc);
+    }
+
 
   Bfunction* bfn = context->function()->func_value()->get_decl();
   if (this->end_ == NULL)
     {
       // Simple array indexing.  This has to return an l-value, so
       // wrap the index check into START.
-      start =
-        gogo->backend()->conditional_expression(bfn, int_btype, bad_index,
-						crash, start, loc);
+      if (this->needs_bounds_check_)
+        start =
+          gogo->backend()->conditional_expression(bfn, int_btype, bad_index,
+                                                  crash, start, loc);
 
       Bexpression* ret;
       if (array_type->length() != NULL)
@@ -11396,22 +11402,26 @@  Array_index_expression::do_get_backend(T
 
   if (this->cap_ != NULL)
     {
-      Bexpression* bounds_bcheck =
-	Expression::check_bounds(this->cap_, loc)->get_backend(context);
-      bad_index =
-	gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
-					   bad_index, loc);
       cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
 
-      Bexpression* cap_too_small =
-	gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
-      Bexpression* cap_too_large =
-	gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
-      Bexpression* bad_cap =
-	gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
-					   cap_too_large, loc);
-      bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
-						     bad_index, loc);
+      if (this->needs_bounds_check_)
+        {
+          Bexpression* bounds_bcheck =
+            Expression::check_bounds(this->cap_, loc)->get_backend(context);
+          bad_index =
+            gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+                                               bad_index, loc);
+
+          Bexpression* cap_too_small =
+            gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
+          Bexpression* cap_too_large =
+            gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
+          Bexpression* bad_cap =
+            gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
+                                               cap_too_large, loc);
+          bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
+                                                         bad_index, loc);
+        }
     }
 
   Bexpression* end;
@@ -11419,24 +11429,26 @@  Array_index_expression::do_get_backend(T
     end = length;
   else
     {
-      Bexpression* bounds_bcheck =
-	Expression::check_bounds(this->end_, loc)->get_backend(context);
-
-      bad_index =
-	gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
-					   bad_index, loc);
-
       end = this->end_->get_backend(context);
       end = gogo->backend()->convert_expression(int_btype, end, loc);
-      Bexpression* end_too_small =
-	gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
-      Bexpression* end_too_large =
-	gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
-      Bexpression* bad_end =
-	gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
-					   end_too_large, loc);
-      bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
-						     bad_index, loc);
+      if (this->needs_bounds_check_)
+        {
+          Bexpression* bounds_bcheck =
+            Expression::check_bounds(this->end_, loc)->get_backend(context);
+          bad_index =
+            gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+                                               bad_index, loc);
+
+          Bexpression* end_too_small =
+            gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
+          Bexpression* end_too_large =
+            gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
+          Bexpression* bad_end =
+            gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
+                                               end_too_large, loc);
+          bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
+                                                         bad_index, loc);
+        }
     }
 
   Bexpression* result_length =
@@ -11468,10 +11480,12 @@  Array_index_expression::do_get_backend(T
   init.push_back(result_length);
   init.push_back(result_capacity);
 
-  Bexpression* ctor =
+  Bexpression* ret =
     gogo->backend()->constructor_expression(struct_btype, init, loc);
-  return gogo->backend()->conditional_expression(bfn, struct_btype, bad_index,
-						 crash, ctor, loc);
+  if (this->needs_bounds_check_)
+    ret = gogo->backend()->conditional_expression(bfn, struct_btype, bad_index,
+                                                  crash, ret, loc);
+  return ret;
 }
 
 // Dump ast representation for an array index expression.
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 269619)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -2854,7 +2854,7 @@  class Array_index_expression : public Ex
 			 Expression* end, Expression* cap, Location location)
     : Expression(EXPRESSION_ARRAY_INDEX, location),
       array_(array), start_(start), end_(end), cap_(cap), type_(NULL),
-      is_lvalue_(false)
+      is_lvalue_(false), needs_bounds_check_(true)
   { }
 
   // Return the array.
@@ -2898,6 +2898,10 @@  class Array_index_expression : public Ex
   set_is_lvalue()
   { this->is_lvalue_ = true; }
 
+  void
+  set_needs_bounds_check(bool b)
+  { this->needs_bounds_check_ = b; }
+
  protected:
   int
   do_traverse(Traverse*);
@@ -2917,15 +2921,17 @@  class Array_index_expression : public Ex
   Expression*
   do_copy()
   {
-    return Expression::make_array_index(this->array_->copy(),
-					this->start_->copy(),
-					(this->end_ == NULL
-					 ? NULL
-					 : this->end_->copy()),
-					(this->cap_ == NULL
-					 ? NULL
-					 : this->cap_->copy()),
-					this->location());
+    Expression* ret = Expression::make_array_index(this->array_->copy(),
+                                                   this->start_->copy(),
+                                                   (this->end_ == NULL
+                                                    ? NULL
+                                                    : this->end_->copy()),
+                                                   (this->cap_ == NULL
+                                                    ? NULL
+                                                    : this->cap_->copy()),
+                                                   this->location());
+    ret->array_index_expression()->set_needs_bounds_check(this->needs_bounds_check_);
+    return ret;
   }
 
   bool
@@ -2962,6 +2968,8 @@  class Array_index_expression : public Ex
   Type* type_;
   // Whether expr appears in an lvalue context.
   bool is_lvalue_;
+  // Whether bounds check is needed.
+  bool needs_bounds_check_;
 };
 
 // A string index.  This is used for both indexing and slicing.