gollvm: add no-return flag to Backend function API

This brings gollvm into sync with a recent change to the Backend API at
https://go-review.googlesource.com/c/gofrontend/+/80416, to allow
marking of functions as no-return. Also adds support for the
__builtin_unreachable intrinsic.

Change-Id: I18f75ef4eacef11095da22afd4610dbbc4f25369
Reviewed-on: https://go-review.googlesource.com/80995
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/llvm-gofrontend/go-llvm-builtins.cpp b/llvm-gofrontend/go-llvm-builtins.cpp
index 445fc80..8d5bbbb 100644
--- a/llvm-gofrontend/go-llvm-builtins.cpp
+++ b/llvm-gofrontend/go-llvm-builtins.cpp
@@ -119,7 +119,6 @@
 
   defineIntrinsicBuiltin("__builtin_trap", nullptr, llvm::Intrinsic::trap,
                          nullptr);
-
   defineIntrinsicBuiltin("__builtin_return_address", nullptr,
                          llvm::Intrinsic::returnaddress, ptrType,
                          uint32Type, nullptr);
@@ -332,14 +331,29 @@
   return args[0];
 }
 
+static llvm::Value *builtinUnreachableMaker(llvm::SmallVector<llvm::Value*, 16> args,
+                                            BinstructionsLIRBuilder *builder)
+{
+  llvm::UnreachableInst *unr = builder->CreateUnreachable();
+  return unr;
+}
+
 void BuiltinTable::defineExprBuiltins()
 {
   unsigned bitsInPtr = tman_->datalayout()->getPointerSizeInBits();
   Btype *uintPtrType = tman_->integerType(true, bitsInPtr);
 
-  BuiltinEntryTypeVec typeVec(2);
-  typeVec[0] = uintPtrType;
-  typeVec[1] = uintPtrType;
-  registerExprBuiltin("__builtin_extract_return_addr", nullptr,
-                      typeVec, builtinExtractReturnAddrMaker);
+  {
+    BuiltinEntryTypeVec typeVec(2);
+    typeVec[0] = uintPtrType;
+    typeVec[1] = uintPtrType;
+    registerExprBuiltin("__builtin_extract_return_addr", nullptr,
+                        typeVec, builtinExtractReturnAddrMaker);
+  }
+
+  {
+    BuiltinEntryTypeVec typeVec;
+    registerExprBuiltin("__builtin_unreachable", nullptr,
+                        typeVec, builtinUnreachableMaker);
+  }
 }
diff --git a/llvm-gofrontend/go-llvm.cpp b/llvm-gofrontend/go-llvm.cpp
index f8e9099..49535d0 100644
--- a/llvm-gofrontend/go-llvm.cpp
+++ b/llvm-gofrontend/go-llvm.cpp
@@ -437,17 +437,30 @@
   std::vector<Btyped_identifier> results;
   Location bloc(linemap_->get_predeclared_location());
   const BuiltinEntryTypeVec &types = be->types();
-  Btyped_identifier result("ret", types[0], bloc);
-  results.push_back(result);
+  if (types.size() > 0) {
+    Btyped_identifier result("ret", types[0], bloc);
+    results.push_back(result);
+  }
   for (unsigned idx = 1; idx < types.size(); ++idx)
     params.push_back(Btyped_identifier("", types[idx], bloc));
   bool followsCabi = false;
   Btype *fcnType = functionType(receiver, params, results, nullptr,
                                 followsCabi, bloc);
 
+  // FIXME: may want to revisit these settings at some point. For example,
+  // do we want to mark builtins as no-split-stack? Also it might be useful
+  // to allow for creation of no-return builtins (such as longjmp, perhaps).
+  bool is_visible = true;
+  bool is_declaration = false;
+  bool is_inl = true;
+  bool is_splitstack = true;
+  bool in_unique_section = false;
+  bool is_noret = false;
+
   // Create function
   return function(fcnType, be->name(), be->name(),
-                  true, false, false, false, false, bloc);
+                  is_visible, is_declaration, is_inl, is_splitstack,
+                  is_noret, in_unique_section, bloc);
 }
 
 bool Llvm_backend::moduleScopeValue(llvm::Value *val, Btype *btype) const
