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 *> ¶mTypes = befty->paramTypes();
for (unsigned idx = 0; idx < paramTypes.size(); ++idx) {
std::stringstream ss;