gollvm: fix an unary minus operations effect on expressions of complex types

The current implementation translates '-EXPR' into
'ZERO_EXPR - EXPR'. It handles EXPR of floating-point types as a
special case for which ZERO_EXPR is -0.0. This change applies the
same approach to EXPR of complex types so that '-CMPLX_EXPR'
translates into '(-0.0-0.0i) - CMPLX_EXPR' instead of
'(0.0+0.0i) - CMPLX_EXPR'.

Updates golang/go#51648

Change-Id: I66bcfaa9864a83d108c2719fe6dce59975e1c205
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/393595
Reviewed-by: Than McIntosh <thanm@google.com>
Trust: Bryan Mills <bcmills@google.com>
diff --git a/bridge/go-llvm.cpp b/bridge/go-llvm.cpp
index 301a062..312b38b 100644
--- a/bridge/go-llvm.cpp
+++ b/bridge/go-llvm.cpp
@@ -1531,10 +1531,21 @@
 
   Btype *bt = expr->btype();
 
+  // Special handling for unary minus applied to fp or complex type.
   if (op == OPERATOR_MINUS) {
-    // Special handling for unary minus applied to fp type.
-    BFloatType *ft = bt->castToBFloatType();
-    Bexpression *zerexp = (ft ? minusZeroExpr(ft) : zero_expression(bt));
+    Bexpression *zerexp;
+
+    switch (bt->flavor()) {
+    case Btype::FloatT:
+      zerexp = minusZeroExpr(bt->castToBFloatType());
+      break;
+    case Btype::ComplexT:
+      zerexp = minusZeroExpr(bt->castToBComplexType());
+      break;
+    default:
+      zerexp = zero_expression(bt);
+    }
+
     return binary_expression(OPERATOR_MINUS, zerexp, expr, location);
   }
 
@@ -1542,6 +1553,21 @@
   return rval;
 }
 
+Bexpression *Llvm_backend::minusZeroExpr(BComplexType *typ)
+{
+  assert(typ);
+  assert(typ->type()->getTypeID() == llvm::Type::StructTyID);
+
+  llvm::StructType *styp = llvm::cast<llvm::StructType>(typ->type());
+  llvm::Constant *nzrealcon = llvm::ConstantFP::getNegativeZero(styp->getElementType(0));
+  llvm::Constant *nzimagcon = llvm::ConstantFP::getNegativeZero(styp->getElementType(1));
+  std::vector<llvm::Constant*> structVals {nzrealcon, nzimagcon};
+  llvm::Constant *nzcmplxcon = llvm::ConstantStruct::get(styp, structVals);
+  Bexpression *bconst = nbuilder_.mkConst(typ, nzcmplxcon);
+
+  return makeGlobalExpression(bconst, nzcmplxcon, typ, Location());
+}
+
 Bexpression *Llvm_backend::minusZeroExpr(BFloatType *typ)
 {
   assert(typ);
diff --git a/bridge/go-llvm.h b/bridge/go-llvm.h
index db1e941..880ae39 100644
--- a/bridge/go-llvm.h
+++ b/bridge/go-llvm.h
@@ -687,6 +687,9 @@
   // hence no delayed value creation).
   Bexpression *lateConvert(Btype *type, Bexpression *expr, Location);
 
+  // Manufacture a complex constant corresponding to -0.0-0.0i
+  Bexpression *minusZeroExpr(BComplexType *typ);
+
   // Manufacture a floating point constant corresponding to -0.0
   Bexpression *minusZeroExpr(BFloatType *typ);