aboutsummaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/APFloatTest.cpp59
-rw-r--r--unittests/ADT/BitVectorTest.cpp52
-rw-r--r--unittests/ADT/CMakeLists.txt16
-rw-r--r--unittests/ADT/DenseMapTest.cpp33
-rw-r--r--unittests/ADT/DenseSetTest.cpp2
-rw-r--r--unittests/ADT/ImmutableMapTest.cpp50
-rw-r--r--unittests/ADT/StringRefTest.cpp23
-rw-r--r--unittests/ADT/TripleTest.cpp12
-rw-r--r--unittests/Analysis/ScalarEvolutionTest.cpp16
-rw-r--r--unittests/ExecutionEngine/CMakeLists.txt1
-rw-r--r--unittests/ExecutionEngine/JIT/CMakeLists.txt2
-rw-r--r--unittests/ExecutionEngine/JIT/IntelJITEventListenerTest.cpp7
-rw-r--r--unittests/ExecutionEngine/JIT/JITTest.cpp37
-rw-r--r--unittests/ExecutionEngine/JIT/Makefile7
-rw-r--r--unittests/ExecutionEngine/JIT/MultiJITTest.cpp6
-rw-r--r--unittests/ExecutionEngine/MCJIT/CMakeLists.txt25
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTest.cpp231
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTestBase.h245
-rw-r--r--unittests/ExecutionEngine/MCJIT/MCJITTests.def1
-rw-r--r--unittests/ExecutionEngine/MCJIT/Makefile18
-rw-r--r--unittests/ExecutionEngine/MCJIT/SectionMemoryManager.cpp143
-rw-r--r--unittests/ExecutionEngine/MCJIT/SectionMemoryManager.h118
-rw-r--r--unittests/ExecutionEngine/Makefile2
-rw-r--r--unittests/Support/AlignOfTest.cpp129
-rw-r--r--unittests/Support/CMakeLists.txt5
-rw-r--r--unittests/Support/Casting.cpp59
-rw-r--r--unittests/Support/DataExtractorTest.cpp9
-rw-r--r--unittests/Support/MemoryBufferTest.cpp99
-rw-r--r--unittests/Support/MemoryTest.cpp356
-rw-r--r--unittests/Support/formatted_raw_ostream_test.cpp33
-rw-r--r--unittests/Transforms/Utils/CMakeLists.txt1
-rw-r--r--unittests/Transforms/Utils/IntegerDivision.cpp142
-rw-r--r--unittests/VMCore/IRBuilderTest.cpp12
-rw-r--r--unittests/VMCore/InstructionsTest.cpp41
-rw-r--r--unittests/VMCore/PassManagerTest.cpp24
35 files changed, 1898 insertions, 118 deletions
diff --git a/unittests/ADT/APFloatTest.cpp b/unittests/ADT/APFloatTest.cpp
index 00b62feaeb15..117b8204b9ed 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 d836036aeaea..dc298a83d571 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 d272b09088f5..94f7fda2a9e3 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 75e7006434a0..15eb6988f669 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 7a35f521a196..ada5f6db83af 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 000000000000..774581ca4eeb
--- /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 315eacbaa400..ead372f365d6 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 967437ca05a2..7c3ab9738940 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 ea5aeb38b01e..c30492a5f006 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 5fffadd4ca0c..ed7f10a23c8a 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 d43d72de4095..11cf784e1e59 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 8ed7a15be37c..d3f66a27e942 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 89f7e8e4229f..59604dfbf5cf 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 b535a6b29605..9e0bb9ea5930 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 5b99d5b676e2..4a22e2f641e7 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 000000000000..3e9c5b631e45
--- /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 000000000000..6b79a683bce0
--- /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 000000000000..9b4a4ac3cf00
--- /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 000000000000..aabd2247c049
--- /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 000000000000..454f83099d4b
--- /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 000000000000..d6baf3c9bb8e
--- /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 000000000000..e44217c90638
--- /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 63508d2399b5..ca1195631a22 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 6f576681a3e2..f01e6609390c 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 3b9bf8437031..09a0ea50d748 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 ca0b40b1f55b..ad564aa366df 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 9813e465f7ed..ec8bd3d18c8a 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 000000000000..6c78cd80e8b5
--- /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 000000000000..21cb27eaf0ef
--- /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 000000000000..4725cedc2119
--- /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 365bfbb0bf03..730d83b838fb 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 000000000000..a3211391d689
--- /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 b6a3795fd0f4..9f26936df475 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 72cdc8b99420..a3b13ce92d15 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 60d33c19c337..9c070c84bbc7 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);