blob: aa88be4d266ac2024693f4ab5d13a0733a680fcb [file] [log] [blame]
//===- llvm/tools/gollvm/unittests/BackendCore/BackendCoreTests.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 "gtest/gtest.h"
using namespace llvm;
using namespace goBackendUnitTests;
namespace {
TEST(BackendCoreTests, MakeBackend) {
LLVMContext C;
std::unique_ptr<Backend> makeit(go_get_backend(C));
}
TEST(BackendCoreTests, ScalarTypes) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Btype *et = be->error_type();
EXPECT_TRUE(et != nullptr);
Btype *vt = be->void_type();
EXPECT_TRUE(vt != nullptr);
EXPECT_TRUE(vt != et);
Btype *bt = be->bool_type();
EXPECT_TRUE(bt != nullptr);
Btype *pbt = be->pointer_type(bt);
ASSERT_TRUE(pbt != nullptr);
EXPECT_TRUE(pbt->type()->isPointerTy());
std::vector<bool> isuns = {false, true};
std::vector<int> ibits = {8, 16, 32, 64, 128};
for (auto uns : isuns) {
for (auto nbits : ibits) {
Btype *it = be->integer_type(uns, nbits);
ASSERT_TRUE(it != nullptr);
EXPECT_TRUE(it->type()->isIntegerTy());
}
}
std::vector<int> fbits = {32, 64, 128};
for (auto nbits : fbits) {
Btype *ft = be->float_type(nbits);
ASSERT_TRUE(ft != nullptr);
EXPECT_TRUE(ft->type()->isFloatingPointTy());
}
}
TEST(BackendCoreTests, StructTypes) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
// Empty struct
std::vector<Backend::Btyped_identifier> nofields;
Btype *emptyst = be->struct_type(nofields);
SmallVector<Type *, 3> smv_empty(0);
Type *llvm_emptyst = StructType::get(C, smv_empty);
ASSERT_TRUE(llvm_emptyst != nullptr);
ASSERT_TRUE(emptyst != nullptr);
EXPECT_EQ(llvm_emptyst, emptyst->type());
// Three-field struct
Btype *best = mkBackendThreeFieldStruct(be.get());
Type *llst = mkLlvmThreeFieldStruct(C);
ASSERT_TRUE(best != nullptr);
ASSERT_TRUE(llst != nullptr);
EXPECT_EQ(llst, best->type());
EXPECT_EQ(repr(best->type()), "{ i8, float*, i64 }");
// If a field has error type, entire struct has error type
std::vector<Backend::Btyped_identifier> fields = {
Backend::Btyped_identifier("f1", be->bool_type(), Location()),
Backend::Btyped_identifier("fe", be->error_type(), Location())};
Btype *badst = be->struct_type(fields);
EXPECT_TRUE(badst != nullptr);
EXPECT_EQ(badst, be->error_type());
// Llvm_backend should be caching and reusing anonymous types
Btype *st1 = mkBackendThreeFieldStruct(be.get());
Btype *st2 = mkBackendThreeFieldStruct(be.get());
EXPECT_EQ(st1, st2);
}
TEST(BackendCoreTests, TypeHashAndCompare) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Btype *st1 = mkBackendThreeFieldStruct(be.get());
Btype *st2 = mkBackendThreeFieldStruct(be.get());
EXPECT_EQ(st1->hash(), st2->hash());
EXPECT_TRUE(st1->equal(*st1));
}
TEST(BackendCoreTests, ComplexTypes) {
LLVMContext C;
Type *ft = Type::getFloatTy(C);
Type *dt = Type::getDoubleTy(C);
std::unique_ptr<Backend> be(go_get_backend(C));
Btype *c32 = be->complex_type(64);
ASSERT_TRUE(c32 != nullptr);
EXPECT_EQ(c32->type(), mkTwoFieldLLvmStruct(C, ft, ft));
Btype *c64 = be->complex_type(128);
ASSERT_TRUE(c64 != nullptr);
EXPECT_EQ(c64->type(), mkTwoFieldLLvmStruct(C, dt, dt));
}
TEST(BackendCoreTests, FunctionTypes) {
LLVMContext C;
Type *i64t = IntegerType::get(C, 64);
std::unique_ptr<Backend> be(go_get_backend(C));
// func foo() {}
Btype *emptyf = mkFuncTyp(be.get(), L_END);
Type *llemptyf = mkLLFuncTyp(&C, L_END);
ASSERT_TRUE(llemptyf != nullptr && emptyf != nullptr);
EXPECT_TRUE(llemptyf == emptyf->type());
{
// func (Blah) foo() {}
Btype *pt = be->pointer_type(mkBackendThreeFieldStruct(be.get()));
Btype *befn =
mkFuncTyp(be.get(), L_RCV, pt, L_END);
llvm::PointerType *llpt =
llvm::PointerType::get(mkLlvmThreeFieldStruct(C), 0);
Type *llfn = mkLLFuncTyp(&C, L_RCV, llpt, L_END);
ASSERT_TRUE(befn != nullptr && llfn != nullptr);
EXPECT_TRUE(befn->type() == llfn);
}
{
// func foo(x int64) {}
Btype *befn =
mkFuncTyp(be.get(), L_PARM, be->integer_type(false, 64), L_END);
Type *llfn = mkLLFuncTyp(&C, L_PARM, i64t, L_END);
ASSERT_TRUE(befn != nullptr && llfn != nullptr);
EXPECT_TRUE(befn->type() == llfn);
}
{
// func foo() int64 {}
Btype *befn =
mkFuncTyp(be.get(), L_RES, be->integer_type(false, 64), L_END);
Type *llfn = mkLLFuncTyp(&C, L_RES, i64t, L_END);
ASSERT_TRUE(befn != nullptr && llfn != nullptr);
EXPECT_TRUE(befn->type() == llfn);
}
}
TEST(BackendCoreTests, PlaceholderTypes) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
// Create a placeholder pointer type
Location loc;
Btype *phpt1 = be->placeholder_pointer_type("ph1", loc, false);
ASSERT_TRUE(phpt1 != nullptr);
EXPECT_TRUE(phpt1->type()->isPointerTy());
// Placeholder pointer types should not be cached
Btype *phpt2 = be->placeholder_pointer_type("ph", loc, false);
Btype *phpt3 = be->placeholder_pointer_type("ph", loc, false);
ASSERT_TRUE(phpt2 != phpt3);
EXPECT_TRUE(phpt2->type() != phpt3->type());
// Replace placeholder pointer type
Btype *pst = be->pointer_type(mkBackendThreeFieldStruct(be.get()));
be->set_placeholder_pointer_type(phpt1, pst);
ASSERT_TRUE(phpt1->type()->isPointerTy());
PointerType *llpt = cast<PointerType>(phpt1->type());
EXPECT_TRUE(llpt->getElementType()->isStructTy());
// Placeholder struct type
Btype *phst1 = be->placeholder_struct_type("ph", loc);
ASSERT_TRUE(phpt1 != nullptr);
// Replace placeholder struct type
std::vector<Backend::Btyped_identifier> fields = {
Backend::Btyped_identifier("f1", be->integer_type(false, 64), Location()),
Backend::Btyped_identifier("f2", be->integer_type(false, 64),
Location())};
be->set_placeholder_struct_type(phst1, fields);
Type *i64t = IntegerType::get(C, 64);
EXPECT_TRUE(llvmTypesEquiv(phst1->type(),
mkTwoFieldLLvmStruct(C, i64t, i64t)));
// Placeholder array type
Btype *phat1 = be->placeholder_array_type("pha", loc);
ASSERT_TRUE(phat1 != nullptr);
// Replace placeholder array type
Btype *bi64t = be->integer_type(false, 64);
Bexpression *val10 = mkInt64Const(be.get(), int64_t(10));
Btype *at10 = be->array_type(bi64t, val10);
ASSERT_TRUE(at10 != nullptr);
be->set_placeholder_array_type(phat1, bi64t, val10);
EXPECT_TRUE(phat1->type() == at10->type());
// Circular pointer support
Btype *php4 = be->placeholder_pointer_type("ph", loc, false);
Btype *cpt = be->circular_pointer_type(php4, false);
Btype *cpt2 = be->circular_pointer_type(php4, false);
EXPECT_EQ(cpt, cpt2);
be->set_placeholder_pointer_type(php4, cpt);
EXPECT_EQ(php4->type(), cpt->type());
}
TEST(BackendCoreTests, ArrayTypes) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Location loc;
// Very basic tests of array type creation: array of integers
Btype *bi32t = be->integer_type(false, 32);
Btype *bi64t = be->integer_type(false, 64);
Bexpression *val10 = mkInt64Const(be.get(), int64_t(10));
Btype *at10 = be->array_type(bi64t, val10);
ASSERT_TRUE(at10 != nullptr);
EXPECT_EQ(at10->type(), llvm::ArrayType::get(bi64t->type(), 10));
// Array of structs
Bexpression *val1023 = mkUint64Const(be.get(), uint64_t(1023));
Btype *st = mkTwoFieldStruct(be.get(), bi32t, bi64t);
Btype *at1023 = be->array_type(st, val1023);
ASSERT_TRUE(at1023 != nullptr);
llvm::Type *lst = mkTwoFieldLLvmStruct(C, bi32t->type(), bi64t->type());
EXPECT_EQ(at1023->type(), llvm::ArrayType::get(lst, 1023));
// Zero sized array
Bexpression *val0 = mkInt64Const(be.get(), 0);
Btype *at0 = be->array_type(bi64t, val0);
ASSERT_TRUE(at0 != nullptr);
// Error cases
Bexpression *badval = be->error_expression();
Btype *badt1 = be->array_type(bi64t, badval);
EXPECT_EQ(badt1, be->error_type());
Btype *badt2 = be->array_type(be->error_type(), val10);
EXPECT_EQ(badt2, be->error_type());
}
TEST(BackendCoreTests, NamedTypes) {
LLVMContext C;
std::unique_ptr<Backend> be(go_get_backend(C));
Location loc;
Btype *nt = be->named_type("named_int32", be->integer_type(false, 32), loc);
ASSERT_TRUE(nt != nullptr);
Btype *nt2 =
be->named_type("another_int32", be->integer_type(false, 32), loc);
ASSERT_TRUE(nt2 != nullptr);
EXPECT_TRUE(nt != nt2);
}
TEST(BackendCoreTests, TypeUtils) {
LLVMContext C;
// Type size and alignment. Size and align are in bytes.
std::unique_ptr<Backend> be(go_get_backend(C));
Btype *i8t = be->integer_type(false, 8);
EXPECT_EQ(be->type_size(i8t), int64_t(1));
EXPECT_EQ(be->type_alignment(i8t), 1);
// Slightly more complicated example
Btype *u64 = be->integer_type(true, 64);
Btype *st = mkTwoFieldStruct(be.get(), u64, u64);
EXPECT_EQ(be->type_size(st), int64_t(16));
EXPECT_EQ(be->type_alignment(st), 8);
// Strictly speaking, one should be asking for the size
// of a pointer-to-function type, not a function type, however
// it does appear that this needs to be supported.
Btype *emptyf = mkFuncTyp(be.get(), L_END);
EXPECT_EQ(be->type_size(emptyf), be->type_size(be->pointer_type(u64)));
// type field alignment
Btype *u32 = be->integer_type(true, 32);
EXPECT_EQ(be->type_field_alignment(u32), 4);
}
}