diff options
Diffstat (limited to 'unittests')
52 files changed, 3516 insertions, 1249 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 3b69de2..e57c8d4 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -866,10 +866,11 @@ TEST(APFloatTest, toString) { ASSERT_EQ("0.0101", convertToString(1.01E-2, 5, 2)); ASSERT_EQ("0.0101", convertToString(1.01E-2, 4, 2)); ASSERT_EQ("1.01E-2", convertToString(1.01E-2, 5, 1)); - ASSERT_EQ("0.7853981633974483", convertToString(0.78539816339744830961, 0, 3)); - ASSERT_EQ("4.940656458412465E-324", convertToString(4.9406564584124654e-324, 0, 3)); - ASSERT_EQ("873.1834", convertToString(873.1834, 0, 1)); - ASSERT_EQ("8.731834E+2", convertToString(873.1834, 0, 0)); + ASSERT_EQ("0.78539816339744828", convertToString(0.78539816339744830961, 0, 3)); + ASSERT_EQ("4.9406564584124654E-324", convertToString(4.9406564584124654e-324, 0, 3)); + ASSERT_EQ("873.18340000000001", convertToString(873.1834, 0, 1)); + ASSERT_EQ("8.7318340000000001E+2", convertToString(873.1834, 0, 0)); + ASSERT_EQ("1.7976931348623157E+308", convertToString(1.7976931348623157E+308, 0, 0)); } TEST(APFloatTest, toInteger) { diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt index 9aad793..8ad303a 100644 --- a/unittests/ADT/CMakeLists.txt +++ b/unittests/ADT/CMakeLists.txt @@ -21,6 +21,7 @@ set(ADTSources MapVectorTest.cpp OptionalTest.cpp PackedVectorTest.cpp + PointerUnionTest.cpp SCCIteratorTest.cpp SmallPtrSetTest.cpp SmallStringTest.cpp @@ -34,6 +35,7 @@ set(ADTSources TripleTest.cpp TwineTest.cpp VariadicFunctionTest.cpp + polymorphic_ptr_test.cpp ) # They cannot be compiled on MSVC9 due to its bug. diff --git a/unittests/ADT/IntrusiveRefCntPtrTest.cpp b/unittests/ADT/IntrusiveRefCntPtrTest.cpp index 0c8c4ca..c67ec13 100644 --- a/unittests/ADT/IntrusiveRefCntPtrTest.cpp +++ b/unittests/ADT/IntrusiveRefCntPtrTest.cpp @@ -10,11 +10,13 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "gtest/gtest.h" -namespace llvm { - -struct VirtualRefCounted : public RefCountedBaseVPTR { +namespace { +struct VirtualRefCounted : public llvm::RefCountedBaseVPTR { virtual void f() {} }; +} + +namespace llvm { // Run this test with valgrind to detect memory leaks. TEST(IntrusiveRefCntPtr, RefCountedBaseVPTRCopyDoesNotLeak) { diff --git a/unittests/ADT/PointerUnionTest.cpp b/unittests/ADT/PointerUnionTest.cpp new file mode 100644 index 0000000..7eb7181 --- /dev/null +++ b/unittests/ADT/PointerUnionTest.cpp @@ -0,0 +1,64 @@ +//===- llvm/unittest/ADT/PointerUnionTest.cpp - Optional unit tests -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/PointerUnion.h" +using namespace llvm; + +namespace { + +typedef PointerUnion<int*, float*> PU; + +// Test fixture +class PointerUnionTest : public testing::Test { +}; + +float f = 3.14f; +int i = 42; + +const PU a(&f); +const PU b(&i); +const PU n; + +TEST_F(PointerUnionTest, Comparison) { + EXPECT_TRUE(a != b); + EXPECT_FALSE(a == b); + EXPECT_TRUE(b != n); + EXPECT_FALSE(b == n); +} + +TEST_F(PointerUnionTest, Null) { + EXPECT_FALSE(a.isNull()); + EXPECT_FALSE(b.isNull()); + EXPECT_TRUE(n.isNull()); + EXPECT_FALSE(!a); + EXPECT_FALSE(!b); + EXPECT_TRUE(!n); + // workaround an issue with EXPECT macros and explicit bool + EXPECT_TRUE((bool)a); + EXPECT_TRUE((bool)b); + EXPECT_FALSE(n); +} + +TEST_F(PointerUnionTest, Is) { + EXPECT_FALSE(a.is<int*>()); + EXPECT_TRUE(a.is<float*>()); + EXPECT_TRUE(b.is<int*>()); + EXPECT_FALSE(b.is<float*>()); + EXPECT_TRUE(n.is<int*>()); + EXPECT_FALSE(n.is<float*>()); +} + +TEST_F(PointerUnionTest, Get) { + EXPECT_EQ(a.get<float*>(), &f); + EXPECT_EQ(b.get<int*>(), &i); + EXPECT_EQ(n.get<int*>(), (int*)0); +} + +} // end anonymous namespace diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp index fa87cd0..88691ae 100644 --- a/unittests/ADT/StringRefTest.cpp +++ b/unittests/ADT/StringRefTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" @@ -60,6 +61,9 @@ TEST(StringRefTest, StringOps) { EXPECT_EQ( 0, StringRef("AaB").compare_lower("aab")); EXPECT_EQ( 1, StringRef("AaB").compare_lower("AAA")); EXPECT_EQ(-1, StringRef("AaB").compare_lower("aaBb")); + EXPECT_EQ(-1, StringRef("AaB").compare_lower("bb")); + EXPECT_EQ( 1, StringRef("aaBb").compare_lower("AaB")); + EXPECT_EQ( 1, StringRef("bb").compare_lower("AaB")); EXPECT_EQ( 1, StringRef("AaB").compare_lower("aA")); EXPECT_EQ( 1, StringRef("\xFF").compare_lower("\1")); @@ -247,19 +251,41 @@ TEST(StringRefTest, Trim) { TEST(StringRefTest, StartsWith) { StringRef Str("hello"); + EXPECT_TRUE(Str.startswith("")); EXPECT_TRUE(Str.startswith("he")); EXPECT_FALSE(Str.startswith("helloworld")); EXPECT_FALSE(Str.startswith("hi")); } +TEST(StringRefTest, StartsWithLower) { + StringRef Str("heLLo"); + EXPECT_TRUE(Str.startswith_lower("")); + EXPECT_TRUE(Str.startswith_lower("he")); + EXPECT_TRUE(Str.startswith_lower("hell")); + EXPECT_TRUE(Str.startswith_lower("HELlo")); + EXPECT_FALSE(Str.startswith_lower("helloworld")); + EXPECT_FALSE(Str.startswith_lower("hi")); +} + TEST(StringRefTest, EndsWith) { StringRef Str("hello"); + EXPECT_TRUE(Str.endswith("")); EXPECT_TRUE(Str.endswith("lo")); EXPECT_FALSE(Str.endswith("helloworld")); EXPECT_FALSE(Str.endswith("worldhello")); EXPECT_FALSE(Str.endswith("so")); } +TEST(StringRefTest, EndsWithLower) { + StringRef Str("heLLo"); + EXPECT_TRUE(Str.endswith_lower("")); + EXPECT_TRUE(Str.endswith_lower("lo")); + EXPECT_TRUE(Str.endswith_lower("LO")); + EXPECT_TRUE(Str.endswith_lower("ELlo")); + EXPECT_FALSE(Str.endswith_lower("helloworld")); + EXPECT_FALSE(Str.endswith_lower("hi")); +} + TEST(StringRefTest, Find) { StringRef Str("hello"); EXPECT_EQ(2U, Str.find('l')); @@ -477,6 +503,32 @@ TEST(StringRefTest, getAsUnsignedIntegerBadStrings) { } } +static const char *join_input[] = { "a", "b", "c" }; +static const char join_result1[] = "a"; +static const char join_result2[] = "a:b:c"; +static const char join_result3[] = "a::b::c"; + +TEST(StringRefTest, joinStrings) { + std::vector<StringRef> v1; + std::vector<std::string> v2; + for (size_t i = 0; i < array_lengthof(join_input); ++i) { + v1.push_back(join_input[i]); + v2.push_back(join_input[i]); + } + bool v1_join1 = join(v1.begin(), v1.begin() + 1, ":") == join_result1; + EXPECT_TRUE(v1_join1); + bool v1_join2 = join(v1.begin(), v1.end(), ":") == join_result2; + EXPECT_TRUE(v1_join2); + bool v1_join3 = join(v1.begin(), v1.end(), "::") == join_result3; + EXPECT_TRUE(v1_join3); + + bool v2_join1 = join(v2.begin(), v2.begin() + 1, ":") == join_result1; + EXPECT_TRUE(v2_join1); + bool v2_join2 = join(v2.begin(), v2.end(), ":") == join_result2; + EXPECT_TRUE(v2_join2); + bool v2_join3 = join(v2.begin(), v2.end(), "::") == join_result3; + EXPECT_TRUE(v2_join3); +} } // end anonymous namespace diff --git a/unittests/ADT/polymorphic_ptr_test.cpp b/unittests/ADT/polymorphic_ptr_test.cpp new file mode 100644 index 0000000..bd5d838 --- /dev/null +++ b/unittests/ADT/polymorphic_ptr_test.cpp @@ -0,0 +1,129 @@ +//===- llvm/unittest/ADT/polymorphic_ptr.h - polymorphic_ptr<T> tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" +#include "llvm/ADT/polymorphic_ptr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +struct S { + S(int x) : x(x) {} + S *clone() { return new S(*this); } + int x; +}; + +// A function that forces the return of a copy. +template <typename T> +T dummy_copy(const T &arg) { return arg; } + +TEST(polymorphic_ptr_test, Basic) { + polymorphic_ptr<S> null; + EXPECT_FALSE((bool)null); + EXPECT_TRUE(!null); + EXPECT_EQ((S*)0, null.get()); + + S *s = new S(42); + polymorphic_ptr<S> p(s); + EXPECT_TRUE((bool)p); + EXPECT_FALSE(!p); + EXPECT_TRUE(p != null); + EXPECT_FALSE(p == null); + EXPECT_TRUE(p == s); + EXPECT_TRUE(s == p); + EXPECT_FALSE(p != s); + EXPECT_FALSE(s != p); + EXPECT_EQ(s, &*p); + EXPECT_EQ(s, p.operator->()); + EXPECT_EQ(s, p.get()); + EXPECT_EQ(42, p->x); + + EXPECT_EQ(s, p.take()); + EXPECT_FALSE((bool)p); + EXPECT_TRUE(!p); + p = s; + EXPECT_TRUE((bool)p); + EXPECT_FALSE(!p); + EXPECT_EQ(s, &*p); + EXPECT_EQ(s, p.operator->()); + EXPECT_EQ(s, p.get()); + EXPECT_EQ(42, p->x); + + polymorphic_ptr<S> p2((llvm_move(p))); +#if !LLVM_HAS_RVALUE_REFERENCES + // 'p' may not have been moved from in C++98, fake it for the test. + p2 = p.take(); +#endif + EXPECT_FALSE((bool)p); + EXPECT_TRUE(!p); + EXPECT_TRUE((bool)p2); + EXPECT_FALSE(!p2); + EXPECT_EQ(s, &*p2); + + using std::swap; + swap(p, p2); + EXPECT_TRUE((bool)p); + EXPECT_FALSE(!p); + EXPECT_EQ(s, &*p); + EXPECT_FALSE((bool)p2); + EXPECT_TRUE(!p2); + + // Force copies and that everything survives. + polymorphic_ptr<S> p3 = dummy_copy(polymorphic_ptr<S>(p)); + EXPECT_TRUE((bool)p3); + EXPECT_FALSE(!p3); + EXPECT_NE(s, &*p3); + EXPECT_EQ(42, p3->x); + + // Force copies of null without trying to dereference anything. + polymorphic_ptr<S> null_copy = dummy_copy(polymorphic_ptr<S>(null)); + EXPECT_FALSE((bool)null_copy); + EXPECT_TRUE(!null_copy); + EXPECT_EQ(null, null_copy); +} + +struct Base { + virtual ~Base() {} + virtual Base *clone() = 0; + virtual StringRef name() { return "Base"; } +}; + +struct DerivedA : Base { + virtual DerivedA *clone() { return new DerivedA(); } + virtual StringRef name() { return "DerivedA"; } +}; +struct DerivedB : Base { + virtual DerivedB *clone() { return new DerivedB(); } + virtual StringRef name() { return "DerivedB"; } +}; + +TEST(polymorphic_ptr_test, Polymorphism) { + polymorphic_ptr<Base> a(new DerivedA()); + polymorphic_ptr<Base> b(new DerivedB()); + + EXPECT_EQ("DerivedA", a->name()); + EXPECT_EQ("DerivedB", b->name()); + + polymorphic_ptr<Base> copy = dummy_copy(a); + EXPECT_NE(a, copy); + EXPECT_EQ("DerivedA", copy->name()); + + copy = dummy_copy(b); + EXPECT_NE(b, copy); + EXPECT_EQ("DerivedB", copy->name()); + + // Test creating a copy out of a temporary directly. + copy = dummy_copy<polymorphic_ptr<Base> >(new DerivedA()); + EXPECT_NE(a, copy); + EXPECT_EQ("DerivedA", copy->name()); +} + +} diff --git a/unittests/Analysis/CFGTest.cpp b/unittests/Analysis/CFGTest.cpp index 2358803..e931709 100644 --- a/unittests/Analysis/CFGTest.cpp +++ b/unittests/Analysis/CFGTest.cpp @@ -147,6 +147,23 @@ TEST_F(IsPotentiallyReachableTest, SameBlockPath) { ExpectPath(true); } +TEST_F(IsPotentiallyReachableTest, SameBlockNoLoop) { + ParseAssembly( + "define void @test() {\n" + "entry:\n" + " br label %middle\n" + "middle:\n" + " %B = bitcast i8 undef to i8\n" + " bitcast i8 undef to i8\n" + " bitcast i8 undef to i8\n" + " %A = bitcast i8 undef to i8\n" + " br label %nextblock\n" + "nextblock:\n" + " ret void\n" + "}\n"); + ExpectPath(false); +} + TEST_F(IsPotentiallyReachableTest, StraightNoPath) { ParseAssembly( "define void @test() {\n" diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index 53b7e9c..52702ba 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -7,11 +7,13 @@ endfunction() add_subdirectory(ADT) add_subdirectory(Analysis) -add_subdirectory(ExecutionEngine) add_subdirectory(Bitcode) +add_subdirectory(CodeGen) +add_subdirectory(DebugInfo) +add_subdirectory(ExecutionEngine) +add_subdirectory(IR) +add_subdirectory(MC) +add_subdirectory(Object) add_subdirectory(Option) add_subdirectory(Support) add_subdirectory(Transforms) -add_subdirectory(IR) -add_subdirectory(DebugInfo) -add_subdirectory(Object) diff --git a/unittests/CodeGen/CMakeLists.txt b/unittests/CodeGen/CMakeLists.txt new file mode 100644 index 0000000..5973bae --- /dev/null +++ b/unittests/CodeGen/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_LINK_COMPONENTS + asmprinter + codegen + support + ) + +set(CodeGenSources + DIEHashTest.cpp + ) + +add_llvm_unittest(CodeGenTests + ${CodeGenSources} + ) diff --git a/unittests/CodeGen/DIEHashTest.cpp b/unittests/CodeGen/DIEHashTest.cpp new file mode 100644 index 0000000..8d8fc39 --- /dev/null +++ b/unittests/CodeGen/DIEHashTest.cpp @@ -0,0 +1,517 @@ +//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "../lib/CodeGen/AsmPrinter/DIE.h" +#include "../lib/CodeGen/AsmPrinter/DIEHash.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { +TEST(DIEHashTest, Data1) { + DIEHash Hash; + DIE Die(dwarf::DW_TAG_base_type); + DIEInteger Size(4); + Die.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Size); + uint64_t MD5Res = Hash.computeTypeSignature(Die); + ASSERT_EQ(0x1AFE116E83701108ULL, MD5Res); +} + +// struct {}; +TEST(DIEHashTest, TrivialType) { + DIE Unnamed(dwarf::DW_TAG_structure_type); + DIEInteger One(1); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + // Line and file number are ignored. + Unnamed.addValue(dwarf::DW_AT_decl_file, dwarf::DW_FORM_data1, &One); + Unnamed.addValue(dwarf::DW_AT_decl_line, dwarf::DW_FORM_data1, &One); + uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed); + + // The exact same hash GCC produces for this DIE. + ASSERT_EQ(0x715305ce6cfd9ad1ULL, MD5Res); +} + +// struct foo { }; +TEST(DIEHashTest, NamedType) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger One(1); + DIEString FooStr(&One, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + // The exact same hash GCC produces for this DIE. + ASSERT_EQ(0xd566dbd2ca5265ffULL, MD5Res); +} + +// namespace space { struct foo { }; } +TEST(DIEHashTest, NamespacedType) { + DIE CU(dwarf::DW_TAG_compile_unit); + + DIE *Space = new DIE(dwarf::DW_TAG_namespace); + DIEInteger One(1); + DIEString SpaceStr(&One, "space"); + Space->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &SpaceStr); + // DW_AT_declaration is ignored. + Space->addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One); + // sibling? + + DIE *Foo = new DIE(dwarf::DW_TAG_structure_type); + DIEString FooStr(&One, "foo"); + Foo->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + Foo->addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + Space->addChild(Foo); + CU.addChild(Space); + + uint64_t MD5Res = DIEHash().computeTypeSignature(*Foo); + + // The exact same hash GCC produces for this DIE. + ASSERT_EQ(0x7b80381fd17f1e33ULL, MD5Res); +} + +// struct { int member; }; +TEST(DIEHashTest, TypeWithMember) { + DIE Unnamed(dwarf::DW_TAG_structure_type); + DIEInteger Four(4); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); + + DIE *Member = new DIE(dwarf::DW_TAG_member); + DIEString MemberStr(&Four, "member"); + Member->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemberStr); + DIEInteger Zero(0); + Member->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + Unnamed.addChild(Member); + + DIE Int(dwarf::DW_TAG_base_type); + DIEString IntStr(&Four, "int"); + Int.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &IntStr); + Int.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); + DIEInteger Five(5); + Int.addValue(dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, &Five); + + DIEEntry IntRef(&Int); + Member->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &IntRef); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed); + + ASSERT_EQ(0x5646aa436b7e07c6ULL, MD5Res); +} + +// struct foo { int mem1, mem2; }; +TEST(DIEHashTest, ReusedType) { + DIE Unnamed(dwarf::DW_TAG_structure_type); + DIEInteger Eight(8); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + + DIE *Mem1 = new DIE(dwarf::DW_TAG_member); + DIEInteger Four(4); + DIEString Mem1Str(&Four, "mem1"); + Mem1->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &Mem1Str); + DIEInteger Zero(0); + Mem1->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + Unnamed.addChild(Mem1); + + DIE *Mem2 = new DIE(dwarf::DW_TAG_member); + DIEString Mem2Str(&Four, "mem2"); + Mem2->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &Mem2Str); + Mem2->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Four); + + Unnamed.addChild(Mem2); + + DIE Int(dwarf::DW_TAG_base_type); + DIEString IntStr(&Four, "int"); + Int.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &IntStr); + Int.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Four); + DIEInteger Five(5); + Int.addValue(dwarf::DW_AT_encoding, dwarf::DW_FORM_data1, &Five); + + DIEEntry IntRef(&Int); + Mem1->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &IntRef); + Mem2->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &IntRef); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed); + + ASSERT_EQ(0x3a7dc3ed7b76b2f8ULL, MD5Res); +} + +// struct foo { static foo f; }; +TEST(DIEHashTest, RecursiveType) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger One(1); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + DIEString FooStr(&One, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + DIEString MemStr(&One, "mem"); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + DIEEntry FooRef(&Foo); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRef); + // DW_AT_external and DW_AT_declaration are ignored anyway, so skip them. + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0x73d8b25aef227b06ULL, MD5Res); +} + +// struct foo { foo *mem; }; +TEST(DIEHashTest, Pointer) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger Eight(8); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEString FooStr(&Eight, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + DIEString MemStr(&Eight, "mem"); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + DIEInteger Zero(0); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + DIE FooPtr(dwarf::DW_TAG_pointer_type); + FooPtr.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEEntry FooRef(&Foo); + FooPtr.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRef); + + DIEEntry FooPtrRef(&FooPtr); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooPtrRef); + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0x74ea73862e8708d2ULL, MD5Res); +} + +// struct foo { foo &mem; }; +TEST(DIEHashTest, Reference) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger Eight(8); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEString FooStr(&Eight, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + DIEString MemStr(&Eight, "mem"); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + DIEInteger Zero(0); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + DIE FooRef(dwarf::DW_TAG_reference_type); + FooRef.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEEntry FooEntry(&Foo); + FooRef.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooEntry); + + DIE FooRefConst(dwarf::DW_TAG_const_type); + DIEEntry FooRefRef(&FooRef); + FooRefConst.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRefRef); + + DIEEntry FooRefConstRef(&FooRefConst); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRefConstRef); + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0xa0b15f467ad4525bULL, MD5Res); +} + +// struct foo { foo &&mem; }; +TEST(DIEHashTest, RValueReference) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger Eight(8); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEString FooStr(&Eight, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + DIEString MemStr(&Eight, "mem"); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + DIEInteger Zero(0); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + DIE FooRef(dwarf::DW_TAG_rvalue_reference_type); + FooRef.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEEntry FooEntry(&Foo); + FooRef.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooEntry); + + DIE FooRefConst(dwarf::DW_TAG_const_type); + DIEEntry FooRefRef(&FooRef); + FooRefConst.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRefRef); + + DIEEntry FooRefConstRef(&FooRefConst); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooRefConstRef); + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0xad211c8c3b31e57ULL, MD5Res); +} + +// struct foo { foo foo::*mem; }; +TEST(DIEHashTest, PtrToMember) { + DIE Foo(dwarf::DW_TAG_structure_type); + DIEInteger Eight(8); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEString FooStr(&Eight, "foo"); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + DIEString MemStr(&Eight, "mem"); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + DIEInteger Zero(0); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type); + DIEEntry FooEntry(&Foo); + PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &FooEntry); + PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, &FooEntry); + + DIEEntry PtrToFooMemRef(&PtrToFooMem); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef); + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0x852e0c9ff7c04ebULL, MD5Res); +} + +// Check that the hash for a pointer-to-member matches regardless of whether the +// pointed-to type is a declaration or a definition. +// +// struct bar; // { }; +// struct foo { bar foo::*mem; }; +TEST(DIEHashTest, PtrToMemberDeclDefMatch) { + DIEInteger Zero(0); + DIEInteger One(1); + DIEInteger Eight(8); + DIEString FooStr(&Eight, "foo"); + DIEString BarStr(&Eight, "bar"); + DIEString MemStr(&Eight, "mem"); + uint64_t MD5ResDecl; + { + DIE Bar(dwarf::DW_TAG_structure_type); + Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr); + Bar.addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One); + + DIE Foo(dwarf::DW_TAG_structure_type); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, + &Zero); + + DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type); + DIEEntry BarEntry(&Bar); + PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry); + DIEEntry FooEntry(&Foo); + PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, + &FooEntry); + + DIEEntry PtrToFooMemRef(&PtrToFooMem); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef); + + Foo.addChild(Mem); + + MD5ResDecl = DIEHash().computeTypeSignature(Foo); + } + uint64_t MD5ResDef; + { + DIE Bar(dwarf::DW_TAG_structure_type); + Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr); + Bar.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + DIE Foo(dwarf::DW_TAG_structure_type); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, + &Zero); + + DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type); + DIEEntry BarEntry(&Bar); + PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry); + DIEEntry FooEntry(&Foo); + PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, + &FooEntry); + + DIEEntry PtrToFooMemRef(&PtrToFooMem); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef); + + Foo.addChild(Mem); + + MD5ResDef = DIEHash().computeTypeSignature(Foo); + } + ASSERT_EQ(MD5ResDef, MD5ResDecl); +} + +// Check that the hash for a pointer-to-member matches regardless of whether the +// pointed-to type is a declaration or a definition. +// +// struct bar; // { }; +// struct foo { bar bar::*mem; }; +TEST(DIEHashTest, PtrToMemberDeclDefMisMatch) { + DIEInteger Zero(0); + DIEInteger One(1); + DIEInteger Eight(8); + DIEString FooStr(&Eight, "foo"); + DIEString BarStr(&Eight, "bar"); + DIEString MemStr(&Eight, "mem"); + uint64_t MD5ResDecl; + { + DIE Bar(dwarf::DW_TAG_structure_type); + Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr); + Bar.addValue(dwarf::DW_AT_declaration, dwarf::DW_FORM_flag_present, &One); + + DIE Foo(dwarf::DW_TAG_structure_type); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, + &Zero); + + DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type); + DIEEntry BarEntry(&Bar); + PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry); + PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, + &BarEntry); + + DIEEntry PtrToFooMemRef(&PtrToFooMem); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef); + + Foo.addChild(Mem); + + MD5ResDecl = DIEHash().computeTypeSignature(Foo); + } + uint64_t MD5ResDef; + { + DIE Bar(dwarf::DW_TAG_structure_type); + Bar.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &BarStr); + Bar.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + DIE Foo(dwarf::DW_TAG_structure_type); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, + &Zero); + + DIE PtrToFooMem(dwarf::DW_TAG_ptr_to_member_type); + DIEEntry BarEntry(&Bar); + PtrToFooMem.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &BarEntry); + PtrToFooMem.addValue(dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, + &BarEntry); + + DIEEntry PtrToFooMemRef(&PtrToFooMem); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &PtrToFooMemRef); + + Foo.addChild(Mem); + + MD5ResDef = DIEHash().computeTypeSignature(Foo); + } + // FIXME: This seems to be a bug in the DWARF type hashing specification that + // only uses the brief name hashing for types referenced via DW_AT_type. In + // this case the type is referenced via DW_AT_containing_type and full hashing + // causes a hash to differ when the containing type is a declaration in one TU + // and a definition in another. + ASSERT_NE(MD5ResDef, MD5ResDecl); +} + +// struct { } a; +// struct foo { decltype(a) mem; }; +TEST(DIEHashTest, RefUnnamedType) { + DIEInteger Zero(0); + DIEInteger One(1); + DIEInteger Eight(8); + DIEString FooStr(&Zero, "foo"); + DIEString MemStr(&Zero, "mem"); + + DIE Unnamed(dwarf::DW_TAG_structure_type); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + DIE Foo(dwarf::DW_TAG_structure_type); + Foo.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + Foo.addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + + DIE *Mem = new DIE(dwarf::DW_TAG_member); + Mem->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &MemStr); + Mem->addValue(dwarf::DW_AT_data_member_location, dwarf::DW_FORM_data1, &Zero); + + DIE UnnamedPtr(dwarf::DW_TAG_pointer_type); + UnnamedPtr.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &Eight); + DIEEntry UnnamedRef(&Unnamed); + UnnamedPtr.addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &UnnamedRef); + + DIEEntry UnnamedPtrRef(&UnnamedPtr); + Mem->addValue(dwarf::DW_AT_type, dwarf::DW_FORM_ref4, &UnnamedPtrRef); + + Foo.addChild(Mem); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Foo); + + ASSERT_EQ(0x954e026f01c02529ULL, MD5Res); +} + +// struct { struct bar { }; }; +TEST(DIEHashTest, NestedType) { + DIE Unnamed(dwarf::DW_TAG_structure_type); + DIEInteger One(1); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + DIE *Foo = new DIE(dwarf::DW_TAG_structure_type); + DIEString FooStr(&One, "foo"); + Foo->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FooStr); + Foo->addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + Unnamed.addChild(Foo); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed); + + // The exact same hash GCC produces for this DIE. + ASSERT_EQ(0xde8a3b7b43807f4aULL, MD5Res); +} + +// struct { static void func(); }; +TEST(DIEHashTest, MemberFunc) { + DIE Unnamed(dwarf::DW_TAG_structure_type); + DIEInteger One(1); + Unnamed.addValue(dwarf::DW_AT_byte_size, dwarf::DW_FORM_data1, &One); + + DIE *Func = new DIE(dwarf::DW_TAG_subprogram); + DIEString FuncStr(&One, "func"); + Func->addValue(dwarf::DW_AT_name, dwarf::DW_FORM_strp, &FuncStr); + + Unnamed.addChild(Func); + + uint64_t MD5Res = DIEHash().computeTypeSignature(Unnamed); + + // The exact same hash GCC produces for this DIE. + ASSERT_EQ(0xd36a1b6dfb604ba0ULL, MD5Res); +} +} diff --git a/unittests/CodeGen/Makefile b/unittests/CodeGen/Makefile new file mode 100644 index 0000000..4f07017 --- /dev/null +++ b/unittests/CodeGen/Makefile @@ -0,0 +1,16 @@ +##===- unittests/DebugInfo/Makefile ------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = CodeGen +LINK_COMPONENTS := asmprinter codegen support + +include $(LEVEL)/Makefile.config + +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/DebugInfo/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARFFormValueTest.cpp index 04b859b..38b932e 100644 --- a/unittests/DebugInfo/DWARFFormValueTest.cpp +++ b/unittests/DebugInfo/DWARFFormValueTest.cpp @@ -18,14 +18,32 @@ namespace { TEST(DWARFFormValue, FixedFormSizes) { // Size of DW_FORM_addr and DW_FORM_ref_addr are equal in DWARF2, // DW_FORM_ref_addr is always 4 bytes in DWARF32 starting from DWARF3. - const uint8_t *sizes = DWARFFormValue::getFixedFormSizes(4, 2); + ArrayRef<uint8_t> sizes = DWARFFormValue::getFixedFormSizes(4, 2); EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); sizes = DWARFFormValue::getFixedFormSizes(8, 2); EXPECT_EQ(sizes[DW_FORM_addr], sizes[DW_FORM_ref_addr]); sizes = DWARFFormValue::getFixedFormSizes(8, 3); EXPECT_EQ(4, sizes[DW_FORM_ref_addr]); // Check that we don't have fixed form sizes for weird address sizes. - EXPECT_EQ(0, DWARFFormValue::getFixedFormSizes(16, 2)); + EXPECT_EQ(0U, DWARFFormValue::getFixedFormSizes(16, 2).size()); +} + +bool isFormClass(uint16_t Form, DWARFFormValue::FormClass FC) { + return DWARFFormValue(Form).isFormClass(FC); +} + +TEST(DWARFFormValue, FormClass) { + EXPECT_TRUE(isFormClass(DW_FORM_addr, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Constant)); + EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE( + isFormClass(DW_FORM_sec_offset, DWARFFormValue::FC_SectionOffset)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_str_index, DWARFFormValue::FC_String)); + EXPECT_TRUE(isFormClass(DW_FORM_GNU_addr_index, DWARFFormValue::FC_Address)); + EXPECT_FALSE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Address)); + EXPECT_TRUE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Reference)); + EXPECT_TRUE(isFormClass(DW_FORM_ref_sig8, DWARFFormValue::FC_Reference)); } } // end anonymous namespace diff --git a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp index 68ca53d..731f780 100644 --- a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp @@ -281,11 +281,11 @@ TEST(JITMemoryManagerTest, TestManyStubs) { TEST(JITMemoryManagerTest, AllocateSection) { OwningPtr<JITMemoryManager> MemMgr( JITMemoryManager::CreateDefaultMemManager()); - uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1); - uint8_t *data1 = MemMgr->allocateDataSection(256, 16, 2, true); - uint8_t *code2 = MemMgr->allocateCodeSection(257, 32, 3); - uint8_t *data2 = MemMgr->allocateDataSection(256, 64, 4, false); - uint8_t *code3 = MemMgr->allocateCodeSection(258, 64, 5); + uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1, StringRef()); + uint8_t *data1 = MemMgr->allocateDataSection(256, 16, 2, StringRef(), true); + uint8_t *code2 = MemMgr->allocateCodeSection(257, 32, 3, StringRef()); + uint8_t *data2 = MemMgr->allocateDataSection(256, 64, 4, StringRef(), false); + uint8_t *code3 = MemMgr->allocateCodeSection(258, 64, 5, StringRef()); EXPECT_NE((uint8_t*)0, code1); EXPECT_NE((uint8_t*)0, code2); diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index 3b94d76..4c7b1e2 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -135,13 +135,17 @@ public: EndFunctionBodyCall(F, FunctionStart, FunctionEnd)); Base->endFunctionBody(F, FunctionStart, FunctionEnd); } - virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly) { - return Base->allocateDataSection(Size, Alignment, SectionID, IsReadOnly); + virtual uint8_t *allocateDataSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName, bool IsReadOnly) { + return Base->allocateDataSection( + Size, Alignment, SectionID, SectionName, IsReadOnly); } - virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID) { - return Base->allocateCodeSection(Size, Alignment, SectionID); + virtual uint8_t *allocateCodeSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + return Base->allocateCodeSection( + Size, Alignment, SectionID, SectionName); } virtual bool finalizeMemory(std::string *ErrMsg) { return false; } virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { @@ -717,16 +721,4 @@ TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) { } #endif // !defined(__arm__) && !defined(__powerpc__) && !defined(__s390__) -// This code is copied from JITEventListenerTest, but it only runs once for all -// the tests in this directory. Everything seems fine, but that's strange -// behavior. -class JITEnvironment : public testing::Environment { - virtual void SetUp() { - // Required to create a JIT. - InitializeNativeTarget(); - } -}; -testing::Environment* const jit_env = - testing::AddGlobalTestEnvironment(new JITEnvironment); - } diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt index 922cb7e..ed43099 100644 --- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -2,7 +2,6 @@ set(LLVM_LINK_COMPONENTS asmparser bitreader bitwriter - jit mcjit nativecodegen ) @@ -11,6 +10,7 @@ set(MCJITTestsSources MCJITTest.cpp MCJITCAPITest.cpp MCJITMemoryManagerTest.cpp + MCJITMultipleModuleTest.cpp MCJITObjectCacheTest.cpp ) diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index c434a7c..46d6d9b 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -28,18 +28,20 @@ static bool didCallAllocateCodeSection; static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, unsigned alignment, - unsigned sectionID) { + unsigned sectionID, + const char *sectionName) { didCallAllocateCodeSection = true; return static_cast<SectionMemoryManager*>(object)->allocateCodeSection( - size, alignment, sectionID); + size, alignment, sectionID, sectionName); } static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size, unsigned alignment, unsigned sectionID, + const char *sectionName, LLVMBool isReadOnly) { return static_cast<SectionMemoryManager*>(object)->allocateDataSection( - size, alignment, sectionID, isReadOnly); + size, alignment, sectionID, sectionName, isReadOnly); } static LLVMBool roundTripFinalizeMemory(void *object, char **errMsg) { @@ -57,6 +59,7 @@ static void roundTripDestroy(void *object) { delete static_cast<SectionMemoryManager*>(object); } +namespace { class MCJITCAPITest : public testing::Test, public MCJITTestAPICommon { protected: MCJITCAPITest() { @@ -154,6 +157,7 @@ protected: LLVMExecutionEngineRef Engine; char *Error; }; +} // end anonymous namespace TEST_F(MCJITCAPITest, simple_function) { SKIP_UNSUPPORTED_PLATFORM; diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp index f6dbf98..c24346d 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITMemoryManagerTest.cpp @@ -19,10 +19,10 @@ namespace { TEST(MCJITMemoryManagerTest, BasicAllocations) { OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager()); - uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1); - uint8_t *data1 = MemMgr->allocateDataSection(256, 0, 2, true); - uint8_t *code2 = MemMgr->allocateCodeSection(256, 0, 3); - uint8_t *data2 = MemMgr->allocateDataSection(256, 0, 4, false); + uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1, ""); + uint8_t *data1 = MemMgr->allocateDataSection(256, 0, 2, "", true); + uint8_t *code2 = MemMgr->allocateCodeSection(256, 0, 3, ""); + uint8_t *data2 = MemMgr->allocateDataSection(256, 0, 4, "", false); EXPECT_NE((uint8_t*)0, code1); EXPECT_NE((uint8_t*)0, code2); @@ -52,10 +52,10 @@ TEST(MCJITMemoryManagerTest, BasicAllocations) { TEST(MCJITMemoryManagerTest, LargeAllocations) { OwningPtr<SectionMemoryManager> MemMgr(new SectionMemoryManager()); - uint8_t *code1 = MemMgr->allocateCodeSection(0x100000, 0, 1); - uint8_t *data1 = MemMgr->allocateDataSection(0x100000, 0, 2, true); - uint8_t *code2 = MemMgr->allocateCodeSection(0x100000, 0, 3); - uint8_t *data2 = MemMgr->allocateDataSection(0x100000, 0, 4, false); + uint8_t *code1 = MemMgr->allocateCodeSection(0x100000, 0, 1, ""); + uint8_t *data1 = MemMgr->allocateDataSection(0x100000, 0, 2, "", true); + uint8_t *code2 = MemMgr->allocateCodeSection(0x100000, 0, 3, ""); + uint8_t *data2 = MemMgr->allocateDataSection(0x100000, 0, 4, "", false); EXPECT_NE((uint8_t*)0, code1); EXPECT_NE((uint8_t*)0, code2); @@ -91,8 +91,8 @@ TEST(MCJITMemoryManagerTest, ManyAllocations) { for (unsigned i = 0; i < 10000; ++i) { const bool isReadOnly = i % 2 == 0; - code[i] = MemMgr->allocateCodeSection(32, 0, 1); - data[i] = MemMgr->allocateDataSection(32, 0, 2, isReadOnly); + code[i] = MemMgr->allocateCodeSection(32, 0, 1, ""); + data[i] = MemMgr->allocateDataSection(32, 0, 2, "", isReadOnly); for (unsigned j = 0; j < 32; j++) { code[i][j] = 1 + (i % 254); @@ -130,8 +130,8 @@ TEST(MCJITMemoryManagerTest, ManyVariedAllocations) { bool isReadOnly = i % 3 == 0; unsigned Align = 8 << (i % 4); - code[i] = MemMgr->allocateCodeSection(CodeSize, Align, i); - data[i] = MemMgr->allocateDataSection(DataSize, Align, i + 10000, + code[i] = MemMgr->allocateCodeSection(CodeSize, Align, i, ""); + data[i] = MemMgr->allocateDataSection(DataSize, Align, i + 10000, "", isReadOnly); for (unsigned j = 0; j < CodeSize; j++) { diff --git a/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp new file mode 100644 index 0000000..7c3239e --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITMultipleModuleTest.cpp @@ -0,0 +1,395 @@ +//===- MCJITMultipeModuleTest.cpp - Unit tests for the MCJIT---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This test suite verifies MCJIT for handling multiple modules in a single +// ExecutionEngine by building multiple modules, making function calls across +// modules, accessing global variables, etc. +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/MCJIT.h" +#include "MCJITTestBase.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class MCJITMultipleModuleTest : public testing::Test, public MCJITTestBase {}; + +// FIXME: ExecutionEngine has no support empty modules +/* +TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) { + SKIP_UNSUPPORTED_PLATFORM; + + createJIT(M.take()); + // JIT-compile + EXPECT_NE(0, TheJIT->getObjectImage()) + << "Unable to generate executable loaded object image"; + + TheJIT->addModule(createEmptyModule("<other module>")); + TheJIT->addModule(createEmptyModule("<other other module>")); + + // JIT again + EXPECT_NE(0, TheJIT->getObjectImage()) + << "Unable to generate executable loaded object image"; +} +*/ + +// Helper Function to test add operation +void checkAdd(uint64_t ptr) { + ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function."; + int (*AddPtr)(int, int) = (int (*)(int, int))ptr; + EXPECT_EQ(0, AddPtr(0, 0)); + EXPECT_EQ(1, AddPtr(1, 0)); + EXPECT_EQ(3, AddPtr(1, 2)); + EXPECT_EQ(-5, AddPtr(-2, -3)); + EXPECT_EQ(30, AddPtr(10, 20)); + EXPECT_EQ(-30, AddPtr(-10, -20)); + EXPECT_EQ(-40, AddPtr(-10, -30)); +} + +void checkAccumulate(uint64_t ptr) { + ASSERT_TRUE(ptr != 0) << "Unable to get pointer to function."; + int32_t (*FPtr)(int32_t) = (int32_t (*)(int32_t))(intptr_t)ptr; + EXPECT_EQ(0, FPtr(0)); + EXPECT_EQ(1, FPtr(1)); + EXPECT_EQ(3, FPtr(2)); + EXPECT_EQ(6, FPtr(3)); + EXPECT_EQ(10, FPtr(4)); + EXPECT_EQ(15, FPtr(5)); +} + +// FIXME: ExecutionEngine has no support empty modules +/* +TEST_F(MCJITMultipleModuleTest, multiple_empty_modules) { + SKIP_UNSUPPORTED_PLATFORM; + + createJIT(M.take()); + // JIT-compile + EXPECT_NE(0, TheJIT->getObjectImage()) + << "Unable to generate executable loaded object image"; + + TheJIT->addModule(createEmptyModule("<other module>")); + TheJIT->addModule(createEmptyModule("<other other module>")); + + // JIT again + EXPECT_NE(0, TheJIT->getObjectImage()) + << "Unable to generate executable loaded object image"; +} +*/ + +// Module A { Function FA }, +// Module B { Function FB }, +// execute FA then FB +TEST_F(MCJITMultipleModuleTest, two_module_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB; + createTwoModuleCase(A, FA, B, FB); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Function FB }, +// execute FB then FA +TEST_F(MCJITMultipleModuleTest, two_module_reverse_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB; + createTwoModuleCase(A, FA, B, FB); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str()); + TheJIT->finalizeObject(); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// execute FB then FA +TEST_F(MCJITMultipleModuleTest, two_module_extern_reverse_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB; + createTwoModuleExternCase(A, FA, B, FB); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str()); + TheJIT->finalizeObject(); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// execute FA then FB +TEST_F(MCJITMultipleModuleTest, two_module_extern_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB; + createTwoModuleExternCase(A, FA, B, FB); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA1, Function FA2 which calls FA1 }, +// Module B { Extern FA1, Function FB which calls FA1 }, +// execute FB then FA2 +TEST_F(MCJITMultipleModuleTest, two_module_consecutive_call_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA1, *FA2, *FB; + createTwoModuleExternCase(A, FA1, B, FB); + FA2 = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(A.get(), FA1); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FB->getName().str()); + TheJIT->finalizeObject(); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FA2->getName().str()); + checkAdd(ptr); +} + +// TODO: +// Module A { Extern Global GVB, Global Variable GVA, Function FA loads GVB }, +// Module B { Extern Global GVA, Global Variable GVB, Function FB loads GVA }, + + +// Module A { Global Variable GVA, Function FA loads GVA }, +// Module B { Global Variable GVB, Function FB loads GVB }, +// execute FB then FA +TEST_F(MCJITMultipleModuleTest, two_module_global_variables_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB; + GlobalVariable *GVA, *GVB; + A.reset(createEmptyModule("A")); + B.reset(createEmptyModule("B")); + + int32_t initialNum = 7; + GVA = insertGlobalInt32(A.get(), "GVA", initialNum); + GVB = insertGlobalInt32(B.get(), "GVB", initialNum); + FA = startFunction<int32_t(void)>(A.get(), "FA"); + endFunctionWithRet(FA, Builder.CreateLoad(GVA)); + FB = startFunction<int32_t(void)>(B.get(), "FB"); + endFunctionWithRet(FB, Builder.CreateLoad(GVB)); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t FBPtr = TheJIT->getFunctionAddress(FB->getName().str()); + TheJIT->finalizeObject(); + EXPECT_TRUE(0 != FBPtr); + int32_t(*FuncPtr)(void) = (int32_t(*)(void))FBPtr; + EXPECT_EQ(initialNum, FuncPtr()) + << "Invalid value for global returned from JITted function in module B"; + + uint64_t FAPtr = TheJIT->getFunctionAddress(FA->getName().str()); + EXPECT_TRUE(0 != FAPtr); + FuncPtr = (int32_t(*)(void))FAPtr; + EXPECT_EQ(initialNum, FuncPtr()) + << "Invalid value for global returned from JITted function in module A"; +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// Module C { Extern FA, Function FC which calls FA }, +// execute FC, FB, FA +TEST_F(MCJITMultipleModuleTest, three_module_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B, C; + Function *FA, *FB, *FC; + createThreeModuleCase(A, FA, B, FB, C, FC); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + TheJIT->addModule(C.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// Module C { Extern FA, Function FC which calls FA }, +// execute FA, FB, FC +TEST_F(MCJITMultipleModuleTest, three_module_case_reverse_order) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B, C; + Function *FA, *FB, *FC; + createThreeModuleCase(A, FA, B, FB, C, FC); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + TheJIT->addModule(C.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FC->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// Module C { Extern FB, Function FC which calls FB }, +// execute FC, FB, FA +TEST_F(MCJITMultipleModuleTest, three_module_chain_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B, C; + Function *FA, *FB, *FC; + createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + TheJIT->addModule(C.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FC->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); +} + +// Module A { Function FA }, +// Module B { Extern FA, Function FB which calls FA }, +// Module C { Extern FB, Function FC which calls FB }, +// execute FA, FB, FC +TEST_F(MCJITMultipleModuleTest, three_modules_chain_case_reverse_order) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B, C; + Function *FA, *FB, *FC; + createThreeModuleChainedCallsCase(A, FA, B, FB, C, FC); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + TheJIT->addModule(C.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FB->getName().str()); + checkAdd(ptr); + + ptr = TheJIT->getFunctionAddress(FC->getName().str()); + checkAdd(ptr); +} + +// Module A { Extern FB, Function FA which calls FB1 }, +// Module B { Extern FA, Function FB1, Function FB2 which calls FA }, +// execute FA, then FB1 +// FIXME: this test case is not supported by MCJIT +TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB1, *FB2; + createCrossModuleRecursiveCase(A, FA, B, FB1, FB2); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAccumulate(ptr); + + ptr = TheJIT->getFunctionAddress(FB1->getName().str()); + checkAccumulate(ptr); +} + +// Module A { Extern FB, Function FA which calls FB1 }, +// Module B { Extern FA, Function FB1, Function FB2 which calls FA }, +// execute FB1 then FA +// FIXME: this test case is not supported by MCJIT +TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case_reverse_order) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB1, *FB2; + createCrossModuleRecursiveCase(A, FA, B, FB1, FB2); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str()); + checkAccumulate(ptr); + + ptr = TheJIT->getFunctionAddress(FA->getName().str()); + checkAccumulate(ptr); +} + +// Module A { Extern FB1, Function FA which calls FB1 }, +// Module B { Extern FA, Function FB1, Function FB2 which calls FA }, +// execute FB1 then FB2 +// FIXME: this test case is not supported by MCJIT +TEST_F(MCJITMultipleModuleTest, cross_module_dependency_case3) { + SKIP_UNSUPPORTED_PLATFORM; + + OwningPtr<Module> A, B; + Function *FA, *FB1, *FB2; + createCrossModuleRecursiveCase(A, FA, B, FB1, FB2); + + createJIT(A.take()); + TheJIT->addModule(B.take()); + + uint64_t ptr = TheJIT->getFunctionAddress(FB1->getName().str()); + checkAccumulate(ptr); + + ptr = TheJIT->getFunctionAddress(FB2->getName().str()); + checkAccumulate(ptr); +} +} diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp index 43a8298..fab8155 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -18,23 +18,27 @@ using namespace llvm; +namespace { + class MCJITTest : public testing::Test, public MCJITTestBase { protected: - - virtual void SetUp() { - M.reset(createEmptyModule("<main>")); - } + virtual void SetUp() { M.reset(createEmptyModule("<main>")); } }; -namespace { +// FIXME: Ensure creating an execution engine does not crash when constructed +// with a null module. +/* +TEST_F(MCJITTest, null_module) { + createJIT(0); +} +*/ // FIXME: In order to JIT an empty module, there needs to be // an interface to ExecutionEngine that forces compilation but -// does require retrieval of a pointer to a function/global. +// does not require retrieval of a pointer to a function/global. /* TEST_F(MCJITTest, empty_module) { createJIT(M.take()); - TheJIT->finalizeObject(); //EXPECT_NE(0, TheJIT->getObjectImage()) // << "Unable to generate executable loaded object image"; } @@ -47,7 +51,6 @@ TEST_F(MCJITTest, global_variable) { GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); createJIT(M.take()); void *globalPtr = TheJIT->getPointerToGlobal(Global); - TheJIT->finalizeObject(); EXPECT_TRUE(0 != globalPtr) << "Unable to get pointer to global value from JIT"; @@ -60,15 +63,19 @@ TEST_F(MCJITTest, add_function) { Function *F = insertAddFunction(M.get()); createJIT(M.take()); - void *addPtr = TheJIT->getPointerToFunction(F); - TheJIT->finalizeObject(); + uint64_t addPtr = TheJIT->getFunctionAddress(F->getName().str()); EXPECT_TRUE(0 != addPtr) << "Unable to get pointer to function from JIT"; - int (*AddPtrTy)(int, int) = (int(*)(int, int))(intptr_t)addPtr; - EXPECT_EQ(0, AddPtrTy(0, 0)); - EXPECT_EQ(3, AddPtrTy(1, 2)); - EXPECT_EQ(-5, AddPtrTy(-2, -3)); + ASSERT_TRUE(addPtr != 0) << "Unable to get pointer to function ."; + int (*AddPtr)(int, int) = (int(*)(int, int))addPtr ; + EXPECT_EQ(0, AddPtr(0, 0)); + EXPECT_EQ(1, AddPtr(1, 0)); + EXPECT_EQ(3, AddPtr(1, 2)); + EXPECT_EQ(-5, AddPtr(-2, -3)); + EXPECT_EQ(30, AddPtr(10, 20)); + EXPECT_EQ(-30, AddPtr(-10, -20)); + EXPECT_EQ(-40, AddPtr(-10, -30)); } TEST_F(MCJITTest, run_main) { @@ -77,12 +84,11 @@ TEST_F(MCJITTest, run_main) { int rc = 6; Function *Main = insertMainFunction(M.get(), 6); createJIT(M.take()); - void *vPtr = TheJIT->getPointerToFunction(Main); - TheJIT->finalizeObject(); - EXPECT_TRUE(0 != vPtr) + uint64_t ptr = TheJIT->getFunctionAddress(Main->getName().str()); + EXPECT_TRUE(0 != ptr) << "Unable to get pointer to main() from JIT"; - int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr; + int (*FuncPtr)(void) = (int(*)(void))ptr; int returnCode = FuncPtr(); EXPECT_EQ(returnCode, rc); } @@ -99,11 +105,10 @@ TEST_F(MCJITTest, return_global) { endFunctionWithRet(ReturnGlobal, ReadGlobal); createJIT(M.take()); - void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); - TheJIT->finalizeObject(); + uint64_t rgvPtr = TheJIT->getFunctionAddress(ReturnGlobal->getName().str()); EXPECT_TRUE(0 != rgvPtr); - int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr; + int32_t(*FuncPtr)(void) = (int32_t(*)(void))rgvPtr; EXPECT_EQ(initialNum, FuncPtr()) << "Invalid value for global returned from JITted function"; } @@ -131,10 +136,9 @@ TEST_F(MCJITTest, increment_global) { createJIT(M.take()); void *gvPtr = TheJIT->getPointerToGlobal(GV); - TheJIT->finalizeObject(); EXPECT_EQ(initialNum, *(int32_t*)gvPtr); - void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal); + void *vPtr = TheJIT->getFunctionAddress(IncrementGlobal->getName().str()); EXPECT_TRUE(0 != vPtr) << "Unable to get pointer to main() from JIT"; @@ -172,67 +176,15 @@ TEST_F(MCJITTest, multiple_functions) { } createJIT(M.take()); - void *vPtr = TheJIT->getPointerToFunction(Outer); - TheJIT->finalizeObject(); - EXPECT_TRUE(0 != vPtr) + uint64_t ptr = TheJIT->getFunctionAddress(Outer->getName().str()); + EXPECT_TRUE(0 != ptr) << "Unable to get pointer to outer function from JIT"; - int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr; + int32_t(*FuncPtr)(void) = (int32_t(*)(void))ptr; EXPECT_EQ(innerRetVal, FuncPtr()) << "Incorrect result returned from function"; } #endif /*!defined(__arm__)*/ -// FIXME: ExecutionEngine has no support empty modules -/* -TEST_F(MCJITTest, multiple_empty_modules) { - SKIP_UNSUPPORTED_PLATFORM; - - createJIT(M.take()); - // JIT-compile - EXPECT_NE(0, TheJIT->getObjectImage()) - << "Unable to generate executable loaded object image"; - - TheJIT->addModule(createEmptyModule("<other module>")); - TheJIT->addModule(createEmptyModule("<other other module>")); - - // JIT again - EXPECT_NE(0, TheJIT->getObjectImage()) - << "Unable to generate executable loaded object image"; -} -*/ - -// FIXME: MCJIT must support multiple modules -/* -TEST_F(MCJITTest, multiple_modules) { - SKIP_UNSUPPORTED_PLATFORM; - - Function *Callee = insertAddFunction(M.get()); - createJIT(M.take()); - - // caller function is defined in a different module - M.reset(createEmptyModule("<caller module>")); - - Function *CalleeRef = insertExternalReferenceToFunction(M.get(), Callee); - Function *Caller = insertSimpleCallFunction(M.get(), CalleeRef); - - TheJIT->addModule(M.take()); - - // get a function pointer in a module that was not used in EE construction - void *vPtr = TheJIT->getPointerToFunction(Caller); - TheJIT->finalizeObject(); - EXPECT_NE(0, vPtr) - << "Unable to get pointer to caller function from JIT"; - - int(*FuncPtr)(int, int) = (int(*)(int, int))(intptr_t)vPtr; - EXPECT_EQ(0, FuncPtr(0, 0)); - EXPECT_EQ(30, FuncPtr(10, 20)); - EXPECT_EQ(-30, FuncPtr(-10, -20)); - - // ensure caller is destroyed before callee (free use before def) - M.reset(); -} -*/ - } diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h index 5debb8b..b42a9c0 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -119,12 +119,13 @@ protected: // Inserts an declaration to a function defined elsewhere Function *insertExternalReferenceToFunction(Module *M, Function *Func) { Function *Result = Function::Create(Func->getFunctionType(), - GlobalValue::AvailableExternallyLinkage, + GlobalValue::ExternalLinkage, Func->getName(), M); return Result; } // Inserts a global variable of type int32 + // FIXME: make this a template function to support any type GlobalVariable *insertGlobalInt32(Module *M, StringRef name, int32_t InitialValue) { @@ -138,11 +139,148 @@ protected: name); return Global; } + + // Inserts a function + // int32_t recursive_add(int32_t num) { + // if (num == 0) { + // return num; + // } else { + // int32_t recursive_param = num - 1; + // return num + Helper(recursive_param); + // } + // } + // NOTE: if Helper is left as the default parameter, Helper == recursive_add. + Function *insertAccumulateFunction(Module *M, + Function *Helper = 0, + StringRef Name = "accumulate") { + Function *Result = startFunction<int32_t(int32_t)>(M, Name); + if (Helper == 0) + Helper = Result; + + BasicBlock *BaseCase = BasicBlock::Create(Context, "", Result); + BasicBlock *RecursiveCase = BasicBlock::Create(Context, "", Result); + + // if (num == 0) + Value *Param = Result->arg_begin(); + Value *Zero = ConstantInt::get(Context, APInt(32, 0)); + Builder.CreateCondBr(Builder.CreateICmpEQ(Param, Zero), + BaseCase, RecursiveCase); + + // return num; + Builder.SetInsertPoint(BaseCase); + Builder.CreateRet(Param); + + // int32_t recursive_param = num - 1; + // return Helper(recursive_param); + Builder.SetInsertPoint(RecursiveCase); + Value *One = ConstantInt::get(Context, APInt(32, 1)); + Value *RecursiveParam = Builder.CreateSub(Param, One); + Value *RecursiveReturn = Builder.CreateCall(Helper, RecursiveParam); + Value *Accumulator = Builder.CreateAdd(Param, RecursiveReturn); + Builder.CreateRet(Accumulator); + + return Result; + } + + // Populates Modules A and B: + // Module A { Extern FB1, Function FA which calls FB1 }, + // Module B { Extern FA, Function FB1, Function FB2 which calls FA }, + void createCrossModuleRecursiveCase(OwningPtr<Module> &A, + Function *&FA, + OwningPtr<Module> &B, + Function *&FB1, + Function *&FB2) { + // Define FB1 in B. + B.reset(createEmptyModule("B")); + FB1 = insertAccumulateFunction(B.get(), 0, "FB1"); + + // Declare FB1 in A (as an external). + A.reset(createEmptyModule("A")); + Function *FB1Extern = insertExternalReferenceToFunction(A.get(), FB1); + + // Define FA in A (with a call to FB1). + FA = insertAccumulateFunction(A.get(), FB1Extern, "FA"); + + // Declare FA in B (as an external) + Function *FAExtern = insertExternalReferenceToFunction(B.get(), FA); + + // Define FB2 in B (with a call to FA) + FB2 = insertAccumulateFunction(B.get(), FAExtern, "FB2"); + } + + // Module A { Function FA }, + // Module B { Extern FA, Function FB which calls FA }, + // Module C { Extern FB, Function FC which calls FB }, + void createThreeModuleChainedCallsCase(OwningPtr<Module> &A, + Function *&FA, + OwningPtr<Module> &B, + Function *&FB, + OwningPtr<Module> &C, + Function *&FC) { + A.reset(createEmptyModule("A")); + FA = insertAddFunction(A.get()); + + B.reset(createEmptyModule("B")); + Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA); + FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(), FAExtern_in_B); + + C.reset(createEmptyModule("C")); + Function *FBExtern_in_C = insertExternalReferenceToFunction(C.get(), FB); + FC = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(C.get(), FBExtern_in_C); + } + + + // Module A { Function FA }, + // Populates Modules A and B: + // Module B { Function FB } + void createTwoModuleCase(OwningPtr<Module> &A, Function *&FA, + OwningPtr<Module> &B, Function *&FB) { + A.reset(createEmptyModule("A")); + FA = insertAddFunction(A.get()); + + B.reset(createEmptyModule("B")); + FB = insertAddFunction(B.get()); + } + + // Module A { Function FA }, + // Module B { Extern FA, Function FB which calls FA } + void createTwoModuleExternCase(OwningPtr<Module> &A, Function *&FA, + OwningPtr<Module> &B, Function *&FB) { + A.reset(createEmptyModule("A")); + FA = insertAddFunction(A.get()); + + B.reset(createEmptyModule("B")); + Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA); + FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(), + FAExtern_in_B); + } + + // Module A { Function FA }, + // Module B { Extern FA, Function FB which calls FA }, + // Module C { Extern FB, Function FC which calls FA }, + void createThreeModuleCase(OwningPtr<Module> &A, + Function *&FA, + OwningPtr<Module> &B, + Function *&FB, + OwningPtr<Module> &C, + Function *&FC) { + A.reset(createEmptyModule("A")); + FA = insertAddFunction(A.get()); + + B.reset(createEmptyModule("B")); + Function *FAExtern_in_B = insertExternalReferenceToFunction(B.get(), FA); + FB = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(B.get(), FAExtern_in_B); + + C.reset(createEmptyModule("C")); + Function *FAExtern_in_C = insertExternalReferenceToFunction(C.get(), FA); + FC = insertSimpleCallFunction<int32_t(int32_t, int32_t)>(C.get(), FAExtern_in_C); + } }; + class MCJITTestBase : public MCJITTestAPICommon, public TrivialModuleBuilder { protected: - + MCJITTestBase() : TrivialModuleBuilder(HostTriple) , OptLevel(CodeGenOpt::None) diff --git a/unittests/ExecutionEngine/MCJIT/Makefile b/unittests/ExecutionEngine/MCJIT/Makefile index 454f830..33b043b 100644 --- a/unittests/ExecutionEngine/MCJIT/Makefile +++ b/unittests/ExecutionEngine/MCJIT/Makefile @@ -9,7 +9,7 @@ LEVEL = ../../.. TESTNAME = MCJIT -LINK_COMPONENTS := core jit mcjit native support +LINK_COMPONENTS := core mcjit native support include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/IR/CMakeLists.txt b/unittests/IR/CMakeLists.txt index c53043e..fd0831f 100644 --- a/unittests/IR/CMakeLists.txt +++ b/unittests/IR/CMakeLists.txt @@ -10,6 +10,7 @@ set(IRSources DominatorTreeTest.cpp IRBuilderTest.cpp InstructionsTest.cpp + LegacyPassManagerTest.cpp MDBuilderTest.cpp MetadataTest.cpp PassManagerTest.cpp diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp index fecc4a4..2f390f7 100644 --- a/unittests/IR/IRBuilderTest.cpp +++ b/unittests/IR/IRBuilderTest.cpp @@ -25,12 +25,12 @@ namespace { class IRBuilderTest : public testing::Test { protected: virtual void SetUp() { - M.reset(new Module("MyModule", getGlobalContext())); - FunctionType *FTy = FunctionType::get(Type::getVoidTy(getGlobalContext()), + M.reset(new Module("MyModule", Ctx)); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), /*isVarArg=*/false); F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); - BB = BasicBlock::Create(getGlobalContext(), "", F); - GV = new GlobalVariable(*M, Type::getFloatTy(getGlobalContext()), true, + BB = BasicBlock::Create(Ctx, "", F); + GV = new GlobalVariable(*M, Type::getFloatTy(Ctx), true, GlobalValue::ExternalLinkage, 0); } @@ -39,6 +39,7 @@ protected: M.reset(); } + LLVMContext Ctx; OwningPtr<Module> M; Function *F; BasicBlock *BB; @@ -78,8 +79,8 @@ TEST_F(IRBuilderTest, Lifetime) { TEST_F(IRBuilderTest, CreateCondBr) { IRBuilder<> Builder(BB); - BasicBlock *TBB = BasicBlock::Create(getGlobalContext(), "", F); - BasicBlock *FBB = BasicBlock::Create(getGlobalContext(), "", F); + BasicBlock *TBB = BasicBlock::Create(Ctx, "", F); + BasicBlock *FBB = BasicBlock::Create(Ctx, "", F); BranchInst *BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB); TerminatorInst *TI = BB->getTerminator(); @@ -89,7 +90,7 @@ TEST_F(IRBuilderTest, CreateCondBr) { EXPECT_EQ(FBB, TI->getSuccessor(1)); BI->eraseFromParent(); - MDNode *Weights = MDBuilder(getGlobalContext()).createBranchWeights(42, 13); + MDNode *Weights = MDBuilder(Ctx).createBranchWeights(42, 13); BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB, Weights); TI = BB->getTerminator(); EXPECT_EQ(BI, TI); @@ -109,12 +110,12 @@ TEST_F(IRBuilderTest, LandingPadName) { TEST_F(IRBuilderTest, GetIntTy) { IRBuilder<> Builder(BB); IntegerType *Ty1 = Builder.getInt1Ty(); - EXPECT_EQ(Ty1, IntegerType::get(getGlobalContext(), 1)); + EXPECT_EQ(Ty1, IntegerType::get(Ctx, 1)); DataLayout* DL = new DataLayout(M.get()); IntegerType *IntPtrTy = Builder.getIntPtrTy(DL); unsigned IntPtrBitSize = DL->getPointerSizeInBits(0); - EXPECT_EQ(IntPtrTy, IntegerType::get(getGlobalContext(), IntPtrBitSize)); + EXPECT_EQ(IntPtrTy, IntegerType::get(Ctx, IntPtrBitSize)); delete DL; } @@ -182,4 +183,40 @@ TEST_F(IRBuilderTest, FastMathFlags) { } +TEST_F(IRBuilderTest, RAIIHelpersTest) { + IRBuilder<> Builder(BB); + EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); + MDBuilder MDB(M->getContext()); + + MDNode *FPMathA = MDB.createFPMath(0.01f); + MDNode *FPMathB = MDB.createFPMath(0.1f); + + Builder.SetDefaultFPMathTag(FPMathA); + + { + IRBuilder<>::FastMathFlagGuard Guard(Builder); + FastMathFlags FMF; + FMF.setAllowReciprocal(); + Builder.SetFastMathFlags(FMF); + Builder.SetDefaultFPMathTag(FPMathB); + EXPECT_TRUE(Builder.getFastMathFlags().allowReciprocal()); + EXPECT_EQ(FPMathB, Builder.getDefaultFPMathTag()); + } + + EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); + EXPECT_EQ(FPMathA, Builder.getDefaultFPMathTag()); + + Value *F = Builder.CreateLoad(GV); + + { + IRBuilder<>::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(cast<Instruction>(F)); + EXPECT_EQ(F, Builder.GetInsertPoint()); + } + + EXPECT_EQ(BB->end(), Builder.GetInsertPoint()); + EXPECT_EQ(BB, Builder.GetInsertBlock()); +} + + } diff --git a/unittests/IR/InstructionsTest.cpp b/unittests/IR/InstructionsTest.cpp index ce6c465..65f85ba 100644 --- a/unittests/IR/InstructionsTest.cpp +++ b/unittests/IR/InstructionsTest.cpp @@ -149,6 +149,8 @@ TEST(InstructionsTest, CastInst) { const Constant* c8 = Constant::getNullValue(V8x8Ty); const Constant* c64 = Constant::getNullValue(V8x64Ty); + const Constant *v2ptr32 = Constant::getNullValue(V2Int32PtrTy); + EXPECT_TRUE(CastInst::isCastable(V8x8Ty, X86MMXTy)); EXPECT_TRUE(CastInst::isCastable(X86MMXTy, V8x8Ty)); EXPECT_FALSE(CastInst::isCastable(Int64Ty, X86MMXTy)); @@ -169,6 +171,10 @@ TEST(InstructionsTest, CastInst) { EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, V2Int32PtrAS1Ty)); EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int32PtrTy)); EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int64PtrAS1Ty)); + EXPECT_TRUE(CastInst::isCastable(V2Int32PtrAS1Ty, V2Int32PtrTy)); + EXPECT_EQ(CastInst::AddrSpaceCast, CastInst::getCastOpcode(v2ptr32, true, + V2Int32PtrAS1Ty, + true)); // Test mismatched number of elements for pointers EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int64PtrAS1Ty)); @@ -371,7 +377,6 @@ TEST(InstructionsTest, isEliminableCastPair) { 0, Int32Ty, 0), 0U); - // Test that we don't eliminate bitcasts between different address spaces, // or if we don't have available pointer size information. DataLayout DL("e-p:32:32:32-p1:16:16:16-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16" @@ -384,26 +389,18 @@ TEST(InstructionsTest, isEliminableCastPair) { IntegerType *Int16SizePtr = DL.getIntPtrType(C, 1); IntegerType *Int64SizePtr = DL.getIntPtrType(C, 2); - // Fail since the ptr int types are not provided + // Cannot simplify inttoptr, addrspacecast EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, - CastInst::BitCast, + CastInst::AddrSpaceCast, Int16Ty, Int64PtrTyAS1, Int64PtrTyAS2, - 0, 0, 0), - 0U); - - // Fail since the the bitcast is between different sized address spaces - EXPECT_EQ(CastInst::isEliminableCastPair( - CastInst::IntToPtr, - CastInst::BitCast, - Int16Ty, Int64PtrTyAS1, Int64PtrTyAS2, - 0, Int16SizePtr, Int64SizePtr), + 0, Int16SizePtr, Int64SizePtr), 0U); - // Fail since the the bitcast is between different sized address spaces - EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, - CastInst::BitCast, - Int16Ty, Int64PtrTyAS1, Int64PtrTyAS2, - 0, Int16SizePtr, Int64SizePtr), + // Cannot simplify addrspacecast, ptrtoint + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::AddrSpaceCast, + CastInst::PtrToInt, + Int64PtrTyAS1, Int64PtrTyAS2, Int16Ty, + Int64SizePtr, Int16SizePtr, 0), 0U); // Pass since the bitcast address spaces are the same @@ -413,28 +410,6 @@ TEST(InstructionsTest, isEliminableCastPair) { 0, 0, 0), CastInst::IntToPtr); - - // Fail without known pointer sizes and different address spaces - EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::BitCast, - CastInst::PtrToInt, - Int64PtrTyAS1, Int64PtrTyAS2, Int16Ty, - 0, 0, 0), - 0U); - - // Pass since the address spaces are the same, even though the pointer sizes - // are unknown - EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::BitCast, - CastInst::PtrToInt, - Int64PtrTyAS1, Int64PtrTyAS1, Int32Ty, - 0, 0, 0), - Instruction::PtrToInt); - - // Fail since the bitcast is the wrong size - EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::BitCast, - CastInst::PtrToInt, - Int64PtrTyAS1, Int64PtrTyAS2, Int64Ty, - Int16SizePtr, Int64SizePtr, 0), - 0U); } } // end anonymous namespace diff --git a/unittests/IR/LegacyPassManagerTest.cpp b/unittests/IR/LegacyPassManagerTest.cpp new file mode 100644 index 0000000..11841bd --- /dev/null +++ b/unittests/IR/LegacyPassManagerTest.cpp @@ -0,0 +1,559 @@ +//===- llvm/unittest/IR/LegacyPassManager.cpp - Legacy PassManager tests --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This unit test exercises the legacy pass manager infrastructure. We use the +// old names as well to ensure that the source-level compatibility wrapper +// works for out-of-tree code that expects to include llvm/PassManager.h and +// subclass the core pass classes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/PassManager.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace llvm { + void initializeModuleNDMPass(PassRegistry&); + void initializeFPassPass(PassRegistry&); + void initializeCGPassPass(PassRegistry&); + void initializeLPassPass(PassRegistry&); + void initializeBPassPass(PassRegistry&); + + namespace { + // ND = no deps + // NM = no modifications + struct ModuleNDNM: public ModulePass { + public: + static char run; + static char ID; + ModuleNDNM() : ModulePass(ID) { } + virtual bool runOnModule(Module &M) { + run++; + return false; + } + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + }; + char ModuleNDNM::ID=0; + char ModuleNDNM::run=0; + + struct ModuleNDM : public ModulePass { + public: + static char run; + static char ID; + ModuleNDM() : ModulePass(ID) {} + virtual bool runOnModule(Module &M) { + run++; + return true; + } + }; + char ModuleNDM::ID=0; + char ModuleNDM::run=0; + + struct ModuleNDM2 : public ModulePass { + public: + static char run; + static char ID; + ModuleNDM2() : ModulePass(ID) {} + virtual bool runOnModule(Module &M) { + run++; + return true; + } + }; + char ModuleNDM2::ID=0; + char ModuleNDM2::run=0; + + struct ModuleDNM : public ModulePass { + public: + static char run; + static char ID; + ModuleDNM() : ModulePass(ID) { + initializeModuleNDMPass(*PassRegistry::getPassRegistry()); + } + virtual bool runOnModule(Module &M) { + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run++; + return false; + } + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<ModuleNDM>(); + AU.setPreservesAll(); + } + }; + char ModuleDNM::ID=0; + char ModuleDNM::run=0; + + template<typename P> + struct PassTestBase : public P { + protected: + static int runc; + static bool initialized; + static bool finalized; + int allocated; + void run() { + EXPECT_TRUE(initialized); + EXPECT_FALSE(finalized); + EXPECT_EQ(0, allocated); + allocated++; + runc++; + } + public: + static char ID; + static void finishedOK(int run) { + EXPECT_GT(runc, 0); + EXPECT_TRUE(initialized); + EXPECT_TRUE(finalized); + EXPECT_EQ(run, runc); + } + PassTestBase() : P(ID), allocated(0) { + initialized = false; + finalized = false; + runc = 0; + } + + virtual void releaseMemory() { + EXPECT_GT(runc, 0); + EXPECT_GT(allocated, 0); + allocated--; + } + }; + template<typename P> char PassTestBase<P>::ID; + template<typename P> int PassTestBase<P>::runc; + template<typename P> bool PassTestBase<P>::initialized; + template<typename P> bool PassTestBase<P>::finalized; + + template<typename T, typename P> + struct PassTest : public PassTestBase<P> { + public: +#ifndef _MSC_VER // MSVC complains that Pass is not base class. + using llvm::Pass::doInitialization; + using llvm::Pass::doFinalization; +#endif + virtual bool doInitialization(T &t) { + EXPECT_FALSE(PassTestBase<P>::initialized); + PassTestBase<P>::initialized = true; + return false; + } + virtual bool doFinalization(T &t) { + EXPECT_FALSE(PassTestBase<P>::finalized); + PassTestBase<P>::finalized = true; + EXPECT_EQ(0, PassTestBase<P>::allocated); + return false; + } + }; + + struct CGPass : public PassTest<CallGraph, CallGraphSCCPass> { + public: + CGPass() { + initializeCGPassPass(*PassRegistry::getPassRegistry()); + } + virtual bool runOnSCC(CallGraphSCC &SCMM) { + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run(); + return false; + } + }; + + struct FPass : public PassTest<Module, FunctionPass> { + public: + virtual bool runOnFunction(Function &F) { + // FIXME: PR4112 + // EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run(); + return false; + } + }; + + struct LPass : public PassTestBase<LoopPass> { + private: + static int initcount; + static int fincount; + public: + LPass() { + initializeLPassPass(*PassRegistry::getPassRegistry()); + initcount = 0; fincount=0; + EXPECT_FALSE(initialized); + } + static void finishedOK(int run, int finalized) { + PassTestBase<LoopPass>::finishedOK(run); + EXPECT_EQ(run, initcount); + EXPECT_EQ(finalized, fincount); + } + using llvm::Pass::doInitialization; + using llvm::Pass::doFinalization; + virtual bool doInitialization(Loop* L, LPPassManager &LPM) { + initialized = true; + initcount++; + return false; + } + virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run(); + return false; + } + virtual bool doFinalization() { + fincount++; + finalized = true; + return false; + } + }; + int LPass::initcount=0; + int LPass::fincount=0; + + struct BPass : public PassTestBase<BasicBlockPass> { + private: + static int inited; + static int fin; + public: + static void finishedOK(int run, int N) { + PassTestBase<BasicBlockPass>::finishedOK(run); + EXPECT_EQ(inited, N); + EXPECT_EQ(fin, N); + } + BPass() { + inited = 0; + fin = 0; + } + virtual bool doInitialization(Module &M) { + EXPECT_FALSE(initialized); + initialized = true; + return false; + } + virtual bool doInitialization(Function &F) { + inited++; + return false; + } + virtual bool runOnBasicBlock(BasicBlock &BB) { + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run(); + return false; + } + virtual bool doFinalization(Function &F) { + fin++; + return false; + } + virtual bool doFinalization(Module &M) { + EXPECT_FALSE(finalized); + finalized = true; + EXPECT_EQ(0, allocated); + return false; + } + }; + int BPass::inited=0; + int BPass::fin=0; + + struct OnTheFlyTest: public ModulePass { + public: + static char ID; + OnTheFlyTest() : ModulePass(ID) { + initializeFPassPass(*PassRegistry::getPassRegistry()); + } + virtual bool runOnModule(Module &M) { + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) { + Function &F = *I; + { + SCOPED_TRACE("Running on the fly function pass"); + getAnalysis<FPass>(F); + } + } + return false; + } + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired<FPass>(); + } + }; + char OnTheFlyTest::ID=0; + + TEST(PassManager, RunOnce) { + Module M("test-once", getGlobalContext()); + struct ModuleNDNM *mNDNM = new ModuleNDNM(); + struct ModuleDNM *mDNM = new ModuleDNM(); + struct ModuleNDM *mNDM = new ModuleNDM(); + struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); + + mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; + + PassManager Passes; + Passes.add(new DataLayout(&M)); + Passes.add(mNDM2); + Passes.add(mNDM); + Passes.add(mNDNM); + Passes.add(mDNM); + + Passes.run(M); + // each pass must be run exactly once, since nothing invalidates them + EXPECT_EQ(1, mNDM->run); + EXPECT_EQ(1, mNDNM->run); + EXPECT_EQ(1, mDNM->run); + EXPECT_EQ(1, mNDM2->run); + } + + TEST(PassManager, ReRun) { + Module M("test-rerun", getGlobalContext()); + struct ModuleNDNM *mNDNM = new ModuleNDNM(); + struct ModuleDNM *mDNM = new ModuleDNM(); + struct ModuleNDM *mNDM = new ModuleNDM(); + struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); + + mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; + + PassManager Passes; + Passes.add(new DataLayout(&M)); + Passes.add(mNDM); + Passes.add(mNDNM); + Passes.add(mNDM2);// invalidates mNDM needed by mDNM + Passes.add(mDNM); + + Passes.run(M); + // Some passes must be rerun because a pass that modified the + // module/function was run in between + EXPECT_EQ(2, mNDM->run); + EXPECT_EQ(1, mNDNM->run); + EXPECT_EQ(1, mNDM2->run); + EXPECT_EQ(1, mDNM->run); + } + + Module* makeLLVMModule(); + + template<typename T> + void MemoryTestHelper(int run) { + OwningPtr<Module> M(makeLLVMModule()); + T *P = new T(); + PassManager Passes; + Passes.add(new DataLayout(M.get())); + Passes.add(P); + Passes.run(*M); + T::finishedOK(run); + } + + template<typename T> + void MemoryTestHelper(int run, int N) { + Module *M = makeLLVMModule(); + T *P = new T(); + PassManager Passes; + Passes.add(new DataLayout(M)); + Passes.add(P); + Passes.run(*M); + T::finishedOK(run, N); + delete M; + } + + TEST(PassManager, Memory) { + // SCC#1: test1->test2->test3->test1 + // SCC#2: test4 + // SCC#3: indirect call node + { + SCOPED_TRACE("Callgraph pass"); + MemoryTestHelper<CGPass>(3); + } + + { + SCOPED_TRACE("Function pass"); + MemoryTestHelper<FPass>(4);// 4 functions + } + + { + SCOPED_TRACE("Loop pass"); + MemoryTestHelper<LPass>(2, 1); //2 loops, 1 function + } + { + SCOPED_TRACE("Basic block pass"); + MemoryTestHelper<BPass>(7, 4); //9 basic blocks + } + + } + + TEST(PassManager, MemoryOnTheFly) { + Module *M = makeLLVMModule(); + { + SCOPED_TRACE("Running OnTheFlyTest"); + struct OnTheFlyTest *O = new OnTheFlyTest(); + PassManager Passes; + Passes.add(new DataLayout(M)); + Passes.add(O); + Passes.run(*M); + + FPass::finishedOK(4); + } + delete M; + } + + Module* makeLLVMModule() { + // Module Construction + Module* mod = new Module("test-mem", getGlobalContext()); + mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a0:0:64-s0:64:64-f80:128:128"); + mod->setTargetTriple("x86_64-unknown-linux-gnu"); + + // Type Definitions + std::vector<Type*>FuncTy_0_args; + FunctionType* FuncTy_0 = FunctionType::get( + /*Result=*/IntegerType::get(getGlobalContext(), 32), + /*Params=*/FuncTy_0_args, + /*isVarArg=*/false); + + std::vector<Type*>FuncTy_2_args; + FuncTy_2_args.push_back(IntegerType::get(getGlobalContext(), 1)); + FunctionType* FuncTy_2 = FunctionType::get( + /*Result=*/Type::getVoidTy(getGlobalContext()), + /*Params=*/FuncTy_2_args, + /*isVarArg=*/false); + + + // Function Declarations + + Function* func_test1 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test1", mod); + func_test1->setCallingConv(CallingConv::C); + AttributeSet func_test1_PAL; + func_test1->setAttributes(func_test1_PAL); + + Function* func_test2 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test2", mod); + func_test2->setCallingConv(CallingConv::C); + AttributeSet func_test2_PAL; + func_test2->setAttributes(func_test2_PAL); + + Function* func_test3 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test3", mod); + func_test3->setCallingConv(CallingConv::C); + AttributeSet func_test3_PAL; + func_test3->setAttributes(func_test3_PAL); + + Function* func_test4 = Function::Create( + /*Type=*/FuncTy_2, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test4", mod); + func_test4->setCallingConv(CallingConv::C); + AttributeSet func_test4_PAL; + func_test4->setAttributes(func_test4_PAL); + + // Global Variable Declarations + + + // Constant Definitions + + // Global Variable Definitions + + // Function Definitions + + // Function: test1 (func_test1) + { + + BasicBlock* label_entry = BasicBlock::Create(getGlobalContext(), "entry",func_test1,0); + + // Block entry (label_entry) + CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry); + int32_3->setCallingConv(CallingConv::C); + int32_3->setTailCall(false);AttributeSet int32_3_PAL; + int32_3->setAttributes(int32_3_PAL); + + ReturnInst::Create(getGlobalContext(), int32_3, label_entry); + + } + + // Function: test2 (func_test2) + { + + BasicBlock* label_entry_5 = BasicBlock::Create(getGlobalContext(), "entry",func_test2,0); + + // Block entry (label_entry_5) + CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5); + int32_6->setCallingConv(CallingConv::C); + int32_6->setTailCall(false);AttributeSet int32_6_PAL; + int32_6->setAttributes(int32_6_PAL); + + ReturnInst::Create(getGlobalContext(), int32_6, label_entry_5); + + } + + // Function: test3 (func_test3) + { + + BasicBlock* label_entry_8 = BasicBlock::Create(getGlobalContext(), "entry",func_test3,0); + + // Block entry (label_entry_8) + CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8); + int32_9->setCallingConv(CallingConv::C); + int32_9->setTailCall(false);AttributeSet int32_9_PAL; + int32_9->setAttributes(int32_9_PAL); + + ReturnInst::Create(getGlobalContext(), int32_9, label_entry_8); + + } + + // Function: test4 (func_test4) + { + Function::arg_iterator args = func_test4->arg_begin(); + Value* int1_f = args++; + int1_f->setName("f"); + + BasicBlock* label_entry_11 = BasicBlock::Create(getGlobalContext(), "entry",func_test4,0); + BasicBlock* label_bb = BasicBlock::Create(getGlobalContext(), "bb",func_test4,0); + BasicBlock* label_bb1 = BasicBlock::Create(getGlobalContext(), "bb1",func_test4,0); + BasicBlock* label_return = BasicBlock::Create(getGlobalContext(), "return",func_test4,0); + + // Block entry (label_entry_11) + BranchInst::Create(label_bb, label_entry_11); + + // Block bb (label_bb) + BranchInst::Create(label_bb, label_bb1, int1_f, label_bb); + + // Block bb1 (label_bb1) + BranchInst::Create(label_bb1, label_return, int1_f, label_bb1); + + // Block return (label_return) + ReturnInst::Create(getGlobalContext(), label_return); + + } + return mod; + } + + } +} + +INITIALIZE_PASS(ModuleNDM, "mndm", "mndm", false, false) +INITIALIZE_PASS_BEGIN(CGPass, "cgp","cgp", false, false) +INITIALIZE_PASS_DEPENDENCY(CallGraph) +INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false) +INITIALIZE_PASS(FPass, "fp","fp", false, false) +INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false) +INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_END(LPass, "lp","lp", false, false) +INITIALIZE_PASS(BPass, "bp","bp", false, false) diff --git a/unittests/IR/PassManagerTest.cpp b/unittests/IR/PassManagerTest.cpp index 1097da6..7b60e38 100644 --- a/unittests/IR/PassManagerTest.cpp +++ b/unittests/IR/PassManagerTest.cpp @@ -1,4 +1,4 @@ -//===- llvm/unittest/IR/PassManager.cpp - PassManager unit tests ----------===// +//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===// // // The LLVM Compiler Infrastructure // @@ -7,546 +7,125 @@ // //===----------------------------------------------------------------------===// -#include "llvm/PassManager.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Analysis/CallGraphSCCPass.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/CallingConv.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" +#include "llvm/Assembly/Parser.h" #include "llvm/IR/Function.h" -#include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" using namespace llvm; -namespace llvm { - void initializeModuleNDMPass(PassRegistry&); - void initializeFPassPass(PassRegistry&); - void initializeCGPassPass(PassRegistry&); - void initializeLPassPass(PassRegistry&); - void initializeBPassPass(PassRegistry&); - - namespace { - // ND = no deps - // NM = no modifications - struct ModuleNDNM: public ModulePass { - public: - static char run; - static char ID; - ModuleNDNM() : ModulePass(ID) { } - virtual bool runOnModule(Module &M) { - run++; - return false; - } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - } - }; - char ModuleNDNM::ID=0; - char ModuleNDNM::run=0; - - struct ModuleNDM : public ModulePass { - public: - static char run; - static char ID; - ModuleNDM() : ModulePass(ID) {} - virtual bool runOnModule(Module &M) { - run++; - return true; - } - }; - char ModuleNDM::ID=0; - char ModuleNDM::run=0; - - struct ModuleNDM2 : public ModulePass { - public: - static char run; - static char ID; - ModuleNDM2() : ModulePass(ID) {} - virtual bool runOnModule(Module &M) { - run++; - return true; - } - }; - char ModuleNDM2::ID=0; - char ModuleNDM2::run=0; - - struct ModuleDNM : public ModulePass { - public: - static char run; - static char ID; - ModuleDNM() : ModulePass(ID) { - initializeModuleNDMPass(*PassRegistry::getPassRegistry()); - } - virtual bool runOnModule(Module &M) { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - run++; - return false; - } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<ModuleNDM>(); - AU.setPreservesAll(); - } - }; - char ModuleDNM::ID=0; - char ModuleDNM::run=0; - - template<typename P> - struct PassTestBase : public P { - protected: - static int runc; - static bool initialized; - static bool finalized; - int allocated; - void run() { - EXPECT_TRUE(initialized); - EXPECT_FALSE(finalized); - EXPECT_EQ(0, allocated); - allocated++; - runc++; - } - public: - static char ID; - static void finishedOK(int run) { - EXPECT_GT(runc, 0); - EXPECT_TRUE(initialized); - EXPECT_TRUE(finalized); - EXPECT_EQ(run, runc); - } - PassTestBase() : P(ID), allocated(0) { - initialized = false; - finalized = false; - runc = 0; - } - - virtual void releaseMemory() { - EXPECT_GT(runc, 0); - EXPECT_GT(allocated, 0); - allocated--; - } - }; - template<typename P> char PassTestBase<P>::ID; - template<typename P> int PassTestBase<P>::runc; - template<typename P> bool PassTestBase<P>::initialized; - template<typename P> bool PassTestBase<P>::finalized; - - template<typename T, typename P> - struct PassTest : public PassTestBase<P> { - public: -#ifndef _MSC_VER // MSVC complains that Pass is not base class. - using llvm::Pass::doInitialization; - using llvm::Pass::doFinalization; -#endif - virtual bool doInitialization(T &t) { - EXPECT_FALSE(PassTestBase<P>::initialized); - PassTestBase<P>::initialized = true; - return false; - } - virtual bool doFinalization(T &t) { - EXPECT_FALSE(PassTestBase<P>::finalized); - PassTestBase<P>::finalized = true; - EXPECT_EQ(0, PassTestBase<P>::allocated); - return false; - } - }; - - struct CGPass : public PassTest<CallGraph, CallGraphSCCPass> { - public: - CGPass() { - initializeCGPassPass(*PassRegistry::getPassRegistry()); - } - virtual bool runOnSCC(CallGraphSCC &SCMM) { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - run(); - return false; - } - }; - - struct FPass : public PassTest<Module, FunctionPass> { - public: - virtual bool runOnFunction(Function &F) { - // FIXME: PR4112 - // EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - run(); - return false; - } - }; - - struct LPass : public PassTestBase<LoopPass> { - private: - static int initcount; - static int fincount; - public: - LPass() { - initializeLPassPass(*PassRegistry::getPassRegistry()); - initcount = 0; fincount=0; - EXPECT_FALSE(initialized); - } - static void finishedOK(int run, int finalized) { - PassTestBase<LoopPass>::finishedOK(run); - EXPECT_EQ(run, initcount); - EXPECT_EQ(finalized, fincount); - } - using llvm::Pass::doInitialization; - using llvm::Pass::doFinalization; - virtual bool doInitialization(Loop* L, LPPassManager &LPM) { - initialized = true; - initcount++; - return false; - } - virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - run(); - return false; - } - virtual bool doFinalization() { - fincount++; - finalized = true; - return false; - } - }; - int LPass::initcount=0; - int LPass::fincount=0; - - struct BPass : public PassTestBase<BasicBlockPass> { - private: - static int inited; - static int fin; - public: - static void finishedOK(int run, int N) { - PassTestBase<BasicBlockPass>::finishedOK(run); - EXPECT_EQ(inited, N); - EXPECT_EQ(fin, N); - } - BPass() { - inited = 0; - fin = 0; - } - virtual bool doInitialization(Module &M) { - EXPECT_FALSE(initialized); - initialized = true; - return false; - } - virtual bool doInitialization(Function &F) { - inited++; - return false; - } - virtual bool runOnBasicBlock(BasicBlock &BB) { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - run(); - return false; - } - virtual bool doFinalization(Function &F) { - fin++; - return false; - } - virtual bool doFinalization(Module &M) { - EXPECT_FALSE(finalized); - finalized = true; - EXPECT_EQ(0, allocated); - return false; - } - }; - int BPass::inited=0; - int BPass::fin=0; - - struct OnTheFlyTest: public ModulePass { - public: - static char ID; - OnTheFlyTest() : ModulePass(ID) { - initializeFPassPass(*PassRegistry::getPassRegistry()); - } - virtual bool runOnModule(Module &M) { - EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); - for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) { - Function &F = *I; - { - SCOPED_TRACE("Running on the fly function pass"); - getAnalysis<FPass>(F); - } - } - return false; - } - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<FPass>(); - } - }; - char OnTheFlyTest::ID=0; - - TEST(PassManager, RunOnce) { - Module M("test-once", getGlobalContext()); - struct ModuleNDNM *mNDNM = new ModuleNDNM(); - struct ModuleDNM *mDNM = new ModuleDNM(); - struct ModuleNDM *mNDM = new ModuleNDM(); - struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); - - mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; - - PassManager Passes; - Passes.add(new DataLayout(&M)); - Passes.add(mNDM2); - Passes.add(mNDM); - Passes.add(mNDNM); - Passes.add(mDNM); - - Passes.run(M); - // each pass must be run exactly once, since nothing invalidates them - EXPECT_EQ(1, mNDM->run); - EXPECT_EQ(1, mNDNM->run); - EXPECT_EQ(1, mDNM->run); - EXPECT_EQ(1, mNDM2->run); - } - - TEST(PassManager, ReRun) { - Module M("test-rerun", getGlobalContext()); - struct ModuleNDNM *mNDNM = new ModuleNDNM(); - struct ModuleDNM *mDNM = new ModuleDNM(); - struct ModuleNDM *mNDM = new ModuleNDM(); - struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); - - mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; - - PassManager Passes; - Passes.add(new DataLayout(&M)); - Passes.add(mNDM); - Passes.add(mNDNM); - Passes.add(mNDM2);// invalidates mNDM needed by mDNM - Passes.add(mDNM); - - Passes.run(M); - // Some passes must be rerun because a pass that modified the - // module/function was run in between - EXPECT_EQ(2, mNDM->run); - EXPECT_EQ(1, mNDNM->run); - EXPECT_EQ(1, mNDM2->run); - EXPECT_EQ(1, mDNM->run); - } - - Module* makeLLVMModule(); - - template<typename T> - void MemoryTestHelper(int run) { - OwningPtr<Module> M(makeLLVMModule()); - T *P = new T(); - PassManager Passes; - Passes.add(new DataLayout(M.get())); - Passes.add(P); - Passes.run(*M); - T::finishedOK(run); - } - - template<typename T> - void MemoryTestHelper(int run, int N) { - Module *M = makeLLVMModule(); - T *P = new T(); - PassManager Passes; - Passes.add(new DataLayout(M)); - Passes.add(P); - Passes.run(*M); - T::finishedOK(run, N); - delete M; - } - - TEST(PassManager, Memory) { - // SCC#1: test1->test2->test3->test1 - // SCC#2: test4 - // SCC#3: indirect call node - { - SCOPED_TRACE("Callgraph pass"); - MemoryTestHelper<CGPass>(3); - } - - { - SCOPED_TRACE("Function pass"); - MemoryTestHelper<FPass>(4);// 4 functions - } - - { - SCOPED_TRACE("Loop pass"); - MemoryTestHelper<LPass>(2, 1); //2 loops, 1 function - } - { - SCOPED_TRACE("Basic block pass"); - MemoryTestHelper<BPass>(7, 4); //9 basic blocks - } - - } - - TEST(PassManager, MemoryOnTheFly) { - Module *M = makeLLVMModule(); - { - SCOPED_TRACE("Running OnTheFlyTest"); - struct OnTheFlyTest *O = new OnTheFlyTest(); - PassManager Passes; - Passes.add(new DataLayout(M)); - Passes.add(O); - Passes.run(*M); - - FPass::finishedOK(4); - } - delete M; - } - - Module* makeLLVMModule() { - // Module Construction - Module* mod = new Module("test-mem", getGlobalContext()); - mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" - "a0:0:64-s0:64:64-f80:128:128"); - mod->setTargetTriple("x86_64-unknown-linux-gnu"); - - // Type Definitions - std::vector<Type*>FuncTy_0_args; - FunctionType* FuncTy_0 = FunctionType::get( - /*Result=*/IntegerType::get(getGlobalContext(), 32), - /*Params=*/FuncTy_0_args, - /*isVarArg=*/false); - - std::vector<Type*>FuncTy_2_args; - FuncTy_2_args.push_back(IntegerType::get(getGlobalContext(), 1)); - FunctionType* FuncTy_2 = FunctionType::get( - /*Result=*/Type::getVoidTy(getGlobalContext()), - /*Params=*/FuncTy_2_args, - /*isVarArg=*/false); - - - // Function Declarations - - Function* func_test1 = Function::Create( - /*Type=*/FuncTy_0, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"test1", mod); - func_test1->setCallingConv(CallingConv::C); - AttributeSet func_test1_PAL; - func_test1->setAttributes(func_test1_PAL); - - Function* func_test2 = Function::Create( - /*Type=*/FuncTy_0, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"test2", mod); - func_test2->setCallingConv(CallingConv::C); - AttributeSet func_test2_PAL; - func_test2->setAttributes(func_test2_PAL); - - Function* func_test3 = Function::Create( - /*Type=*/FuncTy_0, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"test3", mod); - func_test3->setCallingConv(CallingConv::C); - AttributeSet func_test3_PAL; - func_test3->setAttributes(func_test3_PAL); - - Function* func_test4 = Function::Create( - /*Type=*/FuncTy_2, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"test4", mod); - func_test4->setCallingConv(CallingConv::C); - AttributeSet func_test4_PAL; - func_test4->setAttributes(func_test4_PAL); - - // Global Variable Declarations - - - // Constant Definitions - - // Global Variable Definitions - - // Function Definitions - - // Function: test1 (func_test1) - { - - BasicBlock* label_entry = BasicBlock::Create(getGlobalContext(), "entry",func_test1,0); - - // Block entry (label_entry) - CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry); - int32_3->setCallingConv(CallingConv::C); - int32_3->setTailCall(false);AttributeSet int32_3_PAL; - int32_3->setAttributes(int32_3_PAL); - - ReturnInst::Create(getGlobalContext(), int32_3, label_entry); - - } - - // Function: test2 (func_test2) - { - - BasicBlock* label_entry_5 = BasicBlock::Create(getGlobalContext(), "entry",func_test2,0); - - // Block entry (label_entry_5) - CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5); - int32_6->setCallingConv(CallingConv::C); - int32_6->setTailCall(false);AttributeSet int32_6_PAL; - int32_6->setAttributes(int32_6_PAL); - - ReturnInst::Create(getGlobalContext(), int32_6, label_entry_5); - - } - - // Function: test3 (func_test3) - { +namespace { + +class TestAnalysisPass { +public: + typedef Function IRUnitT; + + struct Result { + Result(int Count) : InstructionCount(Count) {} + bool invalidate(Function *) { return true; } + int InstructionCount; + }; + + /// \brief Returns an opaque, unique ID for this pass type. + static void *ID() { return (void *)&PassID; } + + /// \brief Run the analysis pass over the function and return a result. + Result run(Function *F) { + int Count = 0; + for (Function::iterator BBI = F->begin(), BBE = F->end(); BBI != BBE; ++BBI) + for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; + ++II) + ++Count; + return Result(Count); + } - BasicBlock* label_entry_8 = BasicBlock::Create(getGlobalContext(), "entry",func_test3,0); +private: + /// \brief Private static data to provide unique ID. + static char PassID; +}; - // Block entry (label_entry_8) - CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8); - int32_9->setCallingConv(CallingConv::C); - int32_9->setTailCall(false);AttributeSet int32_9_PAL; - int32_9->setAttributes(int32_9_PAL); +char TestAnalysisPass::PassID; - ReturnInst::Create(getGlobalContext(), int32_9, label_entry_8); +struct TestModulePass { + TestModulePass(int &RunCount) : RunCount(RunCount) {} - } + bool run(Module *M) { + ++RunCount; + return true; + } - // Function: test4 (func_test4) - { - Function::arg_iterator args = func_test4->arg_begin(); - Value* int1_f = args++; - int1_f->setName("f"); + int &RunCount; +}; - BasicBlock* label_entry_11 = BasicBlock::Create(getGlobalContext(), "entry",func_test4,0); - BasicBlock* label_bb = BasicBlock::Create(getGlobalContext(), "bb",func_test4,0); - BasicBlock* label_bb1 = BasicBlock::Create(getGlobalContext(), "bb1",func_test4,0); - BasicBlock* label_return = BasicBlock::Create(getGlobalContext(), "return",func_test4,0); +struct TestFunctionPass { + TestFunctionPass(AnalysisManager &AM, int &RunCount, int &AnalyzedInstrCount) + : AM(AM), RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount) { + } - // Block entry (label_entry_11) - BranchInst::Create(label_bb, label_entry_11); + bool run(Function *F) { + ++RunCount; - // Block bb (label_bb) - BranchInst::Create(label_bb, label_bb1, int1_f, label_bb); + const TestAnalysisPass::Result &AR = AM.getResult<TestAnalysisPass>(F); + AnalyzedInstrCount += AR.InstructionCount; - // Block bb1 (label_bb1) - BranchInst::Create(label_bb1, label_return, int1_f, label_bb1); + return true; + } - // Block return (label_return) - ReturnInst::Create(getGlobalContext(), label_return); + AnalysisManager &AM; + int &RunCount; + int &AnalyzedInstrCount; +}; - } - return mod; - } +Module *parseIR(const char *IR) { + LLVMContext &C = getGlobalContext(); + SMDiagnostic Err; + return ParseAssemblyString(IR, 0, Err, C); +} - } +class PassManagerTest : public ::testing::Test { +protected: + OwningPtr<Module> M; + +public: + PassManagerTest() + : M(parseIR("define void @f() {\n" + "entry:\n" + " call void @g()\n" + " call void @h()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + " ret void\n" + "}\n" + "define void @h() {\n" + " ret void\n" + "}\n")) {} +}; + +TEST_F(PassManagerTest, Basic) { + AnalysisManager AM(M.get()); + AM.registerAnalysisPass(TestAnalysisPass()); + + ModulePassManager MPM(M.get(), &AM); + FunctionPassManager FPM(&AM); + + // Count the runs over a module. + int ModulePassRunCount = 0; + MPM.addPass(TestModulePass(ModulePassRunCount)); + + // Count the runs over a Function. + int FunctionPassRunCount = 0; + int AnalyzedInstrCount = 0; + FPM.addPass(TestFunctionPass(AM, FunctionPassRunCount, AnalyzedInstrCount)); + MPM.addPass(FPM); + + MPM.run(); + EXPECT_EQ(1, ModulePassRunCount); + EXPECT_EQ(3, FunctionPassRunCount); + EXPECT_EQ(5, AnalyzedInstrCount); } -INITIALIZE_PASS(ModuleNDM, "mndm", "mndm", false, false) -INITIALIZE_PASS_BEGIN(CGPass, "cgp","cgp", false, false) -INITIALIZE_AG_DEPENDENCY(CallGraph) -INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false) -INITIALIZE_PASS(FPass, "fp","fp", false, false) -INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false) -INITIALIZE_PASS_DEPENDENCY(LoopInfo) -INITIALIZE_PASS_END(LPass, "lp","lp", false, false) -INITIALIZE_PASS(BPass, "bp","bp", false, false) +} diff --git a/unittests/IR/ValueTest.cpp b/unittests/IR/ValueTest.cpp index 52efb1a..ebe23e8 100644 --- a/unittests/IR/ValueTest.cpp +++ b/unittests/IR/ValueTest.cpp @@ -43,4 +43,44 @@ TEST(ValueTest, UsedInBasicBlock) { EXPECT_TRUE(F->arg_begin()->isUsedInBasicBlock(F->begin())); } +TEST(GlobalTest, CreateAddressSpace) { + LLVMContext &Ctx = getGlobalContext(); + OwningPtr<Module> M(new Module("TestModule", Ctx)); + Type *Int8Ty = Type::getInt8Ty(Ctx); + Type *Int32Ty = Type::getInt32Ty(Ctx); + + GlobalVariable *Dummy0 + = new GlobalVariable(*M, + Int32Ty, + true, + GlobalValue::ExternalLinkage, + Constant::getAllOnesValue(Int32Ty), + "dummy", + 0, + GlobalVariable::NotThreadLocal, + 1); + + // Make sure the address space isn't dropped when returning this. + Constant *Dummy1 = M->getOrInsertGlobal("dummy", Int32Ty); + EXPECT_EQ(Dummy0, Dummy1); + EXPECT_EQ(1u, Dummy1->getType()->getPointerAddressSpace()); + + + // This one requires a bitcast, but the address space must also stay the same. + GlobalVariable *DummyCast0 + = new GlobalVariable(*M, + Int32Ty, + true, + GlobalValue::ExternalLinkage, + Constant::getAllOnesValue(Int32Ty), + "dummy_cast", + 0, + GlobalVariable::NotThreadLocal, + 1); + + // Make sure the address space isn't dropped when returning this. + Constant *DummyCast1 = M->getOrInsertGlobal("dummy_cast", Int8Ty); + EXPECT_EQ(1u, DummyCast1->getType()->getPointerAddressSpace()); + EXPECT_NE(DummyCast0, DummyCast1) << *DummyCast1; +} } // end anonymous namespace diff --git a/unittests/IR/VerifierTest.cpp b/unittests/IR/VerifierTest.cpp index 2848cb8..31936c3 100644 --- a/unittests/IR/VerifierTest.cpp +++ b/unittests/IR/VerifierTest.cpp @@ -24,10 +24,11 @@ namespace { TEST(VerifierTest, Branch_i1) { LLVMContext &C = getGlobalContext(); + Module M("M", C); FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); - OwningPtr<Function> F(Function::Create(FTy, GlobalValue::ExternalLinkage)); - BasicBlock *Entry = BasicBlock::Create(C, "entry", F.get()); - BasicBlock *Exit = BasicBlock::Create(C, "exit", F.get()); + Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy)); + BasicBlock *Entry = BasicBlock::Create(C, "entry", F); + BasicBlock *Exit = BasicBlock::Create(C, "exit", F); ReturnInst::Create(C, Exit); // To avoid triggering an assertion in BranchInst::Create, we first create diff --git a/unittests/IR/WaymarkTest.cpp b/unittests/IR/WaymarkTest.cpp index cf7d76d..9a9b4a2 100644 --- a/unittests/IR/WaymarkTest.cpp +++ b/unittests/IR/WaymarkTest.cpp @@ -9,6 +9,7 @@ // we perform white-box tests // +#include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" diff --git a/unittests/MC/CMakeLists.txt b/unittests/MC/CMakeLists.txt new file mode 100644 index 0000000..0e4782c --- /dev/null +++ b/unittests/MC/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_LINK_COMPONENTS + MC + ) + +set(MCSources + MCAtomTest.cpp + ) + +add_llvm_unittest(MCTests + ${MCSources} + ) diff --git a/unittests/MC/MCAtomTest.cpp b/unittests/MC/MCAtomTest.cpp new file mode 100644 index 0000000..17b056c --- /dev/null +++ b/unittests/MC/MCAtomTest.cpp @@ -0,0 +1,31 @@ +//===- llvm/unittest/MC/MCAtomTest.cpp - Instructions unit tests ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCModule.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +TEST(MCAtomTest, MCDataSize) { + MCModule M; + MCDataAtom *Atom = M.createDataAtom(0, 0); + EXPECT_EQ(uint64_t(0), Atom->getEndAddr()); + Atom->addData(0); + EXPECT_EQ(uint64_t(0), Atom->getEndAddr()); + Atom->addData(1); + EXPECT_EQ(uint64_t(1), Atom->getEndAddr()); + Atom->addData(2); + EXPECT_EQ(uint64_t(2), Atom->getEndAddr()); + EXPECT_EQ(size_t(3), Atom->getData().size()); +} + +} // end anonymous namespace +} // end namespace llvm diff --git a/unittests/MC/Makefile b/unittests/MC/Makefile new file mode 100644 index 0000000..4c25697 --- /dev/null +++ b/unittests/MC/Makefile @@ -0,0 +1,15 @@ +##===- unittests/IR/Makefile -------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = MC +LINK_COMPONENTS := MC + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Makefile b/unittests/Makefile index 36b82da..06ba932 100644 --- a/unittests/Makefile +++ b/unittests/Makefile @@ -9,8 +9,8 @@ LEVEL = .. -PARALLEL_DIRS = ADT Analysis Bitcode DebugInfo ExecutionEngine IR Object \ - Option Support Transforms +PARALLEL_DIRS = ADT Analysis Bitcode CodeGen DebugInfo ExecutionEngine IR \ + MC Object Option Support Transforms include $(LEVEL)/Makefile.common diff --git a/unittests/Option/OptionParsingTest.cpp b/unittests/Option/OptionParsingTest.cpp index 5a76d65..11d6d1e 100644 --- a/unittests/Option/OptionParsingTest.cpp +++ b/unittests/Option/OptionParsingTest.cpp @@ -20,7 +20,7 @@ using namespace llvm::opt; enum ID { OPT_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) OPT_##ID, + HELPTEXT, METAVAR) OPT_##ID, #include "Opts.inc" LastOption #undef OPTION @@ -48,8 +48,8 @@ static const OptTable::Info InfoTable[] = { namespace { class TestOptTable : public OptTable { public: - TestOptTable() - : OptTable(InfoTable, array_lengthof(InfoTable)) {} + TestOptTable(bool IgnoreCase = false) + : OptTable(InfoTable, array_lengthof(InfoTable), IgnoreCase) {} }; } @@ -157,15 +157,49 @@ TEST(Option, AliasArgs) { EXPECT_EQ(AL->getAllArgValues(OPT_B)[1], "bar"); } -TEST(Option, DashDash) { +TEST(Option, IgnoreCase) { + TestOptTable T(true); + unsigned MAI, MAC; + + const char *MyArgs[] = { "-a", "-joo" }; + OwningPtr<InputArgList> AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC)); + EXPECT_TRUE(AL->hasArg(OPT_A)); + EXPECT_TRUE(AL->hasArg(OPT_B)); +} + +TEST(Option, DoNotIgnoreCase) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-a", "-joo" }; + OwningPtr<InputArgList> AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC)); + EXPECT_FALSE(AL->hasArg(OPT_A)); + EXPECT_FALSE(AL->hasArg(OPT_B)); +} + +TEST(Option, SlurpEmpty) { + TestOptTable T; + unsigned MAI, MAC; + + const char *MyArgs[] = { "-A", "-slurp" }; + OwningPtr<InputArgList> AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC)); + EXPECT_TRUE(AL->hasArg(OPT_A)); + EXPECT_TRUE(AL->hasArg(OPT_Slurp)); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp).size(), 0U); +} + +TEST(Option, Slurp) { TestOptTable T; unsigned MAI, MAC; - const char *MyArgs[] = { "-A", "--", "-B", "--" }; + const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" }; OwningPtr<InputArgList> AL(T.ParseArgs(MyArgs, array_endof(MyArgs), MAI, MAC)); + EXPECT_EQ(AL->size(), 2U); EXPECT_TRUE(AL->hasArg(OPT_A)); EXPECT_FALSE(AL->hasArg(OPT_B)); - EXPECT_EQ(AL->getAllArgValues(OPT_INPUT).size(), 2U); - EXPECT_EQ(AL->getAllArgValues(OPT_INPUT)[0], "-B"); - EXPECT_EQ(AL->getAllArgValues(OPT_INPUT)[1], "--"); + EXPECT_TRUE(AL->hasArg(OPT_Slurp)); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp).size(), 3U); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[0], "-B"); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[1], "--"); + EXPECT_EQ(AL->getAllArgValues(OPT_Slurp)[2], "foo"); } diff --git a/unittests/Option/Opts.td b/unittests/Option/Opts.td index 986b312..aaed6b2 100644 --- a/unittests/Option/Opts.td +++ b/unittests/Option/Opts.td @@ -22,3 +22,5 @@ def I : Flag<["-"], "I">, Alias<H>, Group<my_group>; def J : Flag<["-"], "J">, Alias<B>, AliasArgs<["foo"]>; def Joo : Flag<["-"], "Joo">, Alias<B>, AliasArgs<["bar"]>; + +def Slurp : Option<["-"], "slurp", KIND_REMAINING_ARGS>; diff --git a/unittests/Support/BlockFrequencyTest.cpp b/unittests/Support/BlockFrequencyTest.cpp index ca420fc..ffdea2c 100644 --- a/unittests/Support/BlockFrequencyTest.cpp +++ b/unittests/Support/BlockFrequencyTest.cpp @@ -13,6 +13,11 @@ TEST(BlockFrequencyTest, OneToZero) { BranchProbability Prob(UINT32_MAX - 1, UINT32_MAX); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), 0u); + + Freq = BlockFrequency(1); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), 0u); + EXPECT_EQ(Remainder, UINT32_MAX - 1); } TEST(BlockFrequencyTest, OneToOne) { @@ -20,6 +25,11 @@ TEST(BlockFrequencyTest, OneToOne) { BranchProbability Prob(UINT32_MAX, UINT32_MAX); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), 1u); + + Freq = BlockFrequency(1); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), 1u); + EXPECT_EQ(Remainder, 0u); } TEST(BlockFrequencyTest, ThreeToOne) { @@ -27,6 +37,11 @@ TEST(BlockFrequencyTest, ThreeToOne) { BranchProbability Prob(3000000, 9000000); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), 1u); + + Freq = BlockFrequency(3); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), 1u); + EXPECT_EQ(Remainder, 0u); } TEST(BlockFrequencyTest, MaxToHalfMax) { @@ -34,6 +49,11 @@ TEST(BlockFrequencyTest, MaxToHalfMax) { BranchProbability Prob(UINT32_MAX / 2, UINT32_MAX); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), 9223372034707292159ULL); + + Freq = BlockFrequency(UINT64_MAX); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), 9223372034707292159ULL); + EXPECT_EQ(Remainder, 0u); } TEST(BlockFrequencyTest, BigToBig) { @@ -43,6 +63,11 @@ TEST(BlockFrequencyTest, BigToBig) { BranchProbability Prob(P, P); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), Big); + + Freq = BlockFrequency(Big); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), Big); + EXPECT_EQ(Remainder, 0u); } TEST(BlockFrequencyTest, MaxToMax) { @@ -50,6 +75,114 @@ TEST(BlockFrequencyTest, MaxToMax) { BranchProbability Prob(UINT32_MAX, UINT32_MAX); Freq *= Prob; EXPECT_EQ(Freq.getFrequency(), UINT64_MAX); + + // This additionally makes sure if we have a value equal to our saturating + // value, we do not signal saturation if the result equals said value, but + // saturating does not occur. + Freq = BlockFrequency(UINT64_MAX); + uint32_t Remainder = Freq.scale(Prob); + EXPECT_EQ(Freq.getFrequency(), UINT64_MAX); + EXPECT_EQ(Remainder, 0u); +} + +TEST(BlockFrequencyTest, ScaleResultRemainderTest) { + struct { + uint64_t Freq; + uint32_t Prob[2]; + uint64_t ExpectedFreq; + uint32_t ExpectedRemainder; + } Tests[80] = { + // Data for scaling that results in <= 64 bit division. + { 0x1423e2a50ULL, { 0x64819521, 0x7765dd13 }, 0x10f418889ULL, 0x92b9d25 }, + { 0x35ef14ceULL, { 0x28ade3c7, 0x304532ae }, 0x2d73c33aULL, 0x2c0fd0b6 }, + { 0xd03dbfbe24ULL, { 0x790079, 0xe419f3 }, 0x6e776fc1fdULL, 0x4a06dd }, + { 0x21d67410bULL, { 0x302a9dc2, 0x3ddb4442 }, 0x1a5948fd6ULL, 0x265d1c2a }, + { 0x8664aeadULL, { 0x3d523513, 0x403523b1 }, 0x805a04cfULL, 0x324c27b8 }, + { 0x201db0cf4ULL, { 0x35112a7b, 0x79fc0c74 }, 0xdf8b07f6ULL, 0x490c1dc4 }, + { 0x13f1e4430aULL, { 0x21c92bf, 0x21e63aae }, 0x13e0cba15ULL, 0x1df47c30 }, + { 0x16c83229ULL, { 0x3793f66f, 0x53180dea }, 0xf3ce7b6ULL, 0x1d0c1b6b }, + { 0xc62415be8ULL, { 0x9cc4a63, 0x4327ae9b }, 0x1ce8b71caULL, 0x3f2c696a }, + { 0x6fac5e434ULL, { 0xe5f9170, 0x1115e10b }, 0x5df23dd4cULL, 0x4dafc7c }, + { 0x1929375f2ULL, { 0x3a851375, 0x76c08456 }, 0xc662b082ULL, 0x343589ee }, + { 0x243c89db6ULL, { 0x354ebfc0, 0x450ef197 }, 0x1bf8c1661ULL, 0x4948e49 }, + { 0x310e9b31aULL, { 0x1b1b8acf, 0x2d3629f0 }, 0x1d69c93f9ULL, 0x73e3b96 }, + { 0xa1fae921dULL, { 0xa7a098c, 0x10469f44 }, 0x684413d6cULL, 0x86a882c }, + { 0xc1582d957ULL, { 0x498e061, 0x59856bc }, 0x9edc5f4e7ULL, 0x29b0653 }, + { 0x57cfee75ULL, { 0x1d061dc3, 0x7c8bfc17 }, 0x1476a220ULL, 0x2383d33f }, + { 0x139220080ULL, { 0x294a6c71, 0x2a2b07c9 }, 0x1329e1c76ULL, 0x7aa5da }, + { 0x1665d353cULL, { 0x7080db5, 0xde0d75c }, 0xb590d9fbULL, 0x7ba8c38 }, + { 0xe8f14541ULL, { 0x5188e8b2, 0x736527ef }, 0xa4971be5ULL, 0x6b612167 }, + { 0x2f4775f29ULL, { 0x254ef0fe, 0x435fcf50 }, 0x1a2e449c1ULL, 0x28bbf5e }, + { 0x27b85d8d7ULL, { 0x304c8220, 0x5de678f2 }, 0x146e3bef9ULL, 0x4b27097e }, + { 0x1d362e36bULL, { 0x36c85b12, 0x37a66f55 }, 0x1cc19b8e6ULL, 0x688e828 }, + { 0x155fd48c7ULL, { 0xf5894d, 0x1256108 }, 0x11e383602ULL, 0x111f0cb }, + { 0xb5db2d15ULL, { 0x39bb26c5, 0x5bdcda3e }, 0x72499259ULL, 0x59c4939b }, + { 0x153990298ULL, { 0x48921c09, 0x706eb817 }, 0xdb3268e8ULL, 0x66bb8a80 }, + { 0x28a7c3ed7ULL, { 0x1f776fd7, 0x349f7a70 }, 0x184f73ae1ULL, 0x28910321 }, + { 0x724dbeabULL, { 0x1bd149f5, 0x253a085e }, 0x5569c0b3ULL, 0xff8e2ed }, + { 0xd8f0c513ULL, { 0x18c8cc4c, 0x1b72bad0 }, 0xc3e30643ULL, 0xd85e134 }, + { 0x17ce3dcbULL, { 0x1e4c6260, 0x233b359e }, 0x1478f4afULL, 0x49ea31e }, + { 0x1ce036ce0ULL, { 0x29e3c8af, 0x5318dd4a }, 0xe8e76196ULL, 0x11d5b9c4 }, + { 0x1473ae2aULL, { 0x29b897ba, 0x2be29378 }, 0x13718185ULL, 0x6f93b2c }, + { 0x1dd41aa68ULL, { 0x3d0a4441, 0x5a0e8f12 }, 0x1437b6bbfULL, 0x54b09ffa }, + { 0x1b49e4a53ULL, { 0x3430c1fe, 0x5a204aed }, 0xfcd6852fULL, 0x15ad6ed7 }, + { 0x217941b19ULL, { 0x12ced2bd, 0x21b68310 }, 0x12aca65b1ULL, 0x1b2a9565 }, + { 0xac6a4dc8ULL, { 0x3ed68da8, 0x6fdca34c }, 0x60da926dULL, 0x22ff53e4 }, + { 0x1c503a4e7ULL, { 0xfcbbd32, 0x11e48d17 }, 0x18fec7d38ULL, 0xa8aa816 }, + { 0x1c885855ULL, { 0x213e919d, 0x25941897 }, 0x193de743ULL, 0x4ea09c }, + { 0x29b9c168eULL, { 0x2b644aea, 0x45725ee7 }, 0x1a122e5d5ULL, 0xbee1099 }, + { 0x806a33f2ULL, { 0x30a80a23, 0x5063733a }, 0x4db9a264ULL, 0x1eaed76e }, + { 0x282afc96bULL, { 0x143ae554, 0x1a9863ff }, 0x1e8de5204ULL, 0x158d9020 }, + // Data for scaling that results in > 64 bit division. + { 0x23ca5f2f672ca41cULL, { 0xecbc641, 0x111373f7 }, 0x1f0301e5e8295ab5ULL, 0xf627f79 }, + { 0x5e4f2468142265e3ULL, { 0x1ddf5837, 0x32189233 }, 0x383ca7ba9fdd2c8cULL, 0x1c8f33e1 }, + { 0x277a1a6f6b266bf6ULL, { 0x415d81a8, 0x61eb5e1e }, 0x1a5a3e1d41b30c0fULL, 0x29cde3ae }, + { 0x1bdbb49a237035cbULL, { 0xea5bf17, 0x1d25ffb3 }, 0xdffc51c53d44b93ULL, 0x5170574 }, + { 0x2bce6d29b64fb8ULL, { 0x3bfd5631, 0x7525c9bb }, 0x166ebedda7ac57ULL, 0x3026dfab }, + { 0x3a02116103df5013ULL, { 0x2ee18a83, 0x3299aea8 }, 0x35be8922ab1e2a84ULL, 0x298d9919 }, + { 0x7b5762390799b18cULL, { 0x12f8e5b9, 0x2563bcd4 }, 0x3e960077aca01209ULL, 0x93afeb8 }, + { 0x69cfd72537021579ULL, { 0x4c35f468, 0x6a40feee }, 0x4be4cb3848be98a3ULL, 0x4ff96b9e }, + { 0x49dfdf835120f1c1ULL, { 0x8cb3759, 0x559eb891 }, 0x79663f7120edadeULL, 0x51b1fb5b }, + { 0x74b5be5c27676381ULL, { 0x47e4c5e0, 0x7c7b19ff }, 0x4367d2dff36a1028ULL, 0x7a7b5608 }, + { 0x4f50f97075e7f431ULL, { 0x9a50a17, 0x11cd1185 }, 0x2af952b34c032df4ULL, 0xfddc6a3 }, + { 0x2f8b0d712e393be4ULL, { 0x1487e386, 0x15aa356e }, 0x2d0df36478a776aaULL, 0x14e2564c }, + { 0x224c1c75999d3deULL, { 0x3b2df0ea, 0x4523b100 }, 0x1d5b481d145f08aULL, 0x15145eec }, + { 0x2bcbcea22a399a76ULL, { 0x28b58212, 0x48dd013e }, 0x187814d084c47cabULL, 0x3a38ebe2 }, + { 0x1dbfca91257cb2d1ULL, { 0x1a8c04d9, 0x5e92502c }, 0x859cf7d00f77545ULL, 0x7431f4d }, + { 0x7f20039b57cda935ULL, { 0xeccf651, 0x323f476e }, 0x25720cd976461a77ULL, 0x202817a3 }, + { 0x40512c6a586aa087ULL, { 0x113b0423, 0x398c9eab }, 0x1341c03de8696a7eULL, 0x1e27284b }, + { 0x63d802693f050a11ULL, { 0xf50cdd6, 0xfce2a44 }, 0x60c0177bb5e46846ULL, 0xf7ad89e }, + { 0x2d956b422838de77ULL, { 0xb2d345b, 0x1321e557 }, 0x1aa0ed16b6aa5319ULL, 0xfe1a5ce }, + { 0x5a1cdf0c1657bc91ULL, { 0x1d77bb0c, 0x1f991ff1 }, 0x54097ee94ff87560ULL, 0x11c4a26c }, + { 0x3801b26d7e00176bULL, { 0xeed25da, 0x1a819d8b }, 0x1f89e96a3a639526ULL, 0xcd51e7c }, + { 0x37655e74338e1e45ULL, { 0x300e170a, 0x5a1595fe }, 0x1d8cfb55fddc0441ULL, 0x3df05434 }, + { 0x7b38703f2a84e6ULL, { 0x66d9053, 0xc79b6b9 }, 0x3f7d4c91774094ULL, 0x26d939e }, + { 0x2245063c0acb3215ULL, { 0x30ce2f5b, 0x610e7271 }, 0x113b916468389235ULL, 0x1b588512 }, + { 0x6bc195877b7b8a7eULL, { 0x392004aa, 0x4a24e60c }, 0x530594fb17db6ba5ULL, 0x35c0a5f0 }, + { 0x40a3fde23c7b43dbULL, { 0x4e712195, 0x6553e56e }, 0x320a799bc76a466aULL, 0x5e23a5eb }, + { 0x1d3dfc2866fbccbaULL, { 0x5075b517, 0x5fc42245 }, 0x18917f0061595bc3ULL, 0x3fcf4527 }, + { 0x19aeb14045a61121ULL, { 0x1bf6edec, 0x707e2f4b }, 0x6626672a070bcc7ULL, 0x3607801f }, + { 0x44ff90486c531e9fULL, { 0x66598a, 0x8a90dc }, 0x32f6f2b0525199b0ULL, 0x5ab576 }, + { 0x3f3e7121092c5bcbULL, { 0x1c754df7, 0x5951a1b9 }, 0x14267f50b7ef375dULL, 0x221220a8 }, + { 0x60e2dafb7e50a67eULL, { 0x4d96c66e, 0x65bd878d }, 0x49e31715ac393f8bULL, 0x4e97b195 }, + { 0x656286667e0e6e29ULL, { 0x9d971a2, 0xacda23b }, 0x5c6ee315ead6cb4fULL, 0x516f5bd }, + { 0x1114e0974255d507ULL, { 0x1c693, 0x2d6ff }, 0xaae42e4b35f6e60ULL, 0x8b65 }, + { 0x508c8baf3a70ff5aULL, { 0x3b26b779, 0x6ad78745 }, 0x2c98387636c4b365ULL, 0x11dc6a51 }, + { 0x5b47bc666bf1f9cfULL, { 0x10a87ed6, 0x187d358a }, 0x3e1767155848368bULL, 0xfb871c }, + { 0x50954e3744460395ULL, { 0x7a42263, 0xcdaa048 }, 0x2fe739f0aee1fee1ULL, 0xb8add57 }, + { 0x20020b406550dd8fULL, { 0x3318539, 0x42eead0 }, 0x186f326325fa346bULL, 0x10d3ae7 }, + { 0x5bcb0b872439ffd5ULL, { 0x6f61fb2, 0x9af7344 }, 0x41fa1e3bec3c1b30ULL, 0x4fee45a }, + { 0x7a670f365db87a53ULL, { 0x417e102, 0x3bb54c67 }, 0x8642a558304fd9eULL, 0x3b65f514 }, + { 0x1ef0db1e7bab1cd0ULL, { 0x2b60cf38, 0x4188f78f }, 0x147ae0d6226b2ee6ULL, 0x336b6106 } + }; + + for (unsigned i = 0; i < 80; i++) { + BlockFrequency Freq(Tests[i].Freq); + uint32_t Remainder = Freq.scale(BranchProbability(Tests[i].Prob[0], + Tests[i].Prob[1])); + EXPECT_EQ(Tests[i].ExpectedFreq, Freq.getFrequency()); + EXPECT_EQ(Tests[i].ExpectedRemainder, Remainder); + } } TEST(BlockFrequency, Divide) { diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index 197561e..0abc2ff 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -17,9 +17,7 @@ add_llvm_unittest(SupportTests EndianTest.cpp ErrorOrTest.cpp FileOutputBufferTest.cpp - IntegersSubsetTest.cpp LeakDetectorTest.cpp - LocaleTest.cpp LockFileManagerTest.cpp ManagedStatic.cpp MathExtrasTest.cpp @@ -30,8 +28,11 @@ add_llvm_unittest(SupportTests ProcessTest.cpp ProgramTest.cpp RegexTest.cpp + SourceMgrTest.cpp SwapByteOrderTest.cpp + ThreadLocalTest.cpp TimeValueTest.cpp + UnicodeTest.cpp ValueHandleTest.cpp YAMLIOTest.cpp YAMLParserTest.cpp diff --git a/unittests/Support/CompressionTest.cpp b/unittests/Support/CompressionTest.cpp index c8e2cd9..c0a9ada 100644 --- a/unittests/Support/CompressionTest.cpp +++ b/unittests/Support/CompressionTest.cpp @@ -63,6 +63,12 @@ TEST(CompressionTest, Zlib) { TestZlibCompression(BinaryDataStr, zlib::DefaultCompression); } +TEST(CompressionTest, ZlibCRC32) { + EXPECT_EQ( + 0x414FA339U, + zlib::crc32(StringRef("The quick brown fox jumps over the lazy dog"))); +} + #endif } diff --git a/unittests/Support/ConstantRangeTest.cpp b/unittests/Support/ConstantRangeTest.cpp index 4d6bbf6..3e0a085 100644 --- a/unittests/Support/ConstantRangeTest.cpp +++ b/unittests/Support/ConstantRangeTest.cpp @@ -216,6 +216,9 @@ TEST_F(ConstantRangeTest, SExt) { EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, 140)).signExtend(16), ConstantRange(APInt(16, -128), APInt(16, 128))); + + EXPECT_EQ(ConstantRange(APInt(16, 0x0200), APInt(16, 0x8000)).signExtend(19), + ConstantRange(APInt(19, 0x0200), APInt(19, 0x8000))); } TEST_F(ConstantRangeTest, IntersectWith) { diff --git a/unittests/Support/ErrorOrTest.cpp b/unittests/Support/ErrorOrTest.cpp index 4853426..feb6a08 100644 --- a/unittests/Support/ErrorOrTest.cpp +++ b/unittests/Support/ErrorOrTest.cpp @@ -45,9 +45,6 @@ TEST(ErrorOr, Types) { *a = 42; EXPECT_EQ(42, x); - EXPECT_FALSE(ErrorOr<void>(errc::broken_pipe)); - EXPECT_TRUE(ErrorOr<void>(errc::success)); - #if LLVM_HAS_CXX11_STDLIB // Move only types. EXPECT_EQ(3, **t3()); @@ -67,38 +64,3 @@ TEST(ErrorOr, Covariant) { #endif } } // end anon namespace - -struct InvalidArgError { - InvalidArgError() {} - InvalidArgError(std::string S) : ArgName(S) {} - std::string ArgName; -}; - -namespace llvm { -template<> -struct ErrorOrUserDataTraits<InvalidArgError> : true_type { - static error_code error() { - return make_error_code(errc::invalid_argument); - } -}; -} // end namespace llvm - -ErrorOr<int> t4() { - return InvalidArgError("adena"); -} - -ErrorOr<void> t5() { - return InvalidArgError("pie"); -} - -namespace { -TEST(ErrorOr, UserErrorData) { - ErrorOr<int> a = t4(); - EXPECT_EQ(errc::invalid_argument, a); - EXPECT_EQ("adena", t4().getError<InvalidArgError>().ArgName); - - ErrorOr<void> b = t5(); - EXPECT_EQ(errc::invalid_argument, b); - EXPECT_EQ("pie", b.getError<InvalidArgError>().ArgName); -} -} // end anon namespace diff --git a/unittests/Support/IntegersSubsetTest.cpp b/unittests/Support/IntegersSubsetTest.cpp deleted file mode 100644 index f4298bf..0000000 --- a/unittests/Support/IntegersSubsetTest.cpp +++ /dev/null @@ -1,326 +0,0 @@ -//===- llvm/unittest/Support/IntegersSubsetTest.cpp - IntegersSubset tests ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/IntegersSubset.h" -#include "llvm/ADT/APInt.h" -#include "llvm/Support/IntegersSubsetMapping.h" -#include "gtest/gtest.h" -#include <vector> - -using namespace llvm; - -namespace { - - class Int : public APInt { - public: - Int() {} - Int(uint64_t V) : APInt(64, V) {} - Int(const APInt& Src) : APInt(Src) {} - bool operator < (const APInt& RHS) const { return ult(RHS); } - bool operator > (const APInt& RHS) const { return ugt(RHS); } - bool operator <= (const APInt& RHS) const { return ule(RHS); } - bool operator >= (const APInt& RHS) const { return uge(RHS); } - }; - - typedef IntRange<Int> Range; - typedef IntegersSubsetGeneric<Int> Subset; - typedef IntegersSubsetMapping<unsigned,Subset,Int> Mapping; - - TEST(IntegersSubsetTest, GeneralTest) { - - // Test construction. - - std::vector<Range> Ranges; - Ranges.reserve(3); - - // Initialize Subset as union of three pairs: - // { {0, 8}, {10, 18}, {20, 28} } - for (unsigned i = 0; i < 3; ++i) - Ranges.push_back(Range(Int(i*10), Int(i*10 + 8))); - - Subset TheSubset(Ranges); - - for (unsigned i = 0; i < 3; ++i) { - EXPECT_EQ(TheSubset.getItem(i).getLow(), Int(i*10)); - EXPECT_EQ(TheSubset.getItem(i).getHigh(), Int(i*10 + 8)); - } - - EXPECT_EQ(TheSubset.getNumItems(), 3ULL); - - // Test belonging to range. - - EXPECT_TRUE(TheSubset.isSatisfies(Int(5))); - EXPECT_FALSE(TheSubset.isSatisfies(Int(9))); - - // Test when subset contains the only item. - - Ranges.clear(); - Ranges.push_back(Range(Int(10), Int(10))); - - Subset TheSingleNumber(Ranges); - - EXPECT_TRUE(TheSingleNumber.isSingleNumber()); - - Ranges.push_back(Range(Int(12), Int(15))); - - Subset NotASingleNumber(Ranges); - - EXPECT_FALSE(NotASingleNumber.isSingleNumber()); - - // Test when subset contains items that are not a ranges but - // the single numbers. - - Ranges.clear(); - Ranges.push_back(Range(Int(10), Int(10))); - Ranges.push_back(Range(Int(15), Int(19))); - - Subset WithSingleNumberItems(Ranges); - - EXPECT_TRUE(WithSingleNumberItems.isSingleNumber(0)); - EXPECT_FALSE(WithSingleNumberItems.isSingleNumber(1)); - - // Test size of subset. Note subset itself may be not optimized (improper), - // so it may contain duplicates, and the size of subset { {0, 9} {5, 9} } - // will 15 instead of 10. - - Ranges.clear(); - Ranges.push_back(Range(Int(0), Int(9))); - Ranges.push_back(Range(Int(5), Int(9))); - - Subset NotOptimizedSubset(Ranges); - - EXPECT_EQ(NotOptimizedSubset.getSize(), 15ULL); - - // Test access to a single value. - // getSingleValue(idx) method represents subset as flat numbers collection, - // so subset { {0, 3}, {8, 10} } will represented as array - // { 0, 1, 2, 3, 8, 9, 10 }. - - Ranges.clear(); - Ranges.push_back(Range(Int(0), Int(3))); - Ranges.push_back(Range(Int(8), Int(10))); - - Subset OneMoreSubset(Ranges); - - EXPECT_EQ(OneMoreSubset.getSingleValue(5), Int(9)); - } - - TEST(IntegersSubsetTest, MappingTest) { - - Mapping::Cases TheCases; - - unsigned Successors[3] = {0, 1, 2}; - - // Test construction. - - Mapping TheMapping; - for (unsigned i = 0; i < 3; ++i) - TheMapping.add(Int(10*i), Int(10*i + 9), Successors + i); - TheMapping.add(Int(111), Int(222), Successors); - TheMapping.removeItem(--TheMapping.end()); - - TheMapping.getCases(TheCases); - - EXPECT_EQ(TheCases.size(), 3ULL); - - for (unsigned i = 0; i < 3; ++i) { - Mapping::Cases::iterator CaseIt = TheCases.begin(); - std::advance(CaseIt, i); - EXPECT_EQ(CaseIt->first, Successors + i); - EXPECT_EQ(CaseIt->second.getNumItems(), 1ULL); - EXPECT_EQ(CaseIt->second.getItem(0), Range(Int(10*i), Int(10*i + 9))); - } - - // Test verification. - - Mapping ImproperMapping; - ImproperMapping.add(Int(10), Int(11), Successors + 0); - ImproperMapping.add(Int(11), Int(12), Successors + 1); - - Mapping::RangeIterator ErrItem; - EXPECT_FALSE(ImproperMapping.verify(ErrItem)); - EXPECT_EQ(ErrItem, --ImproperMapping.end()); - - Mapping ProperMapping; - ProperMapping.add(Int(10), Int(11), Successors + 0); - ProperMapping.add(Int(12), Int(13), Successors + 1); - - EXPECT_TRUE(ProperMapping.verify(ErrItem)); - - // Test optimization. - - Mapping ToBeOptimized; - - for (unsigned i = 0; i < 3; ++i) { - ToBeOptimized.add(Int(i * 10), Int(i * 10 + 1), Successors + i); - ToBeOptimized.add(Int(i * 10 + 2), Int(i * 10 + 9), Successors + i); - } - - ToBeOptimized.optimize(); - - TheCases.clear(); - ToBeOptimized.getCases(TheCases); - - EXPECT_EQ(TheCases.size(), 3ULL); - - for (unsigned i = 0; i < 3; ++i) { - Mapping::Cases::iterator CaseIt = TheCases.begin(); - std::advance(CaseIt, i); - EXPECT_EQ(CaseIt->first, Successors + i); - EXPECT_EQ(CaseIt->second.getNumItems(), 1ULL); - EXPECT_EQ(CaseIt->second.getItem(0), Range(Int(i * 10), Int(i * 10 + 9))); - } - } - - typedef unsigned unsigned_pair[2]; - typedef unsigned_pair unsigned_ranges[]; - - void TestDiff( - const unsigned_ranges LHS, - unsigned LSize, - const unsigned_ranges RHS, - unsigned RSize, - const unsigned_ranges ExcludeRes, - unsigned ExcludeResSize, - const unsigned_ranges IntersectRes, - unsigned IntersectResSize - ) { - - Mapping::RangesCollection Ranges; - - Mapping LHSMapping; - for (unsigned i = 0; i < LSize; ++i) - Ranges.push_back(Range(Int(LHS[i][0]), Int(LHS[i][1]))); - LHSMapping.add(Ranges); - - Ranges.clear(); - - Mapping RHSMapping; - for (unsigned i = 0; i < RSize; ++i) - Ranges.push_back(Range(Int(RHS[i][0]), Int(RHS[i][1]))); - RHSMapping.add(Ranges); - - Mapping LExclude, Intersection; - - LHSMapping.diff(&LExclude, &Intersection, 0, RHSMapping); - - if (ExcludeResSize) { - EXPECT_EQ(LExclude.size(), ExcludeResSize); - - unsigned i = 0; - for (Mapping::RangeIterator rei = LExclude.begin(), - e = LExclude.end(); rei != e; ++rei, ++i) - EXPECT_EQ(rei->first, Range(ExcludeRes[i][0], ExcludeRes[i][1])); - } else - EXPECT_TRUE(LExclude.empty()); - - if (IntersectResSize) { - EXPECT_EQ(Intersection.size(), IntersectResSize); - - unsigned i = 0; - for (Mapping::RangeIterator ii = Intersection.begin(), - e = Intersection.end(); ii != e; ++ii, ++i) - EXPECT_EQ(ii->first, Range(IntersectRes[i][0], IntersectRes[i][1])); - } else - EXPECT_TRUE(Intersection.empty()); - - LExclude.clear(); - Intersection.clear(); - RHSMapping.diff(0, &Intersection, &LExclude, LHSMapping); - - // Check LExclude again. - if (ExcludeResSize) { - EXPECT_EQ(LExclude.size(), ExcludeResSize); - - unsigned i = 0; - for (Mapping::RangeIterator rei = LExclude.begin(), - e = LExclude.end(); rei != e; ++rei, ++i) - EXPECT_EQ(rei->first, Range(ExcludeRes[i][0], ExcludeRes[i][1])); - } else - EXPECT_TRUE(LExclude.empty()); - } - - TEST(IntegersSubsetTest, DiffTest) { - - static const unsigned NOT_A_NUMBER = 0xffff; - - { - unsigned_ranges LHS = { { 0, 4 }, { 7, 10 }, { 13, 17 } }; - unsigned_ranges RHS = { { 3, 14 } }; - unsigned_ranges ExcludeRes = { { 0, 2 }, { 15, 17 } }; - unsigned_ranges IntersectRes = { { 3, 4 }, { 7, 10 }, { 13, 14 } }; - - TestDiff(LHS, 3, RHS, 1, ExcludeRes, 2, IntersectRes, 3); - } - - { - unsigned_ranges LHS = { { 0, 4 }, { 7, 10 }, { 13, 17 } }; - unsigned_ranges RHS = { { 0, 4 }, { 13, 17 } }; - unsigned_ranges ExcludeRes = { { 7, 10 } }; - unsigned_ranges IntersectRes = { { 0, 4 }, { 13, 17 } }; - - TestDiff(LHS, 3, RHS, 2, ExcludeRes, 1, IntersectRes, 2); - } - - { - unsigned_ranges LHS = { { 0, 17 } }; - unsigned_ranges RHS = { { 1, 5 }, { 10, 12 }, { 15, 16 } }; - unsigned_ranges ExcludeRes = - { { 0, 0 }, { 6, 9 }, { 13, 14 }, { 17, 17 } }; - unsigned_ranges IntersectRes = { { 1, 5 }, { 10, 12 }, { 15, 16 } }; - - TestDiff(LHS, 1, RHS, 3, ExcludeRes, 4, IntersectRes, 3); - } - - { - unsigned_ranges LHS = { { 2, 4 } }; - unsigned_ranges RHS = { { 0, 5 } }; - unsigned_ranges ExcludeRes = { {NOT_A_NUMBER, NOT_A_NUMBER} }; - unsigned_ranges IntersectRes = { { 2, 4 } }; - - TestDiff(LHS, 1, RHS, 1, ExcludeRes, 0, IntersectRes, 1); - } - - { - unsigned_ranges LHS = { { 2, 4 } }; - unsigned_ranges RHS = { { 7, 8 } }; - unsigned_ranges ExcludeRes = { { 2, 4 } }; - unsigned_ranges IntersectRes = { {NOT_A_NUMBER, NOT_A_NUMBER} }; - - TestDiff(LHS, 1, RHS, 1, ExcludeRes, 1, IntersectRes, 0); - } - - { - unsigned_ranges LHS = { { 3, 7 } }; - unsigned_ranges RHS = { { 1, 4 } }; - unsigned_ranges ExcludeRes = { { 5, 7 } }; - unsigned_ranges IntersectRes = { { 3, 4 } }; - - TestDiff(LHS, 1, RHS, 1, ExcludeRes, 1, IntersectRes, 1); - } - - { - unsigned_ranges LHS = { { 0, 7 } }; - unsigned_ranges RHS = { { 0, 5 }, { 6, 9 } }; - unsigned_ranges ExcludeRes = { {NOT_A_NUMBER, NOT_A_NUMBER} }; - unsigned_ranges IntersectRes = { { 0, 5 }, {6, 7} }; - - TestDiff(LHS, 1, RHS, 2, ExcludeRes, 0, IntersectRes, 2); - } - - { - unsigned_ranges LHS = { { 17, 17 } }; - unsigned_ranges RHS = { { 4, 4 } }; - unsigned_ranges ExcludeRes = { {17, 17} }; - unsigned_ranges IntersectRes = { { NOT_A_NUMBER, NOT_A_NUMBER } }; - - TestDiff(LHS, 1, RHS, 1, ExcludeRes, 1, IntersectRes, 0); - } - } -} diff --git a/unittests/Support/LocaleTest.cpp b/unittests/Support/LocaleTest.cpp deleted file mode 100644 index 3524b4b..0000000 --- a/unittests/Support/LocaleTest.cpp +++ /dev/null @@ -1,100 +0,0 @@ -//===- unittests/Support/LocaleTest.cpp - Locale.h tests ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Locale.h" -#include "gtest/gtest.h" - -namespace llvm { -namespace sys { -namespace locale { -namespace { - -// FIXME: WIN32 implementation is incorrect. We should consider using the one -// from LocaleGeneric.inc for WIN32. -#ifndef _WIN32 -TEST(Locale, columnWidth) { - // FIXME: This test fails with MacOSX implementation of columnWidth. -#ifndef __APPLE__ - EXPECT_EQ(0, columnWidth("")); - EXPECT_EQ(1, columnWidth(" ")); - EXPECT_EQ(1, columnWidth("a")); - EXPECT_EQ(1, columnWidth("~")); - - EXPECT_EQ(6, columnWidth("abcdef")); - - EXPECT_EQ(-1, columnWidth("\x01")); - EXPECT_EQ(-1, columnWidth("aaaaaaaaaa\x01")); - EXPECT_EQ(-1, columnWidth("\342\200\213")); // 200B ZERO WIDTH SPACE - - EXPECT_EQ(0, columnWidth("\314\200")); // 0300 COMBINING GRAVE ACCENT - EXPECT_EQ(1, columnWidth("\340\270\201")); // 0E01 THAI CHARACTER KO KAI - EXPECT_EQ(2, columnWidth("\344\270\200")); // CJK UNIFIED IDEOGRAPH-4E00 - - EXPECT_EQ(4, columnWidth("\344\270\200\344\270\200")); - EXPECT_EQ(3, columnWidth("q\344\270\200")); - EXPECT_EQ(3, columnWidth("\314\200\340\270\201\344\270\200")); - - // Invalid UTF-8 strings, columnWidth should error out. - EXPECT_EQ(-2, columnWidth("\344")); - EXPECT_EQ(-2, columnWidth("\344\270")); - EXPECT_EQ(-2, columnWidth("\344\270\033")); - EXPECT_EQ(-2, columnWidth("\344\270\300")); - EXPECT_EQ(-2, columnWidth("\377\366\355")); - - EXPECT_EQ(-2, columnWidth("qwer\344")); - EXPECT_EQ(-2, columnWidth("qwer\344\270")); - EXPECT_EQ(-2, columnWidth("qwer\344\270\033")); - EXPECT_EQ(-2, columnWidth("qwer\344\270\300")); - EXPECT_EQ(-2, columnWidth("qwer\377\366\355")); - - // UTF-8 sequences longer than 4 bytes correspond to unallocated Unicode - // characters. - EXPECT_EQ(-2, columnWidth("\370\200\200\200\200")); // U+200000 - EXPECT_EQ(-2, columnWidth("\374\200\200\200\200\200")); // U+4000000 -#endif // __APPLE__ -} - -TEST(Locale, isPrint) { - EXPECT_EQ(false, isPrint(0)); // <control-0000>-<control-001F> - EXPECT_EQ(false, isPrint(0x01)); - EXPECT_EQ(false, isPrint(0x1F)); - EXPECT_EQ(true, isPrint(' ')); - EXPECT_EQ(true, isPrint('A')); - EXPECT_EQ(true, isPrint('~')); - EXPECT_EQ(false, isPrint(0x7F)); // <control-007F>..<control-009F> - EXPECT_EQ(false, isPrint(0x90)); - EXPECT_EQ(false, isPrint(0x9F)); - - EXPECT_EQ(true, isPrint(0xAC)); - // FIXME: Figure out if we want to treat SOFT HYPHEN as printable character. -#ifndef __APPLE__ - EXPECT_EQ(false, isPrint(0xAD)); // SOFT HYPHEN -#endif // __APPLE__ - EXPECT_EQ(true, isPrint(0xAE)); - - // MacOS implementation doesn't think it's printable. -#ifndef __APPLE__ - EXPECT_EQ(true, isPrint(0x0377)); // GREEK SMALL LETTER PAMPHYLIAN DIGAMMA -#endif // __APPLE__ - EXPECT_EQ(false, isPrint(0x0378)); // <reserved-0378>..<reserved-0379> - - EXPECT_EQ(false, isPrint(0x0600)); // ARABIC NUMBER SIGN - - EXPECT_EQ(false, isPrint(0x1FFFF)); // <reserved-1F774>..<noncharacter-1FFFF> - EXPECT_EQ(true, isPrint(0x20000)); // CJK UNIFIED IDEOGRAPH-20000 - - EXPECT_EQ(false, isPrint(0x10FFFF)); // noncharacter -} - -#endif // _WIN32 - -} // namespace -} // namespace locale -} // namespace sys -} // namespace llvm diff --git a/unittests/Support/MemoryBufferTest.cpp b/unittests/Support/MemoryBufferTest.cpp index de1dbb7..2b8806c 100644 --- a/unittests/Support/MemoryBufferTest.cpp +++ b/unittests/Support/MemoryBufferTest.cpp @@ -65,6 +65,28 @@ TEST_F(MemoryBufferTest, get) { EXPECT_EQ("this is some data", data); } +TEST_F(MemoryBufferTest, NullTerminator4K) { + // Test that a file with size that is a multiple of the page size can be null + // terminated correctly by MemoryBuffer. + int TestFD; + SmallString<64> TestPath; + sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp", + TestFD, TestPath); + raw_fd_ostream OF(TestFD, true, /*unbuffered=*/true); + for (unsigned i = 0; i < 4096 / 16; ++i) { + OF << "0123456789abcdef"; + } + OF.close(); + + OwningPtr<MemoryBuffer> MB; + error_code EC = MemoryBuffer::getFile(TestPath.c_str(), MB); + ASSERT_FALSE(EC); + + const char *BufData = MB->getBufferStart(); + EXPECT_EQ('f', BufData[4095]); + EXPECT_EQ('\0', BufData[4096]); +} + TEST_F(MemoryBufferTest, copy) { // copy with no name OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data)); @@ -112,7 +134,7 @@ void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) { SmallString<64> TestPath; // Create a temporary file and write data into it. sys::fs::createTemporaryFile("prefix", "temp", TestFD, TestPath); - // OF is responsible for closing the file; If the file is not + // OF is responsible for closing the file; If the file is not // reopened, it will be unbuffered so that the results are // immediately visible through the fd. raw_fd_ostream OF(TestFD, true, !Reopen); @@ -128,7 +150,7 @@ void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) { OwningBuffer Buf; error_code EC = MemoryBuffer::getOpenFileSlice(TestFD, TestPath.c_str(), Buf, 40000, // Size - 8000 // Offset + 80000 // Offset ); EXPECT_FALSE(EC); diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 6f5992b..0316241 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -141,6 +141,75 @@ TEST(Support, Path) { } } +TEST(Support, RelativePathIterator) { + SmallString<64> Path(StringRef("c/d/e/foo.txt")); + typedef SmallVector<StringRef, 4> PathComponents; + PathComponents ExpectedPathComponents; + PathComponents ActualPathComponents; + + StringRef(Path).split(ExpectedPathComponents, "/"); + + for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; + ++I) { + ActualPathComponents.push_back(*I); + } + + ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); + + for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { + EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); + } +} + +TEST(Support, AbsolutePathIterator) { + SmallString<64> Path(StringRef("/c/d/e/foo.txt")); + typedef SmallVector<StringRef, 4> PathComponents; + PathComponents ExpectedPathComponents; + PathComponents ActualPathComponents; + + StringRef(Path).split(ExpectedPathComponents, "/"); + + // The root path will also be a component when iterating + ExpectedPathComponents[0] = "/"; + + for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; + ++I) { + ActualPathComponents.push_back(*I); + } + + ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); + + for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { + EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); + } +} + +#ifdef LLVM_ON_WIN32 +TEST(Support, AbsolutePathIteratorWin32) { + SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); + typedef SmallVector<StringRef, 4> PathComponents; + PathComponents ExpectedPathComponents; + PathComponents ActualPathComponents; + + StringRef(Path).split(ExpectedPathComponents, "\\"); + + // The root path (which comes after the drive name) will also be a component + // when iterating. + ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\"); + + for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; + ++I) { + ActualPathComponents.push_back(*I); + } + + ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); + + for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { + EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); + } +} +#endif // LLVM_ON_WIN32 + class FileSystemTest : public testing::Test { protected: /// Unique temporary directory in which all created filesystem entities must @@ -347,7 +416,25 @@ TEST_F(FileSystemTest, DirectoryIteration) { ASSERT_LT(z0, za1); } -const char elf[] = {0x7f, 'E', 'L', 'F', 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; +const char archive[] = "!<arch>\x0A"; +const char bitcode[] = "\xde\xc0\x17\x0b"; +const char coff_object[] = "\x00\x00......"; +const char coff_import_library[] = "\x00\x00\xff\xff...."; +const char elf_relocatable[] = { 0x7f, 'E', 'L', 'F', 1, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1 }; +const char macho_universal_binary[] = "\xca\xfe\xba\xbe...\0x00"; +const char macho_object[] = "\xfe\xed\xfa\xce..........\x00\x01"; +const char macho_executable[] = "\xfe\xed\xfa\xce..........\x00\x02"; +const char macho_fixed_virtual_memory_shared_lib[] = + "\xfe\xed\xfa\xce..........\x00\x03"; +const char macho_core[] = "\xfe\xed\xfa\xce..........\x00\x04"; +const char macho_preload_executable[] = "\xfe\xed\xfa\xce..........\x00\x05"; +const char macho_dynamically_linked_shared_lib[] = + "\xfe\xed\xfa\xce..........\x00\x06"; +const char macho_dynamic_linker[] = "\xfe\xed\xfa\xce..........\x00\x07"; +const char macho_bundle[] = "\xfe\xed\xfa\xce..........\x00\x08"; +const char macho_dsym_companion[] = "\xfe\xed\xfa\xce..........\x00\x0a"; +const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff"; TEST_F(FileSystemTest, Magic) { struct type { @@ -355,11 +442,27 @@ TEST_F(FileSystemTest, Magic) { const char *magic_str; size_t magic_str_len; fs::file_magic magic; - } types [] = { - {"magic.archive", "!<arch>\x0A", 8, fs::file_magic::archive}, - {"magic.elf", elf, sizeof(elf), - fs::file_magic::elf_relocatable} - }; + } types[] = { +#define DEFINE(magic) \ + { #magic, magic, sizeof(magic), fs::file_magic::magic } + DEFINE(archive), + DEFINE(bitcode), + DEFINE(coff_object), + DEFINE(coff_import_library), + DEFINE(elf_relocatable), + DEFINE(macho_universal_binary), + DEFINE(macho_object), + DEFINE(macho_executable), + DEFINE(macho_fixed_virtual_memory_shared_lib), + DEFINE(macho_core), + DEFINE(macho_preload_executable), + DEFINE(macho_dynamically_linked_shared_lib), + DEFINE(macho_dynamic_linker), + DEFINE(macho_bundle), + DEFINE(macho_dsym_companion), + DEFINE(windows_resource) +#undef DEFINE + }; // Create some files filled with magic. for (type *i = types, *e = types + (sizeof(types) / sizeof(type)); i != e; @@ -392,7 +495,7 @@ TEST_F(FileSystemTest, CarriageReturn) { } { OwningPtr<MemoryBuffer> Buf; - MemoryBuffer::getFile(FilePathname, Buf); + MemoryBuffer::getFile(FilePathname.c_str(), Buf); EXPECT_EQ(Buf->getBuffer(), "\r\n"); } @@ -403,7 +506,7 @@ TEST_F(FileSystemTest, CarriageReturn) { } { OwningPtr<MemoryBuffer> Buf; - MemoryBuffer::getFile(FilePathname, Buf); + MemoryBuffer::getFile(FilePathname.c_str(), Buf); EXPECT_EQ(Buf->getBuffer(), "\n"); } } @@ -431,7 +534,7 @@ TEST_F(FileSystemTest, FileMapping) { mfr.data()[Val.size()] = 0; // Unmap temp file } - + // Map it back in read-only fs::mapped_file_region mfr(Twine(TempPath), fs::mapped_file_region::readonly, @@ -439,10 +542,10 @@ TEST_F(FileSystemTest, FileMapping) { 0, EC); ASSERT_NO_ERROR(EC); - + // Verify content EXPECT_EQ(StringRef(mfr.const_data()), Val); - + // Unmap temp file #if LLVM_HAS_RVALUE_REFERENCES diff --git a/unittests/Support/ProcessTest.cpp b/unittests/Support/ProcessTest.cpp index eff9c71..27c2318 100644 --- a/unittests/Support/ProcessTest.cpp +++ b/unittests/Support/ProcessTest.cpp @@ -39,4 +39,32 @@ TEST(ProcessTest, SelfProcess) { EXPECT_GT(TimeValue::MaxTime, process::get_self()->get_wall_time()); } +#ifdef _MSC_VER +#define setenv(name, var, ignore) _putenv_s(name, var) +#endif + +#if HAVE_SETENV || _MSC_VER +TEST(ProcessTest, Basic) { + setenv("__LLVM_TEST_ENVIRON_VAR__", "abc", true); + Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__")); + EXPECT_TRUE(val.hasValue()); + EXPECT_STREQ("abc", val->c_str()); +} + +TEST(ProcessTest, None) { + Optional<std::string> val( + Process::GetEnv("__LLVM_TEST_ENVIRON_NO_SUCH_VAR__")); + EXPECT_FALSE(val.hasValue()); +} +#endif + +#ifdef LLVM_ON_WIN32 +TEST(ProcessTest, Wchar) { + SetEnvironmentVariableW(L"__LLVM_TEST_ENVIRON_VAR__", L"abcdefghijklmnopqrs"); + Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__")); + EXPECT_TRUE(val.hasValue()); + EXPECT_STREQ("abcdefghijklmnopqrs", val->c_str()); +} +#endif + } // end anonymous namespace diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 6852ca6..6eb990f 100644 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -21,6 +21,20 @@ extern char **environ; #endif +#if defined(LLVM_ON_UNIX) +#include <unistd.h> +void sleep_for(unsigned int seconds) { + sleep(seconds); +} +#elif defined(LLVM_ON_WIN32) +#include <windows.h> +void sleep_for(unsigned int seconds) { + Sleep(seconds * 1000); +} +#else +#error sleep_for is not implemented on your platform. +#endif + // From TestMain.cpp. extern const char *TestMainArgv0; @@ -60,7 +74,7 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); const char *argv[] = { my_exe.c_str(), - "--gtest_filter=ProgramTest.CreateProcessTrailingSlashChild", + "--gtest_filter=ProgramTest.CreateProcessTrailingSlash", "-program-test-string-arg1", "has\\\\ trailing\\", "-program-test-string-arg2", "has\\\\ trailing\\", 0 @@ -88,4 +102,93 @@ TEST(ProgramTest, CreateProcessTrailingSlash) { EXPECT_EQ(0, rc); } +TEST(ProgramTest, TestExecuteNoWait) { + using namespace llvm::sys; + + if (getenv("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT")) { + sleep_for(/*seconds*/ 1); + exit(0); + } + + std::string Executable = + sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); + const char *argv[] = { + Executable.c_str(), + "--gtest_filter=ProgramTest.TestExecuteNoWait", + 0 + }; + + // Add LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT to the environment of the child. + std::vector<const char *> envp; + CopyEnvironment(envp); + envp.push_back("LLVM_PROGRAM_TEST_EXECUTE_NO_WAIT=1"); + envp.push_back(0); + + std::string Error; + bool ExecutionFailed; + ProcessInfo PI1 = + ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &Error, &ExecutionFailed); + ASSERT_FALSE(ExecutionFailed) << Error; + ASSERT_NE(PI1.Pid, 0) << "Invalid process id"; + + unsigned LoopCount = 0; + + // Test that Wait() with WaitUntilTerminates=true works. In this case, + // LoopCount should only be incremented once. + while (true) { + ++LoopCount; + ProcessInfo WaitResult = Wait(PI1, 0, true, &Error); + ASSERT_TRUE(Error.empty()); + if (WaitResult.Pid == PI1.Pid) + break; + } + + EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1"; + + ProcessInfo PI2 = + ExecuteNoWait(Executable, argv, &envp[0], 0, 0, &Error, &ExecutionFailed); + ASSERT_FALSE(ExecutionFailed) << Error; + ASSERT_NE(PI2.Pid, 0) << "Invalid process id"; + + // Test that Wait() with SecondsToWait=0 performs a non-blocking wait. In this + // cse, LoopCount should be greater than 1 (more than one increment occurs). + while (true) { + ++LoopCount; + ProcessInfo WaitResult = Wait(PI2, 0, false, &Error); + ASSERT_TRUE(Error.empty()); + if (WaitResult.Pid == PI2.Pid) + break; + } + + ASSERT_GT(LoopCount, 1u) << "LoopCount should be >1"; +} + +TEST(ProgramTest, TestExecuteNegative) { + std::string Executable = "i_dont_exist"; + const char *argv[] = { Executable.c_str(), 0 }; + + { + std::string Error; + bool ExecutionFailed; + int RetCode = + ExecuteAndWait(Executable, argv, 0, 0, 0, 0, &Error, &ExecutionFailed); + ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or " + "positive value indicating the result code"; + ASSERT_TRUE(ExecutionFailed); + ASSERT_FALSE(Error.empty()); + } + + { + std::string Error; + bool ExecutionFailed; + ProcessInfo PI = + ExecuteNoWait(Executable, argv, 0, 0, 0, &Error, &ExecutionFailed); + ASSERT_EQ(PI.Pid, 0) + << "On error ExecuteNoWait should return an invalid ProcessInfo"; + ASSERT_TRUE(ExecutionFailed); + ASSERT_FALSE(Error.empty()); + } + +} + } // end anonymous namespace diff --git a/unittests/Support/RegexTest.cpp b/unittests/Support/RegexTest.cpp index 02869b3..7b977f7 100644 --- a/unittests/Support/RegexTest.cpp +++ b/unittests/Support/RegexTest.cpp @@ -127,4 +127,12 @@ TEST_F(RegexTest, IsLiteralERE) { EXPECT_FALSE(Regex::isLiteralERE("abc{1,2}")); } +TEST_F(RegexTest, IsValid) { + std::string Error; + EXPECT_FALSE(Regex("(foo").isValid(Error)); + EXPECT_EQ("parentheses not balanced", Error); + EXPECT_FALSE(Regex("a[b-").isValid(Error)); + EXPECT_EQ("invalid character range", Error); +} + } diff --git a/unittests/Support/SourceMgrTest.cpp b/unittests/Support/SourceMgrTest.cpp new file mode 100644 index 0000000..2b69fe9 --- /dev/null +++ b/unittests/Support/SourceMgrTest.cpp @@ -0,0 +1,174 @@ +//===- unittests/Support/SourceMgrTest.cpp - SourceMgr tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class SourceMgrTest : public testing::Test { +public: + SourceMgr SM; + unsigned MainBufferID; + std::string Output; + + void setMainBuffer(StringRef Text, StringRef BufferName) { + MemoryBuffer *MainBuffer = MemoryBuffer::getMemBuffer(Text, BufferName); + MainBufferID = SM.AddNewSourceBuffer(MainBuffer, llvm::SMLoc()); + } + + SMLoc getLoc(unsigned Offset) { + return SMLoc::getFromPointer( + SM.getMemoryBuffer(MainBufferID)->getBufferStart() + Offset); + } + + SMRange getRange(unsigned Offset, unsigned Length) { + return SMRange(getLoc(Offset), getLoc(Offset + Length)); + } + + void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, + const Twine &Msg, ArrayRef<SMRange> Ranges, + ArrayRef<SMFixIt> FixIts) { + raw_string_ostream OS(Output); + SM.PrintMessage(OS, Loc, Kind, Msg, Ranges, FixIts); + } +}; + +} // unnamed namespace + +TEST_F(SourceMgrTest, BasicError) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + +TEST_F(SourceMgrTest, BasicWarning) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Warning, "message", None, None); + + EXPECT_EQ("file.in:1:5: warning: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + +TEST_F(SourceMgrTest, BasicNote) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Note, "message", None, None); + + EXPECT_EQ("file.in:1:5: note: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + +TEST_F(SourceMgrTest, LocationAtEndOfLine) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(6), SourceMgr::DK_Error, "message", None, None); + + EXPECT_EQ("file.in:1:7: error: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + +TEST_F(SourceMgrTest, LocationAtNewline) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(7), SourceMgr::DK_Error, "message", None, None); + + EXPECT_EQ("file.in:1:8: error: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + +TEST_F(SourceMgrTest, BasicRange) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 3), None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + " ^~~\n", + Output); +} + +TEST_F(SourceMgrTest, RangeWithTab) { + setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(3, 3), None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + " ~~~~~^~\n", + Output); +} + +TEST_F(SourceMgrTest, MultiLineRange) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Error, "message", getRange(4, 7), None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + " ^~~\n", + Output); +} + +TEST_F(SourceMgrTest, MultipleRanges) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + SMRange Ranges[] = { getRange(0, 3), getRange(4, 3) }; + printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + "~~~ ^~~\n", + Output); +} + +TEST_F(SourceMgrTest, OverlappingRanges) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + SMRange Ranges[] = { getRange(0, 3), getRange(2, 4) }; + printMessage(getLoc(4), SourceMgr::DK_Error, "message", Ranges, None); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + "~~~~^~\n", + Output); +} + +TEST_F(SourceMgrTest, BasicFixit) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Error, "message", None, + makeArrayRef(SMFixIt(getRange(4, 3), "zzz"))); + + EXPECT_EQ("file.in:1:5: error: message\n" + "aaa bbb\n" + " ^~~\n" + " zzz\n", + Output); +} + +TEST_F(SourceMgrTest, FixitForTab) { + setMainBuffer("aaa\tbbb\nccc ddd\n", "file.in"); + printMessage(getLoc(3), SourceMgr::DK_Error, "message", None, + makeArrayRef(SMFixIt(getRange(3, 1), "zzz"))); + + EXPECT_EQ("file.in:1:4: error: message\n" + "aaa bbb\n" + " ^^^^^\n" + " zzz\n", + Output); +} + diff --git a/unittests/Support/ThreadLocalTest.cpp b/unittests/Support/ThreadLocalTest.cpp new file mode 100644 index 0000000..dd4d706 --- /dev/null +++ b/unittests/Support/ThreadLocalTest.cpp @@ -0,0 +1,38 @@ +//===- llvm/unittest/Support/ThreadLocalTest.cpp - Therad Local tests ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ThreadLocal.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace sys; + +namespace { + +class ThreadLocalTest : public ::testing::Test { +}; + +struct S { + int i; +}; + +TEST_F(ThreadLocalTest, Basics) { + ThreadLocal<const S> x; + + EXPECT_EQ(0, x.get()); + + S s; + x.set(&s); + EXPECT_EQ(&s, x.get()); + + x.erase(); + EXPECT_EQ(0, x.get()); +} + +} diff --git a/unittests/Support/UnicodeTest.cpp b/unittests/Support/UnicodeTest.cpp new file mode 100644 index 0000000..0733397 --- /dev/null +++ b/unittests/Support/UnicodeTest.cpp @@ -0,0 +1,93 @@ +//===- unittests/Support/UnicodeTest.cpp - Unicode.h tests ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Unicode.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace sys { +namespace unicode { +namespace { + +TEST(Unicode, columnWidthUTF8) { + EXPECT_EQ(0, columnWidthUTF8("")); + EXPECT_EQ(1, columnWidthUTF8(" ")); + EXPECT_EQ(1, columnWidthUTF8("a")); + EXPECT_EQ(1, columnWidthUTF8("~")); + + EXPECT_EQ(6, columnWidthUTF8("abcdef")); + + EXPECT_EQ(-1, columnWidthUTF8("\x01")); + EXPECT_EQ(-1, columnWidthUTF8("aaaaaaaaaa\x01")); + EXPECT_EQ(-1, columnWidthUTF8("\342\200\213")); // 200B ZERO WIDTH SPACE + + // 00AD SOFT HYPHEN is displayed on most terminals as a space or a dash. Some + // text editors display it only when a line is broken at it, some use it as a + // line-break hint, but don't display. We choose terminal-oriented + // interpretation. + EXPECT_EQ(1, columnWidthUTF8("\302\255")); + + EXPECT_EQ(0, columnWidthUTF8("\314\200")); // 0300 COMBINING GRAVE ACCENT + EXPECT_EQ(1, columnWidthUTF8("\340\270\201")); // 0E01 THAI CHARACTER KO KAI + EXPECT_EQ(2, columnWidthUTF8("\344\270\200")); // CJK UNIFIED IDEOGRAPH-4E00 + + EXPECT_EQ(4, columnWidthUTF8("\344\270\200\344\270\200")); + EXPECT_EQ(3, columnWidthUTF8("q\344\270\200")); + EXPECT_EQ(3, columnWidthUTF8("\314\200\340\270\201\344\270\200")); + + // Invalid UTF-8 strings, columnWidthUTF8 should error out. + EXPECT_EQ(-2, columnWidthUTF8("\344")); + EXPECT_EQ(-2, columnWidthUTF8("\344\270")); + EXPECT_EQ(-2, columnWidthUTF8("\344\270\033")); + EXPECT_EQ(-2, columnWidthUTF8("\344\270\300")); + EXPECT_EQ(-2, columnWidthUTF8("\377\366\355")); + + EXPECT_EQ(-2, columnWidthUTF8("qwer\344")); + EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270")); + EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270\033")); + EXPECT_EQ(-2, columnWidthUTF8("qwer\344\270\300")); + EXPECT_EQ(-2, columnWidthUTF8("qwer\377\366\355")); + + // UTF-8 sequences longer than 4 bytes correspond to unallocated Unicode + // characters. + EXPECT_EQ(-2, columnWidthUTF8("\370\200\200\200\200")); // U+200000 + EXPECT_EQ(-2, columnWidthUTF8("\374\200\200\200\200\200")); // U+4000000 +} + +TEST(Unicode, isPrintable) { + EXPECT_FALSE(isPrintable(0)); // <control-0000>-<control-001F> + EXPECT_FALSE(isPrintable(0x01)); + EXPECT_FALSE(isPrintable(0x1F)); + EXPECT_TRUE(isPrintable(' ')); + EXPECT_TRUE(isPrintable('A')); + EXPECT_TRUE(isPrintable('~')); + EXPECT_FALSE(isPrintable(0x7F)); // <control-007F>..<control-009F> + EXPECT_FALSE(isPrintable(0x90)); + EXPECT_FALSE(isPrintable(0x9F)); + + EXPECT_TRUE(isPrintable(0xAC)); + EXPECT_TRUE(isPrintable(0xAD)); // SOFT HYPHEN is displayed on most terminals + // as either a space or a dash. + EXPECT_TRUE(isPrintable(0xAE)); + + EXPECT_TRUE(isPrintable(0x0377)); // GREEK SMALL LETTER PAMPHYLIAN DIGAMMA + EXPECT_FALSE(isPrintable(0x0378)); // <reserved-0378>..<reserved-0379> + + EXPECT_FALSE(isPrintable(0x0600)); // ARABIC NUMBER SIGN + + EXPECT_FALSE(isPrintable(0x1FFFF)); // <reserved-1F774>..<noncharacter-1FFFF> + EXPECT_TRUE(isPrintable(0x20000)); // CJK UNIFIED IDEOGRAPH-20000 + + EXPECT_FALSE(isPrintable(0x10FFFF)); // noncharacter +} + +} // namespace +} // namespace unicode +} // namespace sys +} // namespace llvm diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 0993d8c..6c0b9e6 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -58,14 +58,24 @@ namespace yaml { // TEST(YAMLIO, TestMapRead) { FooBar doc; - Input yin("---\nfoo: 3\nbar: 5\n...\n"); - yin >> doc; + { + Input yin("---\nfoo: 3\nbar: 5\n...\n"); + yin >> doc; - EXPECT_FALSE(yin.error()); - EXPECT_EQ(doc.foo, 3); - EXPECT_EQ(doc.bar,5); -} + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc.foo, 3); + EXPECT_EQ(doc.bar, 5); + } + { + Input yin("{foo: 3, bar: 5}"); + yin >> doc; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc.foo, 3); + EXPECT_EQ(doc.bar, 5); + } +} // // Test the reading of a yaml sequence of mappings @@ -273,7 +283,64 @@ TEST(YAMLIO, TestReadWriteBuiltInTypes) { } } +struct StringTypes { + llvm::StringRef str1; + llvm::StringRef str2; + llvm::StringRef str3; + llvm::StringRef str4; + llvm::StringRef str5; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<StringTypes> { + static void mapping(IO &io, StringTypes& st) { + io.mapRequired("str1", st.str1); + io.mapRequired("str2", st.str2); + io.mapRequired("str3", st.str3); + io.mapRequired("str4", st.str4); + io.mapRequired("str5", st.str5); + } + }; +} +} + +TEST(YAMLIO, TestReadWriteStringTypes) { + std::string intermediate; + { + StringTypes map; + map.str1 = "'aaa"; + map.str2 = "\"bbb"; + map.str3 = "`ccc"; + map.str4 = "@ddd"; + map.str5 = ""; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + } + llvm::StringRef flowOut(intermediate); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'''aaa")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'\"bbb'")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'`ccc'")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("'@ddd'")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("''\n")); + + { + Input yin(intermediate); + StringTypes map; + yin >> map; + + EXPECT_FALSE(yin.error()); + EXPECT_TRUE(map.str1.equals("'aaa")); + EXPECT_TRUE(map.str2.equals("\"bbb")); + EXPECT_TRUE(map.str3.equals("`ccc")); + EXPECT_TRUE(map.str4.equals("@ddd")); + EXPECT_TRUE(map.str5.equals("")); + } +} //===----------------------------------------------------------------------===// // Test ScalarEnumerationTraits @@ -600,9 +667,9 @@ TEST(YAMLIO, TestReadWriteMyFlowSequence) { map.numbers.push_back(1024); llvm::raw_string_ostream ostr(intermediate); - Output yout(ostr); + Output yout(ostr); yout << map; - + // Verify sequences were written in flow style ostr.flush(); llvm::StringRef flowOut(intermediate); @@ -932,6 +999,161 @@ TEST(YAMLIO, TestSequenceDocListWriteAndRead) { } } +//===----------------------------------------------------------------------===// +// Test document tags +//===----------------------------------------------------------------------===// + +struct MyDouble { + MyDouble() : value(0.0) { } + MyDouble(double x) : value(x) { } + double value; +}; + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDouble) + + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<MyDouble> { + static void mapping(IO &io, MyDouble &d) { + if (io.mapTag("!decimal", true)) { + mappingDecimal(io, d); + } else if (io.mapTag("!fraction")) { + mappingFraction(io, d); + } + } + static void mappingDecimal(IO &io, MyDouble &d) { + io.mapRequired("value", d.value); + } + static void mappingFraction(IO &io, MyDouble &d) { + double num, denom; + io.mapRequired("numerator", num); + io.mapRequired("denominator", denom); + // convert fraction to double + d.value = num/denom; + } + }; + } +} + + +// +// Test the reading of two different tagged yaml documents. +// +TEST(YAMLIO, TestTaggedDocuments) { + std::vector<MyDouble> docList; + Input yin("--- !decimal\nvalue: 3.0\n" + "--- !fraction\nnumerator: 9.0\ndenominator: 2\n...\n"); + yin >> docList; + EXPECT_FALSE(yin.error()); + EXPECT_EQ(docList.size(), 2UL); + EXPECT_EQ(docList[0].value, 3.0); + EXPECT_EQ(docList[1].value, 4.5); +} + + + +// +// Test writing then reading back tagged documents +// +TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) { + std::string intermediate; + { + MyDouble a(10.25); + MyDouble b(-3.75); + std::vector<MyDouble> docList; + docList.push_back(a); + docList.push_back(b); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << docList; + } + + { + Input yin(intermediate); + std::vector<MyDouble> docList2; + yin >> docList2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(docList2.size(), 2UL); + EXPECT_EQ(docList2[0].value, 10.25); + EXPECT_EQ(docList2[1].value, -3.75); + } +} + + +//===----------------------------------------------------------------------===// +// Test dyn_cast<> on IO object +//===----------------------------------------------------------------------===// + +struct DynCast { + int value; +}; +typedef std::vector<DynCast> DynCastSequence; + +LLVM_YAML_IS_SEQUENCE_VECTOR(DynCast) + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<DynCast> { + static void mapping(IO &io, DynCast& info) { + // Change 10 to 13 when writing yaml. + if (Output *output = dyn_cast<Output>(&io)) { + (void)output; + if (info.value == 10) + info.value = 13; + } + io.mapRequired("value", info.value); + // Change 20 to 23 when parsing yaml. + if (Input *input = dyn_cast<Input>(&io)) { + (void)input; + if (info.value == 20) + info.value = 23; + } + } + }; +} +} + +// +// Test writing then reading back a sequence of mappings +// +TEST(YAMLIO, TestDynCast) { + std::string intermediate; + { + DynCast entry1; + entry1.value = 10; + DynCast entry2; + entry2.value = 20; + DynCast entry3; + entry3.value = 30; + DynCastSequence seq; + seq.push_back(entry1); + seq.push_back(entry2); + seq.push_back(entry3); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << seq; + } + + { + Input yin(intermediate); + DynCastSequence seq2; + yin >> seq2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(seq2.size(), 3UL); + EXPECT_EQ(seq2[0].value, 13); // Verify changed to 13. + EXPECT_EQ(seq2[1].value, 23); // Verify changed to 23. + EXPECT_EQ(seq2[2].value, 30); // Verify stays same. + } +} + + //===----------------------------------------------------------------------===// // Test error handling @@ -952,8 +1174,9 @@ TEST(YAMLIO, TestColorsReadError) { "c1: blue\n" "c2: purple\n" "c3: green\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> map; EXPECT_TRUE(yin.error()); } @@ -968,8 +1191,9 @@ TEST(YAMLIO, TestFlagsReadError) { "f1: [ big ]\n" "f2: [ round, hollow ]\n" "f3: []\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> map; EXPECT_TRUE(yin.error()); @@ -986,8 +1210,9 @@ TEST(YAMLIO, TestReadBuiltInTypesUint8Error) { "- 255\n" "- 0\n" "- 257\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1004,8 +1229,9 @@ TEST(YAMLIO, TestReadBuiltInTypesUint16Error) { "- 65535\n" "- 0\n" "- 66000\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1022,8 +1248,9 @@ TEST(YAMLIO, TestReadBuiltInTypesUint32Error) { "- 4000000000\n" "- 0\n" "- 5000000000\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1040,8 +1267,9 @@ TEST(YAMLIO, TestReadBuiltInTypesUint64Error) { "- 18446744073709551615\n" "- 0\n" "- 19446744073709551615\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1059,8 +1287,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint8OverError) { "- 0\n" "- 127\n" "- 128\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1076,8 +1305,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) { "- 0\n" "- 127\n" "- -129\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1095,8 +1325,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) { "- 0\n" "- -32768\n" "- -32769\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1113,8 +1344,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint16OverError) { "- 0\n" "- -32768\n" "- 32768\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1132,8 +1364,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) { "- 0\n" "- -2147483648\n" "- -2147483649\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1149,8 +1382,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint32OverError) { "- 0\n" "- -2147483648\n" "- 2147483649\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1168,8 +1402,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) { "- 0\n" "- 9223372036854775807\n" "- -9223372036854775809\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1185,8 +1420,9 @@ TEST(YAMLIO, TestReadBuiltInTypesint64OverError) { "- 0\n" "- 9223372036854775807\n" "- 9223372036854775809\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1203,8 +1439,9 @@ TEST(YAMLIO, TestReadBuiltInTypesFloatError) { "- 1000.1\n" "- -123.456\n" "- 1.2.3\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1221,8 +1458,9 @@ TEST(YAMLIO, TestReadBuiltInTypesDoubleError) { "- 1000.1\n" "- -123.456\n" "- 1.2.3\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1238,8 +1476,9 @@ TEST(YAMLIO, TestReadBuiltInTypesHex8Error) { "- 0x12\n" "- 0xFE\n" "- 0x123\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1256,8 +1495,9 @@ TEST(YAMLIO, TestReadBuiltInTypesHex16Error) { "- 0x0012\n" "- 0xFEFF\n" "- 0x12345\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1273,8 +1513,9 @@ TEST(YAMLIO, TestReadBuiltInTypesHex32Error) { "- 0x0012\n" "- 0xFEFF0000\n" "- 0x1234556789\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); @@ -1290,10 +1531,114 @@ TEST(YAMLIO, TestReadBuiltInTypesHex64Error) { "- 0x0012\n" "- 0xFFEEDDCCBBAA9988\n" "- 0x12345567890ABCDEF0\n" - "...\n"); - yin.setDiagHandler(suppressErrorMessages); + "...\n", + /*Ctxt=*/NULL, + suppressErrorMessages); yin >> seq; EXPECT_TRUE(yin.error()); } +TEST(YAMLIO, TestMalformedMapFailsGracefully) { + FooBar doc; + { + // We pass the suppressErrorMessages handler to handle the error + // message generated in the constructor of Input. + Input yin("{foo:3, bar: 5}", /*Ctxt=*/NULL, suppressErrorMessages); + yin >> doc; + EXPECT_TRUE(yin.error()); + } + + { + Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/NULL, suppressErrorMessages); + yin >> doc; + EXPECT_TRUE(yin.error()); + } +} + +struct OptionalTest { + std::vector<int> Numbers; +}; + +struct OptionalTestSeq { + std::vector<OptionalTest> Tests; +}; + +LLVM_YAML_IS_SEQUENCE_VECTOR(OptionalTest) +namespace llvm { +namespace yaml { + template <> + struct MappingTraits<OptionalTest> { + static void mapping(IO& IO, OptionalTest &OT) { + IO.mapOptional("Numbers", OT.Numbers); + } + }; + + template <> + struct MappingTraits<OptionalTestSeq> { + static void mapping(IO &IO, OptionalTestSeq &OTS) { + IO.mapOptional("Tests", OTS.Tests); + } + }; +} +} + +TEST(YAMLIO, SequenceElideTest) { + // Test that writing out a purely optional structure with its fields set to + // default followed by other data is properly read back in. + OptionalTestSeq Seq; + OptionalTest One, Two, Three, Four; + int N[] = {1, 2, 3}; + Three.Numbers.assign(N, N + 3); + Seq.Tests.push_back(One); + Seq.Tests.push_back(Two); + Seq.Tests.push_back(Three); + Seq.Tests.push_back(Four); + + std::string intermediate; + { + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << Seq; + } + + Input yin(intermediate); + OptionalTestSeq Seq2; + yin >> Seq2; + + EXPECT_FALSE(yin.error()); + + EXPECT_EQ(4UL, Seq2.Tests.size()); + + EXPECT_TRUE(Seq2.Tests[0].Numbers.empty()); + EXPECT_TRUE(Seq2.Tests[1].Numbers.empty()); + + EXPECT_EQ(1, Seq2.Tests[2].Numbers[0]); + EXPECT_EQ(2, Seq2.Tests[2].Numbers[1]); + EXPECT_EQ(3, Seq2.Tests[2].Numbers[2]); + + EXPECT_TRUE(Seq2.Tests[3].Numbers.empty()); +} + +TEST(YAMLIO, TestEmptyStringFailsForMapWithRequiredFields) { + FooBar doc; + Input yin(""); + yin >> doc; + EXPECT_TRUE(yin.error()); +} + +TEST(YAMLIO, TestEmptyStringSucceedsForMapWithOptionalFields) { + OptionalTest doc; + Input yin(""); + yin >> doc; + EXPECT_FALSE(yin.error()); +} + +TEST(YAMLIO, TestEmptyStringSucceedsForSequence) { + std::vector<uint8_t> seq; + Input yin("", /*Ctxt=*/NULL, suppressErrorMessages); + yin >> seq; + + EXPECT_FALSE(yin.error()); + EXPECT_TRUE(seq.empty()); +} diff --git a/unittests/Transforms/Utils/SpecialCaseList.cpp b/unittests/Transforms/Utils/SpecialCaseList.cpp index 9deee3c..07ac908 100644 --- a/unittests/Transforms/Utils/SpecialCaseList.cpp +++ b/unittests/Transforms/Utils/SpecialCaseList.cpp @@ -34,9 +34,22 @@ protected: M, ST, false, GlobalValue::ExternalLinkage, 0, Name); } - SpecialCaseList *makeSpecialCaseList(StringRef List) { + GlobalAlias *makeAlias(StringRef Name, GlobalValue *Aliasee) { + return new GlobalAlias(Aliasee->getType(), GlobalValue::ExternalLinkage, + Name, Aliasee, Aliasee->getParent()); + } + + SpecialCaseList *makeSpecialCaseList(StringRef List, std::string &Error) { OwningPtr<MemoryBuffer> MB(MemoryBuffer::getMemBuffer(List)); - return new SpecialCaseList(MB.get()); + return SpecialCaseList::create(MB.get(), Error); + } + + SpecialCaseList *makeSpecialCaseList(StringRef List) { + std::string Error; + SpecialCaseList *SCL = makeSpecialCaseList(List, Error); + assert(SCL); + assert(Error == ""); + return SCL; } LLVMContext Ctx; @@ -86,8 +99,6 @@ TEST_F(SpecialCaseListTest, FunctionIsIn) { SCL.reset(makeSpecialCaseList("fun:foo=functional\n")); EXPECT_TRUE(SCL->isIn(*Foo, "functional")); StringRef Category; - EXPECT_TRUE(SCL->findCategory(*Foo, Category)); - EXPECT_EQ("functional", Category); EXPECT_FALSE(SCL->isIn(*Bar, "functional")); } @@ -139,10 +150,48 @@ TEST_F(SpecialCaseListTest, GlobalIsIn) { EXPECT_TRUE(SCL->isIn(*Bar, "init")); } +TEST_F(SpecialCaseListTest, AliasIsIn) { + Module M("hello", Ctx); + Function *Foo = makeFunction("foo", M); + GlobalVariable *Bar = makeGlobal("bar", "t", M); + GlobalAlias *FooAlias = makeAlias("fooalias", Foo); + GlobalAlias *BarAlias = makeAlias("baralias", Bar); + + OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("fun:foo\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias)); + EXPECT_FALSE(SCL->isIn(*BarAlias)); + + SCL.reset(makeSpecialCaseList("global:bar\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias)); + EXPECT_FALSE(SCL->isIn(*BarAlias)); + + SCL.reset(makeSpecialCaseList("global:fooalias\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias)); + EXPECT_FALSE(SCL->isIn(*BarAlias)); + + SCL.reset(makeSpecialCaseList("fun:fooalias\n")); + EXPECT_TRUE(SCL->isIn(*FooAlias)); + EXPECT_FALSE(SCL->isIn(*BarAlias)); + + SCL.reset(makeSpecialCaseList("global:baralias=init\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); + EXPECT_TRUE(SCL->isIn(*BarAlias, "init")); + + SCL.reset(makeSpecialCaseList("type:t=init\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); + EXPECT_TRUE(SCL->isIn(*BarAlias, "init")); + + SCL.reset(makeSpecialCaseList("fun:baralias=init\n")); + EXPECT_FALSE(SCL->isIn(*FooAlias, "init")); + EXPECT_FALSE(SCL->isIn(*BarAlias, "init")); +} + TEST_F(SpecialCaseListTest, Substring) { Module M("othello", Ctx); Function *F = makeFunction("tomfoolery", M); GlobalVariable *GV = makeGlobal("bartender", "t", M); + GlobalAlias *GA1 = makeAlias("buffoonery", F); + GlobalAlias *GA2 = makeAlias("foobar", GV); OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("src:hello\n" "fun:foo\n" @@ -150,9 +199,34 @@ TEST_F(SpecialCaseListTest, Substring) { EXPECT_FALSE(SCL->isIn(M)); EXPECT_FALSE(SCL->isIn(*F)); EXPECT_FALSE(SCL->isIn(*GV)); + EXPECT_FALSE(SCL->isIn(*GA1)); + EXPECT_FALSE(SCL->isIn(*GA2)); SCL.reset(makeSpecialCaseList("fun:*foo*\n")); EXPECT_TRUE(SCL->isIn(*F)); + EXPECT_TRUE(SCL->isIn(*GA1)); +} + +TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) { + std::string Error; + EXPECT_EQ(0, makeSpecialCaseList("badline", Error)); + EXPECT_EQ("Malformed line 1: 'badline'", Error); + EXPECT_EQ(0, makeSpecialCaseList("src:bad[a-", Error)); + EXPECT_EQ("Malformed regex in line 1: 'bad[a-': invalid character range", + Error); + EXPECT_EQ(0, makeSpecialCaseList("src:a.c\n" + "fun:fun(a\n", + Error)); + EXPECT_EQ("Malformed regex in line 2: 'fun(a': parentheses not balanced", + Error); + EXPECT_EQ(0, SpecialCaseList::create("unexisting", Error)); + EXPECT_EQ(0U, Error.find("Can't open file 'unexisting':")); +} + +TEST_F(SpecialCaseListTest, EmptySpecialCaseList) { + OwningPtr<SpecialCaseList> SCL(makeSpecialCaseList("")); + Module M("foo", Ctx); + EXPECT_FALSE(SCL->isIn(M)); } } |