blob: 33024dcd64dd01e00308686ea354458e1c639039 [file] [log] [blame]
//===- llvm/tools/gollvm/unittests/BackendCore/BackendFcnTests.cpp ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "TestUtils.h"
#include "go-llvm-backend.h"
#include "llvm/IR/Function.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace goBackendUnitTests;
namespace {
TEST(BackendFcnTests, MakeEmptyFunction) {
// Create empty function
FcnTestHarness h;
Llvm_backend *be = h.be();
BFunctionType *befty1 = mkFuncTyp(be, L_END);
h.mkFunction("foo", befty1);
const char *exp = R"RAW_RESULT(
)RAW_RESULT";
bool isOK = h.expectBlock(exp);
EXPECT_TRUE(isOK && "Block does not have expected contents");
bool broken = h.finish(PreserveDebugInfo);
EXPECT_FALSE(broken && "Module failed to verify.");
}
TEST(BackendFcnTests, MakeFuncWithLotsOfArgs) {
// Create empty function
FcnTestHarness h;
Llvm_backend *be = h.be();
Btype *bi32t = be->integer_type(false, 32);
Btype *bi64t = be->integer_type(false, 64);
Bexpression *val10 = mkInt64Const(be, int64_t(10));
Btype *at10 = be->array_type(bi64t, val10);
Btype *st3 = mkBackendThreeFieldStruct(be);
BFunctionType *befty1 = mkFuncTyp(be,
L_RCV, st3,
L_PARM, at10,
L_PARM, be->bool_type(),
L_PARM, bi32t,
L_PARM, bi64t,
L_PARM, be->pointer_type(st3),
L_RES, bi32t,
L_RES, bi64t,
L_END);
h.mkFunction("foo", befty1);
const char *exp = R"RAW_RESULT(
)RAW_RESULT";
bool isOK = h.expectBlock(exp);
EXPECT_TRUE(isOK && "Block does not have expected contents");
bool broken = h.finish(PreserveDebugInfo);
EXPECT_FALSE(broken && "Module failed to verify.");
}
TEST(BackendFcnTests, MakeFunction) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Btype *bi64t = be->integer_type(false, 64);
Btype *bi32t = be->integer_type(false, 32);
// func foo(i1, i2 int32) int64 { }
BFunctionType *befty =
mkFuncTyp(be.get(), L_PARM, bi32t, L_PARM, bi32t, L_RES, bi64t, L_END);
// FIXME: this is not supported yet.
bool in_unique_section = false;
const bool is_declaration = true;
const bool is_visible[2] = {true, false};
const bool is_inlinable[2] = {true, false};
bool split_stack[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->hasHiddenVisibility(), !vis);
EXPECT_EQ(befcn->splitStack() == Bfunction::YesSplit, !split);
}
}
}
// Error function
Bfunction *be_error_fcn = be->error_function();
ASSERT_TRUE(be_error_fcn != NULL);
// 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);
EXPECT_EQ(mistake, be_error_fcn);
}
TEST(BackendFcnTests, BuiltinFunctionsMisc) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
std::unordered_set<Bfunction *> results;
std::vector<std::string> tocheck = {
"__sync_fetch_and_add_1", "__sync_fetch_and_add_2",
"__sync_fetch_and_add_4", "__sync_fetch_and_add_8",
"__builtin_trap", "__builtin_expect",
"__builtin_memcmp", "__builtin_ctz",
"__builtin_ctzll", "__builtin_bswap32",
"__builtin_bswap64", "__builtin_return_address",
"__builtin_frame_address",
};
for (auto fname : tocheck) {
Bfunction *bfcn = be->lookup_builtin(fname);
ASSERT_TRUE(bfcn != NULL);
EXPECT_TRUE(results.find(bfcn) == results.end());
results.insert(bfcn);
}
EXPECT_TRUE(results.size() == tocheck.size());
}
TEST(BackendFcnTests, BuiltinFunctionsTrig) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
std::unordered_set<Bfunction *> results;
std::vector<std::string> tocheck = {
"acos", "asin", "atan", "atan2", "ceil", "cos", "exp",
"expm1", "fabs", "floor", "fmod", "log", "log1p", "log10",
"log2", "sin", "sqrt", "tan", "trunc", "ldexp",
};
for (auto fname : tocheck) {
// function
Bfunction *bfcn = be->lookup_builtin(fname);
ASSERT_TRUE(bfcn != NULL);
EXPECT_TRUE(results.find(bfcn) == results.end());
results.insert(bfcn);
// builtin variant
char nbuf[128];
sprintf(nbuf, "__builtin_%s", fname.c_str());
Bfunction *bifcn = be->lookup_builtin(nbuf);
EXPECT_TRUE(bifcn != NULL);
EXPECT_TRUE(bifcn == bfcn);
}
EXPECT_TRUE(results.size() == tocheck.size());
}
TEST(BackendFcnTests, MakeBlocks) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Bfunction *bfcn = mkFunci32o64(be.get(), "foo");
const std::vector<Bvariable *> vars;
Bblock *bb = be->block(bfcn, nullptr, vars, Location(), Location());
ASSERT_TRUE(bb != nullptr);
}
TEST(BackendFcnTests, MakeFuncWithRecursiveTypeParam) {
// Create empty function
FcnTestHarness h;
Llvm_backend *be = h.be();
Location loc;
// type P *P
Btype *cpht = be->placeholder_pointer_type("ph", loc, false);
Btype *cpt = be->circular_pointer_type(cpht, false);
be->set_placeholder_pointer_type(cpht, cpt);
// struct A { f2 bool, fn *A }
Btype *php = be->placeholder_pointer_type("ph", loc, false);
std::vector<Backend::Btyped_identifier> fields = {
Backend::Btyped_identifier("f1", be->bool_type(), Location()),
Backend::Btyped_identifier("fn", php, Location())
};
Btype *bst = be->struct_type(fields);
Btype *bpst = be->pointer_type(bst);
be->set_placeholder_pointer_type(php, bpst);
Btype *bi64t = be->integer_type(false, 64);
BFunctionType *befty1 = mkFuncTyp(be,
L_RCV, php,
L_PARM, cpht,
L_PARM, bpst,
L_PARM, be->bool_type(),
L_PARM, bst,
L_RES, bi64t,
L_END);
h.mkFunction("foo", befty1);
const char *exp = R"RAW_RESULT(
)RAW_RESULT";
bool isOK = h.expectBlock(exp);
EXPECT_TRUE(isOK && "Block does not have expected contents");
bool broken = h.finish(PreserveDebugInfo);
EXPECT_FALSE(broken && "Module failed to verify.");
}
TEST(BackendFcnTests, MakeMultipleDeclarations) {
FcnTestHarness h("foo");
Llvm_backend *be = h.be();
Location loc;
// If a function of a given name is declared more than once,
// we expect to get back the original decl on the second time.
// For definitions, a new function will be created each time (although
// this could certainly be changed if needed);
Btype *bi32t = be->integer_type(false, 32);
Btype *bi64t = be->integer_type(false, 64);
BFunctionType *befty1 = mkFuncTyp(be, L_RES, bi32t, L_PARM, bi64t, L_END);
bool is_visible = false;
bool is_declaration = true;
bool is_inl = true;
bool is_splitstack = true;
bool in_unique_section = false;
Bfunction *bf1 =
be->function(befty1, "_foo", "bar", is_visible, is_declaration,
is_inl, is_splitstack, in_unique_section, loc);
Bfunction *bf2 =
be->function(befty1, "_foo", "bar", is_visible, is_declaration,
is_inl, is_splitstack, in_unique_section, loc);
Bfunction *bf3 =
be->function(befty1, "_foo", "bar", is_visible, !is_declaration,
is_inl, is_splitstack, in_unique_section, loc);
EXPECT_EQ(bf1, bf2);
EXPECT_NE(bf1, bf3);
bool broken = h.finish(PreserveDebugInfo);
EXPECT_FALSE(broken && "Module failed to verify.");
}
}