diff options
author | dim <dim@FreeBSD.org> | 2012-12-02 13:10:19 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-12-02 13:10:19 +0000 |
commit | 6de2c08bc400b4aca9fb46684e8bdb56eed9b09f (patch) | |
tree | 32b4679ab4b8f28e5228daafc65e9dc436935353 /unittests | |
parent | 4dc93743c9d40c29c0a3bec2aae328cac0d289e8 (diff) | |
download | FreeBSD-src-6de2c08bc400b4aca9fb46684e8bdb56eed9b09f.zip FreeBSD-src-6de2c08bc400b4aca9fb46684e8bdb56eed9b09f.tar.gz |
Vendor import of llvm release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/llvm/branches/release_32@168974
Diffstat (limited to 'unittests')
35 files changed, 1898 insertions, 118 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp index 00b62fe..117b820 100644 --- a/unittests/ADT/APFloatTest.cpp +++ b/unittests/ADT/APFloatTest.cpp @@ -635,6 +635,12 @@ TEST(APFloatTest, exactInverse) { EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5))); EXPECT_TRUE(APFloat(2.0f).getExactInverse(&inv)); EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(0.5f))); + EXPECT_TRUE(APFloat(APFloat::IEEEquad, "2.0").getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::IEEEquad, "0.5"))); + EXPECT_TRUE(APFloat(APFloat::PPCDoubleDouble, "2.0").getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::PPCDoubleDouble, "0.5"))); + EXPECT_TRUE(APFloat(APFloat::x87DoubleExtended, "2.0").getExactInverse(&inv)); + EXPECT_TRUE(inv.bitwiseIsEqual(APFloat(APFloat::x87DoubleExtended, "0.5"))); // FLT_MIN EXPECT_TRUE(APFloat(1.17549435e-38f).getExactInverse(&inv)); @@ -689,6 +695,23 @@ TEST(APFloatTest, roundToIntegral) { P = R; P.roundToIntegral(APFloat::rmNearestTiesToEven); EXPECT_EQ(R.convertToDouble(), P.convertToDouble()); + + P = APFloat::getZero(APFloat::IEEEdouble); + P.roundToIntegral(APFloat::rmTowardZero); + EXPECT_EQ(0.0, P.convertToDouble()); + P = APFloat::getZero(APFloat::IEEEdouble, true); + P.roundToIntegral(APFloat::rmTowardZero); + EXPECT_EQ(-0.0, P.convertToDouble()); + P = APFloat::getNaN(APFloat::IEEEdouble); + P.roundToIntegral(APFloat::rmTowardZero); + EXPECT_TRUE(IsNAN(P.convertToDouble())); + P = APFloat::getInf(APFloat::IEEEdouble); + P.roundToIntegral(APFloat::rmTowardZero); + EXPECT_TRUE(IsInf(P.convertToDouble()) && P.convertToDouble() > 0.0); + P = APFloat::getInf(APFloat::IEEEdouble, true); + P.roundToIntegral(APFloat::rmTowardZero); + EXPECT_TRUE(IsInf(P.convertToDouble()) && P.convertToDouble() < 0.0); + } TEST(APFloatTest, getLargest) { @@ -720,4 +743,40 @@ TEST(APFloatTest, convert) { EXPECT_EQ(4294967295.0, test.convertToDouble()); EXPECT_FALSE(losesInfo); } + +TEST(APFloatTest, PPCDoubleDouble) { + APFloat test(APFloat::PPCDoubleDouble, "1.0"); + EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]); + EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]); + + test.divide(APFloat(APFloat::PPCDoubleDouble, "3.0"), APFloat::rmNearestTiesToEven); + EXPECT_EQ(0x3fd5555555555555ull, test.bitcastToAPInt().getRawData()[0]); + EXPECT_EQ(0x3c75555555555556ull, test.bitcastToAPInt().getRawData()[1]); + + // LDBL_MAX + test = APFloat(APFloat::PPCDoubleDouble, "1.79769313486231580793728971405301e+308"); + EXPECT_EQ(0x7fefffffffffffffull, test.bitcastToAPInt().getRawData()[0]); + EXPECT_EQ(0x7c8ffffffffffffeull, test.bitcastToAPInt().getRawData()[1]); + + // LDBL_MIN + test = APFloat(APFloat::PPCDoubleDouble, "2.00416836000897277799610805135016e-292"); + EXPECT_EQ(0x0360000000000000ull, test.bitcastToAPInt().getRawData()[0]); + EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]); + + test = APFloat(APFloat::PPCDoubleDouble, "1.0"); + test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-105"), APFloat::rmNearestTiesToEven); + EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]); + EXPECT_EQ(0x3960000000000000ull, test.bitcastToAPInt().getRawData()[1]); + + test = APFloat(APFloat::PPCDoubleDouble, "1.0"); + test.add(APFloat(APFloat::PPCDoubleDouble, "0x1p-106"), APFloat::rmNearestTiesToEven); + EXPECT_EQ(0x3ff0000000000000ull, test.bitcastToAPInt().getRawData()[0]); +#if 0 // XFAIL + // This is what we would expect with a true double-double implementation + EXPECT_EQ(0x3950000000000000ull, test.bitcastToAPInt().getRawData()[1]); +#else + // This is what we get with our 106-bit mantissa approximation + EXPECT_EQ(0x0000000000000000ull, test.bitcastToAPInt().getRawData()[1]); +#endif +} } diff --git a/unittests/ADT/BitVectorTest.cpp b/unittests/ADT/BitVectorTest.cpp index d836036..dc298a8 100644 --- a/unittests/ADT/BitVectorTest.cpp +++ b/unittests/ADT/BitVectorTest.cpp @@ -281,5 +281,57 @@ TYPED_TEST(BitVectorTest, BinOps) { EXPECT_FALSE(A.anyCommon(B)); EXPECT_FALSE(B.anyCommon(A)); } + +TYPED_TEST(BitVectorTest, RangeOps) { + TypeParam A; + A.resize(256); + A.reset(); + A.set(1, 255); + + EXPECT_FALSE(A.test(0)); + EXPECT_TRUE( A.test(1)); + EXPECT_TRUE( A.test(23)); + EXPECT_TRUE( A.test(254)); + EXPECT_FALSE(A.test(255)); + + TypeParam B; + B.resize(256); + B.set(); + B.reset(1, 255); + + EXPECT_TRUE( B.test(0)); + EXPECT_FALSE(B.test(1)); + EXPECT_FALSE(B.test(23)); + EXPECT_FALSE(B.test(254)); + EXPECT_TRUE( B.test(255)); + + TypeParam C; + C.resize(3); + C.reset(); + C.set(0, 1); + + EXPECT_TRUE(C.test(0)); + EXPECT_FALSE( C.test(1)); + EXPECT_FALSE( C.test(2)); + + TypeParam D; + D.resize(3); + D.set(); + D.reset(0, 1); + + EXPECT_FALSE(D.test(0)); + EXPECT_TRUE( D.test(1)); + EXPECT_TRUE( D.test(2)); + + TypeParam E; + E.resize(128); + E.reset(); + E.set(1, 33); + + EXPECT_FALSE(E.test(0)); + EXPECT_TRUE( E.test(1)); + EXPECT_TRUE( E.test(32)); + EXPECT_FALSE(E.test(33)); +} } #endif diff --git a/unittests/ADT/CMakeLists.txt b/unittests/ADT/CMakeLists.txt index d272b09..94f7fda 100644 --- a/unittests/ADT/CMakeLists.txt +++ b/unittests/ADT/CMakeLists.txt @@ -2,7 +2,7 @@ set(LLVM_LINK_COMPONENTS Support ) -add_llvm_unittest(ADTTests +set(ADTSources APFloatTest.cpp APIntTest.cpp BitVectorTest.cpp @@ -13,6 +13,7 @@ add_llvm_unittest(ADTTests FoldingSet.cpp HashingTest.cpp ilistTest.cpp + ImmutableMapTest.cpp ImmutableSetTest.cpp IntEqClassesTest.cpp IntervalMapTest.cpp @@ -31,3 +32,16 @@ add_llvm_unittest(ADTTests TwineTest.cpp VariadicFunctionTest.cpp ) + +# They cannot be compiled on MSVC9 due to its bug. +if(MSVC AND MSVC_VERSION LESS 1600) + set(LLVM_OPTIONAL_SOURCES + DenseMapTest.cpp + SmallVectorTest.cpp + ) + list(REMOVE_ITEM ADTSources ${LLVM_OPTIONAL_SOURCES}) +endif() + +add_llvm_unittest(ADTTests + ${ADTSources} + ) diff --git a/unittests/ADT/DenseMapTest.cpp b/unittests/ADT/DenseMapTest.cpp index 75e7006..15eb698 100644 --- a/unittests/ADT/DenseMapTest.cpp +++ b/unittests/ADT/DenseMapTest.cpp @@ -330,4 +330,37 @@ TEST(DenseMapCustomTest, FindAsTest) { EXPECT_TRUE(map.find_as("d") == map.end()); } +struct ContiguousDenseMapInfo { + static inline unsigned getEmptyKey() { return ~0; } + static inline unsigned getTombstoneKey() { return ~0U - 1; } + static unsigned getHashValue(const unsigned& Val) { return Val; } + static bool isEqual(const unsigned& LHS, const unsigned& RHS) { + return LHS == RHS; + } +}; + +// Test that filling a small dense map with exactly the number of elements in +// the map grows to have enough space for an empty bucket. +TEST(DenseMapCustomTest, SmallDenseMapGrowTest) { + SmallDenseMap<unsigned, unsigned, 32, ContiguousDenseMapInfo> map; + // Add some number of elements, then delete a few to leave us some tombstones. + // If we just filled the map with 32 elements we'd grow because of not enough + // tombstones which masks the issue here. + for (unsigned i = 0; i < 20; ++i) + map[i] = i + 1; + for (unsigned i = 0; i < 10; ++i) + map.erase(i); + for (unsigned i = 20; i < 32; ++i) + map[i] = i + 1; + + // Size tests + EXPECT_EQ(22u, map.size()); + + // Try to find an element which doesn't exist. There was a bug in + // SmallDenseMap which led to a map with num elements == small capacity not + // having an empty bucket any more. Finding an element not in the map would + // therefore never terminate. + EXPECT_TRUE(map.find(32) == map.end()); +} + } diff --git a/unittests/ADT/DenseSetTest.cpp b/unittests/ADT/DenseSetTest.cpp index 7a35f52..ada5f6d 100644 --- a/unittests/ADT/DenseSetTest.cpp +++ b/unittests/ADT/DenseSetTest.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "gtest/gtest.h" -#include <llvm/ADT/DenseSet.h> +#include "llvm/ADT/DenseSet.h" using namespace llvm; diff --git a/unittests/ADT/ImmutableMapTest.cpp b/unittests/ADT/ImmutableMapTest.cpp new file mode 100644 index 0000000..774581c --- /dev/null +++ b/unittests/ADT/ImmutableMapTest.cpp @@ -0,0 +1,50 @@ +//===----------- ImmutableMapTest.cpp - ImmutableMap 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/ImmutableMap.h" + +using namespace llvm; + +namespace { + +TEST(ImmutableMapTest, EmptyIntMapTest) { + ImmutableMap<int, int>::Factory f; + + EXPECT_TRUE(f.getEmptyMap() == f.getEmptyMap()); + EXPECT_FALSE(f.getEmptyMap() != f.getEmptyMap()); + EXPECT_TRUE(f.getEmptyMap().isEmpty()); + + ImmutableMap<int, int> S = f.getEmptyMap(); + EXPECT_EQ(0u, S.getHeight()); + EXPECT_TRUE(S.begin() == S.end()); + EXPECT_FALSE(S.begin() != S.end()); +} + +TEST(ImmutableMapTest, MultiElemIntMapTest) { + ImmutableMap<int, int>::Factory f; + ImmutableMap<int, int> S = f.getEmptyMap(); + + ImmutableMap<int, int> S2 = f.add(f.add(f.add(S, 3, 10), 4, 11), 5, 12); + + EXPECT_TRUE(S.isEmpty()); + EXPECT_FALSE(S2.isEmpty()); + + EXPECT_EQ(0, S.lookup(3)); + EXPECT_EQ(0, S.lookup(9)); + + EXPECT_EQ(10, *S2.lookup(3)); + EXPECT_EQ(11, *S2.lookup(4)); + EXPECT_EQ(12, *S2.lookup(5)); + + EXPECT_EQ(5, S2.getMaxElement()->first); + EXPECT_EQ(3U, S2.getHeight()); +} + +} diff --git a/unittests/ADT/StringRefTest.cpp b/unittests/ADT/StringRefTest.cpp index 315eacb..ead372f 100644 --- a/unittests/ADT/StringRefTest.cpp +++ b/unittests/ADT/StringRefTest.cpp @@ -456,4 +456,27 @@ TEST(StringRefTest, getAsInteger) { } } + +static const char* BadStrings[] = { + "18446744073709551617" // value just over max + , "123456789012345678901" // value way too large + , "4t23v" // illegal decimal characters + , "0x123W56" // illegal hex characters + , "0b2" // illegal bin characters + , "08" // illegal oct characters + , "0o8" // illegal oct characters + , "-123" // negative unsigned value +}; + + +TEST(StringRefTest, getAsUnsignedIntegerBadStrings) { + unsigned long long U64; + for (size_t i = 0; i < array_lengthof(BadStrings); ++i) { + bool IsBadNumber = StringRef(BadStrings[i]).getAsInteger(0, U64); + ASSERT_TRUE(IsBadNumber); + } +} + + + } // end anonymous namespace diff --git a/unittests/ADT/TripleTest.cpp b/unittests/ADT/TripleTest.cpp index 967437c..7c3ab97 100644 --- a/unittests/ADT/TripleTest.cpp +++ b/unittests/ADT/TripleTest.cpp @@ -105,6 +105,18 @@ TEST(TripleTest, ParsedIDs) { EXPECT_EQ(Triple::Linux, T.getOS()); EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("powerpc-ibm-aix"); + EXPECT_EQ(Triple::ppc, T.getArch()); + EXPECT_EQ(Triple::IBM, T.getVendor()); + EXPECT_EQ(Triple::AIX, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + + T = Triple("powerpc64-ibm-aix"); + EXPECT_EQ(Triple::ppc64, T.getArch()); + EXPECT_EQ(Triple::IBM, T.getVendor()); + EXPECT_EQ(Triple::AIX, T.getOS()); + EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment()); + T = Triple("powerpc-dunno-notsure"); EXPECT_EQ(Triple::ppc, T.getArch()); EXPECT_EQ(Triple::UnknownVendor, T.getVendor()); diff --git a/unittests/Analysis/ScalarEvolutionTest.cpp b/unittests/Analysis/ScalarEvolutionTest.cpp index ea5aeb3..c30492a 100644 --- a/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/unittests/Analysis/ScalarEvolutionTest.cpp @@ -7,14 +7,14 @@ // //===----------------------------------------------------------------------===// -#include <llvm/Analysis/ScalarEvolutionExpressions.h> -#include <llvm/Analysis/LoopInfo.h> -#include <llvm/GlobalVariable.h> -#include <llvm/Constants.h> -#include <llvm/LLVMContext.h> -#include <llvm/Module.h> -#include <llvm/PassManager.h> -#include <llvm/ADT/SmallVector.h> +#include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Constants.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/ADT/SmallVector.h" #include "gtest/gtest.h" namespace llvm { diff --git a/unittests/ExecutionEngine/CMakeLists.txt b/unittests/ExecutionEngine/CMakeLists.txt index 5fffadd..ed7f10a 100644 --- a/unittests/ExecutionEngine/CMakeLists.txt +++ b/unittests/ExecutionEngine/CMakeLists.txt @@ -7,3 +7,4 @@ add_llvm_unittest(ExecutionEngineTests ) add_subdirectory(JIT) +add_subdirectory(MCJIT) diff --git a/unittests/ExecutionEngine/JIT/CMakeLists.txt b/unittests/ExecutionEngine/JIT/CMakeLists.txt index d43d72d..11cf784 100644 --- a/unittests/ExecutionEngine/JIT/CMakeLists.txt +++ b/unittests/ExecutionEngine/JIT/CMakeLists.txt @@ -14,8 +14,6 @@ set(LLVM_OPTIONAL_SOURCES ) if( LLVM_USE_INTEL_JITEVENTS ) - include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} ) - link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} ) set(ProfileTestSources IntelJITEventListenerTest.cpp ) diff --git a/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp b/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp index 8ed7a15..d3f66a2 100644 --- a/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp +++ b/unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp @@ -11,7 +11,10 @@ using namespace llvm; -#include "llvm/ExecutionEngine/IntelJITEventsWrapper.h" +// Because we want to keep the implementation details of the Intel API used to +// communicate with Amplifier out of the public header files, the header below +// is included from the source tree instead. +#include "../../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h" #include <map> #include <list> @@ -80,7 +83,7 @@ public: EXPECT_TRUE(0 != MockWrapper); Listener.reset(JITEventListener::createIntelJITEventListener( - MockWrapper.get())); + MockWrapper.take())); EXPECT_TRUE(0 != Listener); EE->RegisterJITEventListener(Listener.get()); } diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp index 89f7e8e..59604df 100644 --- a/unittests/ExecutionEngine/JIT/JITTest.cpp +++ b/unittests/ExecutionEngine/JIT/JITTest.cpp @@ -224,6 +224,9 @@ class JITTest : public testing::Test { OwningPtr<ExecutionEngine> TheJIT; }; +// Tests on ARM and PowerPC disabled as we're running the old jit +#if !defined(__arm__) && !defined(__powerpc__) + // Regression test for a bug. The JIT used to allocate globals inside the same // memory block used for the function, and when the function code was freed, // the global was left in the same place. This test allocates a function @@ -292,12 +295,14 @@ TEST(JIT, GlobalInFunction) { EXPECT_EQ(3, *GPtr); } +#endif // !defined(__arm__) && !defined(__powerpc__) + int PlusOne(int arg) { return arg + 1; } -// ARM tests disabled pending fix for PR10783. -#if !defined(__arm__) +// ARM and PowerPC tests disabled pending fix for PR10783. +#if !defined(__arm__) && !defined(__powerpc__) TEST_F(JITTest, FarCallToKnownFunction) { // x86-64 can only make direct calls to functions within 32 bits of // the current PC. To call anything farther away, we have to load @@ -475,7 +480,7 @@ TEST_F(JITTest, ModuleDeletion) { EXPECT_EQ(RJMM->startExceptionTableCalls.size(), NumTablesDeallocated); } -#endif // !defined(__arm__) +#endif // !defined(__arm__) && !defined(__powerpc__) // ARM, MIPS and PPC still emit stubs for calls since the target may be // too far away to call directly. This #if can probably be removed when @@ -521,6 +526,9 @@ TEST_F(JITTest, NoStubs) { } #endif // !ARM && !PPC +// Tests on ARM and PowerPC disabled as we're running the old jit +#if !defined(__arm__) && !defined(__powerpc__) + TEST_F(JITTest, FunctionPointersOutliveTheirCreator) { TheJIT->DisableLazyCompilation(true); LoadAssembly("define i8()* @get_foo_addr() { " @@ -555,10 +563,13 @@ TEST_F(JITTest, FunctionPointersOutliveTheirCreator) { #endif } -// ARM does not have an implementation +#endif //!defined(__arm__) && !defined(__powerpc__) + +// Tests on ARM and PowerPC disabled as we're running the old jit +// In addition, ARM does not have an implementation // of replaceMachineCodeForFunction(), so recompileAndRelinkFunction // doesn't work. -#if !defined(__arm__) +#if !defined(__arm__) && !defined(__powerpc__) TEST_F(JITTest, FunctionIsRecompiledAndRelinked) { Function *F = Function::Create(TypeBuilder<int(void), false>::get(Context), GlobalValue::ExternalLinkage, "test", M); @@ -589,16 +600,19 @@ TEST_F(JITTest, FunctionIsRecompiledAndRelinked) { EXPECT_EQ(2, OrigFPtr()) << "The old pointer's target should now jump to the new version"; } -#endif // !defined(__arm__) +#endif // !defined(__arm__) && !defined(__powerpc__) } // anonymous namespace // This variable is intentionally defined differently in the statically-compiled // program from the IR input to the JIT to assert that the JIT doesn't use its // definition. extern "C" int32_t JITTest_AvailableExternallyGlobal; -int32_t JITTest_AvailableExternallyGlobal = 42; +int32_t JITTest_AvailableExternallyGlobal LLVM_ATTRIBUTE_USED = 42; namespace { +// Tests on ARM and PowerPC disabled as we're running the old jit +#if !defined(__arm__) && !defined(__powerpc__) + TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) { TheJIT->DisableLazyCompilation(true); LoadAssembly("@JITTest_AvailableExternallyGlobal = " @@ -615,18 +629,19 @@ TEST_F(JITTest, AvailableExternallyGlobalIsntEmitted) { EXPECT_EQ(42, loader()) << "func should return 42 from the external global," << " not 7 from the IR version."; } - +#endif //!defined(__arm__) && !defined(__powerpc__) } // anonymous namespace // This function is intentionally defined differently in the statically-compiled // program from the IR input to the JIT to assert that the JIT doesn't use its // definition. +extern "C" int32_t JITTest_AvailableExternallyFunction() LLVM_ATTRIBUTE_USED; extern "C" int32_t JITTest_AvailableExternallyFunction() { return 42; } namespace { -// ARM tests disabled pending fix for PR10783. -#if !defined(__arm__) +// ARM and PowerPC tests disabled pending fix for PR10783. +#if !defined(__arm__) && !defined(__powerpc__) TEST_F(JITTest, AvailableExternallyFunctionIsntCompiled) { TheJIT->DisableLazyCompilation(true); LoadAssembly("define available_externally i32 " @@ -782,7 +797,7 @@ TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) { (intptr_t)TheJIT->getPointerToFunction(recur1IR)); EXPECT_EQ(3, recur1(4)); } -#endif // !defined(__arm__) +#endif // !defined(__arm__) && !defined(__powerpc__) // 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 diff --git a/unittests/ExecutionEngine/JIT/Makefile b/unittests/ExecutionEngine/JIT/Makefile index b535a6b..9e0bb9e 100644 --- a/unittests/ExecutionEngine/JIT/Makefile +++ b/unittests/ExecutionEngine/JIT/Makefile @@ -35,8 +35,15 @@ ifeq ($(USE_OPROFILE), 1) LINK_COMPONENTS += oprofilejit endif +EXPORTED_SYMBOL_FILE = $(PROJ_OBJ_DIR)/JITTests.exports include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest # Permit these tests to use the JIT's symbolic lookup. LD.Flags += $(RDYNAMIC) + +# Symbol exports are necessary (at least for now) when building with LTO. +$(LLVMUnitTestExe): $(NativeExportsFile) +$(PROJ_OBJ_DIR)/JITTests.exports: $(PROJ_SRC_DIR)/JITTests.def $(PROJ_OBJ_DIR)/.dir + tail -n +2 $< > $@ + diff --git a/unittests/ExecutionEngine/JIT/MultiJITTest.cpp b/unittests/ExecutionEngine/JIT/MultiJITTest.cpp index 5b99d5b..4a22e2f 100644 --- a/unittests/ExecutionEngine/JIT/MultiJITTest.cpp +++ b/unittests/ExecutionEngine/JIT/MultiJITTest.cpp @@ -65,8 +65,8 @@ void createModule2(LLVMContext &Context2, Module *&M2, Function *&FooF2) { FooF2 = M2->getFunction("foo2"); } -// ARM tests disabled pending fix for PR10783. -#if !defined(__arm__) +// ARM and PowerPC tests disabled pending fix for PR10783. +#if !defined(__arm__) && !defined(__powerpc__) TEST(MultiJitTest, EagerMode) { LLVMContext Context1; @@ -176,6 +176,6 @@ TEST(MultiJitTest, JitPool) { #endif EXPECT_TRUE(sa == fa); } -#endif // !defined(__arm__) +#endif // !defined(__arm__) && !defined(__powerpc__) } // anonymous namespace diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt new file mode 100644 index 0000000..3e9c5b6 --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_LINK_COMPONENTS + asmparser + bitreader + bitwriter + mcjit + jit + nativecodegen + ) + +set(MCJITTestsSources + MCJITTest.cpp + SectionMemoryManager.cpp + ) + +if(MSVC) + list(APPEND MCJITTestsSources MCJITTests.def) +endif() + +add_llvm_unittest(MCJITTests + ${MCJITTestsSources} + ) + +if(MINGW OR CYGWIN) + set_property(TARGET MCJITTests PROPERTY LINK_FLAGS -Wl,--export-all-symbols) +endif() diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp new file mode 100644 index 0000000..6b79a68 --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITTest.cpp @@ -0,0 +1,231 @@ +//===- MCJITTest.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 basic MCJIT functionality such as making function +// calls, using global variables, and compiling multpile modules. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/MCJIT.h" +#include "MCJITTestBase.h" +#include "SectionMemoryManager.h" +#include "gtest/gtest.h" + +using namespace llvm; + +class MCJITTest : public testing::Test, public MCJITTestBase { +protected: + + virtual void SetUp() { + M.reset(createEmptyModule("<main>")); + } +}; + +namespace { + +// 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. +/* +TEST_F(MCJITTest, empty_module) { + createJIT(M.take()); + //EXPECT_NE(0, TheJIT->getObjectImage()) + // << "Unable to generate executable loaded object image"; +} +*/ + +TEST_F(MCJITTest, global_variable) { + SKIP_UNSUPPORTED_PLATFORM; + + int initialValue = 5; + GlobalValue *Global = insertGlobalInt32(M.get(), "test_global", initialValue); + createJIT(M.take()); + void *globalPtr = TheJIT->getPointerToGlobal(Global); + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + EXPECT_TRUE(0 != globalPtr) + << "Unable to get pointer to global value from JIT"; + + EXPECT_EQ(initialValue, *(int32_t*)globalPtr) + << "Unexpected initial value of global"; +} + +TEST_F(MCJITTest, add_function) { + SKIP_UNSUPPORTED_PLATFORM; + + Function *F = insertAddFunction(M.get()); + createJIT(M.take()); + void *addPtr = TheJIT->getPointerToFunction(F); + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + 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)); +} + +TEST_F(MCJITTest, run_main) { + SKIP_UNSUPPORTED_PLATFORM; + + int rc = 6; + Function *Main = insertMainFunction(M.get(), 6); + createJIT(M.take()); + void *vPtr = TheJIT->getPointerToFunction(Main); + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + EXPECT_TRUE(0 != vPtr) + << "Unable to get pointer to main() from JIT"; + + int (*FuncPtr)(void) = (int(*)(void))(intptr_t)vPtr; + int returnCode = FuncPtr(); + EXPECT_EQ(returnCode, rc); +} + +TEST_F(MCJITTest, return_global) { + SKIP_UNSUPPORTED_PLATFORM; + + int32_t initialNum = 7; + GlobalVariable *GV = insertGlobalInt32(M.get(), "myglob", initialNum); + + Function *ReturnGlobal = startFunction<int32_t(void)>(M.get(), + "ReturnGlobal"); + Value *ReadGlobal = Builder.CreateLoad(GV); + endFunctionWithRet(ReturnGlobal, ReadGlobal); + + createJIT(M.take()); + void *rgvPtr = TheJIT->getPointerToFunction(ReturnGlobal); + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + EXPECT_TRUE(0 != rgvPtr); + + int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)rgvPtr; + EXPECT_EQ(initialNum, FuncPtr()) + << "Invalid value for global returned from JITted function"; +} + +// FIXME: This case fails due to a bug with getPointerToGlobal(). +// The bug is due to MCJIT not having an implementation of getPointerToGlobal() +// which results in falling back on the ExecutionEngine implementation that +// allocates a new memory block for the global instead of using the same +// global variable that is emitted by MCJIT. Hence, the pointer (gvPtr below) +// has the correct initial value, but updates to the real global (accessed by +// JITted code) are not propagated. Instead, getPointerToGlobal() should return +// a pointer into the loaded ObjectImage to reference the emitted global. +/* +TEST_F(MCJITTest, increment_global) { + SKIP_UNSUPPORTED_PLATFORM; + + int32_t initialNum = 5; + Function *IncrementGlobal = startFunction<int32_t(void)>(M.get(), "IncrementGlobal"); + GlobalVariable *GV = insertGlobalInt32(M.get(), "my_global", initialNum); + Value *DerefGV = Builder.CreateLoad(GV); + Value *AddResult = Builder.CreateAdd(DerefGV, + ConstantInt::get(Context, APInt(32, 1))); + Builder.CreateStore(AddResult, GV); + endFunctionWithRet(IncrementGlobal, AddResult); + + createJIT(M.take()); + void *gvPtr = TheJIT->getPointerToGlobal(GV); + EXPECT_EQ(initialNum, *(int32_t*)gvPtr); + + void *vPtr = TheJIT->getPointerToFunction(IncrementGlobal); + EXPECT_TRUE(0 != vPtr) + << "Unable to get pointer to main() from JIT"; + + int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr; + + for(int i = 1; i < 3; ++i) { + int32_t result = FuncPtr(); + EXPECT_EQ(initialNum + i, result); // OK + EXPECT_EQ(initialNum + i, *(int32_t*)gvPtr); // FAILS + } +} +*/ + +TEST_F(MCJITTest, multiple_functions) { + SKIP_UNSUPPORTED_PLATFORM; + + unsigned int numLevels = 23; + int32_t innerRetVal= 5; + + Function *Inner = startFunction<int32_t(void)>(M.get(), "Inner"); + endFunctionWithRet(Inner, ConstantInt::get(Context, APInt(32, innerRetVal))); + + Function *Outer; + for (unsigned int i = 0; i < numLevels; ++i) { + std::stringstream funcName; + funcName << "level_" << i; + Outer = startFunction<int32_t(void)>(M.get(), funcName.str()); + Value *innerResult = Builder.CreateCall(Inner); + endFunctionWithRet(Outer, innerResult); + + Inner = Outer; + } + + createJIT(M.take()); + void *vPtr = TheJIT->getPointerToFunction(Outer); + static_cast<SectionMemoryManager*>(MM)->invalidateInstructionCache(); + EXPECT_TRUE(0 != vPtr) + << "Unable to get pointer to outer function from JIT"; + + int32_t(*FuncPtr)(void) = (int32_t(*)(void))(intptr_t)vPtr; + EXPECT_EQ(innerRetVal, FuncPtr()) + << "Incorrect result returned from function"; +} + +// 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); + 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 new file mode 100644 index 0000000..9b4a4ac --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITTestBase.h @@ -0,0 +1,245 @@ +//===- MCJITTestBase.h - Common base class for MCJIT Unit tests ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements common functionality required by the MCJIT unit tests, +// as well as logic to skip tests on unsupported architectures and operating +// systems. +// +//===----------------------------------------------------------------------===// + + +#ifndef MCJIT_TEST_BASE_H +#define MCJIT_TEST_BASE_H + +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Function.h" +#include "llvm/IRBuilder.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/TypeBuilder.h" + +#include "SectionMemoryManager.h" + +// Used to skip tests on unsupported architectures and operating systems. +// To skip a test, add this macro at the top of a test-case in a suite that +// inherits from MCJITTestBase. See MCJITTest.cpp for examples. +#define SKIP_UNSUPPORTED_PLATFORM \ + do \ + if (!ArchSupportsMCJIT() || !OSSupportsMCJIT()) \ + return; \ + while(0); + +namespace llvm { + +class MCJITTestBase { +protected: + + MCJITTestBase() + : OptLevel(CodeGenOpt::None) + , RelocModel(Reloc::Default) + , CodeModel(CodeModel::Default) + , MArch("") + , Builder(Context) + , MM(new SectionMemoryManager) + , HostTriple(LLVM_HOSTTRIPLE) + { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + +#ifdef LLVM_ON_WIN32 + // On Windows, generate ELF objects by specifying "-elf" in triple + HostTriple += "-elf"; +#endif // LLVM_ON_WIN32 + HostTriple = Triple::normalize(HostTriple); + + // The architectures below are known to be compatible with MCJIT as they + // are copied from test/ExecutionEngine/MCJIT/lit.local.cfg and should be + // kept in sync. + SupportedArchs.push_back(Triple::arm); + SupportedArchs.push_back(Triple::mips); + SupportedArchs.push_back(Triple::x86); + SupportedArchs.push_back(Triple::x86_64); + + // The operating systems below are known to be incompatible with MCJIT as + // they are copied from the test/ExecutionEngine/MCJIT/lit.local.cfg and + // should be kept in sync. + UnsupportedOSs.push_back(Triple::Cygwin); + UnsupportedOSs.push_back(Triple::Darwin); + } + + /// Returns true if the host architecture is known to support MCJIT + bool ArchSupportsMCJIT() { + Triple Host(HostTriple); + if (std::find(SupportedArchs.begin(), SupportedArchs.end(), Host.getArch()) + == SupportedArchs.end()) { + return false; + } + return true; + } + + /// Returns true if the host OS is known to support MCJIT + bool OSSupportsMCJIT() { + Triple Host(HostTriple); + if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS()) + == UnsupportedOSs.end()) { + return true; + } + return false; + } + + Module *createEmptyModule(StringRef Name) { + Module * M = new Module(Name, Context); + M->setTargetTriple(Triple::normalize(HostTriple)); + return M; + } + + template<typename FuncType> + Function *startFunction(Module *M, StringRef Name) { + Function *Result = Function::Create( + TypeBuilder<FuncType, false>::get(Context), + GlobalValue::ExternalLinkage, Name, M); + + BasicBlock *BB = BasicBlock::Create(Context, Name, Result); + Builder.SetInsertPoint(BB); + + return Result; + } + + void endFunctionWithRet(Function *Func, Value *RetValue) { + Builder.CreateRet(RetValue); + } + + // Inserts a simple function that invokes Callee and takes the same arguments: + // int Caller(...) { return Callee(...); } + template<typename Signature> + Function *insertSimpleCallFunction(Module *M, Function *Callee) { + Function *Result = startFunction<Signature>(M, "caller"); + + SmallVector<Value*, 1> CallArgs; + + Function::arg_iterator arg_iter = Result->arg_begin(); + for(;arg_iter != Result->arg_end(); ++arg_iter) + CallArgs.push_back(arg_iter); + + Value *ReturnCode = Builder.CreateCall(Callee, CallArgs); + Builder.CreateRet(ReturnCode); + return Result; + } + + // Inserts a function named 'main' that returns a uint32_t: + // int32_t main() { return X; } + // where X is given by returnCode + Function *insertMainFunction(Module *M, uint32_t returnCode) { + Function *Result = startFunction<int32_t(void)>(M, "main"); + + Value *ReturnVal = ConstantInt::get(Context, APInt(32, returnCode)); + endFunctionWithRet(Result, ReturnVal); + + return Result; + } + + // Inserts a function + // int32_t add(int32_t a, int32_t b) { return a + b; } + // in the current module and returns a pointer to it. + Function *insertAddFunction(Module *M, StringRef Name = "add") { + Function *Result = startFunction<int32_t(int32_t, int32_t)>(M, Name); + + Function::arg_iterator args = Result->arg_begin(); + Value *Arg1 = args; + Value *Arg2 = ++args; + Value *AddResult = Builder.CreateAdd(Arg1, Arg2); + + endFunctionWithRet(Result, AddResult); + + return Result; + } + + // Inserts an declaration to a function defined elsewhere + Function *insertExternalReferenceToFunction(Module *M, StringRef Name, + FunctionType *FuncTy) { + Function *Result = Function::Create(FuncTy, + GlobalValue::ExternalLinkage, + Name, M); + return Result; + } + + // Inserts an declaration to a function defined elsewhere + Function *insertExternalReferenceToFunction(Module *M, Function *Func) { + Function *Result = Function::Create(Func->getFunctionType(), + GlobalValue::AvailableExternallyLinkage, + Func->getName(), M); + return Result; + } + + // Inserts a global variable of type int32 + GlobalVariable *insertGlobalInt32(Module *M, + StringRef name, + int32_t InitialValue) { + Type *GlobalTy = TypeBuilder<types::i<32>, true>::get(Context); + Constant *IV = ConstantInt::get(Context, APInt(32, InitialValue)); + GlobalVariable *Global = new GlobalVariable(*M, + GlobalTy, + false, + GlobalValue::ExternalLinkage, + IV, + name); + return Global; + } + + void createJIT(Module *M) { + + // Due to the EngineBuilder constructor, it is required to have a Module + // in order to construct an ExecutionEngine (i.e. MCJIT) + assert(M != 0 && "a non-null Module must be provided to create MCJIT"); + + EngineBuilder EB(M); + std::string Error; + TheJIT.reset(EB.setEngineKind(EngineKind::JIT) + .setUseMCJIT(true) /* can this be folded into the EngineKind enum? */ + .setJITMemoryManager(MM) + .setErrorStr(&Error) + .setOptLevel(CodeGenOpt::None) + .setAllocateGVsWithCode(false) /*does this do anything?*/ + .setCodeModel(CodeModel::JITDefault) + .setRelocationModel(Reloc::Default) + .setMArch(MArch) + .setMCPU(sys::getHostCPUName()) + //.setMAttrs(MAttrs) + .create()); + // At this point, we cannot modify the module any more. + assert(TheJIT.get() != NULL && "error creating MCJIT with EngineBuilder"); + } + + LLVMContext Context; + CodeGenOpt::Level OptLevel; + Reloc::Model RelocModel; + CodeModel::Model CodeModel; + StringRef MArch; + SmallVector<std::string, 1> MAttrs; + OwningPtr<TargetMachine> TM; + OwningPtr<ExecutionEngine> TheJIT; + IRBuilder<> Builder; + JITMemoryManager *MM; + + std::string HostTriple; + SmallVector<Triple::ArchType, 4> SupportedArchs; + SmallVector<Triple::OSType, 4> UnsupportedOSs; + + OwningPtr<Module> M; +}; + +} // namespace llvm + +#endif // MCJIT_TEST_H diff --git a/unittests/ExecutionEngine/MCJIT/MCJITTests.def b/unittests/ExecutionEngine/MCJIT/MCJITTests.def new file mode 100644 index 0000000..aabd224 --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/MCJITTests.def @@ -0,0 +1 @@ +EXPORTS diff --git a/unittests/ExecutionEngine/MCJIT/Makefile b/unittests/ExecutionEngine/MCJIT/Makefile new file mode 100644 index 0000000..454f830 --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/Makefile @@ -0,0 +1,18 @@ +##===- unittests/ExecutionEngine/MCJIT/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 = MCJIT +LINK_COMPONENTS := core jit mcjit native support + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest + +# Permit these tests to use the MCJIT's symbolic lookup. +LD.Flags += $(RDYNAMIC) diff --git a/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.cpp b/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.cpp new file mode 100644 index 0000000..d6baf3c --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.cpp @@ -0,0 +1,143 @@ +//===-- SectionMemoryManager.cpp - The memory manager for MCJIT -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the implementation of the section-based memory manager +// used by MCJIT. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/MathExtras.h" + +#include "SectionMemoryManager.h" + +#ifdef __linux__ +// These includes used by SectionMemoryManager::getPointerToNamedFunction() +// for Glibc trickery. Look comments in this function for more information. +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#include <fcntl.h> +#include <unistd.h> +#endif + +namespace llvm { + +uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID) { + if (!Alignment) + Alignment = 16; + // Ensure that enough memory is requested to allow aligning. + size_t NumElementsAligned = 1 + (Size + Alignment - 1)/Alignment; + uint8_t *Addr = (uint8_t*)calloc(NumElementsAligned, Alignment); + + // Honour the alignment requirement. + uint8_t *AlignedAddr = (uint8_t*)RoundUpToAlignment((uint64_t)Addr, Alignment); + + // Store the original address from calloc so we can free it later. + AllocatedDataMem.push_back(sys::MemoryBlock(Addr, NumElementsAligned*Alignment)); + return AlignedAddr; +} + +uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID) { + if (!Alignment) + Alignment = 16; + unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1); + uintptr_t Addr = 0; + // Look in the list of free code memory regions and use a block there if one + // is available. + for (int i = 0, e = FreeCodeMem.size(); i != e; ++i) { + sys::MemoryBlock &MB = FreeCodeMem[i]; + if (MB.size() >= NeedAllocate) { + Addr = (uintptr_t)MB.base(); + uintptr_t EndOfBlock = Addr + MB.size(); + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + // Store cutted free memory block. + FreeCodeMem[i] = sys::MemoryBlock((void*)(Addr + Size), + EndOfBlock - Addr - Size); + return (uint8_t*)Addr; + } + } + + // No pre-allocated free block was large enough. Allocate a new memory region. + sys::MemoryBlock MB = sys::Memory::AllocateRWX(NeedAllocate, 0, 0); + + AllocatedCodeMem.push_back(MB); + Addr = (uintptr_t)MB.base(); + uintptr_t EndOfBlock = Addr + MB.size(); + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + // The AllocateRWX may allocate much more memory than we need. In this case, + // we store the unused memory as a free memory block. + unsigned FreeSize = EndOfBlock-Addr-Size; + if (FreeSize > 16) + FreeCodeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); + + // Return aligned address + return (uint8_t*)Addr; +} + +void SectionMemoryManager::invalidateInstructionCache() { + for (int i = 0, e = AllocatedCodeMem.size(); i != e; ++i) + sys::Memory::InvalidateInstructionCache(AllocatedCodeMem[i].base(), + AllocatedCodeMem[i].size()); +} + +void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { +#if defined(__linux__) + //===--------------------------------------------------------------------===// + // Function stubs that are invoked instead of certain library calls + // + // Force the following functions to be linked in to anything that uses the + // JIT. This is a hack designed to work around the all-too-clever Glibc + // strategy of making these functions work differently when inlined vs. when + // not inlined, and hiding their real definitions in a separate archive file + // that the dynamic linker can't see. For more info, search for + // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274. + if (Name == "stat") return (void*)(intptr_t)&stat; + if (Name == "fstat") return (void*)(intptr_t)&fstat; + if (Name == "lstat") return (void*)(intptr_t)&lstat; + if (Name == "stat64") return (void*)(intptr_t)&stat64; + if (Name == "fstat64") return (void*)(intptr_t)&fstat64; + if (Name == "lstat64") return (void*)(intptr_t)&lstat64; + if (Name == "atexit") return (void*)(intptr_t)&atexit; + if (Name == "mknod") return (void*)(intptr_t)&mknod; +#endif // __linux__ + + const char *NameStr = Name.c_str(); + void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); + if (Ptr) return Ptr; + + // If it wasn't found and if it starts with an underscore ('_') character, + // try again without the underscore. + if (NameStr[0] == '_') { + Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1); + if (Ptr) return Ptr; + } + + if (AbortOnFailure) + report_fatal_error("Program used external function '" + Name + + "' which could not be resolved!"); + return 0; +} + +SectionMemoryManager::~SectionMemoryManager() { + for (unsigned i = 0, e = AllocatedCodeMem.size(); i != e; ++i) + sys::Memory::ReleaseRWX(AllocatedCodeMem[i]); + for (unsigned i = 0, e = AllocatedDataMem.size(); i != e; ++i) + free(AllocatedDataMem[i].base()); +} + +} // namespace llvm diff --git a/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.h b/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.h new file mode 100644 index 0000000..e44217c --- /dev/null +++ b/unittests/ExecutionEngine/MCJIT/SectionMemoryManager.h @@ -0,0 +1,118 @@ +//===-- SectionMemoryManager.h - Memory allocator for MCJIT -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of a section-based memory manager used by +// the MCJIT execution engine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTION_ENGINE_SECTION_MEMORY_MANAGER_H +#define LLVM_EXECUTION_ENGINE_SECTION_MEMORY_MANAGER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Memory.h" + +namespace llvm { + +// Section-based memory manager for MCJIT +class SectionMemoryManager : public JITMemoryManager { + +public: + + SectionMemoryManager() { } + ~SectionMemoryManager(); + + virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID); + + virtual void *getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure = true); + + // Invalidate instruction cache for code sections. Some platforms with + // separate data cache and instruction cache require explicit cache flush, + // otherwise JIT code manipulations (like resolved relocations) will get to + // the data cache but not to the instruction cache. + virtual void invalidateInstructionCache(); + +private: + + SmallVector<sys::MemoryBlock, 16> AllocatedDataMem; + SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem; + SmallVector<sys::MemoryBlock, 16> FreeCodeMem; + +public: + + /// + /// Functions below are not used by MCJIT, but must be implemented because + /// they are declared as pure virtuals in the base class. + /// + + virtual void setMemoryWritable() { + llvm_unreachable("Unexpected call!"); + } + virtual void setMemoryExecutable() { + llvm_unreachable("Unexpected call!"); + } + virtual void setPoisonMemory(bool poison) { + llvm_unreachable("Unexpected call!"); + } + virtual void AllocateGOT() { + llvm_unreachable("Unexpected call!"); + } + virtual uint8_t *getGOTBase() const { + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual uint8_t *startFunctionBody(const Function *F, + uintptr_t &ActualSize){ + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment) { + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + llvm_unreachable("Unexpected call!"); + } + virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual void deallocateFunctionBody(void *Body) { + llvm_unreachable("Unexpected call!"); + } + virtual uint8_t *startExceptionTable(const Function *F, + uintptr_t &ActualSize) { + llvm_unreachable("Unexpected call!"); + return 0; + } + virtual void endExceptionTable(const Function *F, uint8_t *TableStart, + uint8_t *TableEnd, uint8_t *FrameRegister) { + llvm_unreachable("Unexpected call!"); + } + virtual void deallocateExceptionTable(void *ET) { + llvm_unreachable("Unexpected call!"); + } +}; + +} + +#endif // LLVM_EXECUTION_ENGINE_SECTION_MEMORY_MANAGER_H diff --git a/unittests/ExecutionEngine/Makefile b/unittests/ExecutionEngine/Makefile index 63508d2..ca11956 100644 --- a/unittests/ExecutionEngine/Makefile +++ b/unittests/ExecutionEngine/Makefile @@ -10,7 +10,7 @@ LEVEL = ../.. TESTNAME = ExecutionEngine LINK_COMPONENTS :=interpreter -PARALLEL_DIRS = JIT +PARALLEL_DIRS = JIT MCJIT include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/unittests/Support/AlignOfTest.cpp b/unittests/Support/AlignOfTest.cpp index 6f57668..f01e660 100644 --- a/unittests/Support/AlignOfTest.cpp +++ b/unittests/Support/AlignOfTest.cpp @@ -1,4 +1,4 @@ -//===- llvm/unittest/Support/AlignOfTest.cpp - Alignment utility tests ----===// +//=== - llvm/unittest/Support/AlignOfTest.cpp - Alignment utility tests ----===// // // The LLVM Compiler Infrastructure // @@ -23,31 +23,25 @@ namespace { #endif // Define some fixed alignment types to use in these tests. -#if __cplusplus == 201103L || __has_feature(cxx_alignas) -typedef char alignas(1) A1; -typedef char alignas(2) A2; -typedef char alignas(4) A4; -typedef char alignas(8) A8; -#elif defined(__clang__) || defined(__GNUC__) -typedef char A1 __attribute__((aligned(1))); -typedef char A2 __attribute__((aligned(2))); -typedef char A4 __attribute__((aligned(4))); -typedef char A8 __attribute__((aligned(8))); +#if __has_feature(cxx_alignas) +struct alignas(1) A1 { }; +struct alignas(2) A2 { }; +struct alignas(4) A4 { }; +struct alignas(8) A8 { }; +#elif defined(__GNUC__) +struct A1 { } __attribute__((aligned(1))); +struct A2 { } __attribute__((aligned(2))); +struct A4 { } __attribute__((aligned(4))); +struct A8 { } __attribute__((aligned(8))); #elif defined(_MSC_VER) -typedef __declspec(align(1)) char A1; -typedef __declspec(align(2)) char A2; -typedef __declspec(align(4)) char A4; -typedef __declspec(align(8)) char A8; +__declspec(align(1)) struct A1 { }; +__declspec(align(2)) struct A2 { }; +__declspec(align(4)) struct A4 { }; +__declspec(align(8)) struct A8 { }; #else # error No supported align as directive. #endif -// Wrap the forced aligned types in structs to hack around compiler bugs. -struct SA1 { A1 a; }; -struct SA2 { A2 a; }; -struct SA4 { A4 a; }; -struct SA8 { A8 a; }; - struct S1 {}; struct S2 { char a; }; struct S3 { int x; }; @@ -72,6 +66,17 @@ struct V6 : S1 { virtual ~V6(); }; struct V7 : virtual V2, virtual V6 { virtual ~V7(); }; struct V8 : V5, virtual V6, V7 { double zz; virtual ~V8(); }; +double S6::f() { return 0.0; } +float D2::g() { return 0.0f; } +V1::~V1() {} +V2::~V2() {} +V3::~V3() {} +V4::~V4() {} +V5::~V5() {} +V6::~V6() {} +V7::~V7() {} +V8::~V8() {} + // Ensure alignment is a compile-time constant. char LLVM_ATTRIBUTE_UNUSED test_arr1 [AlignOf<char>::Alignment > 0] @@ -90,11 +95,7 @@ char LLVM_ATTRIBUTE_UNUSED test_arr2 [AlignOf<A1>::Alignment > 0] [AlignOf<A2>::Alignment > 0] [AlignOf<A4>::Alignment > 0] - [AlignOf<A8>::Alignment > 0] - [AlignOf<SA1>::Alignment > 0] - [AlignOf<SA2>::Alignment > 0] - [AlignOf<SA4>::Alignment > 0] - [AlignOf<SA8>::Alignment > 0]; + [AlignOf<A8>::Alignment > 0]; char LLVM_ATTRIBUTE_UNUSED test_arr3 [AlignOf<S1>::Alignment > 0] [AlignOf<S2>::Alignment > 0] @@ -123,20 +124,10 @@ char LLVM_ATTRIBUTE_UNUSED test_arr5 [AlignOf<V8>::Alignment > 0]; TEST(AlignOfTest, BasicAlignmentInvariants) { - // For a very strange reason, many compilers do not support this. Both Clang - // and GCC fail to align these properly. - EXPECT_EQ(1u, alignOf<A1>()); -#if 0 - EXPECT_EQ(2u, alignOf<A2>()); - EXPECT_EQ(4u, alignOf<A4>()); - EXPECT_EQ(8u, alignOf<A8>()); -#endif - - // But once wrapped in structs, the alignment is correctly managed. - EXPECT_LE(1u, alignOf<SA1>()); - EXPECT_LE(2u, alignOf<SA2>()); - EXPECT_LE(4u, alignOf<SA4>()); - EXPECT_LE(8u, alignOf<SA8>()); + EXPECT_LE(1u, alignOf<A1>()); + EXPECT_LE(2u, alignOf<A2>()); + EXPECT_LE(4u, alignOf<A4>()); + EXPECT_LE(8u, alignOf<A8>()); EXPECT_EQ(1u, alignOf<char>()); EXPECT_LE(alignOf<char>(), alignOf<short>()); @@ -174,42 +165,38 @@ TEST(AlignOfTest, BasicAlignmentInvariants) { } TEST(AlignOfTest, BasicAlignedArray) { - // Note: this code exclusively uses the struct-wrapped arbitrarily aligned - // types because of the bugs mentioned above where GCC and Clang both - // disregard the arbitrary alignment specifier until the type is used to - // declare a member of a struct. - EXPECT_LE(1u, alignOf<AlignedCharArrayUnion<SA1> >()); - EXPECT_LE(2u, alignOf<AlignedCharArrayUnion<SA2> >()); - EXPECT_LE(4u, alignOf<AlignedCharArrayUnion<SA4> >()); - EXPECT_LE(8u, alignOf<AlignedCharArrayUnion<SA8> >()); + EXPECT_LE(1u, alignOf<AlignedCharArrayUnion<A1> >()); + EXPECT_LE(2u, alignOf<AlignedCharArrayUnion<A2> >()); + EXPECT_LE(4u, alignOf<AlignedCharArrayUnion<A4> >()); + EXPECT_LE(8u, alignOf<AlignedCharArrayUnion<A8> >()); - EXPECT_LE(1u, sizeof(AlignedCharArrayUnion<SA1>)); - EXPECT_LE(2u, sizeof(AlignedCharArrayUnion<SA2>)); - EXPECT_LE(4u, sizeof(AlignedCharArrayUnion<SA4>)); - EXPECT_LE(8u, sizeof(AlignedCharArrayUnion<SA8>)); + EXPECT_LE(1u, sizeof(AlignedCharArrayUnion<A1>)); + EXPECT_LE(2u, sizeof(AlignedCharArrayUnion<A2>)); + EXPECT_LE(4u, sizeof(AlignedCharArrayUnion<A4>)); + EXPECT_LE(8u, sizeof(AlignedCharArrayUnion<A8>)); - EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<SA1> >())); - EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<SA1, SA2> >())); - EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<SA1, SA2, SA4> >())); - EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<SA1, SA2, SA4, SA8> >())); + EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<A1> >())); + EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<A1, A2> >())); + EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<A1, A2, A4> >())); + EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<A1, A2, A4, A8> >())); - EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<SA1>)); - EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<SA1, SA2>)); - EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<SA1, SA2, SA4>)); - EXPECT_EQ(8u, sizeof(AlignedCharArrayUnion<SA1, SA2, SA4, SA8>)); + EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1>)); + EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1, A2>)); + EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<A1, A2, A4>)); + EXPECT_EQ(8u, sizeof(AlignedCharArrayUnion<A1, A2, A4, A8>)); - EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<SA1[1]> >())); - EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<SA1[2], SA2[1]> >())); - EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<SA1[42], SA2[55], - SA4[13]> >())); - EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<SA1[2], SA2[1], - SA4, SA8> >())); + EXPECT_EQ(1u, (alignOf<AlignedCharArrayUnion<A1[1]> >())); + EXPECT_EQ(2u, (alignOf<AlignedCharArrayUnion<A1[2], A2[1]> >())); + EXPECT_EQ(4u, (alignOf<AlignedCharArrayUnion<A1[42], A2[55], + A4[13]> >())); + EXPECT_EQ(8u, (alignOf<AlignedCharArrayUnion<A1[2], A2[1], + A4, A8> >())); - EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<SA1[1]>)); - EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<SA1[2], SA2[1]>)); - EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<SA1[3], SA2[2], SA4>)); - EXPECT_EQ(16u, sizeof(AlignedCharArrayUnion<SA1, SA2[3], - SA4[3], SA8>)); + EXPECT_EQ(1u, sizeof(AlignedCharArrayUnion<A1[1]>)); + EXPECT_EQ(2u, sizeof(AlignedCharArrayUnion<A1[2], A2[1]>)); + EXPECT_EQ(4u, sizeof(AlignedCharArrayUnion<A1[3], A2[2], A4>)); + EXPECT_EQ(16u, sizeof(AlignedCharArrayUnion<A1, A2[3], + A4[3], A8>)); // For other tests we simply assert that the alignment of the union mathes // that of the fundamental type and hope that we have any weird type diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index 3b9bf84..09a0ea5 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -17,11 +17,14 @@ add_llvm_unittest(SupportTests LeakDetectorTest.cpp ManagedStatic.cpp MathExtrasTest.cpp + MemoryBufferTest.cpp + MemoryTest.cpp Path.cpp - raw_ostream_test.cpp RegexTest.cpp SwapByteOrderTest.cpp TimeValue.cpp ValueHandleTest.cpp YAMLParserTest.cpp + formatted_raw_ostream_test.cpp + raw_ostream_test.cpp ) diff --git a/unittests/Support/Casting.cpp b/unittests/Support/Casting.cpp index ca0b40b..ad564aa 100644 --- a/unittests/Support/Casting.cpp +++ b/unittests/Support/Casting.cpp @@ -95,8 +95,9 @@ TEST(CastingTest, cast) { EXPECT_NE(&F5, null_foo); const foo *F6 = cast<foo>(B4); EXPECT_NE(F6, null_foo); - foo *F7 = cast<foo>(fub()); - EXPECT_EQ(F7, null_foo); + // Can't pass null pointer to cast<>. + // foo *F7 = cast<foo>(fub()); + // EXPECT_EQ(F7, null_foo); foo *F8 = B1.baz(); EXPECT_NE(F8, null_foo); } @@ -121,7 +122,8 @@ TEST(CastingTest, dyn_cast) { EXPECT_NE(F2, null_foo); const foo *F3 = dyn_cast<foo>(B4); EXPECT_NE(F3, null_foo); - // foo *F4 = dyn_cast<foo>(fub()); // not permittible + // Can't pass null pointer to dyn_cast<>. + // foo *F4 = dyn_cast<foo>(fub()); // EXPECT_EQ(F4, null_foo); foo *F5 = B1.daz(); EXPECT_NE(F5, null_foo); @@ -151,3 +153,54 @@ const bar *B2 = &B; } // anonymous namespace bar *llvm::fub() { return 0; } + +namespace { +namespace inferred_upcasting { +// This test case verifies correct behavior of inferred upcasts when the +// types are statically known to be OK to upcast. This is the case when, +// for example, Derived inherits from Base, and we do `isa<Base>(Derived)`. + +// Note: This test will actually fail to compile without inferred +// upcasting. + +class Base { +public: + // No classof. We are testing that the upcast is inferred. + Base() {} +}; + +class Derived : public Base { +public: + Derived() {} +}; + +// Even with no explicit classof() in Base, we should still be able to cast +// Derived to its base class. +TEST(CastingTest, UpcastIsInferred) { + Derived D; + EXPECT_TRUE(isa<Base>(D)); + Base *BP = dyn_cast<Base>(&D); + EXPECT_TRUE(BP != NULL); +} + + +// This test verifies that the inferred upcast takes precedence over an +// explicitly written one. This is important because it verifies that the +// dynamic check gets optimized away. +class UseInferredUpcast { +public: + int Dummy; + static bool classof(const UseInferredUpcast *) { + return false; + } +}; + +TEST(CastingTest, InferredUpcastTakesPrecedence) { + UseInferredUpcast UIU; + // Since the explicit classof() returns false, this will fail if the + // explicit one is used. + EXPECT_TRUE(isa<UseInferredUpcast>(&UIU)); +} + +} // end namespace inferred_upcasting +} // end anonymous namespace diff --git a/unittests/Support/DataExtractorTest.cpp b/unittests/Support/DataExtractorTest.cpp index 9813e46..ec8bd3d 100644 --- a/unittests/Support/DataExtractorTest.cpp +++ b/unittests/Support/DataExtractorTest.cpp @@ -16,6 +16,7 @@ namespace { const char numberData[] = "\x80\x90\xFF\xFF\x80\x00\x00\x00"; const char stringData[] = "hellohello\0hello"; const char leb128data[] = "\xA6\x49"; +const char bigleb128data[] = "\xAA\xA9\xFF\xAA\xFF\xAA\xFF\x4A"; TEST(DataExtractorTest, OffsetOverflow) { DataExtractor DE(StringRef(numberData, sizeof(numberData)-1), false, 8); @@ -106,6 +107,14 @@ TEST(DataExtractorTest, LEB128) { offset = 0; EXPECT_EQ(-7002LL, DE.getSLEB128(&offset)); EXPECT_EQ(2U, offset); + + DataExtractor BDE(StringRef(bigleb128data, sizeof(bigleb128data)-1), false,8); + offset = 0; + EXPECT_EQ(42218325750568106ULL, BDE.getULEB128(&offset)); + EXPECT_EQ(8U, offset); + offset = 0; + EXPECT_EQ(-29839268287359830LL, BDE.getSLEB128(&offset)); + EXPECT_EQ(8U, offset); } } diff --git a/unittests/Support/MemoryBufferTest.cpp b/unittests/Support/MemoryBufferTest.cpp new file mode 100644 index 0000000..6c78cd8 --- /dev/null +++ b/unittests/Support/MemoryBufferTest.cpp @@ -0,0 +1,99 @@ +//===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements unit tests for the MemoryBuffer support class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/OwningPtr.h" + +#include "gtest/gtest.h" + +using namespace llvm; + +class MemoryBufferTest : public testing::Test { +protected: + MemoryBufferTest() + : data("this is some data") + { } + + virtual void SetUp() { } + + typedef OwningPtr<MemoryBuffer> OwningBuffer; + + std::string data; +}; + +namespace { + +TEST_F(MemoryBufferTest, get) { + // Default name and null-terminator flag + OwningBuffer MB1(MemoryBuffer::getMemBuffer(data)); + EXPECT_TRUE(0 != MB1.get()); + + // RequiresNullTerminator = false + OwningBuffer MB2(MemoryBuffer::getMemBuffer(data, "one", false)); + EXPECT_TRUE(0 != MB2.get()); + + // RequiresNullTerminator = true + OwningBuffer MB3(MemoryBuffer::getMemBuffer(data, "two", true)); + EXPECT_TRUE(0 != MB3.get()); + + // verify all 3 buffers point to the same address + EXPECT_EQ(MB1->getBufferStart(), MB2->getBufferStart()); + EXPECT_EQ(MB2->getBufferStart(), MB3->getBufferStart()); + + // verify the original data is unmodified after deleting the buffers + MB1.reset(); + MB2.reset(); + MB3.reset(); + EXPECT_EQ("this is some data", data); +} + +TEST_F(MemoryBufferTest, copy) { + // copy with no name + OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data)); + EXPECT_TRUE(0 != MBC1.get()); + + // copy with a name + OwningBuffer MBC2(MemoryBuffer::getMemBufferCopy(data, "copy")); + EXPECT_TRUE(0 != MBC2.get()); + + // verify the two copies do not point to the same place + EXPECT_NE(MBC1->getBufferStart(), MBC2->getBufferStart()); +} + +TEST_F(MemoryBufferTest, make_new) { + // 0-sized buffer + OwningBuffer Zero(MemoryBuffer::getNewUninitMemBuffer(0)); + EXPECT_TRUE(0 != Zero.get()); + + // uninitialized buffer with no name + OwningBuffer One(MemoryBuffer::getNewUninitMemBuffer(321)); + EXPECT_TRUE(0 != One.get()); + + // uninitialized buffer with name + OwningBuffer Two(MemoryBuffer::getNewUninitMemBuffer(123, "bla")); + EXPECT_TRUE(0 != Two.get()); + + // 0-initialized buffer with no name + OwningBuffer Three(MemoryBuffer::getNewMemBuffer(321, data)); + EXPECT_TRUE(0 != Three.get()); + for (size_t i = 0; i < 321; ++i) + EXPECT_EQ(0, Three->getBufferStart()[0]); + + // 0-initialized buffer with name + OwningBuffer Four(MemoryBuffer::getNewMemBuffer(123, "zeros")); + EXPECT_TRUE(0 != Four.get()); + for (size_t i = 0; i < 123; ++i) + EXPECT_EQ(0, Four->getBufferStart()[0]); +} + +} diff --git a/unittests/Support/MemoryTest.cpp b/unittests/Support/MemoryTest.cpp new file mode 100644 index 0000000..21cb27e --- /dev/null +++ b/unittests/Support/MemoryTest.cpp @@ -0,0 +1,356 @@ +//===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator 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/Memory.h"
+#include "llvm/Support/Process.h"
+
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+using namespace llvm;
+using namespace sys;
+
+namespace {
+
+class MappedMemoryTest : public ::testing::TestWithParam<unsigned> {
+public:
+ MappedMemoryTest() {
+ Flags = GetParam();
+ PageSize = sys::Process::GetPageSize();
+ }
+
+protected:
+ // Adds RW flags to permit testing of the resulting memory
+ unsigned getTestableEquivalent(unsigned RequestedFlags) {
+ switch (RequestedFlags) {
+ case Memory::MF_READ:
+ case Memory::MF_WRITE:
+ case Memory::MF_READ|Memory::MF_WRITE:
+ return Memory::MF_READ|Memory::MF_WRITE;
+ case Memory::MF_READ|Memory::MF_EXEC:
+ case Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC:
+ case Memory::MF_EXEC:
+ return Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC;
+ }
+ // Default in case values are added to the enum, as required by some compilers
+ return Memory::MF_READ|Memory::MF_WRITE;
+ }
+
+ // Returns true if the memory blocks overlap
+ bool doesOverlap(MemoryBlock M1, MemoryBlock M2) {
+ if (M1.base() == M2.base())
+ return true;
+
+ if (M1.base() > M2.base())
+ return (unsigned char *)M2.base() + M2.size() > M1.base();
+
+ return (unsigned char *)M1.base() + M1.size() > M2.base();
+ }
+
+ unsigned Flags;
+ size_t PageSize;
+};
+
+TEST_P(MappedMemoryTest, AllocAndRelease) {
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+TEST_P(MappedMemoryTest, MultipleAllocAndRelease) {
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ MemoryBlock M4 = Memory::allocateMappedMemory(16, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ EXPECT_NE((void*)0, M4.base());
+ EXPECT_LE(16U, M4.size());
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, BasicWrite) {
+ // This test applies only to writeable combinations
+ if (Flags && !(Flags & Memory::MF_WRITE))
+ return;
+
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ int *a = (int*)M1.base();
+ *a = 1;
+ EXPECT_EQ(1, *a);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+TEST_P(MappedMemoryTest, MultipleWrite) {
+ // This test applies only to writeable combinations
+ if (Flags && !(Flags & Memory::MF_WRITE))
+ return;
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(1U * sizeof(int), M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(8U * sizeof(int), M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(4U * sizeof(int), M3.size());
+
+ int *x = (int*)M1.base();
+ *x = 1;
+
+ int *y = (int*)M2.base();
+ for (int i = 0; i < 8; i++) {
+ y[i] = i;
+ }
+
+ int *z = (int*)M3.base();
+ *z = 42;
+
+ EXPECT_EQ(1, *x);
+ EXPECT_EQ(7, y[7]);
+ EXPECT_EQ(42, *z);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+
+ MemoryBlock M4 = Memory::allocateMappedMemory(64 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ EXPECT_NE((void*)0, M4.base());
+ EXPECT_LE(64U * sizeof(int), M4.size());
+ x = (int*)M4.base();
+ *x = 4;
+ EXPECT_EQ(4, *x);
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+
+ // Verify that M2 remains unaffected by other activity
+ for (int i = 0; i < 8; i++) {
+ EXPECT_EQ(i, y[i]);
+ }
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, EnabledWrite) {
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(2 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(8 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(4 * sizeof(int), 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(2U * sizeof(int), M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(8U * sizeof(int), M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(4U * sizeof(int), M3.size());
+
+ EXPECT_FALSE(Memory::protectMappedMemory(M1, getTestableEquivalent(Flags)));
+ EXPECT_FALSE(Memory::protectMappedMemory(M2, getTestableEquivalent(Flags)));
+ EXPECT_FALSE(Memory::protectMappedMemory(M3, getTestableEquivalent(Flags)));
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ int *x = (int*)M1.base();
+ *x = 1;
+ int *y = (int*)M2.base();
+ for (unsigned int i = 0; i < 8; i++) {
+ y[i] = i;
+ }
+ int *z = (int*)M3.base();
+ *z = 42;
+
+ EXPECT_EQ(1, *x);
+ EXPECT_EQ(7, y[7]);
+ EXPECT_EQ(42, *z);
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_EQ(6, y[6]);
+
+ MemoryBlock M4 = Memory::allocateMappedMemory(16, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ EXPECT_NE((void*)0, M4.base());
+ EXPECT_LE(16U, M4.size());
+ EXPECT_EQ(error_code::success(), Memory::protectMappedMemory(M4, getTestableEquivalent(Flags)));
+ x = (int*)M4.base();
+ *x = 4;
+ EXPECT_EQ(4, *x);
+ EXPECT_FALSE(Memory::releaseMappedMemory(M4));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, SuccessiveNear) {
+ error_code EC;
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, 0, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &M1, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &M2, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, DuplicateNear) {
+ error_code EC;
+ MemoryBlock Near((void*)(3*PageSize), 16);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, ZeroNear) {
+ error_code EC;
+ MemoryBlock Near(0, 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, ZeroSizeNear) {
+ error_code EC;
+ MemoryBlock Near((void*)(4*PageSize), 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(16, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M2 = Memory::allocateMappedMemory(64, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+ MemoryBlock M3 = Memory::allocateMappedMemory(32, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(16U, M1.size());
+ EXPECT_NE((void*)0, M2.base());
+ EXPECT_LE(64U, M2.size());
+ EXPECT_NE((void*)0, M3.base());
+ EXPECT_LE(32U, M3.size());
+
+ EXPECT_FALSE(doesOverlap(M1, M2));
+ EXPECT_FALSE(doesOverlap(M2, M3));
+ EXPECT_FALSE(doesOverlap(M1, M3));
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M3));
+ EXPECT_FALSE(Memory::releaseMappedMemory(M2));
+}
+
+TEST_P(MappedMemoryTest, UnalignedNear) {
+ error_code EC;
+ MemoryBlock Near((void*)(2*PageSize+5), 0);
+ MemoryBlock M1 = Memory::allocateMappedMemory(15, &Near, Flags, EC);
+ EXPECT_EQ(error_code::success(), EC);
+
+ EXPECT_NE((void*)0, M1.base());
+ EXPECT_LE(sizeof(int), M1.size());
+
+ EXPECT_FALSE(Memory::releaseMappedMemory(M1));
+}
+
+// Note that Memory::MF_WRITE is not supported exclusively across
+// operating systems and architectures and can imply MF_READ|MF_WRITE
+unsigned MemoryFlags[] = {
+ Memory::MF_READ,
+ Memory::MF_WRITE,
+ Memory::MF_READ|Memory::MF_WRITE,
+ Memory::MF_EXEC,
+ Memory::MF_READ|Memory::MF_EXEC,
+ Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC
+ };
+
+INSTANTIATE_TEST_CASE_P(AllocationTests,
+ MappedMemoryTest,
+ ::testing::ValuesIn(MemoryFlags));
+
+} // anonymous namespace
diff --git a/unittests/Support/formatted_raw_ostream_test.cpp b/unittests/Support/formatted_raw_ostream_test.cpp new file mode 100644 index 0000000..4725ced --- /dev/null +++ b/unittests/Support/formatted_raw_ostream_test.cpp @@ -0,0 +1,33 @@ +//===- llvm/unittest/Support/formatted_raw_ostream_test.cpp ---------------===// +// +// 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/SmallString.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +namespace { + +TEST(formatted_raw_ostreamTest, Test_Tell) { + // Check offset when underlying stream has buffer contents. + SmallString<128> A; + raw_svector_ostream B(A); + formatted_raw_ostream C(B); + char tmp[100] = ""; + + for (unsigned i = 0; i != 3; ++i) { + C.write(tmp, 100); + + EXPECT_EQ(100*(i+1), (unsigned) C.tell()); + } +} + +} diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt index 365bfbb..730d83b 100644 --- a/unittests/Transforms/Utils/CMakeLists.txt +++ b/unittests/Transforms/Utils/CMakeLists.txt @@ -4,5 +4,6 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(UtilsTests Cloning.cpp + IntegerDivision.cpp Local.cpp ) diff --git a/unittests/Transforms/Utils/IntegerDivision.cpp b/unittests/Transforms/Utils/IntegerDivision.cpp new file mode 100644 index 0000000..a321139 --- /dev/null +++ b/unittests/Transforms/Utils/IntegerDivision.cpp @@ -0,0 +1,142 @@ +//===- IntegerDivision.cpp - Unit tests for the integer division code -----===// +// +// 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/BasicBlock.h" +#include "llvm/GlobalValue.h" +#include "llvm/Function.h" +#include "llvm/IRBuilder.h" +#include "llvm/Module.h" +#include "llvm/Transforms/Utils/IntegerDivision.h" + +using namespace llvm; + +namespace { + +TEST(IntegerDivision, SDiv) { + LLVMContext &C(getGlobalContext()); + Module M("test division", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt32Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Div = Builder.CreateSDiv(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::SDiv); + + Value *Ret = Builder.CreateRet(Div); + + expandDivision(cast<BinaryOperator>(Div)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr); + + Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::Sub); +} + +TEST(IntegerDivision, UDiv) { + LLVMContext &C(getGlobalContext()); + Module M("test division", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt32Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Div = Builder.CreateUDiv(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::UDiv); + + Value *Ret = Builder.CreateRet(Div); + + expandDivision(cast<BinaryOperator>(Div)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp); + + Instruction* Quotient = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Quotient && Quotient->getOpcode() == Instruction::PHI); +} + +TEST(IntegerDivision, SRem) { + LLVMContext &C(getGlobalContext()); + Module M("test remainder", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt32Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Rem = Builder.CreateSRem(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::SRem); + + Value *Ret = Builder.CreateRet(Rem); + + expandRemainder(cast<BinaryOperator>(Rem)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::AShr); + + Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); +} + +TEST(IntegerDivision, URem) { + LLVMContext &C(getGlobalContext()); + Module M("test remainder", C); + IRBuilder<> Builder(C); + + SmallVector<Type*, 2> ArgTys(2, Builder.getInt32Ty()); + Function *F = Function::Create(FunctionType::get(Builder.getInt32Ty(), + ArgTys, false), + GlobalValue::ExternalLinkage, "F", &M); + assert(F->getArgumentList().size() == 2); + + BasicBlock *BB = BasicBlock::Create(C, "", F); + Builder.SetInsertPoint(BB); + + Function::arg_iterator AI = F->arg_begin(); + Value *A = AI++; + Value *B = AI++; + + Value *Rem = Builder.CreateURem(A, B); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::URem); + + Value *Ret = Builder.CreateRet(Rem); + + expandRemainder(cast<BinaryOperator>(Rem)); + EXPECT_TRUE(BB->front().getOpcode() == Instruction::ICmp); + + Instruction* Remainder = dyn_cast<Instruction>(cast<User>(Ret)->getOperand(0)); + EXPECT_TRUE(Remainder && Remainder->getOpcode() == Instruction::Sub); +} + +} diff --git a/unittests/VMCore/IRBuilderTest.cpp b/unittests/VMCore/IRBuilderTest.cpp index b6a3795..9f26936 100644 --- a/unittests/VMCore/IRBuilderTest.cpp +++ b/unittests/VMCore/IRBuilderTest.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/BasicBlock.h" +#include "llvm/DataLayout.h" #include "llvm/Function.h" #include "llvm/IRBuilder.h" #include "llvm/IntrinsicInst.h" @@ -96,4 +97,15 @@ TEST_F(IRBuilderTest, CreateCondBr) { EXPECT_EQ(Weights, TI->getMetadata(LLVMContext::MD_prof)); } +TEST_F(IRBuilderTest, GetIntTy) { + IRBuilder<> Builder(BB); + IntegerType *Ty1 = Builder.getInt1Ty(); + EXPECT_EQ(Ty1, IntegerType::get(getGlobalContext(), 1)); + + DataLayout* DL = new DataLayout(M.get()); + IntegerType *IntPtrTy = Builder.getIntPtrTy(DL); + unsigned IntPtrBitSize = DL->getPointerSizeInBits(0); + EXPECT_EQ(IntPtrTy, IntegerType::get(getGlobalContext(), IntPtrBitSize)); +} + } diff --git a/unittests/VMCore/InstructionsTest.cpp b/unittests/VMCore/InstructionsTest.cpp index 72cdc8b..a3b13ce 100644 --- a/unittests/VMCore/InstructionsTest.cpp +++ b/unittests/VMCore/InstructionsTest.cpp @@ -9,6 +9,7 @@ #include "llvm/BasicBlock.h" #include "llvm/Constants.h" +#include "llvm/DataLayout.h" #include "llvm/DerivedTypes.h" #include "llvm/IRBuilder.h" #include "llvm/Instructions.h" @@ -17,7 +18,6 @@ #include "llvm/Operator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/ValueTracking.h" -#include "llvm/Target/TargetData.h" #include "gtest/gtest.h" namespace llvm { @@ -183,7 +183,7 @@ TEST(InstructionsTest, VectorGep) { EXPECT_NE(S3, Gep3); int64_t Offset; - TargetData TD("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3" + DataLayout TD("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3" "2:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80" ":128:128-n8:16:32:64-S128"); // Make sure we don't crash @@ -243,5 +243,42 @@ TEST(InstructionsTest, FPMathOperator) { delete I; } + +TEST(InstructionsTest, isEliminableCastPair) { + LLVMContext &C(getGlobalContext()); + + Type* Int32Ty = Type::getInt32Ty(C); + Type* Int64Ty = Type::getInt64Ty(C); + Type* Int64PtrTy = Type::getInt64PtrTy(C); + + // Source and destination pointers have same size -> bitcast. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt, + CastInst::IntToPtr, + Int64PtrTy, Int64Ty, Int64PtrTy, + Int32Ty, 0, Int32Ty), + CastInst::BitCast); + + // Source and destination pointers have different sizes -> fail. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt, + CastInst::IntToPtr, + Int64PtrTy, Int64Ty, Int64PtrTy, + Int32Ty, 0, Int64Ty), + 0U); + + // Middle pointer big enough -> bitcast. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, + Int64Ty, Int64PtrTy, Int64Ty, + 0, Int64Ty, 0), + CastInst::BitCast); + + // Middle pointer too small -> fail. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, + Int64Ty, Int64PtrTy, Int64Ty, + 0, Int32Ty, 0), + 0U); +} + } // end anonymous namespace } // end namespace llvm diff --git a/unittests/VMCore/PassManagerTest.cpp b/unittests/VMCore/PassManagerTest.cpp index 60d33c1..9c070c8 100644 --- a/unittests/VMCore/PassManagerTest.cpp +++ b/unittests/VMCore/PassManagerTest.cpp @@ -14,7 +14,7 @@ #include "llvm/Pass.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/CallGraphSCCPass.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/Support/raw_ostream.h" #include "llvm/DerivedTypes.h" #include "llvm/Constants.h" @@ -94,7 +94,7 @@ namespace llvm { initializeModuleNDMPass(*PassRegistry::getPassRegistry()); } virtual bool runOnModule(Module &M) { - EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); run++; return false; } @@ -167,7 +167,7 @@ namespace llvm { initializeCGPassPass(*PassRegistry::getPassRegistry()); } virtual bool runOnSCC(CallGraphSCC &SCMM) { - EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); run(); return false; } @@ -177,7 +177,7 @@ namespace llvm { public: virtual bool runOnFunction(Function &F) { // FIXME: PR4112 - // EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + // EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); run(); return false; } @@ -204,7 +204,7 @@ namespace llvm { return false; } virtual bool runOnLoop(Loop *L, LPPassManager &LPM) { - EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); run(); return false; } @@ -241,7 +241,7 @@ namespace llvm { return false; } virtual bool runOnBasicBlock(BasicBlock &BB) { - EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); run(); return false; } @@ -266,7 +266,7 @@ namespace llvm { initializeFPassPass(*PassRegistry::getPassRegistry()); } virtual bool runOnModule(Module &M) { - EXPECT_TRUE(getAnalysisIfAvailable<TargetData>()); + EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) { Function &F = *I; { @@ -292,7 +292,7 @@ namespace llvm { mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; PassManager Passes; - Passes.add(new TargetData(&M)); + Passes.add(new DataLayout(&M)); Passes.add(mNDM2); Passes.add(mNDM); Passes.add(mNDNM); @@ -316,7 +316,7 @@ namespace llvm { mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; PassManager Passes; - Passes.add(new TargetData(&M)); + Passes.add(new DataLayout(&M)); Passes.add(mNDM); Passes.add(mNDNM); Passes.add(mNDM2);// invalidates mNDM needed by mDNM @@ -338,7 +338,7 @@ namespace llvm { OwningPtr<Module> M(makeLLVMModule()); T *P = new T(); PassManager Passes; - Passes.add(new TargetData(M.get())); + Passes.add(new DataLayout(M.get())); Passes.add(P); Passes.run(*M); T::finishedOK(run); @@ -349,7 +349,7 @@ namespace llvm { Module *M = makeLLVMModule(); T *P = new T(); PassManager Passes; - Passes.add(new TargetData(M)); + Passes.add(new DataLayout(M)); Passes.add(P); Passes.run(*M); T::finishedOK(run, N); @@ -387,7 +387,7 @@ namespace llvm { SCOPED_TRACE("Running OnTheFlyTest"); struct OnTheFlyTest *O = new OnTheFlyTest(); PassManager Passes; - Passes.add(new TargetData(M)); + Passes.add(new DataLayout(M)); Passes.add(O); Passes.run(*M); |