@@ -2365,7 +2378,7 @@
 Bfunction *Llvm_backend::function(Btype *fntype, const std::string &name,
                                   const std::string &asm_name, bool is_visible,
                                   bool is_declaration, bool is_inlinable,
-                                  bool disable_split_stack,
+                                  bool disable_split_stack, bool no_return,
                                   bool in_unique_section, Location location)
 {
   if (fntype == errorType())
@@ -2425,6 +2438,10 @@
     if (! disable_split_stack)
       fcn->addFnAttr("split-stack");
 
+    // no-return
+    if (no_return)
+      fcn->addFnAttr(llvm::Attribute::NoReturn);
+
     fcnValue = fcn;
 
     // Fix up references to declaration of old type.
diff --git a/llvm-gofrontend/go-llvm.h b/llvm-gofrontend/go-llvm.h
index 14798c5..03f682c 100644
--- a/llvm-gofrontend/go-llvm.h
+++ b/llvm-gofrontend/go-llvm.h
@@ -309,8 +309,8 @@
   Bfunction *function(Btype *fntype, const std::string &name,
                       const std::string &asm_name, bool is_visible,
                       bool is_declaration, bool is_inlinable,
-                      bool disable_split_stack, bool in_unique_section,
-                      Location);
+                      bool disable_split_stack, bool does_not_return,
+                      bool in_unique_section, Location);
 
   Bstatement *function_defer_statement(Bfunction *function,
                                        Bexpression *undefer, Bexpression *defer,
diff --git a/unittests/BackendCore/BackendCallTests.cpp b/unittests/BackendCore/BackendCallTests.cpp
index cc000be..1d82b0d 100644
--- a/unittests/BackendCore/BackendCallTests.cpp
+++ b/unittests/BackendCore/BackendCallTests.cpp
@@ -61,9 +61,10 @@
   Btype *befty = mkFuncTyp(be, L_END);
   bool is_decl = true; bool is_inl = false;
   bool is_vis = true; bool is_split = true;
+  bool is_noret = false; bool is_uniqsec = false;
   Bfunction *befcn = be->function(befty, "bar", "bar",
                                   is_vis, is_decl, is_inl, is_split,
-                                  false, loc);
+                                  is_noret, is_uniqsec, loc);
 
   // Create call to it
   Bexpression *fn = be->function_code_expression(befcn, loc);
diff --git a/unittests/BackendCore/BackendFcnTests.cpp b/unittests/BackendCore/BackendFcnTests.cpp
index c998e46..6332121 100644
--- a/unittests/BackendCore/BackendFcnTests.cpp
+++ b/unittests/BackendCore/BackendFcnTests.cpp
@@ -86,24 +86,28 @@
   const bool is_visible[2] = {true, false};
   const bool is_inlinable[2] = {true, false};
   bool split_stack[2] = {true, false};
+  bool is_noret[2] = {true, false};
   Location loc;
   unsigned count = 0;
   for (auto vis : is_visible) {
     for (auto inl : is_inlinable) {
       for (auto split : split_stack) {
-        std::stringstream ss;
-        ss << "fcn" << count++;
-        Bfunction *befcn =
-            be->function(befty, "_foo", ss.str(), vis, is_declaration,
-                         inl, split, in_unique_section, loc);
-        llvm::Function *llfunc = befcn->function();
-        ASSERT_TRUE(llfunc != NULL);
-        EXPECT_EQ(llfunc->getName(), ss.str());
-        EXPECT_FALSE(llfunc->isVarArg());
-        EXPECT_EQ(llfunc->hasFnAttribute(Attribute::NoInline), !inl);
-        EXPECT_EQ(llfunc->hasExternalLinkage(), vis);
-        EXPECT_EQ(llfunc->hasInternalLinkage(), !vis);
-        EXPECT_EQ(befcn->splitStack() == Bfunction::YesSplit, !split);
+        for (auto noret : is_noret) {
+          std::stringstream ss;
+          ss << "fcn" << count++;
+          Bfunction *befcn =
+              be->function(befty, "_foo", ss.str(), vis, is_declaration,
+                           inl, split, noret, in_unique_section, loc);
+          llvm::Function *llfunc = befcn->function();
+          ASSERT_TRUE(llfunc != NULL);
+          EXPECT_EQ(llfunc->getName(), ss.str());
+          EXPECT_FALSE(llfunc->isVarArg());
+          EXPECT_EQ(llfunc->hasFnAttribute(Attribute::NoInline), !inl);
+          EXPECT_EQ(llfunc->hasFnAttribute(Attribute::NoReturn), noret);
+          EXPECT_EQ(llfunc->hasExternalLinkage(), vis);
+          EXPECT_EQ(llfunc->hasInternalLinkage(), !vis);
+          EXPECT_EQ(befcn->splitStack() == Bfunction::YesSplit, !split);
+        }
       }
     }
   }
@@ -115,7 +119,7 @@
   // Try to create a function with an error type -- we should
   // get back error_function
   Bfunction *mistake = be->function(be->error_type(), "bad", "bad", true, true,
-                                    false, false, false, loc);
+                                    false, false, false, false, loc);
   EXPECT_EQ(mistake, be_error_fcn);
 }
 
