gollvm: rework code for updating call attributes

Revise the code that gollvm uses to update function call attributes.
LLVM trunk has recently changed in ways that make it essential to call
AttrBuilder::addByValAttr for a "by value" parameter as opposed to
calling addAttribute() on the call directly (without the use of
addByValAttr the proper type isn't being recorded/cached, causing
a verifier error).

Updates golang/go#43870.

Change-Id: Ic229cd05328c32cc2bf1d4cde338ad3944134255
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/290532
Trust: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/bridge/go-llvm-materialize.cpp b/bridge/go-llvm-materialize.cpp
index 63fec77..99fa552 100644
--- a/bridge/go-llvm-materialize.cpp
+++ b/bridge/go-llvm-materialize.cpp
@@ -1318,34 +1318,56 @@
 
 void Llvm_backend::genCallAttributes(GenCallState &state, llvm::CallInst *call)
 {
+  const llvm::AttributeList &callAttrList = call->getAttributes();
+  llvm::AttrBuilder retAttrs(callAttrList, llvm::AttributeList::ReturnIndex);
+  const std::vector<Btype *> &paramTypes = state.calleeFcnType->paramTypes();
+  size_t na = state.oracle.getFunctionTypeForABI()->getNumParams();
+  llvm::SmallVector<llvm::AttributeSet, 4> argAttrs(na);
+
   // Sret attribute if needed
   const CABIParamInfo &returnInfo = state.oracle.returnInfo();
   if (returnInfo.disp() == ParmIndirect) {
-    call->addAttribute(1, llvm::Attribute::StructRet);
-    call->addAttribute(1, llvm::Attribute::get(call->getContext(), "go_sret"));
+    llvm::AttrBuilder ab;
+    ab.addAttribute(llvm::Attribute::StructRet);
+    ab.addAttribute(llvm::Attribute::get(call->getContext(), "go_sret"));
+    argAttrs[1] = llvm::AttributeSet::get(context_, ab);
   }
 
   // Nest attribute if needed
   const CABIParamInfo &chainInfo = state.oracle.chainInfo();
-  if (chainInfo.disp() != ParmIgnore)
-    call->addAttribute(chainInfo.sigOffset()+1, llvm::Attribute::Nest);
+  if (chainInfo.disp() != ParmIgnore) {
+    llvm::AttrBuilder ab;
+    ab.addAttribute(llvm::Attribute::Nest);
+    argAttrs[chainInfo.sigOffset()] =
+        llvm::AttributeSet::get(context_, ab);
+  }
 
   // Remainder of param attributes
-  const std::vector<Btype *> &paramTypes = state.calleeFcnType->paramTypes();
   for (unsigned idx = 0; idx < paramTypes.size(); ++idx) {
     const CABIParamInfo &paramInfo = state.oracle.paramInfo(idx);
     if (paramInfo.disp() == ParmIgnore)
       continue;
     assert(paramInfo.attr() != AttrNest);
     assert(paramInfo.attr() != AttrStructReturn);
-    unsigned off = paramInfo.sigOffset() + 1;
-    if (paramInfo.attr() == AttrByVal)
-      call->addAttribute(off, llvm::Attribute::ByVal);
-    else if (paramInfo.attr() == AttrZext)
-      call->addAttribute(off, llvm::Attribute::ZExt);
-    else if (paramInfo.attr() == AttrSext)
-      call->addAttribute(off, llvm::Attribute::SExt);
+    if (paramInfo.attr() != AttrNone) {
+      unsigned off = paramInfo.sigOffset();
+      llvm::AttrBuilder ab;
+      if (paramInfo.attr() == AttrByVal) {
+        ab.addByValAttr(paramTypes[idx]->type());
+      } else if (paramInfo.attr() == AttrZext) {
+        ab.addAttribute(llvm::Attribute::ZExt);
+      } else if (paramInfo.attr() == AttrSext) {
+        ab.addAttribute(llvm::Attribute::SExt);
+      }
+      argAttrs[off] = llvm::AttributeSet::get(context_, ab);
+    }
   }
+
+  call->setAttributes(
+      llvm::AttributeList::get(context_,
+                               callAttrList.getFnAttributes(),
+                               llvm::AttributeSet::get(context_, retAttrs),
+                               argAttrs));
 }
 
 void Llvm_backend::genCallEpilog(GenCallState &state,