compiler: use gcWriteBarrier for pointer-shaped struct/array

If a struct/array is pointer-shaped (i.e. having a single field
that is pointer-shaped), we can use gcWriteBarrier instead of
typedmemmove for the write barrier.

Change-Id: Ic782ed35d8bf8df23e6c5487a78f83c420ff0659
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/181539
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/go/wb.cc b/go/wb.cc
index 47cffee..c1d54e6 100644
--- a/go/wb.cc
+++ b/go/wb.cc
@@ -955,14 +955,21 @@
       // fallthrough
 
     case Type::TYPE_STRUCT:
-      {
-        // TODO: split assignments for small struct/array?
-	rhs = Expression::make_unary(OPERATOR_AND, rhs, loc);
-	rhs->unary_expression()->set_does_not_escape();
-	call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3,
-				  Expression::make_type_descriptor(type, loc),
-				  lhs, rhs);
-      }
+      if (type->is_direct_iface_type())
+        {
+          rhs = Expression::unpack_direct_iface(rhs, loc);
+          rhs = Expression::make_unsafe_cast(uintptr_type, rhs, loc);
+          call = Runtime::make_call(Runtime::GCWRITEBARRIER, loc, 2, lhs, rhs);
+        }
+      else
+        {
+          // TODO: split assignments for small struct/array?
+          rhs = Expression::make_unary(OPERATOR_AND, rhs, loc);
+          rhs->unary_expression()->set_does_not_escape();
+          call = Runtime::make_call(Runtime::TYPEDMEMMOVE, loc, 3,
+                                    Expression::make_type_descriptor(type, loc),
+                                    lhs, rhs);
+        }
       break;
     }