bridge: support compound expression with composite subexpression

Support expressions like (x=foo(); {x, y}). Specifically, we need
to resolve composite init when materializing compound expression.

Change-Id: I1c51865b2ac0f0d38237e7ecf0324e0141ac3d73
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/168401
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/bridge/go-llvm-materialize.cpp b/bridge/go-llvm-materialize.cpp
index e8814c2..5bb59a3 100644
--- a/bridge/go-llvm-materialize.cpp
+++ b/bridge/go-llvm-materialize.cpp
@@ -422,6 +422,10 @@
 
   // Compound expressions can be used to produce lvalues, so we don't
   // want to call resolve() on bexpr here.
+  // But we do want to resolve composite init.
+  if (bexpr->compositeInitPending())
+    bexpr = resolveCompositeInit(bexpr, nullptr);
+
   Bexpression *rval = nbuilder_.mkCompound(bstat, bexpr, bexpr->value(),
                                            location);
   if (bexpr->varExprPending())
diff --git a/unittests/BackendCore/BackendExprTests.cpp b/unittests/BackendCore/BackendExprTests.cpp
index de82e34..16e2f2f 100644
--- a/unittests/BackendCore/BackendExprTests.cpp
+++ b/unittests/BackendCore/BackendExprTests.cpp
@@ -1523,6 +1523,69 @@
   EXPECT_TRUE(isOK && "Function does not have expected contents");
 }
 
+TEST(BackendExprTests, TestCompoundExpression2) {
+
+  FcnTestHarness h("foo");
+  Llvm_backend *be = h.be();
+  Bfunction *func = h.func();
+  Location loc;
+
+  // var x int64
+  // var y = (x = 5; struct{int64; int64}{x, x})
+  Btype *bi64t = be->integer_type(false, 64);
+  Bvariable *xv = h.mkLocal("x", bi64t);
+  Bexpression *vex = be->var_expression(xv, loc);
+  Bstatement *st = be->assignment_statement(func, vex,
+                                            mkInt64Const(be, 5), loc);
+  Bexpression *vex1 = be->var_expression(xv, loc);
+  Bexpression *vex2 = be->var_expression(xv, loc);
+  Btype *bst = mkTwoFieldStruct(be, bi64t, bi64t);
+  Bexpression *sce = be->constructor_expression(bst, {vex1, vex2}, loc);
+  Bexpression *ce = be->compound_expression(st, sce, loc);
+
+  Bvariable *yv = h.mkLocal("y", bst);
+  Bexpression *yvex = be->var_expression(yv, loc);
+  Bstatement *st2 = be->assignment_statement(func, yvex, ce, loc);
+  h.addStmt(st2);
+
+  const char *exp = R"RAW_RESULT(
+    define i64 @foo(i8* nest %nest.0, i32 %param1, i32 %param2, i64* %param3) #0 {
+      entry:
+        %tmp.0 = alloca { i64, i64 }
+        %param1.addr = alloca i32
+        %param2.addr = alloca i32
+        %param3.addr = alloca i64*
+        %x = alloca i64
+        %y = alloca { i64, i64 }
+        store i32 %param1, i32* %param1.addr
+        store i32 %param2, i32* %param2.addr
+        store i64* %param3, i64** %param3.addr
+        store i64 0, i64* %x
+        %cast.0 = bitcast { i64, i64 }* %y to i8*
+        %cast.1 = bitcast { i64, i64 }* @const.0 to i8*
+        call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %cast.0, i8* align 8 %cast.1, i64 16, i1 false)
+        store i64 5, i64* %x
+        %x.ld.0 = load i64, i64* %x
+        %x.ld.1 = load i64, i64* %x
+        %field.0 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp.0, i32 0, i32 0
+        store i64 %x.ld.0, i64* %field.0
+        %field.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp.0, i32 0, i32 1
+        store i64 %x.ld.1, i64* %field.1
+        %cast.2 = bitcast { i64, i64 }* %y to i8*
+        %cast.3 = bitcast { i64, i64 }* %tmp.0 to i8*
+        call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %cast.2, i8* align 8 %cast.3, i64 16, i1 false)
+        ret i64 0
+      }
+    )RAW_RESULT";
+
+  bool broken = h.finish(StripDebugInfo);
+  EXPECT_FALSE(broken && "Module failed to verify.");
+
+  // Note that this
+  bool isOK = h.expectValue(func->function(), exp);
+  EXPECT_TRUE(isOK && "Function does not have expected contents");
+}
+
 TEST(BackendExprTests, TestLhsConditionalExpression) {
 
   FcnTestHarness h;