This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gccgo] Lower map tuple assignments (v, ok = m[k])


I committed this patch to lower map tuple assignments to a function
call to a runtime function, an if statement, and a simple assignment.

Ian

Index: libgo/runtime/map.cgo
===================================================================
--- libgo/runtime/map.cgo	(revision 155929)
+++ libgo/runtime/map.cgo	(working copy)
@@ -4,12 +4,30 @@
 
 package runtime
 #include "map.h"
+#define nil NULL
 
 typedef unsigned char byte;
+typedef _Bool bool;
 
 typedef struct __go_map hmap;
 typedef struct __go_hash_iter hiter;
 
+/* Access a value in a map, returning a value and a presence indicator.  */
+
+func mapaccess2(h *hmap, key *byte, val *byte) (present bool) {
+	byte* mapval;
+	size_t valsize;
+
+	mapval = __go_map_index(h, key, 0);
+	if (mapval == nil) {
+		present = 0;
+	} else {
+		valsize = h->__descriptor->__map_descriptor->__val_type->__size;
+		__builtin_memcpy(val, mapval, valsize);
+		present = 1;
+	}
+}
+
 /* Initialize a range over a map.  */
 
 func mapiterinit(h *hmap, it *hiter) {
Index: gcc/go/statements.cc
===================================================================
--- gcc/go/statements.cc	(revision 155932)
+++ gcc/go/statements.cc	(working copy)
@@ -873,6 +873,7 @@ Statement::make_tuple_assignment(Operato
 }
 
 // A tuple assignment from a map index expression.
+//   v, ok = m[k]
 
 class Tuple_map_assignment_statement : public Statement
 {
@@ -888,17 +889,12 @@ public:
   int
   do_traverse(Traverse* traverse);
 
-  bool
-  do_traverse_assignments(Traverse_assignments*);
-
-  void
-  do_determine_types();
-
-  void
-  do_check_types(Gogo*);
+  Statement*
+  do_lower(Gogo*, Block*);
 
   tree
-  do_get_tree(Translate_context*);
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
 
  private:
   // Lvalue which receives the value from the map.
@@ -920,124 +916,95 @@ Tuple_map_assignment_statement::do_trave
   return this->traverse_expression(traverse, &this->map_index_);
 }
 
-// Traverse assignments.
+// Lower a tuple map assignment.
 
-bool
-Tuple_map_assignment_statement::do_traverse_assignments(
-    Traverse_assignments* tassign)
-{
-  tassign->assignment(&this->val_, &this->map_index_);
-  tassign->assignment(&this->present_, NULL);
-  return true;
-}
-
-// Set types if necessary.
-
-void
-Tuple_map_assignment_statement::do_determine_types()
+Statement*
+Tuple_map_assignment_statement::do_lower(Gogo*, Block* enclosing)
 {
-  this->map_index_->determine_type_no_context();
-
-  if (this->map_index_->map_index_expression() != NULL)
-    this->map_index_->map_index_expression() ->set_is_in_tuple_assignment();
-
-  Type_context subcontext1(this->map_index_->type()->points_to(), false);
-  this->val_->determine_type(&subcontext1);
-
-  Type_context subcontext2(Type::lookup_bool_type(), false);
-  this->present_->determine_type(&subcontext2);
-}
-
-// Check types.
+  source_location loc = this->location();
 
-void
-Tuple_map_assignment_statement::do_check_types(Gogo*)
-{
   Map_index_expression* map_index = this->map_index_->map_index_expression();
   if (map_index == NULL)
     {
       this->report_error(_("expected map index on right hand side"));
-      return;
+      return Statement::make_error_statement(loc);
     }
-  gcc_assert(map_index->is_in_tuple_assignment());
+  Map_type* map_type = map_index->get_map_type();
 
-  if (!this->val_->is_lvalue() || !this->present_->is_lvalue())
-    {
-      this->report_error(_("invalid left hand side of assignment"));
-      return;
-    }
+  Block* b = new Block(enclosing, loc);
 
-  // The type of the map index comes back as a pointer to the actual
-  // value type, because we called set_is_in_tuple_assignment.
-  Type* map_index_type = map_index->type()->points_to();
-  gcc_assert(map_index_type != NULL);
+  // Copy the key value into a temporary so that we can take its
+  // address without pushing the value onto the heap.
 
-  std::string reason;
-  if (!Type::are_compatible_for_assign(this->val_->type(), map_index_type,
-				       &reason))
-    {
-      if (reason.empty())
-	error_at(this->val_->location(),
-		 "incompatible types for variable and map");
-      else
-	error_at(this->val_->location(),
-		 "incompatible types for variable and map (%s)",
-		 reason.c_str());
-      this->set_is_error();
-    }
+  // var key_temp KEY_TYPE
+  Temporary_statement* key_temp =
+    Statement::make_temporary(map_type->key_type(), NULL, loc);
+  b->add_statement(key_temp);
 
-  if (!Type::are_compatible_for_assign(this->present_->type(),
-				       Type::lookup_bool_type(),
-				       &reason))
-    {
-      if (reason.empty())
-	error_at(this->present_->location(), "incompatible type for map index");
-      else
-	error_at(this->present_->location(),
-		 "incompatible type for map index (%s)",
-		 reason.c_str());
-      this->set_is_error();
-    }
-}
+  // key_temp = MAP_INDEX
+  Expression* ref = Expression::make_temporary_reference(key_temp, loc);
+  Statement* s = Statement::make_assignment(OPERATOR_EQ, ref,
+					    map_index->index(), loc);
+  b->add_statement(s);
 
-// Get a tree for a map assignment which returns a pair of values.
+  // var val_temp VAL_TYPE
+  Temporary_statement* val_temp =
+    Statement::make_temporary(map_type->val_type(), NULL, loc);
+  b->add_statement(val_temp);
+
+  // var present_temp bool
+  Temporary_statement* present_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
+  b->add_statement(present_temp);
 
-tree
-Tuple_map_assignment_statement::do_get_tree(Translate_context* context)
-{
-  tree valptr = this->map_index_->get_tree(context);
-  if (valptr == error_mark_node)
-    return error_mark_node;
-  valptr = save_expr(valptr);
+  // func mapaccess2(hmap map[k]v, key *k, val *v) bool
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("hmap", map_type, bloc));
+  Type* pkey_type = Type::make_pointer_type(map_type->key_type());
+  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
+  Type* pval_type = Type::make_pointer_type(map_type->val_type());
+  param_types->push_back(Typed_identifier("val", pval_type, bloc));
 
-  tree present_tree = this->present_->get_tree(context);
-  if (present_tree == error_mark_node)
-    return error_mark_node;
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("", Type::make_boolean_type(), bloc));
 
