This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gccgo] Implement copy
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 04 Dec 2009 11:50:56 -0800
- Subject: [gccgo] Implement copy
A predeclared function "copy" was added to Go. This patch adds
support to gccgo. Committed to gccgo branch.
Ian
Index: gogo.cc
===================================================================
--- gogo.cc (revision 154511)
+++ gogo.cc (working copy)
@@ -171,6 +171,14 @@ Gogo::Gogo()
closed_type->set_is_builtin();
this->globals_->add_function_declaration("closed", NULL, closed_type, loc);
+ Typed_identifier_list* copy_result = new Typed_identifier_list();
+ copy_result->push_back(Typed_identifier("", int_type, loc));
+ Function_type* copy_type = Type::make_function_type(NULL, NULL,
+ copy_result, loc);
+ copy_type->set_is_varargs();
+ copy_type->set_is_builtin();
+ this->globals_->add_function_declaration("copy", NULL, copy_type, loc);
+
this->define_builtin_function_trees();
// Declare "init", to ensure that it is not defined with parameters
Index: gogo-tree.cc
===================================================================
--- gogo-tree.cc (revision 154511)
+++ gogo-tree.cc (working copy)
@@ -97,6 +97,15 @@ Gogo::define_builtin_function_trees()
NULL_TREE),
true);
+ // We use __builtin_memmove for the predeclared copy function.
+ define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
+ build_function_type_list(ptr_type_node,
+ ptr_type_node,
+ const_ptr_type_node,
+ size_type_node,
+ NULL_TREE),
+ false);
+
// We provide sqrt for the math library.
define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
build_function_type_list(double_type_node,
Index: expressions.cc
===================================================================
--- expressions.cc (revision 154511)
+++ expressions.cc (working copy)
@@ -4990,6 +4990,7 @@ class Builtin_call_expression : public C
BUILTIN_CAP,
BUILTIN_CLOSE,
BUILTIN_CLOSED,
+ BUILTIN_COPY,
BUILTIN_LEN,
BUILTIN_MAKE,
BUILTIN_NEW,
@@ -5033,6 +5034,8 @@ Builtin_call_expression::Builtin_call_ex
this->code_ = BUILTIN_CLOSE;
else if (name == "closed")
this->code_ = BUILTIN_CLOSED;
+ else if (name == "copy")
+ this->code_ = BUILTIN_COPY;
else if (name == "len")
this->code_ = BUILTIN_LEN;
else if (name == "make")
@@ -5313,6 +5316,7 @@ Builtin_call_expression::do_type()
}
case BUILTIN_CAP:
+ case BUILTIN_COPY:
case BUILTIN_LEN:
case BUILTIN_ALIGNOF:
case BUILTIN_OFFSETOF:
@@ -5483,6 +5487,55 @@ Builtin_call_expression::do_check_types(
}
break;
+ case BUILTIN_COPY:
+ {
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() < 2)
+ {
+ this->report_error(_("not enough arguments"));
+ break;
+ }
+ else if (args->size() > 2)
+ {
+ this->report_error(_("too many arguments"));
+ break;
+ }
+ Type* arg1_type = args->front()->type();
+ Type* arg2_type = args->back()->type();
+ if (arg1_type->is_error_type() || arg2_type->is_error_type())
+ break;
+
+ Type* e1;
+ if (arg1_type->is_open_array_type())
+ e1 = arg1_type->array_type()->element_type();
+ else if (arg1_type->points_to() != NULL
+ && arg1_type->points_to()->array_type() != NULL
+ && !arg1_type->points_to()->is_open_array_type())
+ e1 = arg1_type->points_to()->array_type()->element_type();
+ else
+ {
+ this->report_error(_("both arguments must be slices"));
+ break;
+ }
+
+ Type* e2;
+ if (arg2_type->is_open_array_type())
+ e2 = arg2_type->array_type()->element_type();
+ else if (arg2_type->points_to() != NULL
+ && arg2_type->points_to()->array_type() != NULL
+ && !arg2_type->points_to()->is_open_array_type())
+ e2 = arg2_type->points_to()->array_type()->element_type();
+ else
+ {
+ this->report_error(_("both arguments must be slices"));
+ break;
+ }
+
+ if (!Type::are_identical(e1, e2))
+ this->report_error(_("element types must be the same"));
+ }
+ break;
+
default:
gcc_unreachable();
}
@@ -5494,6 +5547,7 @@ tree
Builtin_call_expression::do_get_tree(Translate_context* context)
{
Gogo* gogo = context->gogo();
+ source_location location = this->location();
switch (this->code_)
{
case BUILTIN_INVALID:
@@ -5532,7 +5586,7 @@ Builtin_call_expression::do_get_tree(Tra
{
static tree map_len_fndecl;
val_tree = Gogo::call_builtin(&map_len_fndecl,
- this->location(),
+ location,
"__go_map_len",
1,
sizetype,
@@ -5543,7 +5597,7 @@ Builtin_call_expression::do_get_tree(Tra
{
static tree chan_len_fndecl;
val_tree = Gogo::call_builtin(&chan_len_fndecl,
- this->location(),
+ location,
"__go_chan_len",
1,
sizetype,
@@ -5561,7 +5615,7 @@ Builtin_call_expression::do_get_tree(Tra
{
static tree chan_cap_fndecl;
val_tree = Gogo::call_builtin(&chan_cap_fndecl,
- this->location(),
+ location,
"__go_chan_cap",
1,
sizetype,
@@ -5750,11 +5804,10 @@ Builtin_call_expression::do_get_tree(Tra
}
tree fnptr = build_fold_addr_expr(*pfndecl);
- tree call = build_call_array(void_type_node, fnptr, nargs, args);
+ tree call = build_call_array_loc(location, void_type_node,
+ fnptr, nargs, args);
delete[] args;
- SET_EXPR_LOCATION(call, this->location());
-
return call;
}
@@ -5771,7 +5824,7 @@ Builtin_call_expression::do_get_tree(Tra
{
static tree close_fndecl;
return Gogo::call_builtin(&close_fndecl,
- this->location(),
+ location,
"__go_builtin_close",
1,
void_type_node,
@@ -5782,7 +5835,7 @@ Builtin_call_expression::do_get_tree(Tra
{
static tree closed_fndecl;
return Gogo::call_builtin(&closed_fndecl,
- this->location(),
+ location,
"__go_builtin_closed",
1,
boolean_type_node,
@@ -5806,6 +5859,73 @@ Builtin_call_expression::do_get_tree(Tra
return ret;
}
+ case BUILTIN_COPY:
+ {
+ const Expression_list* args = this->args();
+ gcc_assert(args != NULL && args->size() == 2);
+ Expression* arg1 = args->front();
+ Expression* arg2 = args->back();
+
+ tree arg1_tree = arg1->get_tree(context);
+ tree arg2_tree = arg2->get_tree(context);
+ if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
+ return error_mark_node;
+
+ Type* arg1_type = arg1->type();
+ if (!arg1_type->is_open_array_type())
+ {
+ gcc_assert(arg1_type->points_to() != NULL
+ && arg1_type->points_to()->array_type() != NULL
+ && !arg1_type->points_to()->is_open_array_type());
+ arg1_type = arg1_type->points_to();
+ arg1_tree = build_fold_indirect_ref_loc(location, arg1_tree);
+ }
+ Array_type* at = arg1_type->array_type();
+ arg1_tree = save_expr(arg1_tree);
+ tree arg1_val = at->value_pointer_tree(gogo, arg1_tree);
+ tree arg1_len = at->length_tree(gogo, arg1_tree);
+
+ Type* arg2_type = arg2->type();
+ if (!arg2_type->is_open_array_type())
+ {
+ gcc_assert(arg2_type->points_to() != NULL
+ && arg2_type->points_to()->array_type() != NULL
+ && !arg2_type->points_to()->is_open_array_type());
+ arg2_type = arg2_type->points_to();
+ arg2_tree = build_fold_indirect_ref_loc(location, arg2_tree);
+ }
+ at = arg2_type->array_type();
+ arg2_tree = save_expr(arg2_tree);
+ tree arg2_val = at->value_pointer_tree(gogo, arg2_tree);
+ tree arg2_len = at->length_tree(gogo, arg2_tree);
+
+ arg1_len = save_expr(arg1_len);
+ arg2_len = save_expr(arg2_len);
+ tree len = fold_build3_loc(location, COND_EXPR, TREE_TYPE(arg1_len),
+ fold_build2_loc(location, LT_EXPR,
+ boolean_type_node,
+ arg1_len, arg2_len),
+ arg1_len, arg2_len);
+ len = save_expr(len);
+
+ Type* element_type = at->element_type();
+ tree element_type_tree = element_type->get_tree(gogo);
+ tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+ tree bytecount = fold_convert_loc(location, TREE_TYPE(element_size),
+ len);
+ bytecount = fold_build2_loc(location, MULT_EXPR,
+ TREE_TYPE(element_size),
+ bytecount, element_size);
+ bytecount = fold_convert_loc(location, size_type_node, bytecount);
+
+ tree call = build_call_expr_loc(location,
+ built_in_decls[BUILT_IN_MEMMOVE],
+ 3, arg1_val, arg2_val, bytecount);
+
+ return fold_build2_loc(location, COMPOUND_EXPR, TREE_TYPE(len),
+ call, len);
+ }
+
default:
gcc_unreachable();
}