@@ -132,7 +136,7 @@
       "__builtin_memcmp",        "__builtin_ctz",
       "__builtin_ctzll",         "__builtin_bswap32",
       "__builtin_bswap64",       "__builtin_return_address",
-      "__builtin_frame_address",
+      "__builtin_frame_address", "__builtin_unreachable"
   };
   for (auto fname : tocheck) {
     Bfunction *bfcn = be->lookup_builtin(fname);
@@ -243,18 +247,19 @@
   bool is_inl = true;
   bool is_splitstack = true;
   bool in_unique_section = false;
+  bool is_noret = false;
   Bfunction *bf1 =
       be->function(befty1, "_foo", "bar", is_visible, is_declaration,
-                         is_inl, is_splitstack, in_unique_section, loc);
+                   is_inl, is_splitstack, is_noret, in_unique_section, loc);
   Bfunction *bf2 =
       be->function(befty1, "_foo", "bar", is_visible, is_declaration,
-                         is_inl, is_splitstack, in_unique_section, loc);
+                   is_inl, is_splitstack, is_noret, in_unique_section, loc);
   Bfunction *bf3 =
       be->function(befty1, "_foo", "bar", is_visible, !is_declaration,
-                         is_inl, is_splitstack, in_unique_section, loc);
+                   is_inl, is_splitstack, is_noret, in_unique_section, loc);
   Bfunction *bf4 =
       be->function(befty2, "_foo", "bar", is_visible, is_declaration,
-                         is_inl, is_splitstack, in_unique_section, loc);
+                   is_inl, is_splitstack, is_noret, in_unique_section, loc);
   EXPECT_EQ(bf1, bf2);
   EXPECT_NE(bf1, bf3);
   EXPECT_NE(bf2, bf4);
@@ -395,12 +400,13 @@
   bool is_inl = true;
   bool split_stack = false;
   bool unique_sec = false;
+  bool no_ret = false;
   Bfunction *bf1 = be->function(btf1, "syscall", "syscall", visible,
                                 is_declaration, is_inl,
-                                split_stack, unique_sec, loc);
+                                split_stack, no_ret, unique_sec, loc);
   Bfunction *bf2 = be->function(btf2, "syscall", "syscall", visible,
                                 is_declaration, is_inl,
-                                split_stack, unique_sec, loc);
+                                split_stack, no_ret, unique_sec, loc);
 
   // Create calls to the functions
 
@@ -462,22 +468,23 @@
   bool is_inl = true;
   bool split_stack = false;
   bool unique_sec = false;
+  bool no_ret = false;
 
   // bar() declaration and definition
   Bfunction *bf1 = be->function(btf1, "bar", "bar", visible,
                                 true, // is_declaration
-                                is_inl, split_stack, unique_sec, loc);
+                                is_inl, split_stack, no_ret, unique_sec, loc);
   Bfunction *bf2 = be->function(btf1, "bar", "bar", visible,
                                 false, // is_declaration
-                                is_inl, split_stack, unique_sec, loc);
+                                is_inl, split_stack, no_ret, unique_sec, loc);
 
   // baz() declaration and definition
   Bfunction *bf3 = be->function(btf2, "baz", "baz", visible,
                                 true, // is_declaration
-                                is_inl, split_stack, unique_sec, loc);
+                                is_inl, split_stack, no_ret, unique_sec, loc);
   Bfunction *bf4 = be->function(btf3, "baz", "baz", visible,
                                 false, // is_declaration
-                                is_inl, split_stack, unique_sec, loc);
+                                is_inl, split_stack, no_ret, unique_sec, loc);
 
   // Create calls to the functions
   Bexpression *call1 = h.mkCallExpr(be, bf1, nullptr);
diff --git a/unittests/BackendCore/BackendStmtTests.cpp b/unittests/BackendCore/BackendStmtTests.cpp
index 9e55ef8..ce66118 100644
--- a/unittests/BackendCore/BackendStmtTests.cpp
+++ b/unittests/BackendCore/BackendStmtTests.cpp
@@ -515,12 +515,13 @@
   Btype *befty = mkFuncTyp(be, L_PARM, be->pointer_type(bi8t), L_END);
   bool is_decl = true; bool is_inl = false;
   bool is_vis = true; bool is_split = true;
