bridge: support imported inline functions

CL 150062 in gofrontend adds support of imported inline
functions. This CL adds the corresponding support in the
backend. These functions are only used for inlining, but not to
emit a standalone function body, therefore have
AvailableExternally linkage.

Change-Id: I916abf59c96fd96113ce9686a4910e83c6ffa7fa
Reviewed-on: https://go-review.googlesource.com/c/152237
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/bridge/go-llvm.cpp b/bridge/go-llvm.cpp
index a13a74d..52c7c8a 100644
--- a/bridge/go-llvm.cpp
+++ b/bridge/go-llvm.cpp
@@ -2531,8 +2531,11 @@
   }
 
   llvm::GlobalValue::LinkageTypes linkage =
-      ((flags & Backend::function_is_visible) != 0) ?
-      llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::InternalLinkage;
+      llvm::GlobalValue::InternalLinkage;
+  if ((flags & Backend::function_is_visible) != 0)
+    linkage = llvm::GlobalValue::ExternalLinkage;
+  else if ((flags & Backend::function_only_inline) != 0)
+    linkage = llvm::GlobalValue::AvailableExternallyLinkage;
   llvm::StringRef fn(fns);
   llvm::Constant *fcnValue = nullptr;
   llvm::Value *declVal = module_->getNamedValue(fn);
@@ -2564,6 +2567,7 @@
     // inline/noinline
     if ((flags & Backend::function_is_inlinable) == 0 || noInline_)
       fcn->addFnAttr(llvm::Attribute::NoInline);
+    // TODO: should we use inlinehint for imported only_inline functions?
 
     // split-stack or nosplit
     if (useSplitStack_ && (flags & Backend::function_no_split_stack) == 0)
diff --git a/unittests/BackendCore/BackendFcnTests.cpp b/unittests/BackendCore/BackendFcnTests.cpp
index 8c8a627..659b0d5 100644
--- a/unittests/BackendCore/BackendFcnTests.cpp
+++ b/unittests/BackendCore/BackendFcnTests.cpp
@@ -80,34 +80,42 @@
 
   const bool is_visible[2] = {true, false};
   const bool is_inlinable[2] = {true, false};
+  const bool only_inline[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 nosplit : split_stack) {
-        for (auto noret : is_noret) {
-          unsigned fflags =
-              (Backend::function_is_declaration |
-               (vis ? Backend::function_is_visible : 0) |
-               (inl ? Backend::function_is_inlinable : 0) |
-               (nosplit ? Backend::function_no_split_stack : 0) |
-               (noret ? Backend::function_does_not_return : 0));
+      for (auto only_inl : only_inline) {
+        // Functions imported only for inlining cannot be exported.
+        if (only_inl && vis)
+          continue;
+        for (auto nosplit : split_stack) {
+          for (auto noret : is_noret) {
+            unsigned fflags =
+                (Backend::function_is_declaration |
+                 (vis ? Backend::function_is_visible : 0) |
+                 (inl ? Backend::function_is_inlinable : 0) |
+                 (nosplit ? Backend::function_no_split_stack : 0) |
+                 (noret ? Backend::function_does_not_return : 0) |
+                 (only_inl ? Backend::function_only_inline : 0));
 
-          std::stringstream ss;
-          ss << "fcn" << count++;
-          Bfunction *befcn =
-              be->function(befty, "_foo", ss.str(), fflags, 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, !nosplit);
+            std::stringstream ss;
+            ss << "fcn" << count++;
+            Bfunction *befcn =
+                be->function(befty, "_foo", ss.str(), fflags, 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 && !only_inl);
+            EXPECT_EQ(llfunc->hasAvailableExternallyLinkage(), only_inl);
+            EXPECT_EQ(befcn->splitStack() == Bfunction::YesSplit, !nosplit);
+          }
         }
       }
     }