-  Type* rhs_type = this->map_index_->type()->points_to();
-  tree rhs_tree = build_fold_indirect_ref(valptr);
-  source_location location = this->location();
-  tree assign_val = Assignment_statement::get_assignment_tree(context,
-							      OPERATOR_EQ,
-							      this->val_,
-							      NULL_TREE,
-							      this->map_index_,
-							      rhs_type,
-							      rhs_tree,
-							      location);
-  if (assign_val == error_mark_node)
-    return error_mark_node;
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+						   ret_types, bloc);
+  Named_object* mapaccess2 =
+    Named_object::make_function_declaration("mapaccess2", NULL, fntype, bloc);
+  mapaccess2->func_declaration_value()->set_asm_name("runtime.mapaccess2");
 
-  return fold_build3(COND_EXPR, void_type_node,
-		     fold_build2(EQ_EXPR, boolean_type_node, valptr,
-				 fold_convert(TREE_TYPE(valptr),
-					      null_pointer_node)),
-		     fold_build2(MODIFY_EXPR, void_type_node,
-				 present_tree, boolean_false_node),
-		     build2(COMPOUND_EXPR, void_type_node,
-			    fold_build2(MODIFY_EXPR, void_type_node,
-					present_tree, boolean_true_node),
-			    assign_val));
+  // present_temp = mapaccess2(MAP, &key_temp, &val_temp)
+  Expression* func = Expression::make_func_reference(mapaccess2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(map_index->map());
+  ref = Expression::make_temporary_reference(key_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, loc);
+
+  ref = Expression::make_temporary_reference(present_temp, loc);
+  s = Statement::make_assignment(OPERATOR_EQ, ref, call, loc);
+  b->add_statement(s);
+
+  // if present_temp { val = val_temp }
+  Block* then_block = new Block(b, loc);
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  s = Statement::make_assignment(OPERATOR_EQ, this->val_, ref, loc);
+  then_block->add_statement(s);
+
+  ref = Expression::make_temporary_reference(present_temp, loc);
+  s = Statement::make_if_statement(ref, then_block, NULL, loc);
+  b->add_statement(s);
+
+  // present = present_temp
+  ref = Expression::make_temporary_reference(present_temp, loc);
+  s = Statement::make_assignment(OPERATOR_EQ, this->present_, ref, loc);
+  b->add_statement(s);
+
+  return Statement::make_block_statement(b, loc);
 }
 
 // Make a map assignment statement which returns a pair of values.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]