+  bool is_noret = false; bool is_uniqsec = false;
   Bfunction *bchkfcn = be->function(befty, "checkdefer", "checkdefer",
                                     is_vis, is_decl, is_inl, is_split,
-                                    false, h.newloc());
+                                    is_noret, is_uniqsec, h.newloc());
   Bfunction *bdefretfcn = be->function(befty, "deferreturn", "deferreturn",
                                        is_vis, is_decl, is_inl, is_split,
-                                       false, h.newloc());
+                                       is_noret, is_uniqsec, h.newloc());
 
   // Materialize call to deferreturn
   Bexpression *retfn = be->function_code_expression(bdefretfcn, h.newloc());
@@ -605,13 +606,14 @@
 
   bool is_decl = true; bool is_inl = false;
   bool is_vis = true; bool is_split = true;
+  bool is_noret = false; bool is_uniqsec = false;
   const char *fnames[] = { "plark", "plix", "ohstopit" };
   Bfunction *fcns[4];
   Bexpression *calls[4];
   for (unsigned ii = 0; ii < 3; ++ii)  {
     fcns[ii] = be->function(befty, fnames[ii], fnames[ii],
-                                    is_vis, is_decl, is_inl, is_split,
-                                    false, h.newloc());
+                            is_vis, is_decl, is_inl, is_split,
+                            is_noret, is_uniqsec, h.newloc());
     Bexpression *pfn = be->function_code_expression(fcns[ii], h.newloc());
     std::vector<Bexpression *> args;
     calls[ii] = be->call_expression(func, pfn, args,
@@ -619,7 +621,7 @@
   }
   fcns[3] = be->function(befty2, "id", "id",
                          is_vis, is_decl, is_inl, is_split,
-                         false, h.newloc());
+                         is_noret, is_uniqsec, h.newloc());
   Bexpression *idfn = be->function_code_expression(fcns[3], h.newloc());
   std::vector<Bexpression *> iargs;
   iargs.push_back(mkInt64Const(be, 99));
@@ -752,9 +754,10 @@
 
   bool is_decl = true; bool is_inl = false;
   bool is_vis = true; bool is_split = true;
+  bool is_noret = false; bool is_uniqsec = false;
   Bfunction *sfn = be->function(befty, "splat", "splat",
                                 is_vis, is_decl, is_inl, is_split,
-                                false, h.newloc());
+                                is_noret, is_uniqsec, h.newloc());
   Bexpression *splfn = be->function_code_expression(sfn, h.newloc());
 
   // body:
diff --git a/unittests/BackendCore/BackendTreeIntegrity.cpp b/unittests/BackendCore/BackendTreeIntegrity.cpp
index 78f0a2e..77ab24f 100644
--- a/unittests/BackendCore/BackendTreeIntegrity.cpp
+++ b/unittests/BackendCore/BackendTreeIntegrity.cpp
@@ -174,9 +174,9 @@
                                     L_END);
   bool visible = true;  bool is_inl = true;
   bool split_stack = false;  bool uniq_sec = false;
-  bool is_decl = true;
+  bool no_ret = true; bool is_decl = true;
   Bfunction *rtefcn = be->function(bfterr, rtename, rtename, visible, is_decl,
-                                   is_inl, split_stack, uniq_sec, loc);
+                                   is_inl, split_stack, no_ret, uniq_sec, loc);
 
   // p0 != nil ? *p0 + 3 : runtime_error(6)
   Bexpression *cmp2 =
diff --git a/unittests/BackendCore/TestUtils.cpp b/unittests/BackendCore/TestUtils.cpp
index e0acc68..1ad3e79 100644
--- a/unittests/BackendCore/TestUtils.cpp
+++ b/unittests/BackendCore/TestUtils.cpp
@@ -301,10 +301,11 @@
   bool is_inl = true;
   bool split_stack = true;
   bool unique_sec = false;
+  bool no_ret = false;
   Location loc;
   Bfunction *func = be->function(befty, fname, fname, visible,
                                  is_declaration, is_inl,
-                                 split_stack, unique_sec, loc);
+                                 split_stack, no_ret, unique_sec, loc);
   if (mkParams) {
     be->parameter_variable(func, "param1", bi32t, false, loc);
     be->parameter_variable(func, "param2", bi32t, false, loc);
@@ -320,10 +321,11 @@
   bool is_inl = true;
   bool split_stack = true;
   bool unique_sec = false;
+  bool no_ret = false;
   Location loc;
   Bfunction *func = be->function(befty, fname, fname, visible,
                                  is_declaration, is_inl,
-                                 split_stack, unique_sec, loc);
+                                 split_stack, no_ret, unique_sec, loc);
   const std::vector<Btype *> &paramTypes = befty->paramTypes();
   for (unsigned idx = 0; idx < paramTypes.size(); ++idx) {
     std::stringstream ss;