Commit b1403b69 by Ian Lance Taylor

compiler: eliminate bound checks in 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.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/166817

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