diff options
author | Pascal Stumpf <pascal@cvs.openbsd.org> | 2016-09-03 22:47:03 +0000 |
---|---|---|
committer | Pascal Stumpf <pascal@cvs.openbsd.org> | 2016-09-03 22:47:03 +0000 |
commit | c07c59953ad4d4f16e8c3a3e25692ad9657db3ea (patch) | |
tree | e5a516d9d25bf178ab50dad2aa60c32b8684d5ee /gnu/llvm/unittests/IR | |
parent | 62bc401a55deb1281a3a42cd4f08325a6839a171 (diff) |
Use the space freed up by sparc and zaurus to import LLVM.
ok hackroom@
Diffstat (limited to 'gnu/llvm/unittests/IR')
24 files changed, 7748 insertions, 0 deletions
diff --git a/gnu/llvm/unittests/IR/AsmWriterTest.cpp b/gnu/llvm/unittests/IR/AsmWriterTest.cpp new file mode 100644 index 00000000000..c7e7bb5c9f0 --- /dev/null +++ b/gnu/llvm/unittests/IR/AsmWriterTest.cpp @@ -0,0 +1,37 @@ +//===- llvm/unittest/IR/AsmWriter.cpp - AsmWriter tests -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(AsmWriterTest, DebugPrintDetachedInstruction) { + + // PR24852: Ensure that an instruction can be printed even when it + // has metadata attached but no parent. + LLVMContext Ctx; + auto Ty = Type::getInt32Ty(Ctx); + auto Undef = UndefValue::get(Ty); + std::unique_ptr<BinaryOperator> Add(BinaryOperator::CreateAdd(Undef, Undef)); + Add->setMetadata( + "", MDNode::get(Ctx, {ConstantAsMetadata::get(ConstantInt::get(Ty, 1))})); + std::string S; + raw_string_ostream OS(S); + Add->print(OS); + std::size_t r = OS.str().find("<badref> = add i32 undef, undef, !<empty"); + EXPECT_TRUE(r != std::string::npos); +} + +} diff --git a/gnu/llvm/unittests/IR/AttributesTest.cpp b/gnu/llvm/unittests/IR/AttributesTest.cpp new file mode 100644 index 00000000000..ebcb772bc37 --- /dev/null +++ b/gnu/llvm/unittests/IR/AttributesTest.cpp @@ -0,0 +1,47 @@ +//===- llvm/unittest/IR/AttributesTest.cpp - Attributes unit tests --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Attributes.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(Attributes, Uniquing) { + LLVMContext C; + + Attribute AttrA = Attribute::get(C, Attribute::AlwaysInline); + Attribute AttrB = Attribute::get(C, Attribute::AlwaysInline); + EXPECT_EQ(AttrA, AttrB); + + AttributeSet ASs[] = { + AttributeSet::get(C, 1, Attribute::ZExt), + AttributeSet::get(C, 2, Attribute::SExt) + }; + + AttributeSet SetA = AttributeSet::get(C, ASs); + AttributeSet SetB = AttributeSet::get(C, ASs); + EXPECT_EQ(SetA, SetB); +} + +TEST(Attributes, Ordering) { + LLVMContext C; + + AttributeSet ASs[] = { + AttributeSet::get(C, 2, Attribute::ZExt), + AttributeSet::get(C, 1, Attribute::SExt) + }; + + AttributeSet SetA = AttributeSet::get(C, ASs); + AttributeSet SetB = SetA.removeAttributes(C, 1, ASs[1]); + EXPECT_NE(SetA, SetB); +} + +} // end anonymous namespace diff --git a/gnu/llvm/unittests/IR/CMakeLists.txt b/gnu/llvm/unittests/IR/CMakeLists.txt new file mode 100644 index 00000000000..5aad8edc913 --- /dev/null +++ b/gnu/llvm/unittests/IR/CMakeLists.txt @@ -0,0 +1,41 @@ +set(LLVM_LINK_COMPONENTS + Analysis + AsmParser + Core + Support + ) + +set(IRSources + AsmWriterTest.cpp + AttributesTest.cpp + ConstantRangeTest.cpp + ConstantsTest.cpp + DebugInfoTest.cpp + DominatorTreeTest.cpp + IRBuilderTest.cpp + InstructionsTest.cpp + LegacyPassManagerTest.cpp + MDBuilderTest.cpp + MetadataTest.cpp + PassManagerTest.cpp + PatternMatch.cpp + TypeBuilderTest.cpp + TypesTest.cpp + UseTest.cpp + UserTest.cpp + ValueHandleTest.cpp + ValueMapTest.cpp + ValueTest.cpp + VerifierTest.cpp + WaymarkTest.cpp + ) + +# HACK: Declare a couple of source files as optionally compiled to satisfy the +# missing-file-checker in LLVM's weird CMake build. +set(LLVM_OPTIONAL_SOURCES + ValueMapTest.cpp + ) + +add_llvm_unittest(IRTests + ${IRSources} + ) diff --git a/gnu/llvm/unittests/IR/ConstantRangeTest.cpp b/gnu/llvm/unittests/IR/ConstantRangeTest.cpp new file mode 100644 index 00000000000..1f32eea3e43 --- /dev/null +++ b/gnu/llvm/unittests/IR/ConstantRangeTest.cpp @@ -0,0 +1,623 @@ +//===- ConstantRangeTest.cpp - ConstantRange tests ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ConstantRange.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Operator.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class ConstantRangeTest : public ::testing::Test { +protected: + static ConstantRange Full; + static ConstantRange Empty; + static ConstantRange One; + static ConstantRange Some; + static ConstantRange Wrap; +}; + +ConstantRange ConstantRangeTest::Full(16); +ConstantRange ConstantRangeTest::Empty(16, false); +ConstantRange ConstantRangeTest::One(APInt(16, 0xa)); +ConstantRange ConstantRangeTest::Some(APInt(16, 0xa), APInt(16, 0xaaa)); +ConstantRange ConstantRangeTest::Wrap(APInt(16, 0xaaa), APInt(16, 0xa)); + +TEST_F(ConstantRangeTest, Basics) { + EXPECT_TRUE(Full.isFullSet()); + EXPECT_FALSE(Full.isEmptySet()); + EXPECT_TRUE(Full.inverse().isEmptySet()); + EXPECT_FALSE(Full.isWrappedSet()); + EXPECT_TRUE(Full.contains(APInt(16, 0x0))); + EXPECT_TRUE(Full.contains(APInt(16, 0x9))); + EXPECT_TRUE(Full.contains(APInt(16, 0xa))); + EXPECT_TRUE(Full.contains(APInt(16, 0xaa9))); + EXPECT_TRUE(Full.contains(APInt(16, 0xaaa))); + + EXPECT_FALSE(Empty.isFullSet()); + EXPECT_TRUE(Empty.isEmptySet()); + EXPECT_TRUE(Empty.inverse().isFullSet()); + EXPECT_FALSE(Empty.isWrappedSet()); + EXPECT_FALSE(Empty.contains(APInt(16, 0x0))); + EXPECT_FALSE(Empty.contains(APInt(16, 0x9))); + EXPECT_FALSE(Empty.contains(APInt(16, 0xa))); + EXPECT_FALSE(Empty.contains(APInt(16, 0xaa9))); + EXPECT_FALSE(Empty.contains(APInt(16, 0xaaa))); + + EXPECT_FALSE(One.isFullSet()); + EXPECT_FALSE(One.isEmptySet()); + EXPECT_FALSE(One.isWrappedSet()); + EXPECT_FALSE(One.contains(APInt(16, 0x0))); + EXPECT_FALSE(One.contains(APInt(16, 0x9))); + EXPECT_TRUE(One.contains(APInt(16, 0xa))); + EXPECT_FALSE(One.contains(APInt(16, 0xaa9))); + EXPECT_FALSE(One.contains(APInt(16, 0xaaa))); + EXPECT_FALSE(One.inverse().contains(APInt(16, 0xa))); + + EXPECT_FALSE(Some.isFullSet()); + EXPECT_FALSE(Some.isEmptySet()); + EXPECT_FALSE(Some.isWrappedSet()); + EXPECT_FALSE(Some.contains(APInt(16, 0x0))); + EXPECT_FALSE(Some.contains(APInt(16, 0x9))); + EXPECT_TRUE(Some.contains(APInt(16, 0xa))); + EXPECT_TRUE(Some.contains(APInt(16, 0xaa9))); + EXPECT_FALSE(Some.contains(APInt(16, 0xaaa))); + + EXPECT_FALSE(Wrap.isFullSet()); + EXPECT_FALSE(Wrap.isEmptySet()); + EXPECT_TRUE(Wrap.isWrappedSet()); + EXPECT_TRUE(Wrap.contains(APInt(16, 0x0))); + EXPECT_TRUE(Wrap.contains(APInt(16, 0x9))); + EXPECT_FALSE(Wrap.contains(APInt(16, 0xa))); + EXPECT_FALSE(Wrap.contains(APInt(16, 0xaa9))); + EXPECT_TRUE(Wrap.contains(APInt(16, 0xaaa))); +} + +TEST_F(ConstantRangeTest, Equality) { + EXPECT_EQ(Full, Full); + EXPECT_EQ(Empty, Empty); + EXPECT_EQ(One, One); + EXPECT_EQ(Some, Some); + EXPECT_EQ(Wrap, Wrap); + EXPECT_NE(Full, Empty); + EXPECT_NE(Full, One); + EXPECT_NE(Full, Some); + EXPECT_NE(Full, Wrap); + EXPECT_NE(Empty, One); + EXPECT_NE(Empty, Some); + EXPECT_NE(Empty, Wrap); + EXPECT_NE(One, Some); + EXPECT_NE(One, Wrap); + EXPECT_NE(Some, Wrap); +} + +TEST_F(ConstantRangeTest, SingleElement) { + EXPECT_EQ(Full.getSingleElement(), static_cast<APInt *>(nullptr)); + EXPECT_EQ(Empty.getSingleElement(), static_cast<APInt *>(nullptr)); + EXPECT_EQ(*One.getSingleElement(), APInt(16, 0xa)); + EXPECT_EQ(Some.getSingleElement(), static_cast<APInt *>(nullptr)); + EXPECT_EQ(Wrap.getSingleElement(), static_cast<APInt *>(nullptr)); + + EXPECT_FALSE(Full.isSingleElement()); + EXPECT_FALSE(Empty.isSingleElement()); + EXPECT_TRUE(One.isSingleElement()); + EXPECT_FALSE(Some.isSingleElement()); + EXPECT_FALSE(Wrap.isSingleElement()); +} + +TEST_F(ConstantRangeTest, GetSetSize) { + EXPECT_EQ(Full.getSetSize(), APInt(17, 65536)); + EXPECT_EQ(Empty.getSetSize(), APInt(17, 0)); + EXPECT_EQ(One.getSetSize(), APInt(17, 1)); + EXPECT_EQ(Some.getSetSize(), APInt(17, 0xaa0)); + + ConstantRange Wrap(APInt(4, 7), APInt(4, 3)); + ConstantRange Wrap2(APInt(4, 8), APInt(4, 7)); + EXPECT_EQ(Wrap.getSetSize(), APInt(5, 12)); + EXPECT_EQ(Wrap2.getSetSize(), APInt(5, 15)); +} + +TEST_F(ConstantRangeTest, GetMinsAndMaxes) { + EXPECT_EQ(Full.getUnsignedMax(), APInt(16, UINT16_MAX)); + EXPECT_EQ(One.getUnsignedMax(), APInt(16, 0xa)); + EXPECT_EQ(Some.getUnsignedMax(), APInt(16, 0xaa9)); + EXPECT_EQ(Wrap.getUnsignedMax(), APInt(16, UINT16_MAX)); + + EXPECT_EQ(Full.getUnsignedMin(), APInt(16, 0)); + EXPECT_EQ(One.getUnsignedMin(), APInt(16, 0xa)); + EXPECT_EQ(Some.getUnsignedMin(), APInt(16, 0xa)); + EXPECT_EQ(Wrap.getUnsignedMin(), APInt(16, 0)); + + EXPECT_EQ(Full.getSignedMax(), APInt(16, INT16_MAX)); + EXPECT_EQ(One.getSignedMax(), APInt(16, 0xa)); + EXPECT_EQ(Some.getSignedMax(), APInt(16, 0xaa9)); + EXPECT_EQ(Wrap.getSignedMax(), APInt(16, INT16_MAX)); + + EXPECT_EQ(Full.getSignedMin(), APInt(16, (uint64_t)INT16_MIN)); + EXPECT_EQ(One.getSignedMin(), APInt(16, 0xa)); + EXPECT_EQ(Some.getSignedMin(), APInt(16, 0xa)); + EXPECT_EQ(Wrap.getSignedMin(), APInt(16, (uint64_t)INT16_MIN)); + + // Found by Klee + EXPECT_EQ(ConstantRange(APInt(4, 7), APInt(4, 0)).getSignedMax(), + APInt(4, 7)); +} + +TEST_F(ConstantRangeTest, SignWrapped) { + EXPECT_TRUE(Full.isSignWrappedSet()); + EXPECT_FALSE(Empty.isSignWrappedSet()); + EXPECT_FALSE(One.isSignWrappedSet()); + EXPECT_FALSE(Some.isSignWrappedSet()); + EXPECT_TRUE(Wrap.isSignWrappedSet()); + + EXPECT_FALSE(ConstantRange(APInt(8, 127), APInt(8, 128)).isSignWrappedSet()); + EXPECT_TRUE(ConstantRange(APInt(8, 127), APInt(8, 129)).isSignWrappedSet()); + EXPECT_FALSE(ConstantRange(APInt(8, 128), APInt(8, 129)).isSignWrappedSet()); + EXPECT_TRUE(ConstantRange(APInt(8, 10), APInt(8, 9)).isSignWrappedSet()); + EXPECT_TRUE(ConstantRange(APInt(8, 10), APInt(8, 250)).isSignWrappedSet()); + EXPECT_FALSE(ConstantRange(APInt(8, 250), APInt(8, 10)).isSignWrappedSet()); + EXPECT_FALSE(ConstantRange(APInt(8, 250), APInt(8, 251)).isSignWrappedSet()); +} + +TEST_F(ConstantRangeTest, Trunc) { + ConstantRange TFull = Full.truncate(10); + ConstantRange TEmpty = Empty.truncate(10); + ConstantRange TOne = One.truncate(10); + ConstantRange TSome = Some.truncate(10); + ConstantRange TWrap = Wrap.truncate(10); + EXPECT_TRUE(TFull.isFullSet()); + EXPECT_TRUE(TEmpty.isEmptySet()); + EXPECT_EQ(TOne, ConstantRange(One.getLower().trunc(10), + One.getUpper().trunc(10))); + EXPECT_TRUE(TSome.isFullSet()); +} + +TEST_F(ConstantRangeTest, ZExt) { + ConstantRange ZFull = Full.zeroExtend(20); + ConstantRange ZEmpty = Empty.zeroExtend(20); + ConstantRange ZOne = One.zeroExtend(20); + ConstantRange ZSome = Some.zeroExtend(20); + ConstantRange ZWrap = Wrap.zeroExtend(20); + EXPECT_EQ(ZFull, ConstantRange(APInt(20, 0), APInt(20, 0x10000))); + EXPECT_TRUE(ZEmpty.isEmptySet()); + EXPECT_EQ(ZOne, ConstantRange(One.getLower().zext(20), + One.getUpper().zext(20))); + EXPECT_EQ(ZSome, ConstantRange(Some.getLower().zext(20), + Some.getUpper().zext(20))); + EXPECT_EQ(ZWrap, ConstantRange(APInt(20, 0), APInt(20, 0x10000))); + + // zext([5, 0), 3->7) = [5, 8) + ConstantRange FiveZero(APInt(3, 5), APInt(3, 0)); + EXPECT_EQ(FiveZero.zeroExtend(7), ConstantRange(APInt(7, 5), APInt(7, 8))); +} + +TEST_F(ConstantRangeTest, SExt) { + ConstantRange SFull = Full.signExtend(20); + ConstantRange SEmpty = Empty.signExtend(20); + ConstantRange SOne = One.signExtend(20); + ConstantRange SSome = Some.signExtend(20); + ConstantRange SWrap = Wrap.signExtend(20); + EXPECT_EQ(SFull, ConstantRange(APInt(20, (uint64_t)INT16_MIN, true), + APInt(20, INT16_MAX + 1, true))); + EXPECT_TRUE(SEmpty.isEmptySet()); + EXPECT_EQ(SOne, ConstantRange(One.getLower().sext(20), + One.getUpper().sext(20))); + EXPECT_EQ(SSome, ConstantRange(Some.getLower().sext(20), + Some.getUpper().sext(20))); + EXPECT_EQ(SWrap, ConstantRange(APInt(20, (uint64_t)INT16_MIN, true), + APInt(20, INT16_MAX + 1, true))); + + EXPECT_EQ(ConstantRange(APInt(8, 120), APInt(8, 140)).signExtend(16), + ConstantRange(APInt(16, -128), APInt(16, 128))); + + EXPECT_EQ(ConstantRange(APInt(16, 0x0200), APInt(16, 0x8000)).signExtend(19), + ConstantRange(APInt(19, 0x0200), APInt(19, 0x8000))); +} + +TEST_F(ConstantRangeTest, IntersectWith) { + EXPECT_EQ(Empty.intersectWith(Full), Empty); + EXPECT_EQ(Empty.intersectWith(Empty), Empty); + EXPECT_EQ(Empty.intersectWith(One), Empty); + EXPECT_EQ(Empty.intersectWith(Some), Empty); + EXPECT_EQ(Empty.intersectWith(Wrap), Empty); + EXPECT_EQ(Full.intersectWith(Full), Full); + EXPECT_EQ(Some.intersectWith(Some), Some); + EXPECT_EQ(Some.intersectWith(One), One); + EXPECT_EQ(Full.intersectWith(One), One); + EXPECT_EQ(Full.intersectWith(Some), Some); + EXPECT_EQ(Some.intersectWith(Wrap), Empty); + EXPECT_EQ(One.intersectWith(Wrap), Empty); + EXPECT_EQ(One.intersectWith(Wrap), Wrap.intersectWith(One)); + + // Klee generated testcase from PR4545. + // The intersection of i16 [4, 2) and [6, 5) is disjoint, looking like + // 01..4.6789ABCDEF where the dots represent values not in the intersection. + ConstantRange LHS(APInt(16, 4), APInt(16, 2)); + ConstantRange RHS(APInt(16, 6), APInt(16, 5)); + EXPECT_TRUE(LHS.intersectWith(RHS) == LHS); + + // previous bug: intersection of [min, 3) and [2, max) should be 2 + LHS = ConstantRange(APInt(32, -2147483646), APInt(32, 3)); + RHS = ConstantRange(APInt(32, 2), APInt(32, 2147483646)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 2))); + + // [2, 0) /\ [4, 3) = [2, 0) + LHS = ConstantRange(APInt(32, 2), APInt(32, 0)); + RHS = ConstantRange(APInt(32, 4), APInt(32, 3)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 2), APInt(32, 0))); + + // [2, 0) /\ [4, 2) = [4, 0) + LHS = ConstantRange(APInt(32, 2), APInt(32, 0)); + RHS = ConstantRange(APInt(32, 4), APInt(32, 2)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 4), APInt(32, 0))); + + // [4, 2) /\ [5, 1) = [5, 1) + LHS = ConstantRange(APInt(32, 4), APInt(32, 2)); + RHS = ConstantRange(APInt(32, 5), APInt(32, 1)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 5), APInt(32, 1))); + + // [2, 0) /\ [7, 4) = [7, 4) + LHS = ConstantRange(APInt(32, 2), APInt(32, 0)); + RHS = ConstantRange(APInt(32, 7), APInt(32, 4)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 7), APInt(32, 4))); + + // [4, 2) /\ [1, 0) = [1, 0) + LHS = ConstantRange(APInt(32, 4), APInt(32, 2)); + RHS = ConstantRange(APInt(32, 1), APInt(32, 0)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 4), APInt(32, 2))); + + // [15, 0) /\ [7, 6) = [15, 0) + LHS = ConstantRange(APInt(32, 15), APInt(32, 0)); + RHS = ConstantRange(APInt(32, 7), APInt(32, 6)); + EXPECT_EQ(LHS.intersectWith(RHS), ConstantRange(APInt(32, 15), APInt(32, 0))); +} + +TEST_F(ConstantRangeTest, UnionWith) { + EXPECT_EQ(Wrap.unionWith(One), + ConstantRange(APInt(16, 0xaaa), APInt(16, 0xb))); + EXPECT_EQ(One.unionWith(Wrap), Wrap.unionWith(One)); + EXPECT_EQ(Empty.unionWith(Empty), Empty); + EXPECT_EQ(Full.unionWith(Full), Full); + EXPECT_EQ(Some.unionWith(Wrap), Full); + + // PR4545 + EXPECT_EQ(ConstantRange(APInt(16, 14), APInt(16, 1)).unionWith( + ConstantRange(APInt(16, 0), APInt(16, 8))), + ConstantRange(APInt(16, 14), APInt(16, 8))); + EXPECT_EQ(ConstantRange(APInt(16, 6), APInt(16, 4)).unionWith( + ConstantRange(APInt(16, 4), APInt(16, 0))), + ConstantRange(16)); + EXPECT_EQ(ConstantRange(APInt(16, 1), APInt(16, 0)).unionWith( + ConstantRange(APInt(16, 2), APInt(16, 1))), + ConstantRange(16)); +} + +TEST_F(ConstantRangeTest, SetDifference) { + EXPECT_EQ(Full.difference(Empty), Full); + EXPECT_EQ(Full.difference(Full), Empty); + EXPECT_EQ(Empty.difference(Empty), Empty); + EXPECT_EQ(Empty.difference(Full), Empty); + + ConstantRange A(APInt(16, 3), APInt(16, 7)); + ConstantRange B(APInt(16, 5), APInt(16, 9)); + ConstantRange C(APInt(16, 3), APInt(16, 5)); + ConstantRange D(APInt(16, 7), APInt(16, 9)); + ConstantRange E(APInt(16, 5), APInt(16, 4)); + ConstantRange F(APInt(16, 7), APInt(16, 3)); + EXPECT_EQ(A.difference(B), C); + EXPECT_EQ(B.difference(A), D); + EXPECT_EQ(E.difference(A), F); +} + +TEST_F(ConstantRangeTest, SubtractAPInt) { + EXPECT_EQ(Full.subtract(APInt(16, 4)), Full); + EXPECT_EQ(Empty.subtract(APInt(16, 4)), Empty); + EXPECT_EQ(Some.subtract(APInt(16, 4)), + ConstantRange(APInt(16, 0x6), APInt(16, 0xaa6))); + EXPECT_EQ(Wrap.subtract(APInt(16, 4)), + ConstantRange(APInt(16, 0xaa6), APInt(16, 0x6))); + EXPECT_EQ(One.subtract(APInt(16, 4)), + ConstantRange(APInt(16, 0x6))); +} + +TEST_F(ConstantRangeTest, Add) { + EXPECT_EQ(Full.add(APInt(16, 4)), Full); + EXPECT_EQ(Full.add(Full), Full); + EXPECT_EQ(Full.add(Empty), Empty); + EXPECT_EQ(Full.add(One), Full); + EXPECT_EQ(Full.add(Some), Full); + EXPECT_EQ(Full.add(Wrap), Full); + EXPECT_EQ(Empty.add(Empty), Empty); + EXPECT_EQ(Empty.add(One), Empty); + EXPECT_EQ(Empty.add(Some), Empty); + EXPECT_EQ(Empty.add(Wrap), Empty); + EXPECT_EQ(Empty.add(APInt(16, 4)), Empty); + EXPECT_EQ(Some.add(APInt(16, 4)), + ConstantRange(APInt(16, 0xe), APInt(16, 0xaae))); + EXPECT_EQ(Wrap.add(APInt(16, 4)), + ConstantRange(APInt(16, 0xaae), APInt(16, 0xe))); + EXPECT_EQ(One.add(APInt(16, 4)), + ConstantRange(APInt(16, 0xe))); +} + +TEST_F(ConstantRangeTest, Sub) { + EXPECT_EQ(Full.sub(APInt(16, 4)), Full); + EXPECT_EQ(Full.sub(Full), Full); + EXPECT_EQ(Full.sub(Empty), Empty); + EXPECT_EQ(Full.sub(One), Full); + EXPECT_EQ(Full.sub(Some), Full); + EXPECT_EQ(Full.sub(Wrap), Full); + EXPECT_EQ(Empty.sub(Empty), Empty); + EXPECT_EQ(Empty.sub(One), Empty); + EXPECT_EQ(Empty.sub(Some), Empty); + EXPECT_EQ(Empty.sub(Wrap), Empty); + EXPECT_EQ(Empty.sub(APInt(16, 4)), Empty); + EXPECT_EQ(Some.sub(APInt(16, 4)), + ConstantRange(APInt(16, 0x6), APInt(16, 0xaa6))); + EXPECT_EQ(Some.sub(Some), + ConstantRange(APInt(16, 0xf561), APInt(16, 0xaa0))); + EXPECT_EQ(Wrap.sub(APInt(16, 4)), + ConstantRange(APInt(16, 0xaa6), APInt(16, 0x6))); + EXPECT_EQ(One.sub(APInt(16, 4)), + ConstantRange(APInt(16, 0x6))); +} + +TEST_F(ConstantRangeTest, Multiply) { + EXPECT_EQ(Full.multiply(Full), Full); + EXPECT_EQ(Full.multiply(Empty), Empty); + EXPECT_EQ(Full.multiply(One), Full); + EXPECT_EQ(Full.multiply(Some), Full); + EXPECT_EQ(Full.multiply(Wrap), Full); + EXPECT_EQ(Empty.multiply(Empty), Empty); + EXPECT_EQ(Empty.multiply(One), Empty); + EXPECT_EQ(Empty.multiply(Some), Empty); + EXPECT_EQ(Empty.multiply(Wrap), Empty); + EXPECT_EQ(One.multiply(One), ConstantRange(APInt(16, 0xa*0xa), + APInt(16, 0xa*0xa + 1))); + EXPECT_EQ(One.multiply(Some), ConstantRange(APInt(16, 0xa*0xa), + APInt(16, 0xa*0xaa9 + 1))); + EXPECT_EQ(One.multiply(Wrap), Full); + EXPECT_EQ(Some.multiply(Some), Full); + EXPECT_EQ(Some.multiply(Wrap), Full); + EXPECT_EQ(Wrap.multiply(Wrap), Full); + + ConstantRange Zero(APInt(16, 0)); + EXPECT_EQ(Zero.multiply(Full), Zero); + EXPECT_EQ(Zero.multiply(Some), Zero); + EXPECT_EQ(Zero.multiply(Wrap), Zero); + EXPECT_EQ(Full.multiply(Zero), Zero); + EXPECT_EQ(Some.multiply(Zero), Zero); + EXPECT_EQ(Wrap.multiply(Zero), Zero); + + // http://llvm.org/PR4545 + EXPECT_EQ(ConstantRange(APInt(4, 1), APInt(4, 6)).multiply( + ConstantRange(APInt(4, 6), APInt(4, 2))), + ConstantRange(4, /*isFullSet=*/true)); + + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 0)).multiply( + ConstantRange(APInt(8, 252), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 9))); + EXPECT_EQ(ConstantRange(APInt(8, 254), APInt(8, 255)).multiply( + ConstantRange(APInt(8, 2), APInt(8, 4))), + ConstantRange(APInt(8, 250), APInt(8, 253))); +} + +TEST_F(ConstantRangeTest, UMax) { + EXPECT_EQ(Full.umax(Full), Full); + EXPECT_EQ(Full.umax(Empty), Empty); + EXPECT_EQ(Full.umax(Some), ConstantRange(APInt(16, 0xa), APInt(16, 0))); + EXPECT_EQ(Full.umax(Wrap), Full); + EXPECT_EQ(Full.umax(Some), ConstantRange(APInt(16, 0xa), APInt(16, 0))); + EXPECT_EQ(Empty.umax(Empty), Empty); + EXPECT_EQ(Empty.umax(Some), Empty); + EXPECT_EQ(Empty.umax(Wrap), Empty); + EXPECT_EQ(Empty.umax(One), Empty); + EXPECT_EQ(Some.umax(Some), Some); + EXPECT_EQ(Some.umax(Wrap), ConstantRange(APInt(16, 0xa), APInt(16, 0))); + EXPECT_EQ(Some.umax(One), Some); + // TODO: ConstantRange is currently over-conservative here. + EXPECT_EQ(Wrap.umax(Wrap), Full); + EXPECT_EQ(Wrap.umax(One), ConstantRange(APInt(16, 0xa), APInt(16, 0))); + EXPECT_EQ(One.umax(One), One); +} + +TEST_F(ConstantRangeTest, SMax) { + EXPECT_EQ(Full.smax(Full), Full); + EXPECT_EQ(Full.smax(Empty), Empty); + EXPECT_EQ(Full.smax(Some), ConstantRange(APInt(16, 0xa), + APInt::getSignedMinValue(16))); + EXPECT_EQ(Full.smax(Wrap), Full); + EXPECT_EQ(Full.smax(One), ConstantRange(APInt(16, 0xa), + APInt::getSignedMinValue(16))); + EXPECT_EQ(Empty.smax(Empty), Empty); + EXPECT_EQ(Empty.smax(Some), Empty); + EXPECT_EQ(Empty.smax(Wrap), Empty); + EXPECT_EQ(Empty.smax(One), Empty); + EXPECT_EQ(Some.smax(Some), Some); + EXPECT_EQ(Some.smax(Wrap), ConstantRange(APInt(16, 0xa), + APInt(16, (uint64_t)INT16_MIN))); + EXPECT_EQ(Some.smax(One), Some); + EXPECT_EQ(Wrap.smax(One), ConstantRange(APInt(16, 0xa), + APInt(16, (uint64_t)INT16_MIN))); + EXPECT_EQ(One.smax(One), One); +} + +TEST_F(ConstantRangeTest, UDiv) { + EXPECT_EQ(Full.udiv(Full), Full); + EXPECT_EQ(Full.udiv(Empty), Empty); + EXPECT_EQ(Full.udiv(One), ConstantRange(APInt(16, 0), + APInt(16, 0xffff / 0xa + 1))); + EXPECT_EQ(Full.udiv(Some), ConstantRange(APInt(16, 0), + APInt(16, 0xffff / 0xa + 1))); + EXPECT_EQ(Full.udiv(Wrap), Full); + EXPECT_EQ(Empty.udiv(Empty), Empty); + EXPECT_EQ(Empty.udiv(One), Empty); + EXPECT_EQ(Empty.udiv(Some), Empty); + EXPECT_EQ(Empty.udiv(Wrap), Empty); + EXPECT_EQ(One.udiv(One), ConstantRange(APInt(16, 1))); + EXPECT_EQ(One.udiv(Some), ConstantRange(APInt(16, 0), APInt(16, 2))); + EXPECT_EQ(One.udiv(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xb))); + EXPECT_EQ(Some.udiv(Some), ConstantRange(APInt(16, 0), APInt(16, 0x111))); + EXPECT_EQ(Some.udiv(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xaaa))); + EXPECT_EQ(Wrap.udiv(Wrap), Full); +} + +TEST_F(ConstantRangeTest, Shl) { + EXPECT_EQ(Full.shl(Full), Full); + EXPECT_EQ(Full.shl(Empty), Empty); + EXPECT_EQ(Full.shl(One), Full); // TODO: [0, (-1 << 0xa) + 1) + EXPECT_EQ(Full.shl(Some), Full); // TODO: [0, (-1 << 0xa) + 1) + EXPECT_EQ(Full.shl(Wrap), Full); + EXPECT_EQ(Empty.shl(Empty), Empty); + EXPECT_EQ(Empty.shl(One), Empty); + EXPECT_EQ(Empty.shl(Some), Empty); + EXPECT_EQ(Empty.shl(Wrap), Empty); + EXPECT_EQ(One.shl(One), ConstantRange(APInt(16, 0xa << 0xa), + APInt(16, (0xa << 0xa) + 1))); + EXPECT_EQ(One.shl(Some), Full); // TODO: [0xa << 0xa, 0) + EXPECT_EQ(One.shl(Wrap), Full); // TODO: [0xa, 0xa << 14 + 1) + EXPECT_EQ(Some.shl(Some), Full); // TODO: [0xa << 0xa, 0xfc01) + EXPECT_EQ(Some.shl(Wrap), Full); // TODO: [0xa, 0x7ff << 0x5 + 1) + EXPECT_EQ(Wrap.shl(Wrap), Full); +} + +TEST_F(ConstantRangeTest, Lshr) { + EXPECT_EQ(Full.lshr(Full), Full); + EXPECT_EQ(Full.lshr(Empty), Empty); + EXPECT_EQ(Full.lshr(One), ConstantRange(APInt(16, 0), + APInt(16, (0xffff >> 0xa) + 1))); + EXPECT_EQ(Full.lshr(Some), ConstantRange(APInt(16, 0), + APInt(16, (0xffff >> 0xa) + 1))); + EXPECT_EQ(Full.lshr(Wrap), Full); + EXPECT_EQ(Empty.lshr(Empty), Empty); + EXPECT_EQ(Empty.lshr(One), Empty); + EXPECT_EQ(Empty.lshr(Some), Empty); + EXPECT_EQ(Empty.lshr(Wrap), Empty); + EXPECT_EQ(One.lshr(One), ConstantRange(APInt(16, 0))); + EXPECT_EQ(One.lshr(Some), ConstantRange(APInt(16, 0))); + EXPECT_EQ(One.lshr(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xb))); + EXPECT_EQ(Some.lshr(Some), ConstantRange(APInt(16, 0), + APInt(16, (0xaaa >> 0xa) + 1))); + EXPECT_EQ(Some.lshr(Wrap), ConstantRange(APInt(16, 0), APInt(16, 0xaaa))); + EXPECT_EQ(Wrap.lshr(Wrap), Full); +} + +TEST(ConstantRange, MakeAllowedICmpRegion) { + // PR8250 + ConstantRange SMax = ConstantRange(APInt::getSignedMaxValue(32)); + EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(ICmpInst::ICMP_SGT, SMax) + .isEmptySet()); +} + +TEST(ConstantRange, MakeSatisfyingICmpRegion) { + ConstantRange LowHalf(APInt(8, 0), APInt(8, 128)); + ConstantRange HighHalf(APInt(8, 128), APInt(8, 0)); + ConstantRange EmptySet(8, /* isFullSet = */ false); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_NE, LowHalf), + HighHalf); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_NE, HighHalf), + LowHalf); + + EXPECT_TRUE(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_EQ, + HighHalf).isEmptySet()); + + ConstantRange UnsignedSample(APInt(8, 5), APInt(8, 200)); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_ULT, + UnsignedSample), + ConstantRange(APInt(8, 0), APInt(8, 5))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_ULE, + UnsignedSample), + ConstantRange(APInt(8, 0), APInt(8, 6))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_UGT, + UnsignedSample), + ConstantRange(APInt(8, 200), APInt(8, 0))); + + EXPECT_EQ(ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_UGE, + UnsignedSample), + ConstantRange(APInt(8, 199), APInt(8, 0))); + + ConstantRange SignedSample(APInt(8, -5), APInt(8, 5)); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SLT, SignedSample), + ConstantRange(APInt(8, -128), APInt(8, -5))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SLE, SignedSample), + ConstantRange(APInt(8, -128), APInt(8, -4))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SGT, SignedSample), + ConstantRange(APInt(8, 5), APInt(8, -128))); + + EXPECT_EQ( + ConstantRange::makeSatisfyingICmpRegion(ICmpInst::ICMP_SGE, SignedSample), + ConstantRange(APInt(8, 4), APInt(8, -128))); +} + +TEST(ConstantRange, MakeOverflowingRegion) { + const int IntMin4Bits = 8; + const int IntMax4Bits = 7; + typedef OverflowingBinaryOperator OBO; + + for (int Const : {0, -1, -2, 1, 2, IntMin4Bits, IntMax4Bits}) { + APInt C(4, Const, true /* = isSigned */); + + auto NUWRegion = + ConstantRange::makeNoWrapRegion(Instruction::Add, C, OBO::NoUnsignedWrap); + + EXPECT_FALSE(NUWRegion.isEmptySet()); + + auto NSWRegion = + ConstantRange::makeNoWrapRegion(Instruction::Add, C, OBO::NoSignedWrap); + + EXPECT_FALSE(NSWRegion.isEmptySet()); + + auto NoWrapRegion = ConstantRange::makeNoWrapRegion( + Instruction::Add, C, OBO::NoSignedWrap | OBO::NoUnsignedWrap); + + EXPECT_FALSE(NoWrapRegion.isEmptySet()); + EXPECT_TRUE(NUWRegion.intersectWith(NSWRegion).contains(NoWrapRegion)); + + for (APInt I = NUWRegion.getLower(), E = NUWRegion.getUpper(); I != E; + ++I) { + bool Overflow = false; + I.uadd_ov(C, Overflow); + EXPECT_FALSE(Overflow); + } + + for (APInt I = NSWRegion.getLower(), E = NSWRegion.getUpper(); I != E; + ++I) { + bool Overflow = false; + I.sadd_ov(C, Overflow); + EXPECT_FALSE(Overflow); + } + + for (APInt I = NoWrapRegion.getLower(), E = NoWrapRegion.getUpper(); I != E; + ++I) { + bool Overflow = false; + + I.sadd_ov(C, Overflow); + EXPECT_FALSE(Overflow); + + I.uadd_ov(C, Overflow); + EXPECT_FALSE(Overflow); + } + } +} + +} // anonymous namespace diff --git a/gnu/llvm/unittests/IR/ConstantsTest.cpp b/gnu/llvm/unittests/IR/ConstantsTest.cpp new file mode 100644 index 00000000000..7471584097d --- /dev/null +++ b/gnu/llvm/unittests/IR/ConstantsTest.cpp @@ -0,0 +1,455 @@ +//===- llvm/unittest/IR/ConstantsTest.cpp - Constants unit tests ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm-c/Core.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +TEST(ConstantsTest, Integer_i1) { + IntegerType* Int1 = IntegerType::get(getGlobalContext(), 1); + Constant* One = ConstantInt::get(Int1, 1, true); + Constant* Zero = ConstantInt::get(Int1, 0); + Constant* NegOne = ConstantInt::get(Int1, static_cast<uint64_t>(-1), true); + EXPECT_EQ(NegOne, ConstantInt::getSigned(Int1, -1)); + Constant* Undef = UndefValue::get(Int1); + + // Input: @b = constant i1 add(i1 1 , i1 1) + // Output: @b = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getAdd(One, One)); + + // @c = constant i1 add(i1 -1, i1 1) + // @c = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getAdd(NegOne, One)); + + // @d = constant i1 add(i1 -1, i1 -1) + // @d = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getAdd(NegOne, NegOne)); + + // @e = constant i1 sub(i1 -1, i1 1) + // @e = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getSub(NegOne, One)); + + // @f = constant i1 sub(i1 1 , i1 -1) + // @f = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getSub(One, NegOne)); + + // @g = constant i1 sub(i1 1 , i1 1) + // @g = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getSub(One, One)); + + // @h = constant i1 shl(i1 1 , i1 1) ; undefined + // @h = constant i1 undef + EXPECT_EQ(Undef, ConstantExpr::getShl(One, One)); + + // @i = constant i1 shl(i1 1 , i1 0) + // @i = constant i1 true + EXPECT_EQ(One, ConstantExpr::getShl(One, Zero)); + + // @j = constant i1 lshr(i1 1, i1 1) ; undefined + // @j = constant i1 undef + EXPECT_EQ(Undef, ConstantExpr::getLShr(One, One)); + + // @m = constant i1 ashr(i1 1, i1 1) ; undefined + // @m = constant i1 undef + EXPECT_EQ(Undef, ConstantExpr::getAShr(One, One)); + + // @n = constant i1 mul(i1 -1, i1 1) + // @n = constant i1 true + EXPECT_EQ(One, ConstantExpr::getMul(NegOne, One)); + + // @o = constant i1 sdiv(i1 -1, i1 1) ; overflow + // @o = constant i1 true + EXPECT_EQ(One, ConstantExpr::getSDiv(NegOne, One)); + + // @p = constant i1 sdiv(i1 1 , i1 -1); overflow + // @p = constant i1 true + EXPECT_EQ(One, ConstantExpr::getSDiv(One, NegOne)); + + // @q = constant i1 udiv(i1 -1, i1 1) + // @q = constant i1 true + EXPECT_EQ(One, ConstantExpr::getUDiv(NegOne, One)); + + // @r = constant i1 udiv(i1 1, i1 -1) + // @r = constant i1 true + EXPECT_EQ(One, ConstantExpr::getUDiv(One, NegOne)); + + // @s = constant i1 srem(i1 -1, i1 1) ; overflow + // @s = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getSRem(NegOne, One)); + + // @t = constant i1 urem(i1 -1, i1 1) + // @t = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getURem(NegOne, One)); + + // @u = constant i1 srem(i1 1, i1 -1) ; overflow + // @u = constant i1 false + EXPECT_EQ(Zero, ConstantExpr::getSRem(One, NegOne)); +} + +TEST(ConstantsTest, IntSigns) { + IntegerType* Int8Ty = Type::getInt8Ty(getGlobalContext()); + EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, false)->getSExtValue()); + EXPECT_EQ(100, ConstantInt::get(Int8Ty, 100, true)->getSExtValue()); + EXPECT_EQ(100, ConstantInt::getSigned(Int8Ty, 100)->getSExtValue()); + EXPECT_EQ(-50, ConstantInt::get(Int8Ty, 206)->getSExtValue()); + EXPECT_EQ(-50, ConstantInt::getSigned(Int8Ty, -50)->getSExtValue()); + EXPECT_EQ(206U, ConstantInt::getSigned(Int8Ty, -50)->getZExtValue()); + + // Overflow is handled by truncation. + EXPECT_EQ(0x3b, ConstantInt::get(Int8Ty, 0x13b)->getSExtValue()); +} + +TEST(ConstantsTest, FP128Test) { + Type *FP128Ty = Type::getFP128Ty(getGlobalContext()); + + IntegerType *Int128Ty = Type::getIntNTy(getGlobalContext(), 128); + Constant *Zero128 = Constant::getNullValue(Int128Ty); + Constant *X = ConstantExpr::getUIToFP(Zero128, FP128Ty); + EXPECT_TRUE(isa<ConstantFP>(X)); +} + +TEST(ConstantsTest, PointerCast) { + LLVMContext &C(getGlobalContext()); + Type *Int8PtrTy = Type::getInt8PtrTy(C); + Type *Int32PtrTy = Type::getInt32PtrTy(C); + Type *Int64Ty = Type::getInt64Ty(C); + VectorType *Int8PtrVecTy = VectorType::get(Int8PtrTy, 4); + VectorType *Int32PtrVecTy = VectorType::get(Int32PtrTy, 4); + VectorType *Int64VecTy = VectorType::get(Int64Ty, 4); + + // ptrtoint i8* to i64 + EXPECT_EQ(Constant::getNullValue(Int64Ty), + ConstantExpr::getPointerCast( + Constant::getNullValue(Int8PtrTy), Int64Ty)); + + // bitcast i8* to i32* + EXPECT_EQ(Constant::getNullValue(Int32PtrTy), + ConstantExpr::getPointerCast( + Constant::getNullValue(Int8PtrTy), Int32PtrTy)); + + // ptrtoint <4 x i8*> to <4 x i64> + EXPECT_EQ(Constant::getNullValue(Int64VecTy), + ConstantExpr::getPointerCast( + Constant::getNullValue(Int8PtrVecTy), Int64VecTy)); + + // bitcast <4 x i8*> to <4 x i32*> + EXPECT_EQ(Constant::getNullValue(Int32PtrVecTy), + ConstantExpr::getPointerCast( + Constant::getNullValue(Int8PtrVecTy), Int32PtrVecTy)); +} + +#define CHECK(x, y) { \ + std::string __s; \ + raw_string_ostream __o(__s); \ + Instruction *__I = cast<ConstantExpr>(x)->getAsInstruction(); \ + __I->print(__o); \ + delete __I; \ + __o.flush(); \ + EXPECT_EQ(std::string(" <badref> = " y), __s); \ + } + +TEST(ConstantsTest, AsInstructionsTest) { + std::unique_ptr<Module> M(new Module("MyModule", getGlobalContext())); + + Type *Int64Ty = Type::getInt64Ty(getGlobalContext()); + Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); + Type *Int16Ty = Type::getInt16Ty(getGlobalContext()); + Type *Int1Ty = Type::getInt1Ty(getGlobalContext()); + Type *FloatTy = Type::getFloatTy(getGlobalContext()); + Type *DoubleTy = Type::getDoubleTy(getGlobalContext()); + + Constant *Global = M->getOrInsertGlobal("dummy", + PointerType::getUnqual(Int32Ty)); + Constant *Global2 = M->getOrInsertGlobal("dummy2", + PointerType::getUnqual(Int32Ty)); + + Constant *P0 = ConstantExpr::getPtrToInt(Global, Int32Ty); + Constant *P1 = ConstantExpr::getUIToFP(P0, FloatTy); + Constant *P2 = ConstantExpr::getUIToFP(P0, DoubleTy); + Constant *P3 = ConstantExpr::getTrunc(P0, Int1Ty); + Constant *P4 = ConstantExpr::getPtrToInt(Global2, Int32Ty); + Constant *P5 = ConstantExpr::getUIToFP(P4, FloatTy); + Constant *P6 = ConstantExpr::getBitCast(P4, VectorType::get(Int16Ty, 2)); + + Constant *One = ConstantInt::get(Int32Ty, 1); + Constant *Two = ConstantInt::get(Int64Ty, 2); + Constant *Big = ConstantInt::get(getGlobalContext(), + APInt{256, uint64_t(-1), true}); + Constant *Elt = ConstantInt::get(Int16Ty, 2015); + Constant *Undef16 = UndefValue::get(Int16Ty); + Constant *Undef64 = UndefValue::get(Int64Ty); + Constant *UndefV16 = UndefValue::get(P6->getType()); + + #define P0STR "ptrtoint (i32** @dummy to i32)" + #define P1STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to float)" + #define P2STR "uitofp (i32 ptrtoint (i32** @dummy to i32) to double)" + #define P3STR "ptrtoint (i32** @dummy to i1)" + #define P4STR "ptrtoint (i32** @dummy2 to i32)" + #define P5STR "uitofp (i32 ptrtoint (i32** @dummy2 to i32) to float)" + #define P6STR "bitcast (i32 ptrtoint (i32** @dummy2 to i32) to <2 x i16>)" + + CHECK(ConstantExpr::getNeg(P0), "sub i32 0, " P0STR); + CHECK(ConstantExpr::getFNeg(P1), "fsub float -0.000000e+00, " P1STR); + CHECK(ConstantExpr::getNot(P0), "xor i32 " P0STR ", -1"); + CHECK(ConstantExpr::getAdd(P0, P0), "add i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAdd(P0, P0, false, true), "add nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getAdd(P0, P0, true, true), "add nuw nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getFAdd(P1, P1), "fadd float " P1STR ", " P1STR); + CHECK(ConstantExpr::getSub(P0, P0), "sub i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFSub(P1, P1), "fsub float " P1STR ", " P1STR); + CHECK(ConstantExpr::getMul(P0, P0), "mul i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFMul(P1, P1), "fmul float " P1STR ", " P1STR); + CHECK(ConstantExpr::getUDiv(P0, P0), "udiv i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getSDiv(P0, P0), "sdiv i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFDiv(P1, P1), "fdiv float " P1STR ", " P1STR); + CHECK(ConstantExpr::getURem(P0, P0), "urem i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getSRem(P0, P0), "srem i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getFRem(P1, P1), "frem float " P1STR ", " P1STR); + CHECK(ConstantExpr::getAnd(P0, P0), "and i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getOr(P0, P0), "or i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getXor(P0, P0), "xor i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0), "shl i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0, true), "shl nuw i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getShl(P0, P0, false, true), "shl nsw i32 " P0STR ", " + P0STR); + CHECK(ConstantExpr::getLShr(P0, P0, false), "lshr i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getLShr(P0, P0, true), "lshr exact i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAShr(P0, P0, false), "ashr i32 " P0STR ", " P0STR); + CHECK(ConstantExpr::getAShr(P0, P0, true), "ashr exact i32 " P0STR ", " P0STR); + + CHECK(ConstantExpr::getSExt(P0, Int64Ty), "sext i32 " P0STR " to i64"); + CHECK(ConstantExpr::getZExt(P0, Int64Ty), "zext i32 " P0STR " to i64"); + CHECK(ConstantExpr::getFPTrunc(P2, FloatTy), "fptrunc double " P2STR + " to float"); + CHECK(ConstantExpr::getFPExtend(P1, DoubleTy), "fpext float " P1STR + " to double"); + + CHECK(ConstantExpr::getExactUDiv(P0, P0), "udiv exact i32 " P0STR ", " P0STR); + + CHECK(ConstantExpr::getSelect(P3, P0, P4), "select i1 " P3STR ", i32 " P0STR + ", i32 " P4STR); + CHECK(ConstantExpr::getICmp(CmpInst::ICMP_EQ, P0, P4), "icmp eq i32 " P0STR + ", " P4STR); + CHECK(ConstantExpr::getFCmp(CmpInst::FCMP_ULT, P1, P5), "fcmp ult float " + P1STR ", " P5STR); + + std::vector<Constant*> V; + V.push_back(One); + // FIXME: getGetElementPtr() actually creates an inbounds ConstantGEP, + // not a normal one! + //CHECK(ConstantExpr::getGetElementPtr(Global, V, false), + // "getelementptr i32*, i32** @dummy, i32 1"); + CHECK(ConstantExpr::getInBoundsGetElementPtr(PointerType::getUnqual(Int32Ty), + Global, V), + "getelementptr inbounds i32*, i32** @dummy, i32 1"); + + CHECK(ConstantExpr::getExtractElement(P6, One), "extractelement <2 x i16> " + P6STR ", i32 1"); + + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Two)); + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Big)); + EXPECT_EQ(Undef16, ConstantExpr::getExtractElement(P6, Undef64)); + + EXPECT_EQ(Elt, ConstantExpr::getExtractElement( + ConstantExpr::getInsertElement(P6, Elt, One), One)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Two)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Big)); + EXPECT_EQ(UndefV16, ConstantExpr::getInsertElement(P6, Elt, Undef64)); +} + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG +TEST(ConstantsTest, ReplaceWithConstantTest) { + std::unique_ptr<Module> M(new Module("MyModule", getGlobalContext())); + + Type *Int32Ty = Type::getInt32Ty(getGlobalContext()); + Constant *One = ConstantInt::get(Int32Ty, 1); + + Constant *Global = + M->getOrInsertGlobal("dummy", PointerType::getUnqual(Int32Ty)); + Constant *GEP = ConstantExpr::getGetElementPtr( + PointerType::getUnqual(Int32Ty), Global, One); + EXPECT_DEATH(Global->replaceAllUsesWith(GEP), + "this->replaceAllUsesWith\\(expr\\(this\\)\\) is NOT valid!"); +} + +#endif +#endif + +#undef CHECK + +TEST(ConstantsTest, ConstantArrayReplaceWithConstant) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + Type *IntTy = Type::getInt8Ty(Context); + ArrayType *ArrayTy = ArrayType::get(IntTy, 2); + Constant *A01Vals[2] = {ConstantInt::get(IntTy, 0), + ConstantInt::get(IntTy, 1)}; + Constant *A01 = ConstantArray::get(ArrayTy, A01Vals); + + Constant *Global = new GlobalVariable(*M, IntTy, false, + GlobalValue::ExternalLinkage, nullptr); + Constant *GlobalInt = ConstantExpr::getPtrToInt(Global, IntTy); + Constant *A0GVals[2] = {ConstantInt::get(IntTy, 0), GlobalInt}; + Constant *A0G = ConstantArray::get(ArrayTy, A0GVals); + ASSERT_NE(A01, A0G); + + GlobalVariable *RefArray = + new GlobalVariable(*M, ArrayTy, false, GlobalValue::ExternalLinkage, A0G); + ASSERT_EQ(A0G, RefArray->getInitializer()); + + GlobalInt->replaceAllUsesWith(ConstantInt::get(IntTy, 1)); + ASSERT_EQ(A01, RefArray->getInitializer()); +} + +TEST(ConstantsTest, ConstantExprReplaceWithConstant) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + Type *IntTy = Type::getInt8Ty(Context); + Constant *G1 = new GlobalVariable(*M, IntTy, false, + GlobalValue::ExternalLinkage, nullptr); + Constant *G2 = new GlobalVariable(*M, IntTy, false, + GlobalValue::ExternalLinkage, nullptr); + ASSERT_NE(G1, G2); + + Constant *Int1 = ConstantExpr::getPtrToInt(G1, IntTy); + Constant *Int2 = ConstantExpr::getPtrToInt(G2, IntTy); + ASSERT_NE(Int1, Int2); + + GlobalVariable *Ref = + new GlobalVariable(*M, IntTy, false, GlobalValue::ExternalLinkage, Int1); + ASSERT_EQ(Int1, Ref->getInitializer()); + + G1->replaceAllUsesWith(G2); + ASSERT_EQ(Int2, Ref->getInitializer()); +} + +TEST(ConstantsTest, GEPReplaceWithConstant) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + Type *IntTy = Type::getInt32Ty(Context); + Type *PtrTy = PointerType::get(IntTy, 0); + auto *C1 = ConstantInt::get(IntTy, 1); + auto *Placeholder = new GlobalVariable( + *M, IntTy, false, GlobalValue::ExternalWeakLinkage, nullptr); + auto *GEP = ConstantExpr::getGetElementPtr(IntTy, Placeholder, C1); + ASSERT_EQ(GEP->getOperand(0), Placeholder); + + auto *Ref = + new GlobalVariable(*M, PtrTy, false, GlobalValue::ExternalLinkage, GEP); + ASSERT_EQ(GEP, Ref->getInitializer()); + + auto *Global = new GlobalVariable(*M, PtrTy, false, + GlobalValue::ExternalLinkage, nullptr); + auto *Alias = GlobalAlias::create(IntTy, 0, GlobalValue::ExternalLinkage, + "alias", Global, M.get()); + Placeholder->replaceAllUsesWith(Alias); + ASSERT_EQ(GEP, Ref->getInitializer()); + ASSERT_EQ(GEP->getOperand(0), Alias); +} + +TEST(ConstantsTest, AliasCAPI) { + LLVMContext Context; + SMDiagnostic Error; + std::unique_ptr<Module> M = + parseAssemblyString("@g = global i32 42", Error, Context); + GlobalVariable *G = M->getGlobalVariable("g"); + Type *I16Ty = Type::getInt16Ty(Context); + Type *I16PTy = PointerType::get(I16Ty, 0); + Constant *Aliasee = ConstantExpr::getBitCast(G, I16PTy); + LLVMValueRef AliasRef = + LLVMAddAlias(wrap(M.get()), wrap(I16PTy), wrap(Aliasee), "a"); + ASSERT_EQ(unwrap<GlobalAlias>(AliasRef)->getAliasee(), Aliasee); +} + +static std::string getNameOfType(Type *T) { + std::string S; + raw_string_ostream RSOS(S); + T->print(RSOS); + return S; +} + +TEST(ConstantsTest, BuildConstantDataArrays) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + for (Type *T : {Type::getInt8Ty(Context), Type::getInt16Ty(Context), + Type::getInt32Ty(Context), Type::getInt64Ty(Context)}) { + ArrayType *ArrayTy = ArrayType::get(T, 2); + Constant *Vals[] = {ConstantInt::get(T, 0), ConstantInt::get(T, 1)}; + Constant *CDV = ConstantArray::get(ArrayTy, Vals); + ASSERT_TRUE(dyn_cast<ConstantDataArray>(CDV) != nullptr) + << " T = " << getNameOfType(T); + } + + for (Type *T : {Type::getHalfTy(Context), Type::getFloatTy(Context), + Type::getDoubleTy(Context)}) { + ArrayType *ArrayTy = ArrayType::get(T, 2); + Constant *Vals[] = {ConstantFP::get(T, 0), ConstantFP::get(T, 1)}; + Constant *CDV = ConstantArray::get(ArrayTy, Vals); + ASSERT_TRUE(dyn_cast<ConstantDataArray>(CDV) != nullptr) + << " T = " << getNameOfType(T); + } +} + +TEST(ConstantsTest, BuildConstantDataVectors) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + for (Type *T : {Type::getInt8Ty(Context), Type::getInt16Ty(Context), + Type::getInt32Ty(Context), Type::getInt64Ty(Context)}) { + Constant *Vals[] = {ConstantInt::get(T, 0), ConstantInt::get(T, 1)}; + Constant *CDV = ConstantVector::get(Vals); + ASSERT_TRUE(dyn_cast<ConstantDataVector>(CDV) != nullptr) + << " T = " << getNameOfType(T); + } + + for (Type *T : {Type::getHalfTy(Context), Type::getFloatTy(Context), + Type::getDoubleTy(Context)}) { + Constant *Vals[] = {ConstantFP::get(T, 0), ConstantFP::get(T, 1)}; + Constant *CDV = ConstantVector::get(Vals); + ASSERT_TRUE(dyn_cast<ConstantDataVector>(CDV) != nullptr) + << " T = " << getNameOfType(T); + } +} + +TEST(ConstantsTest, BitcastToGEP) { + LLVMContext Context; + std::unique_ptr<Module> M(new Module("MyModule", Context)); + + auto *i32 = Type::getInt32Ty(Context); + auto *U = StructType::create(Context, "Unsized"); + Type *EltTys[] = {i32, U}; + auto *S = StructType::create(EltTys); + + auto *G = new GlobalVariable(*M, S, false, + GlobalValue::ExternalLinkage, nullptr); + auto *PtrTy = PointerType::get(i32, 0); + auto *C = ConstantExpr::getBitCast(G, PtrTy); + ASSERT_EQ(dyn_cast<ConstantExpr>(C)->getOpcode(), + Instruction::BitCast); +} + +} // end anonymous namespace +} // end namespace llvm diff --git a/gnu/llvm/unittests/IR/DebugInfoTest.cpp b/gnu/llvm/unittests/IR/DebugInfoTest.cpp new file mode 100644 index 00000000000..f633782b379 --- /dev/null +++ b/gnu/llvm/unittests/IR/DebugInfoTest.cpp @@ -0,0 +1,81 @@ +//===- llvm/unittest/IR/DebugInfo.cpp - DebugInfo tests -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/DebugInfoMetadata.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(DINodeTest, getFlag) { + // Some valid flags. + EXPECT_EQ(DINode::FlagPublic, DINode::getFlag("DIFlagPublic")); + EXPECT_EQ(DINode::FlagProtected, DINode::getFlag("DIFlagProtected")); + EXPECT_EQ(DINode::FlagPrivate, DINode::getFlag("DIFlagPrivate")); + EXPECT_EQ(DINode::FlagVector, DINode::getFlag("DIFlagVector")); + EXPECT_EQ(DINode::FlagRValueReference, + DINode::getFlag("DIFlagRValueReference")); + + // FlagAccessibility shouldn't work. + EXPECT_EQ(0u, DINode::getFlag("DIFlagAccessibility")); + + // Some other invalid strings. + EXPECT_EQ(0u, DINode::getFlag("FlagVector")); + EXPECT_EQ(0u, DINode::getFlag("Vector")); + EXPECT_EQ(0u, DINode::getFlag("other things")); + EXPECT_EQ(0u, DINode::getFlag("DIFlagOther")); +} + +TEST(DINodeTest, getFlagString) { + // Some valid flags. + EXPECT_EQ(StringRef("DIFlagPublic"), + DINode::getFlagString(DINode::FlagPublic)); + EXPECT_EQ(StringRef("DIFlagProtected"), + DINode::getFlagString(DINode::FlagProtected)); + EXPECT_EQ(StringRef("DIFlagPrivate"), + DINode::getFlagString(DINode::FlagPrivate)); + EXPECT_EQ(StringRef("DIFlagVector"), + DINode::getFlagString(DINode::FlagVector)); + EXPECT_EQ(StringRef("DIFlagRValueReference"), + DINode::getFlagString(DINode::FlagRValueReference)); + + // FlagAccessibility actually equals FlagPublic. + EXPECT_EQ(StringRef("DIFlagPublic"), + DINode::getFlagString(DINode::FlagAccessibility)); + + // Some other invalid flags. + EXPECT_EQ(StringRef(), + DINode::getFlagString(DINode::FlagPublic | DINode::FlagVector)); + EXPECT_EQ(StringRef(), DINode::getFlagString(DINode::FlagFwdDecl | + DINode::FlagArtificial)); + EXPECT_EQ(StringRef(), DINode::getFlagString(0xffff)); +} + +TEST(DINodeTest, splitFlags) { +// Some valid flags. +#define CHECK_SPLIT(FLAGS, VECTOR, REMAINDER) \ + { \ + SmallVector<unsigned, 8> V; \ + EXPECT_EQ(REMAINDER, DINode::splitFlags(FLAGS, V)); \ + EXPECT_TRUE(makeArrayRef(V).equals(VECTOR)); \ + } + CHECK_SPLIT(DINode::FlagPublic, {DINode::FlagPublic}, 0u); + CHECK_SPLIT(DINode::FlagProtected, {DINode::FlagProtected}, 0u); + CHECK_SPLIT(DINode::FlagPrivate, {DINode::FlagPrivate}, 0u); + CHECK_SPLIT(DINode::FlagVector, {DINode::FlagVector}, 0u); + CHECK_SPLIT(DINode::FlagRValueReference, {DINode::FlagRValueReference}, 0u); + unsigned Flags[] = {DINode::FlagFwdDecl, DINode::FlagVector}; + CHECK_SPLIT(DINode::FlagFwdDecl | DINode::FlagVector, Flags, 0u); + CHECK_SPLIT(0x100000u, {}, 0x100000u); + CHECK_SPLIT(0x100000u | DINode::FlagVector, {DINode::FlagVector}, 0x100000u); +#undef CHECK_SPLIT +} + +} // end namespace diff --git a/gnu/llvm/unittests/IR/DominatorTreeTest.cpp b/gnu/llvm/unittests/IR/DominatorTreeTest.cpp new file mode 100644 index 00000000000..3aef4d64cbc --- /dev/null +++ b/gnu/llvm/unittests/IR/DominatorTreeTest.cpp @@ -0,0 +1,259 @@ +//===- llvm/unittests/IR/DominatorTreeTest.cpp - Constants unit tests -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Dominators.h" +#include "llvm/Analysis/PostDominators.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace llvm { + void initializeDPassPass(PassRegistry&); + + namespace { + struct DPass : public FunctionPass { + static char ID; + bool runOnFunction(Function &F) override { + DominatorTree *DT = + &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); + PostDominatorTree *PDT = &getAnalysis<PostDominatorTree>(); + Function::iterator FI = F.begin(); + + BasicBlock *BB0 = &*FI++; + BasicBlock::iterator BBI = BB0->begin(); + Instruction *Y1 = &*BBI++; + Instruction *Y2 = &*BBI++; + Instruction *Y3 = &*BBI++; + + BasicBlock *BB1 = &*FI++; + BBI = BB1->begin(); + Instruction *Y4 = &*BBI++; + + BasicBlock *BB2 = &*FI++; + BBI = BB2->begin(); + Instruction *Y5 = &*BBI++; + + BasicBlock *BB3 = &*FI++; + BBI = BB3->begin(); + Instruction *Y6 = &*BBI++; + Instruction *Y7 = &*BBI++; + + BasicBlock *BB4 = &*FI++; + BBI = BB4->begin(); + Instruction *Y8 = &*BBI++; + Instruction *Y9 = &*BBI++; + + // Reachability + EXPECT_TRUE(DT->isReachableFromEntry(BB0)); + EXPECT_TRUE(DT->isReachableFromEntry(BB1)); + EXPECT_TRUE(DT->isReachableFromEntry(BB2)); + EXPECT_FALSE(DT->isReachableFromEntry(BB3)); + EXPECT_TRUE(DT->isReachableFromEntry(BB4)); + + // BB dominance + EXPECT_TRUE(DT->dominates(BB0, BB0)); + EXPECT_TRUE(DT->dominates(BB0, BB1)); + EXPECT_TRUE(DT->dominates(BB0, BB2)); + EXPECT_TRUE(DT->dominates(BB0, BB3)); + EXPECT_TRUE(DT->dominates(BB0, BB4)); + + EXPECT_FALSE(DT->dominates(BB1, BB0)); + EXPECT_TRUE(DT->dominates(BB1, BB1)); + EXPECT_FALSE(DT->dominates(BB1, BB2)); + EXPECT_TRUE(DT->dominates(BB1, BB3)); + EXPECT_FALSE(DT->dominates(BB1, BB4)); + + EXPECT_FALSE(DT->dominates(BB2, BB0)); + EXPECT_FALSE(DT->dominates(BB2, BB1)); + EXPECT_TRUE(DT->dominates(BB2, BB2)); + EXPECT_TRUE(DT->dominates(BB2, BB3)); + EXPECT_FALSE(DT->dominates(BB2, BB4)); + + EXPECT_FALSE(DT->dominates(BB3, BB0)); + EXPECT_FALSE(DT->dominates(BB3, BB1)); + EXPECT_FALSE(DT->dominates(BB3, BB2)); + EXPECT_TRUE(DT->dominates(BB3, BB3)); + EXPECT_FALSE(DT->dominates(BB3, BB4)); + + // BB proper dominance + EXPECT_FALSE(DT->properlyDominates(BB0, BB0)); + EXPECT_TRUE(DT->properlyDominates(BB0, BB1)); + EXPECT_TRUE(DT->properlyDominates(BB0, BB2)); + EXPECT_TRUE(DT->properlyDominates(BB0, BB3)); + + EXPECT_FALSE(DT->properlyDominates(BB1, BB0)); + EXPECT_FALSE(DT->properlyDominates(BB1, BB1)); + EXPECT_FALSE(DT->properlyDominates(BB1, BB2)); + EXPECT_TRUE(DT->properlyDominates(BB1, BB3)); + + EXPECT_FALSE(DT->properlyDominates(BB2, BB0)); + EXPECT_FALSE(DT->properlyDominates(BB2, BB1)); + EXPECT_FALSE(DT->properlyDominates(BB2, BB2)); + EXPECT_TRUE(DT->properlyDominates(BB2, BB3)); + + EXPECT_FALSE(DT->properlyDominates(BB3, BB0)); + EXPECT_FALSE(DT->properlyDominates(BB3, BB1)); + EXPECT_FALSE(DT->properlyDominates(BB3, BB2)); + EXPECT_FALSE(DT->properlyDominates(BB3, BB3)); + + // Instruction dominance in the same reachable BB + EXPECT_FALSE(DT->dominates(Y1, Y1)); + EXPECT_TRUE(DT->dominates(Y1, Y2)); + EXPECT_FALSE(DT->dominates(Y2, Y1)); + EXPECT_FALSE(DT->dominates(Y2, Y2)); + + // Instruction dominance in the same unreachable BB + EXPECT_TRUE(DT->dominates(Y6, Y6)); + EXPECT_TRUE(DT->dominates(Y6, Y7)); + EXPECT_TRUE(DT->dominates(Y7, Y6)); + EXPECT_TRUE(DT->dominates(Y7, Y7)); + + // Invoke + EXPECT_TRUE(DT->dominates(Y3, Y4)); + EXPECT_FALSE(DT->dominates(Y3, Y5)); + + // Phi + EXPECT_TRUE(DT->dominates(Y2, Y9)); + EXPECT_FALSE(DT->dominates(Y3, Y9)); + EXPECT_FALSE(DT->dominates(Y8, Y9)); + + // Anything dominates unreachable + EXPECT_TRUE(DT->dominates(Y1, Y6)); + EXPECT_TRUE(DT->dominates(Y3, Y6)); + + // Unreachable doesn't dominate reachable + EXPECT_FALSE(DT->dominates(Y6, Y1)); + + // Instruction, BB dominance + EXPECT_FALSE(DT->dominates(Y1, BB0)); + EXPECT_TRUE(DT->dominates(Y1, BB1)); + EXPECT_TRUE(DT->dominates(Y1, BB2)); + EXPECT_TRUE(DT->dominates(Y1, BB3)); + EXPECT_TRUE(DT->dominates(Y1, BB4)); + + EXPECT_FALSE(DT->dominates(Y3, BB0)); + EXPECT_TRUE(DT->dominates(Y3, BB1)); + EXPECT_FALSE(DT->dominates(Y3, BB2)); + EXPECT_TRUE(DT->dominates(Y3, BB3)); + EXPECT_FALSE(DT->dominates(Y3, BB4)); + + EXPECT_TRUE(DT->dominates(Y6, BB3)); + + // Post dominance. + EXPECT_TRUE(PDT->dominates(BB0, BB0)); + EXPECT_FALSE(PDT->dominates(BB1, BB0)); + EXPECT_FALSE(PDT->dominates(BB2, BB0)); + EXPECT_FALSE(PDT->dominates(BB3, BB0)); + EXPECT_TRUE(PDT->dominates(BB4, BB1)); + + // Dominance descendants. + SmallVector<BasicBlock *, 8> DominatedBBs, PostDominatedBBs; + + DT->getDescendants(BB0, DominatedBBs); + PDT->getDescendants(BB0, PostDominatedBBs); + EXPECT_EQ(DominatedBBs.size(), 4UL); + EXPECT_EQ(PostDominatedBBs.size(), 1UL); + + // BB3 is unreachable. It should have no dominators nor postdominators. + DominatedBBs.clear(); + PostDominatedBBs.clear(); + DT->getDescendants(BB3, DominatedBBs); + DT->getDescendants(BB3, PostDominatedBBs); + EXPECT_EQ(DominatedBBs.size(), 0UL); + EXPECT_EQ(PostDominatedBBs.size(), 0UL); + + // Check DFS Numbers before + EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL); + EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 7UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 2UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 5UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 6UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 3UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 4UL); + + // Reattach block 3 to block 1 and recalculate + BB1->getTerminator()->eraseFromParent(); + BranchInst::Create(BB4, BB3, ConstantInt::getTrue(F.getContext()), BB1); + DT->recalculate(F); + + // Check DFS Numbers after + EXPECT_EQ(DT->getNode(BB0)->getDFSNumIn(), 0UL); + EXPECT_EQ(DT->getNode(BB0)->getDFSNumOut(), 9UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumIn(), 1UL); + EXPECT_EQ(DT->getNode(BB1)->getDFSNumOut(), 4UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumIn(), 7UL); + EXPECT_EQ(DT->getNode(BB2)->getDFSNumOut(), 8UL); + EXPECT_EQ(DT->getNode(BB3)->getDFSNumIn(), 2UL); + EXPECT_EQ(DT->getNode(BB3)->getDFSNumOut(), 3UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumIn(), 5UL); + EXPECT_EQ(DT->getNode(BB4)->getDFSNumOut(), 6UL); + + return false; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<DominatorTreeWrapperPass>(); + AU.addRequired<PostDominatorTree>(); + } + DPass() : FunctionPass(ID) { + initializeDPassPass(*PassRegistry::getPassRegistry()); + } + }; + char DPass::ID = 0; + + std::unique_ptr<Module> makeLLVMModule(DPass *P) { + const char *ModuleStrig = + "declare i32 @g()\n" \ + "define void @f(i32 %x) personality i32 ()* @g {\n" \ + "bb0:\n" \ + " %y1 = add i32 %x, 1\n" \ + " %y2 = add i32 %x, 1\n" \ + " %y3 = invoke i32 @g() to label %bb1 unwind label %bb2\n" \ + "bb1:\n" \ + " %y4 = add i32 %x, 1\n" \ + " br label %bb4\n" \ + "bb2:\n" \ + " %y5 = landingpad i32\n" \ + " cleanup\n" \ + " br label %bb4\n" \ + "bb3:\n" \ + " %y6 = add i32 %x, 1\n" \ + " %y7 = add i32 %x, 1\n" \ + " ret void\n" \ + "bb4:\n" \ + " %y8 = phi i32 [0, %bb2], [%y4, %bb1]\n" + " %y9 = phi i32 [0, %bb2], [%y4, %bb1]\n" + " ret void\n" \ + "}\n"; + LLVMContext &C = getGlobalContext(); + SMDiagnostic Err; + return parseAssemblyString(ModuleStrig, Err, C); + } + + TEST(DominatorTree, Unreachable) { + DPass *P = new DPass(); + std::unique_ptr<Module> M = makeLLVMModule(P); + legacy::PassManager Passes; + Passes.add(P); + Passes.run(*M); + } + } +} + +INITIALIZE_PASS_BEGIN(DPass, "dpass", "dpass", false, false) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(PostDominatorTree) +INITIALIZE_PASS_END(DPass, "dpass", "dpass", false, false) diff --git a/gnu/llvm/unittests/IR/IRBuilderTest.cpp b/gnu/llvm/unittests/IR/IRBuilderTest.cpp new file mode 100644 index 00000000000..bd0eae0399a --- /dev/null +++ b/gnu/llvm/unittests/IR/IRBuilderTest.cpp @@ -0,0 +1,421 @@ +//===- llvm/unittest/IR/IRBuilderTest.cpp - IRBuilder tests ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/NoFolder.h" +#include "llvm/IR/Verifier.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class IRBuilderTest : public testing::Test { +protected: + void SetUp() override { + M.reset(new Module("MyModule", Ctx)); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), + /*isVarArg=*/false); + F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); + BB = BasicBlock::Create(Ctx, "", F); + GV = new GlobalVariable(*M, Type::getFloatTy(Ctx), true, + GlobalValue::ExternalLinkage, nullptr); + } + + void TearDown() override { + BB = nullptr; + M.reset(); + } + + LLVMContext Ctx; + std::unique_ptr<Module> M; + Function *F; + BasicBlock *BB; + GlobalVariable *GV; +}; + +TEST_F(IRBuilderTest, Lifetime) { + IRBuilder<> Builder(BB); + AllocaInst *Var1 = Builder.CreateAlloca(Builder.getInt8Ty()); + AllocaInst *Var2 = Builder.CreateAlloca(Builder.getInt32Ty()); + AllocaInst *Var3 = Builder.CreateAlloca(Builder.getInt8Ty(), + Builder.getInt32(123)); + + CallInst *Start1 = Builder.CreateLifetimeStart(Var1); + CallInst *Start2 = Builder.CreateLifetimeStart(Var2); + CallInst *Start3 = Builder.CreateLifetimeStart(Var3, Builder.getInt64(100)); + + EXPECT_EQ(Start1->getArgOperand(0), Builder.getInt64(-1)); + EXPECT_EQ(Start2->getArgOperand(0), Builder.getInt64(-1)); + EXPECT_EQ(Start3->getArgOperand(0), Builder.getInt64(100)); + + EXPECT_EQ(Start1->getArgOperand(1), Var1); + EXPECT_NE(Start2->getArgOperand(1), Var2); + EXPECT_EQ(Start3->getArgOperand(1), Var3); + + Value *End1 = Builder.CreateLifetimeEnd(Var1); + Builder.CreateLifetimeEnd(Var2); + Builder.CreateLifetimeEnd(Var3); + + IntrinsicInst *II_Start1 = dyn_cast<IntrinsicInst>(Start1); + IntrinsicInst *II_End1 = dyn_cast<IntrinsicInst>(End1); + ASSERT_TRUE(II_Start1 != nullptr); + EXPECT_EQ(II_Start1->getIntrinsicID(), Intrinsic::lifetime_start); + ASSERT_TRUE(II_End1 != nullptr); + EXPECT_EQ(II_End1->getIntrinsicID(), Intrinsic::lifetime_end); +} + +TEST_F(IRBuilderTest, CreateCondBr) { + IRBuilder<> Builder(BB); + BasicBlock *TBB = BasicBlock::Create(Ctx, "", F); + BasicBlock *FBB = BasicBlock::Create(Ctx, "", F); + + BranchInst *BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB); + TerminatorInst *TI = BB->getTerminator(); + EXPECT_EQ(BI, TI); + EXPECT_EQ(2u, TI->getNumSuccessors()); + EXPECT_EQ(TBB, TI->getSuccessor(0)); + EXPECT_EQ(FBB, TI->getSuccessor(1)); + + BI->eraseFromParent(); + MDNode *Weights = MDBuilder(Ctx).createBranchWeights(42, 13); + BI = Builder.CreateCondBr(Builder.getTrue(), TBB, FBB, Weights); + TI = BB->getTerminator(); + EXPECT_EQ(BI, TI); + EXPECT_EQ(2u, TI->getNumSuccessors()); + EXPECT_EQ(TBB, TI->getSuccessor(0)); + EXPECT_EQ(FBB, TI->getSuccessor(1)); + EXPECT_EQ(Weights, TI->getMetadata(LLVMContext::MD_prof)); +} + +TEST_F(IRBuilderTest, LandingPadName) { + IRBuilder<> Builder(BB); + LandingPadInst *LP = Builder.CreateLandingPad(Builder.getInt32Ty(), 0, "LP"); + EXPECT_EQ(LP->getName(), "LP"); +} + +TEST_F(IRBuilderTest, DataLayout) { + std::unique_ptr<Module> M(new Module("test", Ctx)); + M->setDataLayout("e-n32"); + EXPECT_TRUE(M->getDataLayout().isLegalInteger(32)); + M->setDataLayout("e"); + EXPECT_FALSE(M->getDataLayout().isLegalInteger(32)); +} + +TEST_F(IRBuilderTest, GetIntTy) { + IRBuilder<> Builder(BB); + IntegerType *Ty1 = Builder.getInt1Ty(); + EXPECT_EQ(Ty1, IntegerType::get(Ctx, 1)); + + DataLayout* DL = new DataLayout(M.get()); + IntegerType *IntPtrTy = Builder.getIntPtrTy(*DL); + unsigned IntPtrBitSize = DL->getPointerSizeInBits(0); + EXPECT_EQ(IntPtrTy, IntegerType::get(Ctx, IntPtrBitSize)); + delete DL; +} + +TEST_F(IRBuilderTest, FastMathFlags) { + IRBuilder<> Builder(BB); + Value *F, *FC; + Instruction *FDiv, *FAdd, *FCmp, *FCall; + + F = Builder.CreateLoad(GV); + F = Builder.CreateFAdd(F, F); + + EXPECT_FALSE(Builder.getFastMathFlags().any()); + ASSERT_TRUE(isa<Instruction>(F)); + FAdd = cast<Instruction>(F); + EXPECT_FALSE(FAdd->hasNoNaNs()); + + FastMathFlags FMF; + Builder.setFastMathFlags(FMF); + + F = Builder.CreateFAdd(F, F); + EXPECT_FALSE(Builder.getFastMathFlags().any()); + + FMF.setUnsafeAlgebra(); + Builder.setFastMathFlags(FMF); + + F = Builder.CreateFAdd(F, F); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + ASSERT_TRUE(isa<Instruction>(F)); + FAdd = cast<Instruction>(F); + EXPECT_TRUE(FAdd->hasNoNaNs()); + + // Now, try it with CreateBinOp + F = Builder.CreateBinOp(Instruction::FAdd, F, F); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + ASSERT_TRUE(isa<Instruction>(F)); + FAdd = cast<Instruction>(F); + EXPECT_TRUE(FAdd->hasNoNaNs()); + + F = Builder.CreateFDiv(F, F); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().UnsafeAlgebra); + ASSERT_TRUE(isa<Instruction>(F)); + FDiv = cast<Instruction>(F); + EXPECT_TRUE(FDiv->hasAllowReciprocal()); + + Builder.clearFastMathFlags(); + + F = Builder.CreateFDiv(F, F); + ASSERT_TRUE(isa<Instruction>(F)); + FDiv = cast<Instruction>(F); + EXPECT_FALSE(FDiv->hasAllowReciprocal()); + + FMF.clear(); + FMF.setAllowReciprocal(); + Builder.setFastMathFlags(FMF); + + F = Builder.CreateFDiv(F, F); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal); + ASSERT_TRUE(isa<Instruction>(F)); + FDiv = cast<Instruction>(F); + EXPECT_TRUE(FDiv->hasAllowReciprocal()); + + Builder.clearFastMathFlags(); + + FC = Builder.CreateFCmpOEQ(F, F); + ASSERT_TRUE(isa<Instruction>(FC)); + FCmp = cast<Instruction>(FC); + EXPECT_FALSE(FCmp->hasAllowReciprocal()); + + FMF.clear(); + FMF.setAllowReciprocal(); + Builder.setFastMathFlags(FMF); + + FC = Builder.CreateFCmpOEQ(F, F); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal); + ASSERT_TRUE(isa<Instruction>(FC)); + FCmp = cast<Instruction>(FC); + EXPECT_TRUE(FCmp->hasAllowReciprocal()); + + Builder.clearFastMathFlags(); + + // Test a call with FMF. + auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx), + /*isVarArg=*/false); + auto Callee = + Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get()); + + FCall = Builder.CreateCall(Callee, None); + EXPECT_FALSE(FCall->hasNoNaNs()); + + Value *V = + Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get()); + FCall = Builder.CreateCall(V, None); + EXPECT_FALSE(FCall->hasNoNaNs()); + + FMF.clear(); + FMF.setNoNaNs(); + Builder.setFastMathFlags(FMF); + + FCall = Builder.CreateCall(Callee, None); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs); + EXPECT_TRUE(FCall->hasNoNaNs()); + + FCall = Builder.CreateCall(V, None); + EXPECT_TRUE(Builder.getFastMathFlags().any()); + EXPECT_TRUE(Builder.getFastMathFlags().NoNaNs); + EXPECT_TRUE(FCall->hasNoNaNs()); + + Builder.clearFastMathFlags(); + + // To test a copy, make sure that a '0' and a '1' change state. + F = Builder.CreateFDiv(F, F); + ASSERT_TRUE(isa<Instruction>(F)); + FDiv = cast<Instruction>(F); + EXPECT_FALSE(FDiv->getFastMathFlags().any()); + FDiv->setHasAllowReciprocal(true); + FAdd->setHasAllowReciprocal(false); + FDiv->copyFastMathFlags(FAdd); + EXPECT_TRUE(FDiv->hasNoNaNs()); + EXPECT_FALSE(FDiv->hasAllowReciprocal()); + +} + +TEST_F(IRBuilderTest, WrapFlags) { + IRBuilder<true, NoFolder> Builder(BB); + + // Test instructions. + GlobalVariable *G = new GlobalVariable(*M, Builder.getInt32Ty(), true, + GlobalValue::ExternalLinkage, nullptr); + Value *V = Builder.CreateLoad(G); + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNSWAdd(V, V))->hasNoSignedWrap()); + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNSWMul(V, V))->hasNoSignedWrap()); + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNSWSub(V, V))->hasNoSignedWrap()); + EXPECT_TRUE(cast<BinaryOperator>( + Builder.CreateShl(V, V, "", /* NUW */ false, /* NSW */ true)) + ->hasNoSignedWrap()); + + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNUWAdd(V, V))->hasNoUnsignedWrap()); + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNUWMul(V, V))->hasNoUnsignedWrap()); + EXPECT_TRUE( + cast<BinaryOperator>(Builder.CreateNUWSub(V, V))->hasNoUnsignedWrap()); + EXPECT_TRUE(cast<BinaryOperator>( + Builder.CreateShl(V, V, "", /* NUW */ true, /* NSW */ false)) + ->hasNoUnsignedWrap()); + + // Test operators created with constants. + Constant *C = Builder.getInt32(42); + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWAdd(C, C)) + ->hasNoSignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWSub(C, C)) + ->hasNoSignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNSWMul(C, C)) + ->hasNoSignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>( + Builder.CreateShl(C, C, "", /* NUW */ false, /* NSW */ true)) + ->hasNoSignedWrap()); + + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWAdd(C, C)) + ->hasNoUnsignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWSub(C, C)) + ->hasNoUnsignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>(Builder.CreateNUWMul(C, C)) + ->hasNoUnsignedWrap()); + EXPECT_TRUE(cast<OverflowingBinaryOperator>( + Builder.CreateShl(C, C, "", /* NUW */ true, /* NSW */ false)) + ->hasNoUnsignedWrap()); +} + +TEST_F(IRBuilderTest, RAIIHelpersTest) { + IRBuilder<> Builder(BB); + EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); + MDBuilder MDB(M->getContext()); + + MDNode *FPMathA = MDB.createFPMath(0.01f); + MDNode *FPMathB = MDB.createFPMath(0.1f); + + Builder.setDefaultFPMathTag(FPMathA); + + { + IRBuilder<>::FastMathFlagGuard Guard(Builder); + FastMathFlags FMF; + FMF.setAllowReciprocal(); + Builder.setFastMathFlags(FMF); + Builder.setDefaultFPMathTag(FPMathB); + EXPECT_TRUE(Builder.getFastMathFlags().allowReciprocal()); + EXPECT_EQ(FPMathB, Builder.getDefaultFPMathTag()); + } + + EXPECT_FALSE(Builder.getFastMathFlags().allowReciprocal()); + EXPECT_EQ(FPMathA, Builder.getDefaultFPMathTag()); + + Value *F = Builder.CreateLoad(GV); + + { + IRBuilder<>::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(cast<Instruction>(F)); + EXPECT_EQ(F, &*Builder.GetInsertPoint()); + } + + EXPECT_EQ(BB->end(), Builder.GetInsertPoint()); + EXPECT_EQ(BB, Builder.GetInsertBlock()); +} + +TEST_F(IRBuilderTest, DIBuilder) { + IRBuilder<> Builder(BB); + DIBuilder DIB(*M); + auto File = DIB.createFile("F.CBL", "/"); + auto CU = DIB.createCompileUnit(dwarf::DW_LANG_Cobol74, "F.CBL", "/", + "llvm-cobol74", true, "", 0); + auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); + auto SP = + DIB.createFunction(CU, "foo", "", File, 1, Type, false, true, 1, 0, true); + F->setSubprogram(SP); + AllocaInst *I = Builder.CreateAlloca(Builder.getInt8Ty()); + auto BarSP = + DIB.createFunction(CU, "bar", "", File, 1, Type, false, true, 1, 0, true); + auto BadScope = DIB.createLexicalBlockFile(BarSP, File, 0); + I->setDebugLoc(DebugLoc::get(2, 0, BadScope)); + DIB.finalize(); + EXPECT_TRUE(verifyModule(*M)); +} + +TEST_F(IRBuilderTest, InsertExtractElement) { + IRBuilder<> Builder(BB); + + auto VecTy = VectorType::get(Builder.getInt64Ty(), 4); + auto Elt1 = Builder.getInt64(-1); + auto Elt2 = Builder.getInt64(-2); + Value *Vec = UndefValue::get(VecTy); + Vec = Builder.CreateInsertElement(Vec, Elt1, Builder.getInt8(1)); + Vec = Builder.CreateInsertElement(Vec, Elt2, 2); + auto X1 = Builder.CreateExtractElement(Vec, 1); + auto X2 = Builder.CreateExtractElement(Vec, Builder.getInt32(2)); + EXPECT_EQ(Elt1, X1); + EXPECT_EQ(Elt2, X2); +} + +TEST_F(IRBuilderTest, CreateGlobalStringPtr) { + IRBuilder<> Builder(BB); + + auto String1a = Builder.CreateGlobalStringPtr("TestString", "String1a"); + auto String1b = Builder.CreateGlobalStringPtr("TestString", "String1b", 0); + auto String2 = Builder.CreateGlobalStringPtr("TestString", "String2", 1); + auto String3 = Builder.CreateGlobalString("TestString", "String3", 2); + + EXPECT_TRUE(String1a->getType()->getPointerAddressSpace() == 0); + EXPECT_TRUE(String1b->getType()->getPointerAddressSpace() == 0); + EXPECT_TRUE(String2->getType()->getPointerAddressSpace() == 1); + EXPECT_TRUE(String3->getType()->getPointerAddressSpace() == 2); +} + +TEST_F(IRBuilderTest, DebugLoc) { + auto CalleeTy = FunctionType::get(Type::getVoidTy(Ctx), + /*isVarArg=*/false); + auto Callee = + Function::Create(CalleeTy, Function::ExternalLinkage, "", M.get()); + + DIBuilder DIB(*M); + auto File = DIB.createFile("tmp.cpp", "/"); + auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C_plus_plus_11, "tmp.cpp", "/", + "", true, "", 0); + auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); + auto SP = + DIB.createFunction(CU, "foo", "foo", File, 1, SPType, false, true, 1); + DebugLoc DL1 = DILocation::get(Ctx, 2, 0, SP); + DebugLoc DL2 = DILocation::get(Ctx, 3, 0, SP); + + auto BB2 = BasicBlock::Create(Ctx, "bb2", F); + auto Br = BranchInst::Create(BB2, BB); + Br->setDebugLoc(DL1); + + IRBuilder<> Builder(Ctx); + Builder.SetInsertPoint(Br); + EXPECT_EQ(DL1, Builder.getCurrentDebugLocation()); + auto Call1 = Builder.CreateCall(Callee, None); + EXPECT_EQ(DL1, Call1->getDebugLoc()); + + Call1->setDebugLoc(DL2); + Builder.SetInsertPoint(Call1->getParent(), Call1->getIterator()); + EXPECT_EQ(DL2, Builder.getCurrentDebugLocation()); + auto Call2 = Builder.CreateCall(Callee, None); + EXPECT_EQ(DL2, Call2->getDebugLoc()); + + DIB.finalize(); +} +} diff --git a/gnu/llvm/unittests/IR/InstructionsTest.cpp b/gnu/llvm/unittests/IR/InstructionsTest.cpp new file mode 100644 index 00000000000..3ca3ad2b6e8 --- /dev/null +++ b/gnu/llvm/unittests/IR/InstructionsTest.cpp @@ -0,0 +1,524 @@ +//===- llvm/unittest/IR/InstructionsTest.cpp - Instructions unit tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Instructions.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "gtest/gtest.h" +#include <memory> + +namespace llvm { +namespace { + +TEST(InstructionsTest, ReturnInst) { + LLVMContext &C(getGlobalContext()); + + // test for PR6589 + const ReturnInst* r0 = ReturnInst::Create(C); + EXPECT_EQ(r0->getNumOperands(), 0U); + EXPECT_EQ(r0->op_begin(), r0->op_end()); + + IntegerType* Int1 = IntegerType::get(C, 1); + Constant* One = ConstantInt::get(Int1, 1, true); + const ReturnInst* r1 = ReturnInst::Create(C, One); + EXPECT_EQ(1U, r1->getNumOperands()); + User::const_op_iterator b(r1->op_begin()); + EXPECT_NE(r1->op_end(), b); + EXPECT_EQ(One, *b); + EXPECT_EQ(One, r1->getOperand(0)); + ++b; + EXPECT_EQ(r1->op_end(), b); + + // clean up + delete r0; + delete r1; +} + +// Test fixture that provides a module and a single function within it. Useful +// for tests that need to refer to the function in some way. +class ModuleWithFunctionTest : public testing::Test { +protected: + ModuleWithFunctionTest() : M(new Module("MyModule", Ctx)) { + FArgTypes.push_back(Type::getInt8Ty(Ctx)); + FArgTypes.push_back(Type::getInt32Ty(Ctx)); + FArgTypes.push_back(Type::getInt64Ty(Ctx)); + FunctionType *FTy = + FunctionType::get(Type::getVoidTy(Ctx), FArgTypes, false); + F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); + } + + LLVMContext Ctx; + std::unique_ptr<Module> M; + SmallVector<Type *, 3> FArgTypes; + Function *F; +}; + +TEST_F(ModuleWithFunctionTest, CallInst) { + Value *Args[] = {ConstantInt::get(Type::getInt8Ty(Ctx), 20), + ConstantInt::get(Type::getInt32Ty(Ctx), 9999), + ConstantInt::get(Type::getInt64Ty(Ctx), 42)}; + std::unique_ptr<CallInst> Call(CallInst::Create(F, Args)); + + // Make sure iteration over a call's arguments works as expected. + unsigned Idx = 0; + for (Value *Arg : Call->arg_operands()) { + EXPECT_EQ(FArgTypes[Idx], Arg->getType()); + EXPECT_EQ(Call->getArgOperand(Idx)->getType(), Arg->getType()); + Idx++; + } +} + +TEST_F(ModuleWithFunctionTest, InvokeInst) { + BasicBlock *BB1 = BasicBlock::Create(Ctx, "", F); + BasicBlock *BB2 = BasicBlock::Create(Ctx, "", F); + + Value *Args[] = {ConstantInt::get(Type::getInt8Ty(Ctx), 20), + ConstantInt::get(Type::getInt32Ty(Ctx), 9999), + ConstantInt::get(Type::getInt64Ty(Ctx), 42)}; + std::unique_ptr<InvokeInst> Invoke(InvokeInst::Create(F, BB1, BB2, Args)); + + // Make sure iteration over invoke's arguments works as expected. + unsigned Idx = 0; + for (Value *Arg : Invoke->arg_operands()) { + EXPECT_EQ(FArgTypes[Idx], Arg->getType()); + EXPECT_EQ(Invoke->getArgOperand(Idx)->getType(), Arg->getType()); + Idx++; + } +} + +TEST(InstructionsTest, BranchInst) { + LLVMContext &C(getGlobalContext()); + + // Make a BasicBlocks + BasicBlock* bb0 = BasicBlock::Create(C); + BasicBlock* bb1 = BasicBlock::Create(C); + + // Mandatory BranchInst + const BranchInst* b0 = BranchInst::Create(bb0); + + EXPECT_TRUE(b0->isUnconditional()); + EXPECT_FALSE(b0->isConditional()); + EXPECT_EQ(1U, b0->getNumSuccessors()); + + // check num operands + EXPECT_EQ(1U, b0->getNumOperands()); + + EXPECT_NE(b0->op_begin(), b0->op_end()); + EXPECT_EQ(b0->op_end(), std::next(b0->op_begin())); + + EXPECT_EQ(b0->op_end(), std::next(b0->op_begin())); + + IntegerType* Int1 = IntegerType::get(C, 1); + Constant* One = ConstantInt::get(Int1, 1, true); + + // Conditional BranchInst + BranchInst* b1 = BranchInst::Create(bb0, bb1, One); + + EXPECT_FALSE(b1->isUnconditional()); + EXPECT_TRUE(b1->isConditional()); + EXPECT_EQ(2U, b1->getNumSuccessors()); + + // check num operands + EXPECT_EQ(3U, b1->getNumOperands()); + + User::const_op_iterator b(b1->op_begin()); + + // check COND + EXPECT_NE(b, b1->op_end()); + EXPECT_EQ(One, *b); + EXPECT_EQ(One, b1->getOperand(0)); + EXPECT_EQ(One, b1->getCondition()); + ++b; + + // check ELSE + EXPECT_EQ(bb1, *b); + EXPECT_EQ(bb1, b1->getOperand(1)); + EXPECT_EQ(bb1, b1->getSuccessor(1)); + ++b; + + // check THEN + EXPECT_EQ(bb0, *b); + EXPECT_EQ(bb0, b1->getOperand(2)); + EXPECT_EQ(bb0, b1->getSuccessor(0)); + ++b; + + EXPECT_EQ(b1->op_end(), b); + + // clean up + delete b0; + delete b1; + + delete bb0; + delete bb1; +} + +TEST(InstructionsTest, CastInst) { + LLVMContext &C(getGlobalContext()); + + Type *Int8Ty = Type::getInt8Ty(C); + Type *Int16Ty = Type::getInt16Ty(C); + Type *Int32Ty = Type::getInt32Ty(C); + Type *Int64Ty = Type::getInt64Ty(C); + Type *V8x8Ty = VectorType::get(Int8Ty, 8); + Type *V8x64Ty = VectorType::get(Int64Ty, 8); + Type *X86MMXTy = Type::getX86_MMXTy(C); + + Type *HalfTy = Type::getHalfTy(C); + Type *FloatTy = Type::getFloatTy(C); + Type *DoubleTy = Type::getDoubleTy(C); + + Type *V2Int32Ty = VectorType::get(Int32Ty, 2); + Type *V2Int64Ty = VectorType::get(Int64Ty, 2); + Type *V4Int16Ty = VectorType::get(Int16Ty, 4); + + Type *Int32PtrTy = PointerType::get(Int32Ty, 0); + Type *Int64PtrTy = PointerType::get(Int64Ty, 0); + + Type *Int32PtrAS1Ty = PointerType::get(Int32Ty, 1); + Type *Int64PtrAS1Ty = PointerType::get(Int64Ty, 1); + + Type *V2Int32PtrAS1Ty = VectorType::get(Int32PtrAS1Ty, 2); + Type *V2Int64PtrAS1Ty = VectorType::get(Int64PtrAS1Ty, 2); + Type *V4Int32PtrAS1Ty = VectorType::get(Int32PtrAS1Ty, 4); + Type *V4Int64PtrAS1Ty = VectorType::get(Int64PtrAS1Ty, 4); + + Type *V2Int64PtrTy = VectorType::get(Int64PtrTy, 2); + Type *V2Int32PtrTy = VectorType::get(Int32PtrTy, 2); + Type *V4Int32PtrTy = VectorType::get(Int32PtrTy, 4); + + const Constant* c8 = Constant::getNullValue(V8x8Ty); + const Constant* c64 = Constant::getNullValue(V8x64Ty); + + const Constant *v2ptr32 = Constant::getNullValue(V2Int32PtrTy); + + EXPECT_TRUE(CastInst::isCastable(V8x8Ty, X86MMXTy)); + EXPECT_TRUE(CastInst::isCastable(X86MMXTy, V8x8Ty)); + EXPECT_FALSE(CastInst::isCastable(Int64Ty, X86MMXTy)); + EXPECT_TRUE(CastInst::isCastable(V8x64Ty, V8x8Ty)); + EXPECT_TRUE(CastInst::isCastable(V8x8Ty, V8x64Ty)); + EXPECT_EQ(CastInst::Trunc, CastInst::getCastOpcode(c64, true, V8x8Ty, true)); + EXPECT_EQ(CastInst::SExt, CastInst::getCastOpcode(c8, true, V8x64Ty, true)); + + EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, X86MMXTy)); + EXPECT_FALSE(CastInst::isBitCastable(X86MMXTy, V8x8Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, X86MMXTy)); + EXPECT_FALSE(CastInst::isBitCastable(V8x64Ty, V8x8Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V8x8Ty, V8x64Ty)); + + // Check address space casts are rejected since we don't know the sizes here + EXPECT_FALSE(CastInst::isBitCastable(Int32PtrTy, Int32PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int32PtrAS1Ty, Int32PtrTy)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, V2Int32PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int32PtrTy)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V2Int64PtrAS1Ty)); + EXPECT_TRUE(CastInst::isCastable(V2Int32PtrAS1Ty, V2Int32PtrTy)); + EXPECT_EQ(CastInst::AddrSpaceCast, CastInst::getCastOpcode(v2ptr32, true, + V2Int32PtrAS1Ty, + true)); + + // Test mismatched number of elements for pointers + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int64PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V4Int64PtrAS1Ty, V2Int32PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrAS1Ty, V4Int32PtrAS1Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int32PtrTy, V2Int32PtrTy)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int32PtrTy)); + + EXPECT_TRUE(CastInst::isBitCastable(Int32PtrTy, Int64PtrTy)); + EXPECT_FALSE(CastInst::isBitCastable(DoubleTy, FloatTy)); + EXPECT_FALSE(CastInst::isBitCastable(FloatTy, DoubleTy)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, FloatTy)); + EXPECT_TRUE(CastInst::isBitCastable(FloatTy, Int32Ty)); + EXPECT_TRUE(CastInst::isBitCastable(Int16Ty, HalfTy)); + EXPECT_TRUE(CastInst::isBitCastable(Int32Ty, FloatTy)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, Int64Ty)); + + EXPECT_TRUE(CastInst::isBitCastable(V2Int32Ty, V4Int16Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int32Ty, Int64Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, Int32Ty)); + + EXPECT_FALSE(CastInst::isBitCastable(V2Int32PtrTy, Int64Ty)); + EXPECT_FALSE(CastInst::isBitCastable(Int64Ty, V2Int32PtrTy)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int64PtrTy, V2Int32PtrTy)); + EXPECT_TRUE(CastInst::isBitCastable(V2Int32PtrTy, V2Int64PtrTy)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int32Ty, V2Int64Ty)); + EXPECT_FALSE(CastInst::isBitCastable(V2Int64Ty, V2Int32Ty)); + + + EXPECT_FALSE(CastInst::castIsValid(Instruction::BitCast, + Constant::getNullValue(V4Int32PtrTy), + V2Int32PtrTy)); + EXPECT_FALSE(CastInst::castIsValid(Instruction::BitCast, + Constant::getNullValue(V2Int32PtrTy), + V4Int32PtrTy)); + + EXPECT_FALSE(CastInst::castIsValid(Instruction::AddrSpaceCast, + Constant::getNullValue(V4Int32PtrAS1Ty), + V2Int32PtrTy)); + EXPECT_FALSE(CastInst::castIsValid(Instruction::AddrSpaceCast, + Constant::getNullValue(V2Int32PtrTy), + V4Int32PtrAS1Ty)); + + + // Check that assertion is not hit when creating a cast with a vector of + // pointers + // First form + BasicBlock *BB = BasicBlock::Create(C); + Constant *NullV2I32Ptr = Constant::getNullValue(V2Int32PtrTy); + CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty, "foo", BB); + + // Second form + CastInst::CreatePointerCast(NullV2I32Ptr, V2Int32Ty); +} + +TEST(InstructionsTest, VectorGep) { + LLVMContext &C(getGlobalContext()); + + // Type Definitions + Type *I8Ty = IntegerType::get(C, 8); + Type *I32Ty = IntegerType::get(C, 32); + PointerType *Ptri8Ty = PointerType::get(I8Ty, 0); + PointerType *Ptri32Ty = PointerType::get(I32Ty, 0); + + VectorType *V2xi8PTy = VectorType::get(Ptri8Ty, 2); + VectorType *V2xi32PTy = VectorType::get(Ptri32Ty, 2); + + // Test different aspects of the vector-of-pointers type + // and GEPs which use this type. + ConstantInt *Ci32a = ConstantInt::get(C, APInt(32, 1492)); + ConstantInt *Ci32b = ConstantInt::get(C, APInt(32, 1948)); + std::vector<Constant*> ConstVa(2, Ci32a); + std::vector<Constant*> ConstVb(2, Ci32b); + Constant *C2xi32a = ConstantVector::get(ConstVa); + Constant *C2xi32b = ConstantVector::get(ConstVb); + + CastInst *PtrVecA = new IntToPtrInst(C2xi32a, V2xi32PTy); + CastInst *PtrVecB = new IntToPtrInst(C2xi32b, V2xi32PTy); + + ICmpInst *ICmp0 = new ICmpInst(ICmpInst::ICMP_SGT, PtrVecA, PtrVecB); + ICmpInst *ICmp1 = new ICmpInst(ICmpInst::ICMP_ULT, PtrVecA, PtrVecB); + EXPECT_NE(ICmp0, ICmp1); // suppress warning. + + BasicBlock* BB0 = BasicBlock::Create(C); + // Test InsertAtEnd ICmpInst constructor. + ICmpInst *ICmp2 = new ICmpInst(*BB0, ICmpInst::ICMP_SGE, PtrVecA, PtrVecB); + EXPECT_NE(ICmp0, ICmp2); // suppress warning. + + GetElementPtrInst *Gep0 = GetElementPtrInst::Create(I32Ty, PtrVecA, C2xi32a); + GetElementPtrInst *Gep1 = GetElementPtrInst::Create(I32Ty, PtrVecA, C2xi32b); + GetElementPtrInst *Gep2 = GetElementPtrInst::Create(I32Ty, PtrVecB, C2xi32a); + GetElementPtrInst *Gep3 = GetElementPtrInst::Create(I32Ty, PtrVecB, C2xi32b); + + CastInst *BTC0 = new BitCastInst(Gep0, V2xi8PTy); + CastInst *BTC1 = new BitCastInst(Gep1, V2xi8PTy); + CastInst *BTC2 = new BitCastInst(Gep2, V2xi8PTy); + CastInst *BTC3 = new BitCastInst(Gep3, V2xi8PTy); + + Value *S0 = BTC0->stripPointerCasts(); + Value *S1 = BTC1->stripPointerCasts(); + Value *S2 = BTC2->stripPointerCasts(); + Value *S3 = BTC3->stripPointerCasts(); + + EXPECT_NE(S0, Gep0); + EXPECT_NE(S1, Gep1); + EXPECT_NE(S2, Gep2); + EXPECT_NE(S3, Gep3); + + int64_t Offset; + 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-a:0:64-s:64:64-f80" + ":128:128-n8:16:32:64-S128"); + // Make sure we don't crash + GetPointerBaseWithConstantOffset(Gep0, Offset, TD); + GetPointerBaseWithConstantOffset(Gep1, Offset, TD); + GetPointerBaseWithConstantOffset(Gep2, Offset, TD); + GetPointerBaseWithConstantOffset(Gep3, Offset, TD); + + // Gep of Geps + GetElementPtrInst *GepII0 = GetElementPtrInst::Create(I32Ty, Gep0, C2xi32b); + GetElementPtrInst *GepII1 = GetElementPtrInst::Create(I32Ty, Gep1, C2xi32a); + GetElementPtrInst *GepII2 = GetElementPtrInst::Create(I32Ty, Gep2, C2xi32b); + GetElementPtrInst *GepII3 = GetElementPtrInst::Create(I32Ty, Gep3, C2xi32a); + + EXPECT_EQ(GepII0->getNumIndices(), 1u); + EXPECT_EQ(GepII1->getNumIndices(), 1u); + EXPECT_EQ(GepII2->getNumIndices(), 1u); + EXPECT_EQ(GepII3->getNumIndices(), 1u); + + EXPECT_FALSE(GepII0->hasAllZeroIndices()); + EXPECT_FALSE(GepII1->hasAllZeroIndices()); + EXPECT_FALSE(GepII2->hasAllZeroIndices()); + EXPECT_FALSE(GepII3->hasAllZeroIndices()); + + delete GepII0; + delete GepII1; + delete GepII2; + delete GepII3; + + delete BTC0; + delete BTC1; + delete BTC2; + delete BTC3; + + delete Gep0; + delete Gep1; + delete Gep2; + delete Gep3; + + ICmp2->eraseFromParent(); + delete BB0; + + delete ICmp0; + delete ICmp1; + delete PtrVecA; + delete PtrVecB; +} + +TEST(InstructionsTest, FPMathOperator) { + LLVMContext &Context = getGlobalContext(); + IRBuilder<> Builder(Context); + MDBuilder MDHelper(Context); + Instruction *I = Builder.CreatePHI(Builder.getDoubleTy(), 0); + MDNode *MD1 = MDHelper.createFPMath(1.0); + Value *V1 = Builder.CreateFAdd(I, I, "", MD1); + EXPECT_TRUE(isa<FPMathOperator>(V1)); + FPMathOperator *O1 = cast<FPMathOperator>(V1); + EXPECT_EQ(O1->getFPAccuracy(), 1.0); + delete V1; + delete I; +} + + +TEST(InstructionsTest, isEliminableCastPair) { + LLVMContext &C(getGlobalContext()); + + Type* Int16Ty = Type::getInt16Ty(C); + 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, nullptr, Int32Ty), + CastInst::BitCast); + + // Source and destination have unknown sizes, but the same address space and + // the intermediate int is the maximum pointer size -> bitcast + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt, + CastInst::IntToPtr, + Int64PtrTy, Int64Ty, Int64PtrTy, + nullptr, nullptr, nullptr), + CastInst::BitCast); + + // Source and destination have unknown sizes, but the same address space and + // the intermediate int is not the maximum pointer size -> nothing + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt, + CastInst::IntToPtr, + Int64PtrTy, Int32Ty, Int64PtrTy, + nullptr, nullptr, nullptr), + 0U); + + // Middle pointer big enough -> bitcast. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, + Int64Ty, Int64PtrTy, Int64Ty, + nullptr, Int64Ty, nullptr), + CastInst::BitCast); + + // Middle pointer too small -> fail. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, + Int64Ty, Int64PtrTy, Int64Ty, + nullptr, Int32Ty, nullptr), + 0U); + + // Test that we don't eliminate bitcasts between different address spaces, + // or if we don't have available pointer size information. + DataLayout DL("e-p:32:32:32-p1:16:16:16-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16" + "-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64" + "-v128:128:128-a:0:64-s:64:64-f80:128:128-n8:16:32:64-S128"); + + Type* Int64PtrTyAS1 = Type::getInt64PtrTy(C, 1); + Type* Int64PtrTyAS2 = Type::getInt64PtrTy(C, 2); + + IntegerType *Int16SizePtr = DL.getIntPtrType(C, 1); + IntegerType *Int64SizePtr = DL.getIntPtrType(C, 2); + + // Cannot simplify inttoptr, addrspacecast + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::AddrSpaceCast, + Int16Ty, Int64PtrTyAS1, Int64PtrTyAS2, + nullptr, Int16SizePtr, Int64SizePtr), + 0U); + + // Cannot simplify addrspacecast, ptrtoint + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::AddrSpaceCast, + CastInst::PtrToInt, + Int64PtrTyAS1, Int64PtrTyAS2, Int16Ty, + Int64SizePtr, Int16SizePtr, nullptr), + 0U); + + // Pass since the bitcast address spaces are the same + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::BitCast, + Int16Ty, Int64PtrTyAS1, Int64PtrTyAS1, + nullptr, nullptr, nullptr), + CastInst::IntToPtr); + +} + +TEST(InstructionsTest, CloneCall) { + LLVMContext &C(getGlobalContext()); + Type *Int32Ty = Type::getInt32Ty(C); + Type *ArgTys[] = {Int32Ty, Int32Ty, Int32Ty}; + Type *FnTy = FunctionType::get(Int32Ty, ArgTys, /*isVarArg=*/false); + Value *Callee = Constant::getNullValue(FnTy->getPointerTo()); + Value *Args[] = { + ConstantInt::get(Int32Ty, 1), + ConstantInt::get(Int32Ty, 2), + ConstantInt::get(Int32Ty, 3) + }; + std::unique_ptr<CallInst> Call(CallInst::Create(Callee, Args, "result")); + + // Test cloning the tail call kind. + CallInst::TailCallKind Kinds[] = {CallInst::TCK_None, CallInst::TCK_Tail, + CallInst::TCK_MustTail}; + for (CallInst::TailCallKind TCK : Kinds) { + Call->setTailCallKind(TCK); + std::unique_ptr<CallInst> Clone(cast<CallInst>(Call->clone())); + EXPECT_EQ(Call->getTailCallKind(), Clone->getTailCallKind()); + } + Call->setTailCallKind(CallInst::TCK_None); + + // Test cloning an attribute. + { + AttrBuilder AB; + AB.addAttribute(Attribute::ReadOnly); + Call->setAttributes(AttributeSet::get(C, AttributeSet::FunctionIndex, AB)); + std::unique_ptr<CallInst> Clone(cast<CallInst>(Call->clone())); + EXPECT_TRUE(Clone->onlyReadsMemory()); + } +} + +} // end anonymous namespace +} // end namespace llvm + + diff --git a/gnu/llvm/unittests/IR/LegacyPassManagerTest.cpp b/gnu/llvm/unittests/IR/LegacyPassManagerTest.cpp new file mode 100644 index 00000000000..1f88283dc0c --- /dev/null +++ b/gnu/llvm/unittests/IR/LegacyPassManagerTest.cpp @@ -0,0 +1,548 @@ +//===- llvm/unittest/IR/LegacyPassManager.cpp - Legacy PassManager tests --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This unit test exercises the legacy pass manager infrastructure. We use the +// old names as well to ensure that the source-level compatibility is preserved +// where possible. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Pass.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace llvm { + void initializeModuleNDMPass(PassRegistry&); + void initializeFPassPass(PassRegistry&); + void initializeCGPassPass(PassRegistry&); + void initializeLPassPass(PassRegistry&); + void initializeBPassPass(PassRegistry&); + + namespace { + // ND = no deps + // NM = no modifications + struct ModuleNDNM: public ModulePass { + public: + static char run; + static char ID; + ModuleNDNM() : ModulePass(ID) { } + bool runOnModule(Module &M) override { + run++; + return false; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + }; + char ModuleNDNM::ID=0; + char ModuleNDNM::run=0; + + struct ModuleNDM : public ModulePass { + public: + static char run; + static char ID; + ModuleNDM() : ModulePass(ID) {} + bool runOnModule(Module &M) override { + run++; + return true; + } + }; + char ModuleNDM::ID=0; + char ModuleNDM::run=0; + + struct ModuleNDM2 : public ModulePass { + public: + static char run; + static char ID; + ModuleNDM2() : ModulePass(ID) {} + bool runOnModule(Module &M) override { + run++; + return true; + } + }; + char ModuleNDM2::ID=0; + char ModuleNDM2::run=0; + + struct ModuleDNM : public ModulePass { + public: + static char run; + static char ID; + ModuleDNM() : ModulePass(ID) { + initializeModuleNDMPass(*PassRegistry::getPassRegistry()); + } + bool runOnModule(Module &M) override { + run++; + return false; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<ModuleNDM>(); + AU.setPreservesAll(); + } + }; + char ModuleDNM::ID=0; + char ModuleDNM::run=0; + + template<typename P> + struct PassTestBase : public P { + protected: + static int runc; + static bool initialized; + static bool finalized; + int allocated; + void run() { + EXPECT_TRUE(initialized); + EXPECT_FALSE(finalized); + EXPECT_EQ(0, allocated); + allocated++; + runc++; + } + public: + static char ID; + static void finishedOK(int run) { + EXPECT_GT(runc, 0); + EXPECT_TRUE(initialized); + EXPECT_TRUE(finalized); + EXPECT_EQ(run, runc); + } + PassTestBase() : P(ID), allocated(0) { + initialized = false; + finalized = false; + runc = 0; + } + + void releaseMemory() override { + EXPECT_GT(runc, 0); + EXPECT_GT(allocated, 0); + allocated--; + } + }; + template<typename P> char PassTestBase<P>::ID; + template<typename P> int PassTestBase<P>::runc; + template<typename P> bool PassTestBase<P>::initialized; + template<typename P> bool PassTestBase<P>::finalized; + + template<typename T, typename P> + struct PassTest : public PassTestBase<P> { + public: +#ifndef _MSC_VER // MSVC complains that Pass is not base class. + using llvm::Pass::doInitialization; + using llvm::Pass::doFinalization; +#endif + bool doInitialization(T &t) override { + EXPECT_FALSE(PassTestBase<P>::initialized); + PassTestBase<P>::initialized = true; + return false; + } + bool doFinalization(T &t) override { + EXPECT_FALSE(PassTestBase<P>::finalized); + PassTestBase<P>::finalized = true; + EXPECT_EQ(0, PassTestBase<P>::allocated); + return false; + } + }; + + struct CGPass : public PassTest<CallGraph, CallGraphSCCPass> { + public: + CGPass() { + initializeCGPassPass(*PassRegistry::getPassRegistry()); + } + bool runOnSCC(CallGraphSCC &SCMM) override { + run(); + return false; + } + }; + + struct FPass : public PassTest<Module, FunctionPass> { + public: + bool runOnFunction(Function &F) override { + // FIXME: PR4112 + // EXPECT_TRUE(getAnalysisIfAvailable<DataLayout>()); + run(); + return false; + } + }; + + struct LPass : public PassTestBase<LoopPass> { + private: + static int initcount; + static int fincount; + public: + LPass() { + initializeLPassPass(*PassRegistry::getPassRegistry()); + initcount = 0; fincount=0; + EXPECT_FALSE(initialized); + } + static void finishedOK(int run, int finalized) { + PassTestBase<LoopPass>::finishedOK(run); + EXPECT_EQ(run, initcount); + EXPECT_EQ(finalized, fincount); + } + using llvm::Pass::doInitialization; + using llvm::Pass::doFinalization; + bool doInitialization(Loop* L, LPPassManager &LPM) override { + initialized = true; + initcount++; + return false; + } + bool runOnLoop(Loop *L, LPPassManager &LPM) override { + run(); + return false; + } + bool doFinalization() override { + fincount++; + finalized = true; + return false; + } + }; + int LPass::initcount=0; + int LPass::fincount=0; + + struct BPass : public PassTestBase<BasicBlockPass> { + private: + static int inited; + static int fin; + public: + static void finishedOK(int run, int N) { + PassTestBase<BasicBlockPass>::finishedOK(run); + EXPECT_EQ(inited, N); + EXPECT_EQ(fin, N); + } + BPass() { + inited = 0; + fin = 0; + } + bool doInitialization(Module &M) override { + EXPECT_FALSE(initialized); + initialized = true; + return false; + } + bool doInitialization(Function &F) override { + inited++; + return false; + } + bool runOnBasicBlock(BasicBlock &BB) override { + run(); + return false; + } + bool doFinalization(Function &F) override { + fin++; + return false; + } + bool doFinalization(Module &M) override { + EXPECT_FALSE(finalized); + finalized = true; + EXPECT_EQ(0, allocated); + return false; + } + }; + int BPass::inited=0; + int BPass::fin=0; + + struct OnTheFlyTest: public ModulePass { + public: + static char ID; + OnTheFlyTest() : ModulePass(ID) { + initializeFPassPass(*PassRegistry::getPassRegistry()); + } + bool runOnModule(Module &M) override { + for (Module::iterator I=M.begin(),E=M.end(); I != E; ++I) { + Function &F = *I; + { + SCOPED_TRACE("Running on the fly function pass"); + getAnalysis<FPass>(F); + } + } + return false; + } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired<FPass>(); + } + }; + char OnTheFlyTest::ID=0; + + TEST(PassManager, RunOnce) { + Module M("test-once", getGlobalContext()); + struct ModuleNDNM *mNDNM = new ModuleNDNM(); + struct ModuleDNM *mDNM = new ModuleDNM(); + struct ModuleNDM *mNDM = new ModuleNDM(); + struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); + + mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; + + legacy::PassManager Passes; + Passes.add(mNDM2); + Passes.add(mNDM); + Passes.add(mNDNM); + Passes.add(mDNM); + + Passes.run(M); + // each pass must be run exactly once, since nothing invalidates them + EXPECT_EQ(1, mNDM->run); + EXPECT_EQ(1, mNDNM->run); + EXPECT_EQ(1, mDNM->run); + EXPECT_EQ(1, mNDM2->run); + } + + TEST(PassManager, ReRun) { + Module M("test-rerun", getGlobalContext()); + struct ModuleNDNM *mNDNM = new ModuleNDNM(); + struct ModuleDNM *mDNM = new ModuleDNM(); + struct ModuleNDM *mNDM = new ModuleNDM(); + struct ModuleNDM2 *mNDM2 = new ModuleNDM2(); + + mNDM->run = mNDNM->run = mDNM->run = mNDM2->run = 0; + + legacy::PassManager Passes; + Passes.add(mNDM); + Passes.add(mNDNM); + Passes.add(mNDM2);// invalidates mNDM needed by mDNM + Passes.add(mDNM); + + Passes.run(M); + // Some passes must be rerun because a pass that modified the + // module/function was run in between + EXPECT_EQ(2, mNDM->run); + EXPECT_EQ(1, mNDNM->run); + EXPECT_EQ(1, mNDM2->run); + EXPECT_EQ(1, mDNM->run); + } + + Module* makeLLVMModule(); + + template<typename T> + void MemoryTestHelper(int run) { + std::unique_ptr<Module> M(makeLLVMModule()); + T *P = new T(); + legacy::PassManager Passes; + Passes.add(P); + Passes.run(*M); + T::finishedOK(run); + } + + template<typename T> + void MemoryTestHelper(int run, int N) { + Module *M = makeLLVMModule(); + T *P = new T(); + legacy::PassManager Passes; + Passes.add(P); + Passes.run(*M); + T::finishedOK(run, N); + delete M; + } + + TEST(PassManager, Memory) { + // SCC#1: test1->test2->test3->test1 + // SCC#2: test4 + // SCC#3: indirect call node + { + SCOPED_TRACE("Callgraph pass"); + MemoryTestHelper<CGPass>(3); + } + + { + SCOPED_TRACE("Function pass"); + MemoryTestHelper<FPass>(4);// 4 functions + } + + { + SCOPED_TRACE("Loop pass"); + MemoryTestHelper<LPass>(2, 1); //2 loops, 1 function + } + { + SCOPED_TRACE("Basic block pass"); + MemoryTestHelper<BPass>(7, 4); //9 basic blocks + } + + } + + TEST(PassManager, MemoryOnTheFly) { + Module *M = makeLLVMModule(); + { + SCOPED_TRACE("Running OnTheFlyTest"); + struct OnTheFlyTest *O = new OnTheFlyTest(); + legacy::PassManager Passes; + Passes.add(O); + Passes.run(*M); + + FPass::finishedOK(4); + } + delete M; + } + + Module* makeLLVMModule() { + // Module Construction + Module* mod = new Module("test-mem", getGlobalContext()); + mod->setDataLayout("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" + "a:0:64-s:64:64-f80:128:128"); + mod->setTargetTriple("x86_64-unknown-linux-gnu"); + + // Type Definitions + std::vector<Type*>FuncTy_0_args; + FunctionType* FuncTy_0 = FunctionType::get( + /*Result=*/IntegerType::get(getGlobalContext(), 32), + /*Params=*/FuncTy_0_args, + /*isVarArg=*/false); + + std::vector<Type*>FuncTy_2_args; + FuncTy_2_args.push_back(IntegerType::get(getGlobalContext(), 1)); + FunctionType* FuncTy_2 = FunctionType::get( + /*Result=*/Type::getVoidTy(getGlobalContext()), + /*Params=*/FuncTy_2_args, + /*isVarArg=*/false); + + + // Function Declarations + + Function* func_test1 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test1", mod); + func_test1->setCallingConv(CallingConv::C); + AttributeSet func_test1_PAL; + func_test1->setAttributes(func_test1_PAL); + + Function* func_test2 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test2", mod); + func_test2->setCallingConv(CallingConv::C); + AttributeSet func_test2_PAL; + func_test2->setAttributes(func_test2_PAL); + + Function* func_test3 = Function::Create( + /*Type=*/FuncTy_0, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test3", mod); + func_test3->setCallingConv(CallingConv::C); + AttributeSet func_test3_PAL; + func_test3->setAttributes(func_test3_PAL); + + Function* func_test4 = Function::Create( + /*Type=*/FuncTy_2, + /*Linkage=*/GlobalValue::ExternalLinkage, + /*Name=*/"test4", mod); + func_test4->setCallingConv(CallingConv::C); + AttributeSet func_test4_PAL; + func_test4->setAttributes(func_test4_PAL); + + // Global Variable Declarations + + + // Constant Definitions + + // Global Variable Definitions + + // Function Definitions + + // Function: test1 (func_test1) + { + + BasicBlock* label_entry = BasicBlock::Create(getGlobalContext(), "entry",func_test1,nullptr); + + // Block entry (label_entry) + CallInst* int32_3 = CallInst::Create(func_test2, "", label_entry); + int32_3->setCallingConv(CallingConv::C); + int32_3->setTailCall(false);AttributeSet int32_3_PAL; + int32_3->setAttributes(int32_3_PAL); + + ReturnInst::Create(getGlobalContext(), int32_3, label_entry); + + } + + // Function: test2 (func_test2) + { + + BasicBlock* label_entry_5 = BasicBlock::Create(getGlobalContext(), "entry",func_test2,nullptr); + + // Block entry (label_entry_5) + CallInst* int32_6 = CallInst::Create(func_test3, "", label_entry_5); + int32_6->setCallingConv(CallingConv::C); + int32_6->setTailCall(false);AttributeSet int32_6_PAL; + int32_6->setAttributes(int32_6_PAL); + + ReturnInst::Create(getGlobalContext(), int32_6, label_entry_5); + + } + + // Function: test3 (func_test3) + { + + BasicBlock* label_entry_8 = BasicBlock::Create(getGlobalContext(), "entry",func_test3,nullptr); + + // Block entry (label_entry_8) + CallInst* int32_9 = CallInst::Create(func_test1, "", label_entry_8); + int32_9->setCallingConv(CallingConv::C); + int32_9->setTailCall(false);AttributeSet int32_9_PAL; + int32_9->setAttributes(int32_9_PAL); + + ReturnInst::Create(getGlobalContext(), int32_9, label_entry_8); + + } + + // Function: test4 (func_test4) + { + Function::arg_iterator args = func_test4->arg_begin(); + Value *int1_f = &*args++; + int1_f->setName("f"); + + BasicBlock* label_entry_11 = BasicBlock::Create(getGlobalContext(), "entry",func_test4,nullptr); + BasicBlock* label_bb = BasicBlock::Create(getGlobalContext(), "bb",func_test4,nullptr); + BasicBlock* label_bb1 = BasicBlock::Create(getGlobalContext(), "bb1",func_test4,nullptr); + BasicBlock* label_return = BasicBlock::Create(getGlobalContext(), "return",func_test4,nullptr); + + // Block entry (label_entry_11) + BranchInst::Create(label_bb, label_entry_11); + + // Block bb (label_bb) + BranchInst::Create(label_bb, label_bb1, int1_f, label_bb); + + // Block bb1 (label_bb1) + BranchInst::Create(label_bb1, label_return, int1_f, label_bb1); + + // Block return (label_return) + ReturnInst::Create(getGlobalContext(), label_return); + + } + return mod; + } + + } +} + +INITIALIZE_PASS(ModuleNDM, "mndm", "mndm", false, false) +INITIALIZE_PASS_BEGIN(CGPass, "cgp","cgp", false, false) +INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) +INITIALIZE_PASS_END(CGPass, "cgp","cgp", false, false) +INITIALIZE_PASS(FPass, "fp","fp", false, false) +INITIALIZE_PASS_BEGIN(LPass, "lp","lp", false, false) +INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) +INITIALIZE_PASS_END(LPass, "lp","lp", false, false) +INITIALIZE_PASS(BPass, "bp","bp", false, false) diff --git a/gnu/llvm/unittests/IR/MDBuilderTest.cpp b/gnu/llvm/unittests/IR/MDBuilderTest.cpp new file mode 100644 index 00000000000..ab2d34e89db --- /dev/null +++ b/gnu/llvm/unittests/IR/MDBuilderTest.cpp @@ -0,0 +1,108 @@ +//===- llvm/unittests/MDBuilderTest.cpp - MDBuilder unit tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Operator.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class MDBuilderTest : public testing::Test { +protected: + LLVMContext Context; +}; + +TEST_F(MDBuilderTest, createString) { + MDBuilder MDHelper(Context); + MDString *Str0 = MDHelper.createString(""); + MDString *Str1 = MDHelper.createString("string"); + EXPECT_EQ(Str0->getString(), StringRef("")); + EXPECT_EQ(Str1->getString(), StringRef("string")); +} +TEST_F(MDBuilderTest, createFPMath) { + MDBuilder MDHelper(Context); + MDNode *MD0 = MDHelper.createFPMath(0.0); + MDNode *MD1 = MDHelper.createFPMath(1.0); + EXPECT_EQ(MD0, (MDNode *)nullptr); + EXPECT_NE(MD1, (MDNode *)nullptr); + EXPECT_EQ(MD1->getNumOperands(), 1U); + Metadata *Op = MD1->getOperand(0); + EXPECT_TRUE(mdconst::hasa<ConstantFP>(Op)); + ConstantFP *Val = mdconst::extract<ConstantFP>(Op); + EXPECT_TRUE(Val->getType()->isFloatingPointTy()); + EXPECT_TRUE(Val->isExactlyValue(1.0)); +} +TEST_F(MDBuilderTest, createRangeMetadata) { + MDBuilder MDHelper(Context); + APInt A(8, 1), B(8, 2); + MDNode *R0 = MDHelper.createRange(A, A); + MDNode *R1 = MDHelper.createRange(A, B); + EXPECT_EQ(R0, (MDNode *)nullptr); + EXPECT_NE(R1, (MDNode *)nullptr); + EXPECT_EQ(R1->getNumOperands(), 2U); + EXPECT_TRUE(mdconst::hasa<ConstantInt>(R1->getOperand(0))); + EXPECT_TRUE(mdconst::hasa<ConstantInt>(R1->getOperand(1))); + ConstantInt *C0 = mdconst::extract<ConstantInt>(R1->getOperand(0)); + ConstantInt *C1 = mdconst::extract<ConstantInt>(R1->getOperand(1)); + EXPECT_EQ(C0->getValue(), A); + EXPECT_EQ(C1->getValue(), B); +} +TEST_F(MDBuilderTest, createAnonymousTBAARoot) { + MDBuilder MDHelper(Context); + MDNode *R0 = MDHelper.createAnonymousTBAARoot(); + MDNode *R1 = MDHelper.createAnonymousTBAARoot(); + EXPECT_NE(R0, R1); + EXPECT_GE(R0->getNumOperands(), 1U); + EXPECT_GE(R1->getNumOperands(), 1U); + EXPECT_EQ(R0->getOperand(0), R0); + EXPECT_EQ(R1->getOperand(0), R1); + EXPECT_TRUE(R0->getNumOperands() == 1 || R0->getOperand(1) == nullptr); + EXPECT_TRUE(R1->getNumOperands() == 1 || R1->getOperand(1) == nullptr); +} +TEST_F(MDBuilderTest, createTBAARoot) { + MDBuilder MDHelper(Context); + MDNode *R0 = MDHelper.createTBAARoot("Root"); + MDNode *R1 = MDHelper.createTBAARoot("Root"); + EXPECT_EQ(R0, R1); + EXPECT_GE(R0->getNumOperands(), 1U); + EXPECT_TRUE(isa<MDString>(R0->getOperand(0))); + EXPECT_EQ(cast<MDString>(R0->getOperand(0))->getString(), "Root"); + EXPECT_TRUE(R0->getNumOperands() == 1 || R0->getOperand(1) == nullptr); +} +TEST_F(MDBuilderTest, createTBAANode) { + MDBuilder MDHelper(Context); + MDNode *R = MDHelper.createTBAARoot("Root"); + MDNode *N0 = MDHelper.createTBAANode("Node", R); + MDNode *N1 = MDHelper.createTBAANode("edoN", R); + MDNode *N2 = MDHelper.createTBAANode("Node", R, true); + MDNode *N3 = MDHelper.createTBAANode("Node", R); + EXPECT_EQ(N0, N3); + EXPECT_NE(N0, N1); + EXPECT_NE(N0, N2); + EXPECT_GE(N0->getNumOperands(), 2U); + EXPECT_GE(N1->getNumOperands(), 2U); + EXPECT_GE(N2->getNumOperands(), 3U); + EXPECT_TRUE(isa<MDString>(N0->getOperand(0))); + EXPECT_TRUE(isa<MDString>(N1->getOperand(0))); + EXPECT_TRUE(isa<MDString>(N2->getOperand(0))); + EXPECT_EQ(cast<MDString>(N0->getOperand(0))->getString(), "Node"); + EXPECT_EQ(cast<MDString>(N1->getOperand(0))->getString(), "edoN"); + EXPECT_EQ(cast<MDString>(N2->getOperand(0))->getString(), "Node"); + EXPECT_EQ(N0->getOperand(1), R); + EXPECT_EQ(N1->getOperand(1), R); + EXPECT_EQ(N2->getOperand(1), R); + EXPECT_TRUE(mdconst::hasa<ConstantInt>(N2->getOperand(2))); + EXPECT_EQ(mdconst::extract<ConstantInt>(N2->getOperand(2))->getZExtValue(), + 1U); +} +} diff --git a/gnu/llvm/unittests/IR/Makefile b/gnu/llvm/unittests/IR/Makefile new file mode 100644 index 00000000000..45aa8d68082 --- /dev/null +++ b/gnu/llvm/unittests/IR/Makefile @@ -0,0 +1,15 @@ +##===- unittests/IR/Makefile -------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TESTNAME = IR +LINK_COMPONENTS := core analysis asmparser + +include $(LEVEL)/Makefile.config +include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/gnu/llvm/unittests/IR/MetadataTest.cpp b/gnu/llvm/unittests/IR/MetadataTest.cpp new file mode 100644 index 00000000000..a745b235a38 --- /dev/null +++ b/gnu/llvm/unittests/IR/MetadataTest.cpp @@ -0,0 +1,2304 @@ +//===- unittests/IR/MetadataTest.cpp - Metadata unit tests ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ModuleSlotTracker.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(ContextAndReplaceableUsesTest, FromContext) { + LLVMContext Context; + ContextAndReplaceableUses CRU(Context); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_FALSE(CRU.hasReplaceableUses()); + EXPECT_FALSE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, FromReplaceableUses) { + LLVMContext Context; + ContextAndReplaceableUses CRU(make_unique<ReplaceableMetadataImpl>(Context)); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_TRUE(CRU.hasReplaceableUses()); + EXPECT_TRUE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, makeReplaceable) { + LLVMContext Context; + ContextAndReplaceableUses CRU(Context); + CRU.makeReplaceable(make_unique<ReplaceableMetadataImpl>(Context)); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_TRUE(CRU.hasReplaceableUses()); + EXPECT_TRUE(CRU.getReplaceableUses()); +} + +TEST(ContextAndReplaceableUsesTest, takeReplaceableUses) { + LLVMContext Context; + auto ReplaceableUses = make_unique<ReplaceableMetadataImpl>(Context); + auto *Ptr = ReplaceableUses.get(); + ContextAndReplaceableUses CRU(std::move(ReplaceableUses)); + ReplaceableUses = CRU.takeReplaceableUses(); + EXPECT_EQ(&Context, &CRU.getContext()); + EXPECT_FALSE(CRU.hasReplaceableUses()); + EXPECT_FALSE(CRU.getReplaceableUses()); + EXPECT_EQ(Ptr, ReplaceableUses.get()); +} + +class MetadataTest : public testing::Test { +public: + MetadataTest() : M("test", Context), Counter(0) {} + +protected: + LLVMContext Context; + Module M; + int Counter; + + MDNode *getNode() { return MDNode::get(Context, None); } + MDNode *getNode(Metadata *MD) { return MDNode::get(Context, MD); } + MDNode *getNode(Metadata *MD1, Metadata *MD2) { + Metadata *MDs[] = {MD1, MD2}; + return MDNode::get(Context, MDs); + } + + MDTuple *getTuple() { return MDTuple::getDistinct(Context, None); } + DISubroutineType *getSubroutineType() { + return DISubroutineType::getDistinct(Context, 0, getNode(nullptr)); + } + DISubprogram *getSubprogram() { + return DISubprogram::getDistinct(Context, nullptr, "", "", nullptr, 0, + nullptr, false, false, 0, nullptr, 0, 0, 0, + 0); + } + DIScopeRef getSubprogramRef() { return getSubprogram()->getRef(); } + DIFile *getFile() { + return DIFile::getDistinct(Context, "file.c", "/path/to/dir"); + } + DITypeRef getBasicType(StringRef Name) { + return DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, Name) + ->getRef(); + } + DITypeRef getDerivedType() { + return DIDerivedType::getDistinct(Context, dwarf::DW_TAG_pointer_type, "", + nullptr, 0, nullptr, + getBasicType("basictype"), 1, 2, 0, 0) + ->getRef(); + } + Constant *getConstant() { + return ConstantInt::get(Type::getInt32Ty(Context), Counter++); + } + ConstantAsMetadata *getConstantAsMetadata() { + return ConstantAsMetadata::get(getConstant()); + } + DITypeRef getCompositeType() { + return DICompositeType::getDistinct( + Context, dwarf::DW_TAG_structure_type, "", nullptr, 0, nullptr, + nullptr, 32, 32, 0, 0, nullptr, 0, nullptr, nullptr, "") + ->getRef(); + } + Function *getFunction(StringRef Name) { + return cast<Function>(M.getOrInsertFunction( + Name, FunctionType::get(Type::getVoidTy(Context), None, false))); + } +}; +typedef MetadataTest MDStringTest; + +// Test that construction of MDString with different value produces different +// MDString objects, even with the same string pointer and nulls in the string. +TEST_F(MDStringTest, CreateDifferent) { + char x[3] = { 'f', 0, 'A' }; + MDString *s1 = MDString::get(Context, StringRef(&x[0], 3)); + x[2] = 'B'; + MDString *s2 = MDString::get(Context, StringRef(&x[0], 3)); + EXPECT_NE(s1, s2); +} + +// Test that creation of MDStrings with the same string contents produces the +// same MDString object, even with different pointers. +TEST_F(MDStringTest, CreateSame) { + char x[4] = { 'a', 'b', 'c', 'X' }; + char y[4] = { 'a', 'b', 'c', 'Y' }; + + MDString *s1 = MDString::get(Context, StringRef(&x[0], 3)); + MDString *s2 = MDString::get(Context, StringRef(&y[0], 3)); + EXPECT_EQ(s1, s2); +} + +// Test that MDString prints out the string we fed it. +TEST_F(MDStringTest, PrintingSimple) { + char *str = new char[13]; + strncpy(str, "testing 1 2 3", 13); + MDString *s = MDString::get(Context, StringRef(str, 13)); + strncpy(str, "aaaaaaaaaaaaa", 13); + delete[] str; + + std::string Str; + raw_string_ostream oss(Str); + s->print(oss); + EXPECT_STREQ("!\"testing 1 2 3\"", oss.str().c_str()); +} + +// Test printing of MDString with non-printable characters. +TEST_F(MDStringTest, PrintingComplex) { + char str[5] = {0, '\n', '"', '\\', (char)-1}; + MDString *s = MDString::get(Context, StringRef(str+0, 5)); + std::string Str; + raw_string_ostream oss(Str); + s->print(oss); + EXPECT_STREQ("!\"\\00\\0A\\22\\5C\\FF\"", oss.str().c_str()); +} + +typedef MetadataTest MDNodeTest; + +// Test the two constructors, and containing other Constants. +TEST_F(MDNodeTest, Simple) { + char x[3] = { 'a', 'b', 'c' }; + char y[3] = { '1', '2', '3' }; + + MDString *s1 = MDString::get(Context, StringRef(&x[0], 3)); + MDString *s2 = MDString::get(Context, StringRef(&y[0], 3)); + ConstantAsMetadata *CI = ConstantAsMetadata::get( + ConstantInt::get(getGlobalContext(), APInt(8, 0))); + + std::vector<Metadata *> V; + V.push_back(s1); + V.push_back(CI); + V.push_back(s2); + + MDNode *n1 = MDNode::get(Context, V); + Metadata *const c1 = n1; + MDNode *n2 = MDNode::get(Context, c1); + Metadata *const c2 = n2; + MDNode *n3 = MDNode::get(Context, V); + MDNode *n4 = MDNode::getIfExists(Context, V); + MDNode *n5 = MDNode::getIfExists(Context, c1); + MDNode *n6 = MDNode::getIfExists(Context, c2); + EXPECT_NE(n1, n2); + EXPECT_EQ(n1, n3); + EXPECT_EQ(n4, n1); + EXPECT_EQ(n5, n2); + EXPECT_EQ(n6, (Metadata *)nullptr); + + EXPECT_EQ(3u, n1->getNumOperands()); + EXPECT_EQ(s1, n1->getOperand(0)); + EXPECT_EQ(CI, n1->getOperand(1)); + EXPECT_EQ(s2, n1->getOperand(2)); + + EXPECT_EQ(1u, n2->getNumOperands()); + EXPECT_EQ(n1, n2->getOperand(0)); +} + +TEST_F(MDNodeTest, Delete) { + Constant *C = ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 1); + Instruction *I = new BitCastInst(C, Type::getInt32Ty(getGlobalContext())); + + Metadata *const V = LocalAsMetadata::get(I); + MDNode *n = MDNode::get(Context, V); + TrackingMDRef wvh(n); + + EXPECT_EQ(n, wvh); + + delete I; +} + +TEST_F(MDNodeTest, SelfReference) { + // !0 = !{!0} + // !1 = !{!0} + { + auto Temp = MDNode::getTemporary(Context, None); + Metadata *Args[] = {Temp.get()}; + MDNode *Self = MDNode::get(Context, Args); + Self->replaceOperandWith(0, Self); + ASSERT_EQ(Self, Self->getOperand(0)); + + // Self-references should be distinct, so MDNode::get() should grab a + // uniqued node that references Self, not Self. + Args[0] = Self; + MDNode *Ref1 = MDNode::get(Context, Args); + MDNode *Ref2 = MDNode::get(Context, Args); + EXPECT_NE(Self, Ref1); + EXPECT_EQ(Ref1, Ref2); + } + + // !0 = !{!0, !{}} + // !1 = !{!0, !{}} + { + auto Temp = MDNode::getTemporary(Context, None); + Metadata *Args[] = {Temp.get(), MDNode::get(Context, None)}; + MDNode *Self = MDNode::get(Context, Args); + Self->replaceOperandWith(0, Self); + ASSERT_EQ(Self, Self->getOperand(0)); + + // Self-references should be distinct, so MDNode::get() should grab a + // uniqued node that references Self, not Self itself. + Args[0] = Self; + MDNode *Ref1 = MDNode::get(Context, Args); + MDNode *Ref2 = MDNode::get(Context, Args); + EXPECT_NE(Self, Ref1); + EXPECT_EQ(Ref1, Ref2); + } +} + +TEST_F(MDNodeTest, Print) { + Constant *C = ConstantInt::get(Type::getInt32Ty(Context), 7); + MDString *S = MDString::get(Context, "foo"); + MDNode *N0 = getNode(); + MDNode *N1 = getNode(N0); + MDNode *N2 = getNode(N0, N1); + + Metadata *Args[] = {ConstantAsMetadata::get(C), S, nullptr, N0, N1, N2}; + MDNode *N = MDNode::get(Context, Args); + + std::string Expected; + { + raw_string_ostream OS(Expected); + OS << "<" << (void *)N << "> = !{"; + C->printAsOperand(OS); + OS << ", "; + S->printAsOperand(OS); + OS << ", null"; + MDNode *Nodes[] = {N0, N1, N2}; + for (auto *Node : Nodes) + OS << ", <" << (void *)Node << ">"; + OS << "}"; + } + + std::string Actual; + { + raw_string_ostream OS(Actual); + N->print(OS); + } + + EXPECT_EQ(Expected, Actual); +} + +#define EXPECT_PRINTER_EQ(EXPECTED, PRINT) \ + do { \ + std::string Actual_; \ + raw_string_ostream OS(Actual_); \ + PRINT; \ + OS.flush(); \ + std::string Expected_(EXPECTED); \ + EXPECT_EQ(Expected_, Actual_); \ + } while (false) + +TEST_F(MDNodeTest, PrintTemporary) { + MDNode *Arg = getNode(); + TempMDNode Temp = MDNode::getTemporary(Context, Arg); + MDNode *N = getNode(Temp.get()); + Module M("test", Context); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("named"); + NMD->addOperand(N); + + EXPECT_PRINTER_EQ("!0 = !{!1}", N->print(OS, &M)); + EXPECT_PRINTER_EQ("!1 = <temporary!> !{!2}", Temp->print(OS, &M)); + EXPECT_PRINTER_EQ("!2 = !{}", Arg->print(OS, &M)); + + // Cleanup. + Temp->replaceAllUsesWith(Arg); +} + +TEST_F(MDNodeTest, PrintFromModule) { + Constant *C = ConstantInt::get(Type::getInt32Ty(Context), 7); + MDString *S = MDString::get(Context, "foo"); + MDNode *N0 = getNode(); + MDNode *N1 = getNode(N0); + MDNode *N2 = getNode(N0, N1); + + Metadata *Args[] = {ConstantAsMetadata::get(C), S, nullptr, N0, N1, N2}; + MDNode *N = MDNode::get(Context, Args); + Module M("test", Context); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("named"); + NMD->addOperand(N); + + std::string Expected; + { + raw_string_ostream OS(Expected); + OS << "!0 = !{"; + C->printAsOperand(OS); + OS << ", "; + S->printAsOperand(OS); + OS << ", null, !1, !2, !3}"; + } + + EXPECT_PRINTER_EQ(Expected, N->print(OS, &M)); +} + +TEST_F(MDNodeTest, PrintFromFunction) { + Module M("test", Context); + auto *FTy = FunctionType::get(Type::getVoidTy(Context), false); + auto *F0 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F0", &M); + auto *F1 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F1", &M); + auto *BB0 = BasicBlock::Create(Context, "entry", F0); + auto *BB1 = BasicBlock::Create(Context, "entry", F1); + auto *R0 = ReturnInst::Create(Context, BB0); + auto *R1 = ReturnInst::Create(Context, BB1); + auto *N0 = MDNode::getDistinct(Context, None); + auto *N1 = MDNode::getDistinct(Context, None); + R0->setMetadata("md", N0); + R1->setMetadata("md", N1); + + EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, &M)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, &M)); + + ModuleSlotTracker MST(&M); + EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, MST)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, MST)); +} + +TEST_F(MDNodeTest, PrintFromMetadataAsValue) { + Module M("test", Context); + + auto *Intrinsic = + Function::Create(FunctionType::get(Type::getVoidTy(Context), + Type::getMetadataTy(Context), false), + GlobalValue::ExternalLinkage, "llvm.intrinsic", &M); + + auto *FTy = FunctionType::get(Type::getVoidTy(Context), false); + auto *F0 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F0", &M); + auto *F1 = Function::Create(FTy, GlobalValue::ExternalLinkage, "F1", &M); + auto *BB0 = BasicBlock::Create(Context, "entry", F0); + auto *BB1 = BasicBlock::Create(Context, "entry", F1); + auto *N0 = MDNode::getDistinct(Context, None); + auto *N1 = MDNode::getDistinct(Context, None); + auto *MAV0 = MetadataAsValue::get(Context, N0); + auto *MAV1 = MetadataAsValue::get(Context, N1); + CallInst::Create(Intrinsic, MAV0, "", BB0); + CallInst::Create(Intrinsic, MAV1, "", BB1); + + EXPECT_PRINTER_EQ("!0 = distinct !{}", MAV0->print(OS)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", MAV1->print(OS)); + EXPECT_PRINTER_EQ("!0", MAV0->printAsOperand(OS, false)); + EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false)); + EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true)); + EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true)); + + ModuleSlotTracker MST(&M); + EXPECT_PRINTER_EQ("!0 = distinct !{}", MAV0->print(OS, MST)); + EXPECT_PRINTER_EQ("!1 = distinct !{}", MAV1->print(OS, MST)); + EXPECT_PRINTER_EQ("!0", MAV0->printAsOperand(OS, false, MST)); + EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false, MST)); + EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true, MST)); + EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true, MST)); +} +#undef EXPECT_PRINTER_EQ + +TEST_F(MDNodeTest, NullOperand) { + // metadata !{} + MDNode *Empty = MDNode::get(Context, None); + + // metadata !{metadata !{}} + Metadata *Ops[] = {Empty}; + MDNode *N = MDNode::get(Context, Ops); + ASSERT_EQ(Empty, N->getOperand(0)); + + // metadata !{metadata !{}} => metadata !{null} + N->replaceOperandWith(0, nullptr); + ASSERT_EQ(nullptr, N->getOperand(0)); + + // metadata !{null} + Ops[0] = nullptr; + MDNode *NullOp = MDNode::get(Context, Ops); + ASSERT_EQ(nullptr, NullOp->getOperand(0)); + EXPECT_EQ(N, NullOp); +} + +TEST_F(MDNodeTest, DistinctOnUniquingCollision) { + // !{} + MDNode *Empty = MDNode::get(Context, None); + ASSERT_TRUE(Empty->isResolved()); + EXPECT_FALSE(Empty->isDistinct()); + + // !{!{}} + Metadata *Wrapped1Ops[] = {Empty}; + MDNode *Wrapped1 = MDNode::get(Context, Wrapped1Ops); + ASSERT_EQ(Empty, Wrapped1->getOperand(0)); + ASSERT_TRUE(Wrapped1->isResolved()); + EXPECT_FALSE(Wrapped1->isDistinct()); + + // !{!{!{}}} + Metadata *Wrapped2Ops[] = {Wrapped1}; + MDNode *Wrapped2 = MDNode::get(Context, Wrapped2Ops); + ASSERT_EQ(Wrapped1, Wrapped2->getOperand(0)); + ASSERT_TRUE(Wrapped2->isResolved()); + EXPECT_FALSE(Wrapped2->isDistinct()); + + // !{!{!{}}} => !{!{}} + Wrapped2->replaceOperandWith(0, Empty); + ASSERT_EQ(Empty, Wrapped2->getOperand(0)); + EXPECT_TRUE(Wrapped2->isDistinct()); + EXPECT_FALSE(Wrapped1->isDistinct()); +} + +TEST_F(MDNodeTest, getDistinct) { + // !{} + MDNode *Empty = MDNode::get(Context, None); + ASSERT_TRUE(Empty->isResolved()); + ASSERT_FALSE(Empty->isDistinct()); + ASSERT_EQ(Empty, MDNode::get(Context, None)); + + // distinct !{} + MDNode *Distinct1 = MDNode::getDistinct(Context, None); + MDNode *Distinct2 = MDNode::getDistinct(Context, None); + EXPECT_TRUE(Distinct1->isResolved()); + EXPECT_TRUE(Distinct2->isDistinct()); + EXPECT_NE(Empty, Distinct1); + EXPECT_NE(Empty, Distinct2); + EXPECT_NE(Distinct1, Distinct2); + + // !{} + ASSERT_EQ(Empty, MDNode::get(Context, None)); +} + +TEST_F(MDNodeTest, isUniqued) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_TRUE(U->isUniqued()); + EXPECT_FALSE(D->isUniqued()); + EXPECT_FALSE(T->isUniqued()); +} + +TEST_F(MDNodeTest, isDistinct) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_FALSE(U->isDistinct()); + EXPECT_TRUE(D->isDistinct()); + EXPECT_FALSE(T->isDistinct()); +} + +TEST_F(MDNodeTest, isTemporary) { + MDNode *U = MDTuple::get(Context, None); + MDNode *D = MDTuple::getDistinct(Context, None); + auto T = MDTuple::getTemporary(Context, None); + EXPECT_FALSE(U->isTemporary()); + EXPECT_FALSE(D->isTemporary()); + EXPECT_TRUE(T->isTemporary()); +} + +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) + +TEST_F(MDNodeTest, deathOnNoReplaceTemporaryRAUW) { + auto Temp = MDNode::getTemporary(Context, None); + Temp->setCanReplace(false); + EXPECT_DEATH(Temp->replaceAllUsesWith(nullptr), + "Attempted to replace Metadata marked for no replacement"); + Temp->setCanReplace(true); + // Remove the references to Temp; required for teardown. + Temp->replaceAllUsesWith(nullptr); +} + +#endif + +TEST_F(MDNodeTest, getDistinctWithUnresolvedOperands) { + // temporary !{} + auto Temp = MDTuple::getTemporary(Context, None); + ASSERT_FALSE(Temp->isResolved()); + + // distinct !{temporary !{}} + Metadata *Ops[] = {Temp.get()}; + MDNode *Distinct = MDNode::getDistinct(Context, Ops); + EXPECT_TRUE(Distinct->isResolved()); + EXPECT_EQ(Temp.get(), Distinct->getOperand(0)); + + // temporary !{} => !{} + MDNode *Empty = MDNode::get(Context, None); + Temp->replaceAllUsesWith(Empty); + EXPECT_EQ(Empty, Distinct->getOperand(0)); +} + +TEST_F(MDNodeTest, handleChangedOperandRecursion) { + // !0 = !{} + MDNode *N0 = MDNode::get(Context, None); + + // !1 = !{!3, null} + auto Temp3 = MDTuple::getTemporary(Context, None); + Metadata *Ops1[] = {Temp3.get(), nullptr}; + MDNode *N1 = MDNode::get(Context, Ops1); + + // !2 = !{!3, !0} + Metadata *Ops2[] = {Temp3.get(), N0}; + MDNode *N2 = MDNode::get(Context, Ops2); + + // !3 = !{!2} + Metadata *Ops3[] = {N2}; + MDNode *N3 = MDNode::get(Context, Ops3); + Temp3->replaceAllUsesWith(N3); + + // !4 = !{!1} + Metadata *Ops4[] = {N1}; + MDNode *N4 = MDNode::get(Context, Ops4); + + // Confirm that the cycle prevented RAUW from getting dropped. + EXPECT_TRUE(N0->isResolved()); + EXPECT_FALSE(N1->isResolved()); + EXPECT_FALSE(N2->isResolved()); + EXPECT_FALSE(N3->isResolved()); + EXPECT_FALSE(N4->isResolved()); + + // Create a couple of distinct nodes to observe what's going on. + // + // !5 = distinct !{!2} + // !6 = distinct !{!3} + Metadata *Ops5[] = {N2}; + MDNode *N5 = MDNode::getDistinct(Context, Ops5); + Metadata *Ops6[] = {N3}; + MDNode *N6 = MDNode::getDistinct(Context, Ops6); + + // Mutate !2 to look like !1, causing a uniquing collision (and an RAUW). + // This will ripple up, with !3 colliding with !4, and RAUWing. Since !2 + // references !3, this can cause a re-entry of handleChangedOperand() when !3 + // is not ready for it. + // + // !2->replaceOperandWith(1, nullptr) + // !2: !{!3, !0} => !{!3, null} + // !2->replaceAllUsesWith(!1) + // !3: !{!2] => !{!1} + // !3->replaceAllUsesWith(!4) + N2->replaceOperandWith(1, nullptr); + + // If all has gone well, N2 and N3 will have been RAUW'ed and deleted from + // under us. Just check that the other nodes are sane. + // + // !1 = !{!4, null} + // !4 = !{!1} + // !5 = distinct !{!1} + // !6 = distinct !{!4} + EXPECT_EQ(N4, N1->getOperand(0)); + EXPECT_EQ(N1, N4->getOperand(0)); + EXPECT_EQ(N1, N5->getOperand(0)); + EXPECT_EQ(N4, N6->getOperand(0)); +} + +TEST_F(MDNodeTest, replaceResolvedOperand) { + // Check code for replacing one resolved operand with another. If doing this + // directly (via replaceOperandWith()) becomes illegal, change the operand to + // a global value that gets RAUW'ed. + // + // Use a temporary node to keep N from being resolved. + auto Temp = MDTuple::getTemporary(Context, None); + Metadata *Ops[] = {nullptr, Temp.get()}; + + MDNode *Empty = MDTuple::get(Context, ArrayRef<Metadata *>()); + MDNode *N = MDTuple::get(Context, Ops); + EXPECT_EQ(nullptr, N->getOperand(0)); + ASSERT_FALSE(N->isResolved()); + + // Check code for replacing resolved nodes. + N->replaceOperandWith(0, Empty); + EXPECT_EQ(Empty, N->getOperand(0)); + + // Check code for adding another unresolved operand. + N->replaceOperandWith(0, Temp.get()); + EXPECT_EQ(Temp.get(), N->getOperand(0)); + + // Remove the references to Temp; required for teardown. + Temp->replaceAllUsesWith(nullptr); +} + +TEST_F(MDNodeTest, replaceWithUniqued) { + auto *Empty = MDTuple::get(Context, None); + MDTuple *FirstUniqued; + { + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Don't expect a collision. + auto *Current = Temp.get(); + FirstUniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(FirstUniqued->isUniqued()); + EXPECT_TRUE(FirstUniqued->isResolved()); + EXPECT_EQ(Current, FirstUniqued); + } + { + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Should collide with Uniqued above this time. + auto *Uniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(Uniqued->isUniqued()); + EXPECT_TRUE(Uniqued->isResolved()); + EXPECT_EQ(FirstUniqued, Uniqued); + } + { + auto Unresolved = MDTuple::getTemporary(Context, None); + Metadata *Ops[] = {Unresolved.get()}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Shouldn't be resolved. + auto *Uniqued = MDNode::replaceWithUniqued(std::move(Temp)); + EXPECT_TRUE(Uniqued->isUniqued()); + EXPECT_FALSE(Uniqued->isResolved()); + + // Should be a different node. + EXPECT_NE(FirstUniqued, Uniqued); + + // Should resolve when we update its node (note: be careful to avoid a + // collision with any other nodes above). + Uniqued->replaceOperandWith(0, nullptr); + EXPECT_TRUE(Uniqued->isResolved()); + } +} + +TEST_F(MDNodeTest, replaceWithUniquedResolvingOperand) { + // temp !{} + MDTuple *Op = MDTuple::getTemporary(Context, None).release(); + EXPECT_FALSE(Op->isResolved()); + + // temp !{temp !{}} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + EXPECT_FALSE(N->isResolved()); + + // temp !{temp !{}} => !{temp !{}} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + EXPECT_FALSE(N->isResolved()); + + // !{temp !{}} => !{!{}} + ASSERT_EQ(Op, MDNode::replaceWithUniqued(TempMDTuple(Op))); + EXPECT_TRUE(Op->isResolved()); + EXPECT_TRUE(N->isResolved()); +} + +TEST_F(MDNodeTest, replaceWithUniquedChangingOperand) { + // i1* @GV + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr<GlobalVariable> GV( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get()); + + // temp !{i1* @GV} + Metadata *Ops[] = {Op}; + MDTuple *N = MDTuple::getTemporary(Context, Ops).release(); + + // temp !{i1* @GV} => !{i1* @GV} + ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N))); + ASSERT_TRUE(N->isUniqued()); + + // !{i1* @GV} => !{null} + GV.reset(); + ASSERT_TRUE(N->isUniqued()); + Metadata *NullOps[] = {nullptr}; + ASSERT_EQ(N, MDTuple::get(Context, NullOps)); +} + +TEST_F(MDNodeTest, replaceWithDistinct) { + { + auto *Empty = MDTuple::get(Context, None); + Metadata *Ops[] = {Empty}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Don't expect a collision. + auto *Current = Temp.get(); + auto *Distinct = MDNode::replaceWithDistinct(std::move(Temp)); + EXPECT_TRUE(Distinct->isDistinct()); + EXPECT_TRUE(Distinct->isResolved()); + EXPECT_EQ(Current, Distinct); + } + { + auto Unresolved = MDTuple::getTemporary(Context, None); + Metadata *Ops[] = {Unresolved.get()}; + auto Temp = MDTuple::getTemporary(Context, Ops); + EXPECT_TRUE(Temp->isTemporary()); + + // Don't expect a collision. + auto *Current = Temp.get(); + auto *Distinct = MDNode::replaceWithDistinct(std::move(Temp)); + EXPECT_TRUE(Distinct->isDistinct()); + EXPECT_TRUE(Distinct->isResolved()); + EXPECT_EQ(Current, Distinct); + + // Cleanup; required for teardown. + Unresolved->replaceAllUsesWith(nullptr); + } +} + +TEST_F(MDNodeTest, replaceWithPermanent) { + Metadata *Ops[] = {nullptr}; + auto Temp = MDTuple::getTemporary(Context, Ops); + auto *T = Temp.get(); + + // U is a normal, uniqued node that references T. + auto *U = MDTuple::get(Context, T); + EXPECT_TRUE(U->isUniqued()); + + // Make Temp self-referencing. + Temp->replaceOperandWith(0, T); + + // Try to uniquify Temp. This should, despite the name in the API, give a + // 'distinct' node, since self-references aren't allowed to be uniqued. + // + // Since it's distinct, N should have the same address as when it was a + // temporary (i.e., be equal to T not U). + auto *N = MDNode::replaceWithPermanent(std::move(Temp)); + EXPECT_EQ(N, T); + EXPECT_TRUE(N->isDistinct()); + + // U should be the canonical unique node with N as the argument. + EXPECT_EQ(U, MDTuple::get(Context, N)); + EXPECT_TRUE(U->isUniqued()); + + // This temporary should collide with U when replaced, but it should still be + // uniqued. + EXPECT_EQ(U, MDNode::replaceWithPermanent(MDTuple::getTemporary(Context, N))); + EXPECT_TRUE(U->isUniqued()); + + // This temporary should become a new uniqued node. + auto Temp2 = MDTuple::getTemporary(Context, U); + auto *V = Temp2.get(); + EXPECT_EQ(V, MDNode::replaceWithPermanent(std::move(Temp2))); + EXPECT_TRUE(V->isUniqued()); + EXPECT_EQ(U, V->getOperand(0)); +} + +TEST_F(MDNodeTest, deleteTemporaryWithTrackingRef) { + TrackingMDRef Ref; + EXPECT_EQ(nullptr, Ref.get()); + { + auto Temp = MDTuple::getTemporary(Context, None); + Ref.reset(Temp.get()); + EXPECT_EQ(Temp.get(), Ref.get()); + } + EXPECT_EQ(nullptr, Ref.get()); +} + +typedef MetadataTest DILocationTest; + +TEST_F(DILocationTest, Overflow) { + DISubprogram *N = getSubprogram(); + { + DILocation *L = DILocation::get(Context, 2, 7, N); + EXPECT_EQ(2u, L->getLine()); + EXPECT_EQ(7u, L->getColumn()); + } + unsigned U16 = 1u << 16; + { + DILocation *L = DILocation::get(Context, UINT32_MAX, U16 - 1, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); + EXPECT_EQ(U16 - 1, L->getColumn()); + } + { + DILocation *L = DILocation::get(Context, UINT32_MAX, U16, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); + EXPECT_EQ(0u, L->getColumn()); + } + { + DILocation *L = DILocation::get(Context, UINT32_MAX, U16 + 1, N); + EXPECT_EQ(UINT32_MAX, L->getLine()); + EXPECT_EQ(0u, L->getColumn()); + } +} + +TEST_F(DILocationTest, getDistinct) { + MDNode *N = getSubprogram(); + DILocation *L0 = DILocation::getDistinct(Context, 2, 7, N); + EXPECT_TRUE(L0->isDistinct()); + DILocation *L1 = DILocation::get(Context, 2, 7, N); + EXPECT_FALSE(L1->isDistinct()); + EXPECT_EQ(L1, DILocation::get(Context, 2, 7, N)); +} + +TEST_F(DILocationTest, getTemporary) { + MDNode *N = MDNode::get(Context, None); + auto L = DILocation::getTemporary(Context, 2, 7, N); + EXPECT_TRUE(L->isTemporary()); + EXPECT_FALSE(L->isResolved()); +} + +TEST_F(DILocationTest, cloneTemporary) { + MDNode *N = MDNode::get(Context, None); + auto L = DILocation::getTemporary(Context, 2, 7, N); + EXPECT_TRUE(L->isTemporary()); + auto L2 = L->clone(); + EXPECT_TRUE(L2->isTemporary()); +} + +typedef MetadataTest GenericDINodeTest; + +TEST_F(GenericDINodeTest, get) { + StringRef Header = "header"; + auto *Empty = MDNode::get(Context, None); + Metadata *Ops1[] = {Empty}; + auto *N = GenericDINode::get(Context, 15, Header, Ops1); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(2u, N->getNumOperands()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(MDString::get(Context, Header), N->getOperand(0)); + EXPECT_EQ(1u, N->getNumDwarfOperands()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + EXPECT_EQ(Empty, N->getOperand(1)); + ASSERT_TRUE(N->isUniqued()); + + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); + + N->replaceOperandWith(1, nullptr); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(nullptr, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + + Metadata *Ops2[] = {nullptr}; + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops2)); + + N->replaceDwarfOperandWith(0, Empty); + EXPECT_EQ(15u, N->getTag()); + EXPECT_EQ(Header, N->getHeader()); + EXPECT_EQ(Empty, N->getDwarfOperand(0)); + ASSERT_TRUE(N->isUniqued()); + EXPECT_EQ(N, GenericDINode::get(Context, 15, Header, Ops1)); + + TempGenericDINode Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(GenericDINodeTest, getEmptyHeader) { + // Canonicalize !"" to null. + auto *N = GenericDINode::get(Context, 15, StringRef(), None); + EXPECT_EQ(StringRef(), N->getHeader()); + EXPECT_EQ(nullptr, N->getOperand(0)); +} + +typedef MetadataTest DISubrangeTest; + +TEST_F(DISubrangeTest, get) { + auto *N = DISubrange::get(Context, 5, 7); + EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); + EXPECT_EQ(5, N->getCount()); + EXPECT_EQ(7, N->getLowerBound()); + EXPECT_EQ(N, DISubrange::get(Context, 5, 7)); + EXPECT_EQ(DISubrange::get(Context, 5, 0), DISubrange::get(Context, 5)); + + TempDISubrange Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DISubrangeTest, getEmptyArray) { + auto *N = DISubrange::get(Context, -1, 0); + EXPECT_EQ(dwarf::DW_TAG_subrange_type, N->getTag()); + EXPECT_EQ(-1, N->getCount()); + EXPECT_EQ(0, N->getLowerBound()); + EXPECT_EQ(N, DISubrange::get(Context, -1, 0)); +} + +typedef MetadataTest DIEnumeratorTest; + +TEST_F(DIEnumeratorTest, get) { + auto *N = DIEnumerator::get(Context, 7, "name"); + EXPECT_EQ(dwarf::DW_TAG_enumerator, N->getTag()); + EXPECT_EQ(7, N->getValue()); + EXPECT_EQ("name", N->getName()); + EXPECT_EQ(N, DIEnumerator::get(Context, 7, "name")); + + EXPECT_NE(N, DIEnumerator::get(Context, 8, "name")); + EXPECT_NE(N, DIEnumerator::get(Context, 7, "nam")); + + TempDIEnumerator Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIBasicTypeTest; + +TEST_F(DIBasicTypeTest, get) { + auto *N = + DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, 26, 7); + EXPECT_EQ(dwarf::DW_TAG_base_type, N->getTag()); + EXPECT_EQ("special", N->getName()); + EXPECT_EQ(33u, N->getSizeInBits()); + EXPECT_EQ(26u, N->getAlignInBits()); + EXPECT_EQ(7u, N->getEncoding()); + EXPECT_EQ(0u, N->getLine()); + EXPECT_EQ(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 26, 7)); + + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, + "special", 33, 26, 7)); + EXPECT_NE(N, + DIBasicType::get(Context, dwarf::DW_TAG_base_type, "s", 33, 26, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 32, + 26, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 25, 7)); + EXPECT_NE(N, DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", 33, + 26, 6)); + + TempDIBasicType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIBasicTypeTest, getWithLargeValues) { + auto *N = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "special", + UINT64_MAX, UINT64_MAX - 1, 7); + EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); + EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits()); +} + +TEST_F(DIBasicTypeTest, getUnspecified) { + auto *N = + DIBasicType::get(Context, dwarf::DW_TAG_unspecified_type, "unspecified"); + EXPECT_EQ(dwarf::DW_TAG_unspecified_type, N->getTag()); + EXPECT_EQ("unspecified", N->getName()); + EXPECT_EQ(0u, N->getSizeInBits()); + EXPECT_EQ(0u, N->getAlignInBits()); + EXPECT_EQ(0u, N->getEncoding()); + EXPECT_EQ(0u, N->getLine()); +} + +typedef MetadataTest DITypeTest; + +TEST_F(DITypeTest, clone) { + // Check that DIType has a specialized clone that returns TempDIType. + DIType *N = DIBasicType::get(Context, dwarf::DW_TAG_base_type, "int", 32, 32, + dwarf::DW_ATE_signed); + + TempDIType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DITypeTest, setFlags) { + // void (void) + Metadata *TypesOps[] = {nullptr}; + Metadata *Types = MDTuple::get(Context, TypesOps); + + DIType *D = DISubroutineType::getDistinct(Context, 0u, Types); + EXPECT_EQ(0u, D->getFlags()); + D->setFlags(DINode::FlagRValueReference); + EXPECT_EQ(DINode::FlagRValueReference, D->getFlags()); + D->setFlags(0u); + EXPECT_EQ(0u, D->getFlags()); + + TempDIType T = DISubroutineType::getTemporary(Context, 0u, Types); + EXPECT_EQ(0u, T->getFlags()); + T->setFlags(DINode::FlagRValueReference); + EXPECT_EQ(DINode::FlagRValueReference, T->getFlags()); + T->setFlags(0u); + EXPECT_EQ(0u, T->getFlags()); +} + +typedef MetadataTest DIDerivedTypeTest; + +TEST_F(DIDerivedTypeTest, get) { + DIFile *File = getFile(); + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getBasicType("basic"); + MDTuple *ExtraData = getTuple(); + + auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", + File, 1, Scope, BaseType, 2, 3, 4, 5, ExtraData); + EXPECT_EQ(dwarf::DW_TAG_pointer_type, N->getTag()); + EXPECT_EQ("something", N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(1u, N->getLine()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(BaseType, N->getBaseType()); + EXPECT_EQ(2u, N->getSizeInBits()); + EXPECT_EQ(3u, N->getAlignInBits()); + EXPECT_EQ(4u, N->getOffsetInBits()); + EXPECT_EQ(5u, N->getFlags()); + EXPECT_EQ(ExtraData, N->getExtraData()); + EXPECT_EQ(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_reference_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "else", + File, 1, Scope, BaseType, 2, 3, 4, 5, + ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", getFile(), 1, Scope, BaseType, 2, + 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 2, Scope, BaseType, 2, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, getSubprogramRef(), + BaseType, 2, 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get( + Context, dwarf::DW_TAG_pointer_type, "something", File, 1, + Scope, getBasicType("basic2"), 2, 3, 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 3, 3, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 2, + 4, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 5, 5, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 4, ExtraData)); + EXPECT_NE(N, DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, + "something", File, 1, Scope, BaseType, 2, 3, + 4, 5, getTuple())); + + TempDIDerivedType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIDerivedTypeTest, getWithLargeValues) { + DIFile *File = getFile(); + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getBasicType("basic"); + MDTuple *ExtraData = getTuple(); + + auto *N = DIDerivedType::get(Context, dwarf::DW_TAG_pointer_type, "something", + File, 1, Scope, BaseType, UINT64_MAX, + UINT64_MAX - 1, UINT64_MAX - 2, 5, ExtraData); + EXPECT_EQ(UINT64_MAX, N->getSizeInBits()); + EXPECT_EQ(UINT64_MAX - 1, N->getAlignInBits()); + EXPECT_EQ(UINT64_MAX - 2, N->getOffsetInBits()); +} + +typedef MetadataTest DICompositeTypeTest; + +TEST_F(DICompositeTypeTest, get) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = 2; + uint64_t AlignInBits = 3; + uint64_t OffsetInBits = 4; + unsigned Flags = 5; + MDTuple *Elements = getTuple(); + unsigned RuntimeLang = 6; + DITypeRef VTableHolder = getCompositeType(); + MDTuple *TemplateParams = getTuple(); + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier); + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(BaseType, N->getBaseType()); + EXPECT_EQ(SizeInBits, N->getSizeInBits()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); + EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(Elements, N->getElements().get()); + EXPECT_EQ(RuntimeLang, N->getRuntimeLang()); + EXPECT_EQ(VTableHolder, N->getVTableHolder()); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + EXPECT_EQ(Identifier, N->getIdentifier()); + + EXPECT_EQ(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + + EXPECT_NE(N, DICompositeType::get(Context, Tag + 1, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, "abc", File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, getFile(), Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line + 1, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, getSubprogramRef(), BaseType, + SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, + RuntimeLang, VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, getBasicType("other"), + SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, + RuntimeLang, VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits + 1, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits + 1, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits + 1, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags + 1, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, getTuple(), RuntimeLang, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang + 1, + VTableHolder, TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, + getCompositeType(), TemplateParams, Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, getTuple(), Identifier)); + EXPECT_NE(N, DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, "other")); + + // Be sure that missing identifiers get null pointers. + EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, "") + ->getRawIdentifier()); + EXPECT_FALSE(DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams) + ->getRawIdentifier()); + + TempDICompositeType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DICompositeTypeTest, getWithLargeValues) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = UINT64_MAX; + uint64_t AlignInBits = UINT64_MAX - 1; + uint64_t OffsetInBits = UINT64_MAX - 2; + unsigned Flags = 5; + MDTuple *Elements = getTuple(); + unsigned RuntimeLang = 6; + DITypeRef VTableHolder = getCompositeType(); + MDTuple *TemplateParams = getTuple(); + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get(Context, Tag, Name, File, Line, Scope, + BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier); + EXPECT_EQ(SizeInBits, N->getSizeInBits()); + EXPECT_EQ(AlignInBits, N->getAlignInBits()); + EXPECT_EQ(OffsetInBits, N->getOffsetInBits()); +} + +TEST_F(DICompositeTypeTest, replaceOperands) { + unsigned Tag = dwarf::DW_TAG_structure_type; + StringRef Name = "some name"; + DIFile *File = getFile(); + unsigned Line = 1; + DIScopeRef Scope = getSubprogramRef(); + DITypeRef BaseType = getCompositeType(); + uint64_t SizeInBits = 2; + uint64_t AlignInBits = 3; + uint64_t OffsetInBits = 4; + unsigned Flags = 5; + unsigned RuntimeLang = 6; + StringRef Identifier = "some id"; + + auto *N = DICompositeType::get( + Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, nullptr, RuntimeLang, nullptr, nullptr, Identifier); + + auto *Elements = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getElements().get()); + N->replaceElements(Elements); + EXPECT_EQ(Elements, N->getElements().get()); + N->replaceElements(nullptr); + EXPECT_EQ(nullptr, N->getElements().get()); + + DITypeRef VTableHolder = getCompositeType(); + EXPECT_EQ(nullptr, N->getVTableHolder()); + N->replaceVTableHolder(VTableHolder); + EXPECT_EQ(VTableHolder, N->getVTableHolder()); + N->replaceVTableHolder(nullptr); + EXPECT_EQ(nullptr, N->getVTableHolder()); + + auto *TemplateParams = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getTemplateParams().get()); + N->replaceTemplateParams(TemplateParams); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + N->replaceTemplateParams(nullptr); + EXPECT_EQ(nullptr, N->getTemplateParams().get()); +} + +typedef MetadataTest DISubroutineTypeTest; + +TEST_F(DISubroutineTypeTest, get) { + unsigned Flags = 1; + MDTuple *TypeArray = getTuple(); + + auto *N = DISubroutineType::get(Context, Flags, TypeArray); + EXPECT_EQ(dwarf::DW_TAG_subroutine_type, N->getTag()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(TypeArray, N->getTypeArray().get()); + EXPECT_EQ(N, DISubroutineType::get(Context, Flags, TypeArray)); + + EXPECT_NE(N, DISubroutineType::get(Context, Flags + 1, TypeArray)); + EXPECT_NE(N, DISubroutineType::get(Context, Flags, getTuple())); + + TempDISubroutineType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); + + // Test always-empty operands. + EXPECT_EQ(nullptr, N->getScope()); + EXPECT_EQ(nullptr, N->getFile()); + EXPECT_EQ("", N->getName()); +} + +typedef MetadataTest DIFileTest; + +TEST_F(DIFileTest, get) { + StringRef Filename = "file"; + StringRef Directory = "dir"; + auto *N = DIFile::get(Context, Filename, Directory); + + EXPECT_EQ(dwarf::DW_TAG_file_type, N->getTag()); + EXPECT_EQ(Filename, N->getFilename()); + EXPECT_EQ(Directory, N->getDirectory()); + EXPECT_EQ(N, DIFile::get(Context, Filename, Directory)); + + EXPECT_NE(N, DIFile::get(Context, "other", Directory)); + EXPECT_NE(N, DIFile::get(Context, Filename, "other")); + + TempDIFile Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIFileTest, ScopeGetFile) { + // Ensure that DIScope::getFile() returns itself. + DIScope *N = DIFile::get(Context, "file", "dir"); + EXPECT_EQ(N, N->getFile()); +} + +typedef MetadataTest DICompileUnitTest; + +TEST_F(DICompileUnitTest, get) { + unsigned SourceLanguage = 1; + DIFile *File = getFile(); + StringRef Producer = "some producer"; + bool IsOptimized = false; + StringRef Flags = "flag after flag"; + unsigned RuntimeVersion = 2; + StringRef SplitDebugFilename = "another/file"; + unsigned EmissionKind = 3; + MDTuple *EnumTypes = getTuple(); + MDTuple *RetainedTypes = getTuple(); + MDTuple *Subprograms = getTuple(); + MDTuple *GlobalVariables = getTuple(); + MDTuple *ImportedEntities = getTuple(); + uint64_t DWOId = 0x10000000c0ffee; + MDTuple *Macros = getTuple(); + auto *N = DICompileUnit::getDistinct( + Context, SourceLanguage, File, Producer, IsOptimized, Flags, + RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, Subprograms, GlobalVariables, ImportedEntities, Macros, + DWOId); + + EXPECT_EQ(dwarf::DW_TAG_compile_unit, N->getTag()); + EXPECT_EQ(SourceLanguage, N->getSourceLanguage()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Producer, N->getProducer()); + EXPECT_EQ(IsOptimized, N->isOptimized()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(RuntimeVersion, N->getRuntimeVersion()); + EXPECT_EQ(SplitDebugFilename, N->getSplitDebugFilename()); + EXPECT_EQ(EmissionKind, N->getEmissionKind()); + EXPECT_EQ(EnumTypes, N->getEnumTypes().get()); + EXPECT_EQ(RetainedTypes, N->getRetainedTypes().get()); + EXPECT_EQ(Subprograms, N->getSubprograms().get()); + EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); + EXPECT_EQ(ImportedEntities, N->getImportedEntities().get()); + EXPECT_EQ(Macros, N->getMacros().get()); + EXPECT_EQ(DWOId, N->getDWOId()); + + TempDICompileUnit Temp = N->clone(); + EXPECT_EQ(dwarf::DW_TAG_compile_unit, Temp->getTag()); + EXPECT_EQ(SourceLanguage, Temp->getSourceLanguage()); + EXPECT_EQ(File, Temp->getFile()); + EXPECT_EQ(Producer, Temp->getProducer()); + EXPECT_EQ(IsOptimized, Temp->isOptimized()); + EXPECT_EQ(Flags, Temp->getFlags()); + EXPECT_EQ(RuntimeVersion, Temp->getRuntimeVersion()); + EXPECT_EQ(SplitDebugFilename, Temp->getSplitDebugFilename()); + EXPECT_EQ(EmissionKind, Temp->getEmissionKind()); + EXPECT_EQ(EnumTypes, Temp->getEnumTypes().get()); + EXPECT_EQ(RetainedTypes, Temp->getRetainedTypes().get()); + EXPECT_EQ(Subprograms, Temp->getSubprograms().get()); + EXPECT_EQ(GlobalVariables, Temp->getGlobalVariables().get()); + EXPECT_EQ(ImportedEntities, Temp->getImportedEntities().get()); + EXPECT_EQ(Macros, Temp->getMacros().get()); + EXPECT_EQ(DWOId, Temp->getDWOId()); + + auto *TempAddress = Temp.get(); + auto *Clone = MDNode::replaceWithPermanent(std::move(Temp)); + EXPECT_TRUE(Clone->isDistinct()); + EXPECT_EQ(TempAddress, Clone); +} + +TEST_F(DICompileUnitTest, replaceArrays) { + unsigned SourceLanguage = 1; + DIFile *File = getFile(); + StringRef Producer = "some producer"; + bool IsOptimized = false; + StringRef Flags = "flag after flag"; + unsigned RuntimeVersion = 2; + StringRef SplitDebugFilename = "another/file"; + unsigned EmissionKind = 3; + MDTuple *EnumTypes = MDTuple::getDistinct(Context, None); + MDTuple *RetainedTypes = MDTuple::getDistinct(Context, None); + MDTuple *ImportedEntities = MDTuple::getDistinct(Context, None); + uint64_t DWOId = 0xc0ffee; + auto *N = DICompileUnit::getDistinct( + Context, SourceLanguage, File, Producer, IsOptimized, Flags, + RuntimeVersion, SplitDebugFilename, EmissionKind, EnumTypes, + RetainedTypes, nullptr, nullptr, ImportedEntities, nullptr, DWOId); + + auto *Subprograms = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getSubprograms().get()); + N->replaceSubprograms(Subprograms); + EXPECT_EQ(Subprograms, N->getSubprograms().get()); + N->replaceSubprograms(nullptr); + EXPECT_EQ(nullptr, N->getSubprograms().get()); + + auto *GlobalVariables = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getGlobalVariables().get()); + N->replaceGlobalVariables(GlobalVariables); + EXPECT_EQ(GlobalVariables, N->getGlobalVariables().get()); + N->replaceGlobalVariables(nullptr); + EXPECT_EQ(nullptr, N->getGlobalVariables().get()); + + auto *Macros = MDTuple::getDistinct(Context, None); + EXPECT_EQ(nullptr, N->getMacros().get()); + N->replaceMacros(Macros); + EXPECT_EQ(Macros, N->getMacros().get()); + N->replaceMacros(nullptr); + EXPECT_EQ(nullptr, N->getMacros().get()); +} + +typedef MetadataTest DISubprogramTest; + +TEST_F(DISubprogramTest, get) { + DIScopeRef Scope = getCompositeType(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 2; + DISubroutineType *Type = getSubroutineType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + unsigned ScopeLine = 3; + DITypeRef ContainingType = getCompositeType(); + unsigned Virtuality = 4; + unsigned VirtualIndex = 5; + unsigned Flags = 6; + bool IsOptimized = false; + MDTuple *TemplateParams = getTuple(); + DISubprogram *Declaration = getSubprogram(); + MDTuple *Variables = getTuple(); + + auto *N = DISubprogram::get( + Context, Scope, Name, LinkageName, File, Line, Type, IsLocalToUnit, + IsDefinition, ScopeLine, ContainingType, Virtuality, VirtualIndex, Flags, + IsOptimized, TemplateParams, Declaration, Variables); + + EXPECT_EQ(dwarf::DW_TAG_subprogram, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(LinkageName, N->getLinkageName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); + EXPECT_EQ(IsDefinition, N->isDefinition()); + EXPECT_EQ(ScopeLine, N->getScopeLine()); + EXPECT_EQ(ContainingType, N->getContainingType()); + EXPECT_EQ(Virtuality, N->getVirtuality()); + EXPECT_EQ(VirtualIndex, N->getVirtualIndex()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(IsOptimized, N->isOptimized()); + EXPECT_EQ(TemplateParams, N->getTemplateParams().get()); + EXPECT_EQ(Declaration, N->getDeclaration()); + EXPECT_EQ(Variables, N->getVariables().get()); + EXPECT_EQ(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + + EXPECT_NE(N, DISubprogram::get(Context, getCompositeType(), Name, LinkageName, + File, Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, "other", LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, "other", File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, getFile(), + Line, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, + Line + 1, Type, IsLocalToUnit, IsDefinition, + ScopeLine, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + getSubroutineType(), IsLocalToUnit, + IsDefinition, ScopeLine, ContainingType, + Virtuality, VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, !IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, !IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, + ScopeLine + 1, ContainingType, Virtuality, + VirtualIndex, Flags, IsOptimized, + TemplateParams, Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + getCompositeType(), Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality + 1, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex + 1, + Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + ~Flags, IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, !IsOptimized, TemplateParams, + Declaration, Variables)); + EXPECT_NE(N, + DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, Flags, + IsOptimized, getTuple(), Declaration, Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + getSubprogram(), Variables)); + EXPECT_NE(N, DISubprogram::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, ScopeLine, + ContainingType, Virtuality, VirtualIndex, + Flags, IsOptimized, TemplateParams, + Declaration, getTuple())); + + TempDISubprogram Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DILexicalBlockTest; + +TEST_F(DILexicalBlockTest, get) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + unsigned Line = 5; + unsigned Column = 8; + + auto *N = DILexicalBlock::get(Context, Scope, File, Line, Column); + + EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Column, N->getColumn()); + EXPECT_EQ(N, DILexicalBlock::get(Context, Scope, File, Line, Column)); + + EXPECT_NE(N, + DILexicalBlock::get(Context, getSubprogram(), File, Line, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, getFile(), Line, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line + 1, Column)); + EXPECT_NE(N, DILexicalBlock::get(Context, Scope, File, Line, Column + 1)); + + TempDILexicalBlock Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DILexicalBlockTest, Overflow) { + DISubprogram *SP = getSubprogram(); + DIFile *F = getFile(); + { + auto *LB = DILexicalBlock::get(Context, SP, F, 2, 7); + EXPECT_EQ(2u, LB->getLine()); + EXPECT_EQ(7u, LB->getColumn()); + } + unsigned U16 = 1u << 16; + { + auto *LB = DILexicalBlock::get(Context, SP, F, UINT32_MAX, U16 - 1); + EXPECT_EQ(UINT32_MAX, LB->getLine()); + EXPECT_EQ(U16 - 1, LB->getColumn()); + } + { + auto *LB = DILexicalBlock::get(Context, SP, F, UINT32_MAX, U16); + EXPECT_EQ(UINT32_MAX, LB->getLine()); + EXPECT_EQ(0u, LB->getColumn()); + } + { + auto *LB = DILexicalBlock::get(Context, SP, F, UINT32_MAX, U16 + 1); + EXPECT_EQ(UINT32_MAX, LB->getLine()); + EXPECT_EQ(0u, LB->getColumn()); + } +} + +typedef MetadataTest DILexicalBlockFileTest; + +TEST_F(DILexicalBlockFileTest, get) { + DILocalScope *Scope = getSubprogram(); + DIFile *File = getFile(); + unsigned Discriminator = 5; + + auto *N = DILexicalBlockFile::get(Context, Scope, File, Discriminator); + + EXPECT_EQ(dwarf::DW_TAG_lexical_block, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Discriminator, N->getDiscriminator()); + EXPECT_EQ(N, DILexicalBlockFile::get(Context, Scope, File, Discriminator)); + + EXPECT_NE(N, DILexicalBlockFile::get(Context, getSubprogram(), File, + Discriminator)); + EXPECT_NE(N, + DILexicalBlockFile::get(Context, Scope, getFile(), Discriminator)); + EXPECT_NE(N, + DILexicalBlockFile::get(Context, Scope, File, Discriminator + 1)); + + TempDILexicalBlockFile Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DINamespaceTest; + +TEST_F(DINamespaceTest, get) { + DIScope *Scope = getFile(); + DIFile *File = getFile(); + StringRef Name = "namespace"; + unsigned Line = 5; + + auto *N = DINamespace::get(Context, Scope, File, Name, Line); + + EXPECT_EQ(dwarf::DW_TAG_namespace, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(N, DINamespace::get(Context, Scope, File, Name, Line)); + + EXPECT_NE(N, DINamespace::get(Context, getFile(), File, Name, Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, getFile(), Name, Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, File, "other", Line)); + EXPECT_NE(N, DINamespace::get(Context, Scope, File, Name, Line + 1)); + + TempDINamespace Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIModuleTest; + +TEST_F(DIModuleTest, get) { + DIScope *Scope = getFile(); + StringRef Name = "module"; + StringRef ConfigMacro = "-DNDEBUG"; + StringRef Includes = "-I."; + StringRef Sysroot = "/"; + + auto *N = DIModule::get(Context, Scope, Name, ConfigMacro, Includes, Sysroot); + + EXPECT_EQ(dwarf::DW_TAG_module, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(ConfigMacro, N->getConfigurationMacros()); + EXPECT_EQ(Includes, N->getIncludePath()); + EXPECT_EQ(Sysroot, N->getISysRoot()); + EXPECT_EQ(N, DIModule::get(Context, Scope, Name, + ConfigMacro, Includes, Sysroot)); + EXPECT_NE(N, DIModule::get(Context, getFile(), Name, + ConfigMacro, Includes, Sysroot)); + EXPECT_NE(N, DIModule::get(Context, Scope, "other", + ConfigMacro, Includes, Sysroot)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, + "other", Includes, Sysroot)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, + ConfigMacro, "other", Sysroot)); + EXPECT_NE(N, DIModule::get(Context, Scope, Name, + ConfigMacro, Includes, "other")); + + TempDIModule Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DITemplateTypeParameterTest; + +TEST_F(DITemplateTypeParameterTest, get) { + StringRef Name = "template"; + DITypeRef Type = getBasicType("basic"); + + auto *N = DITemplateTypeParameter::get(Context, Name, Type); + + EXPECT_EQ(dwarf::DW_TAG_template_type_parameter, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(N, DITemplateTypeParameter::get(Context, Name, Type)); + + EXPECT_NE(N, DITemplateTypeParameter::get(Context, "other", Type)); + EXPECT_NE(N, + DITemplateTypeParameter::get(Context, Name, getBasicType("other"))); + + TempDITemplateTypeParameter Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DITemplateValueParameterTest; + +TEST_F(DITemplateValueParameterTest, get) { + unsigned Tag = dwarf::DW_TAG_template_value_parameter; + StringRef Name = "template"; + DITypeRef Type = getBasicType("basic"); + Metadata *Value = getConstantAsMetadata(); + + auto *N = DITemplateValueParameter::get(Context, Tag, Name, Type, Value); + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(Value, N->getValue()); + EXPECT_EQ(N, DITemplateValueParameter::get(Context, Tag, Name, Type, Value)); + + EXPECT_NE(N, DITemplateValueParameter::get( + Context, dwarf::DW_TAG_GNU_template_template_param, Name, + Type, Value)); + EXPECT_NE(N, + DITemplateValueParameter::get(Context, Tag, "other", Type, Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, + getBasicType("other"), Value)); + EXPECT_NE(N, DITemplateValueParameter::get(Context, Tag, Name, Type, + getConstantAsMetadata())); + + TempDITemplateValueParameter Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIGlobalVariableTest; + +TEST_F(DIGlobalVariableTest, get) { + DIScope *Scope = getSubprogram(); + StringRef Name = "name"; + StringRef LinkageName = "linkage"; + DIFile *File = getFile(); + unsigned Line = 5; + DITypeRef Type = getDerivedType(); + bool IsLocalToUnit = false; + bool IsDefinition = true; + Constant *Variable = getConstant(); + DIDerivedType *StaticDataMemberDeclaration = + cast<DIDerivedType>(getDerivedType()); + + auto *N = DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, Variable, + StaticDataMemberDeclaration); + EXPECT_EQ(dwarf::DW_TAG_variable, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(LinkageName, N->getLinkageName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(IsLocalToUnit, N->isLocalToUnit()); + EXPECT_EQ(IsDefinition, N->isDefinition()); + EXPECT_EQ(Variable, N->getVariable()); + EXPECT_EQ(StaticDataMemberDeclaration, N->getStaticDataMemberDeclaration()); + EXPECT_EQ(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + + EXPECT_NE(N, + DIGlobalVariable::get(Context, getSubprogram(), Name, LinkageName, + File, Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, "other", LinkageName, File, + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, "other", File, Line, + Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, getFile(), + Line, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line + 1, Type, IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + getDerivedType(), IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, !IsLocalToUnit, IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, + Line, Type, IsLocalToUnit, !IsDefinition, + Variable, StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, + getConstant(), StaticDataMemberDeclaration)); + EXPECT_NE(N, + DIGlobalVariable::get(Context, Scope, Name, LinkageName, File, Line, + Type, IsLocalToUnit, IsDefinition, Variable, + cast<DIDerivedType>(getDerivedType()))); + + TempDIGlobalVariable Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DILocalVariableTest; + +TEST_F(DILocalVariableTest, get) { + DILocalScope *Scope = getSubprogram(); + StringRef Name = "name"; + DIFile *File = getFile(); + unsigned Line = 5; + DITypeRef Type = getDerivedType(); + unsigned Arg = 6; + unsigned Flags = 7; + + auto *N = + DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, Flags); + EXPECT_TRUE(N->isParameter()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(Arg, N->getArg()); + EXPECT_EQ(Flags, N->getFlags()); + EXPECT_EQ(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, + Flags)); + + EXPECT_FALSE( + DILocalVariable::get(Context, Scope, Name, File, Line, Type, 0, Flags) + ->isParameter()); + EXPECT_NE(N, DILocalVariable::get(Context, getSubprogram(), Name, File, Line, + Type, Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, "other", File, Line, Type, + Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, getFile(), Line, Type, + Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line + 1, Type, + Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, + getDerivedType(), Arg, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, + Arg + 1, Flags)); + EXPECT_NE(N, DILocalVariable::get(Context, Scope, Name, File, Line, Type, Arg, + ~Flags)); + + TempDILocalVariable Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DILocalVariableTest, getArg256) { + EXPECT_EQ(255u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), + 0, nullptr, 255, 0) + ->getArg()); + EXPECT_EQ(256u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), + 0, nullptr, 256, 0) + ->getArg()); + EXPECT_EQ(257u, DILocalVariable::get(Context, getSubprogram(), "", getFile(), + 0, nullptr, 257, 0) + ->getArg()); + unsigned Max = UINT16_MAX; + EXPECT_EQ(Max, DILocalVariable::get(Context, getSubprogram(), "", getFile(), + 0, nullptr, Max, 0) + ->getArg()); +} + +typedef MetadataTest DIExpressionTest; + +TEST_F(DIExpressionTest, get) { + uint64_t Elements[] = {2, 6, 9, 78, 0}; + auto *N = DIExpression::get(Context, Elements); + EXPECT_EQ(makeArrayRef(Elements), N->getElements()); + EXPECT_EQ(N, DIExpression::get(Context, Elements)); + + EXPECT_EQ(5u, N->getNumElements()); + EXPECT_EQ(2u, N->getElement(0)); + EXPECT_EQ(6u, N->getElement(1)); + EXPECT_EQ(9u, N->getElement(2)); + EXPECT_EQ(78u, N->getElement(3)); + EXPECT_EQ(0u, N->getElement(4)); + + TempDIExpression Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +TEST_F(DIExpressionTest, isValid) { +#define EXPECT_VALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_TRUE(DIExpression::get(Context, Elements)->isValid()); \ + } while (false) +#define EXPECT_INVALID(...) \ + do { \ + uint64_t Elements[] = {__VA_ARGS__}; \ + EXPECT_FALSE(DIExpression::get(Context, Elements)->isValid()); \ + } while (false) + + // Empty expression should be valid. + EXPECT_TRUE(DIExpression::get(Context, None)); + + // Valid constructions. + EXPECT_VALID(dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_plus, 6, dwarf::DW_OP_deref); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_bit_piece, 3, 7); + EXPECT_VALID(dwarf::DW_OP_deref, dwarf::DW_OP_plus, 6, dwarf::DW_OP_bit_piece, 3, 7); + + // Invalid constructions. + EXPECT_INVALID(~0u); + EXPECT_INVALID(dwarf::DW_OP_plus); + EXPECT_INVALID(dwarf::DW_OP_bit_piece); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_plus, 3); + EXPECT_INVALID(dwarf::DW_OP_bit_piece, 3, 7, dwarf::DW_OP_deref); + +#undef EXPECT_VALID +#undef EXPECT_INVALID +} + +typedef MetadataTest DIObjCPropertyTest; + +TEST_F(DIObjCPropertyTest, get) { + StringRef Name = "name"; + DIFile *File = getFile(); + unsigned Line = 5; + StringRef GetterName = "getter"; + StringRef SetterName = "setter"; + unsigned Attributes = 7; + DITypeRef Type = getBasicType("basic"); + + auto *N = DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, Type); + + EXPECT_EQ(dwarf::DW_TAG_APPLE_property, N->getTag()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(File, N->getFile()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(GetterName, N->getGetterName()); + EXPECT_EQ(SetterName, N->getSetterName()); + EXPECT_EQ(Attributes, N->getAttributes()); + EXPECT_EQ(Type, N->getType()); + EXPECT_EQ(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, Type)); + + EXPECT_NE(N, DIObjCProperty::get(Context, "other", File, Line, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, getFile(), Line, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line + 1, GetterName, + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, "other", + SetterName, Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + "other", Attributes, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes + 1, Type)); + EXPECT_NE(N, DIObjCProperty::get(Context, Name, File, Line, GetterName, + SetterName, Attributes, + getBasicType("other"))); + + TempDIObjCProperty Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest DIImportedEntityTest; + +TEST_F(DIImportedEntityTest, get) { + unsigned Tag = dwarf::DW_TAG_imported_module; + DIScope *Scope = getSubprogram(); + DINodeRef Entity = getCompositeType(); + unsigned Line = 5; + StringRef Name = "name"; + + auto *N = DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name); + + EXPECT_EQ(Tag, N->getTag()); + EXPECT_EQ(Scope, N->getScope()); + EXPECT_EQ(Entity, N->getEntity()); + EXPECT_EQ(Line, N->getLine()); + EXPECT_EQ(Name, N->getName()); + EXPECT_EQ(N, DIImportedEntity::get(Context, Tag, Scope, Entity, Line, Name)); + + EXPECT_NE(N, + DIImportedEntity::get(Context, dwarf::DW_TAG_imported_declaration, + Scope, Entity, Line, Name)); + EXPECT_NE(N, DIImportedEntity::get(Context, Tag, getSubprogram(), Entity, + Line, Name)); + EXPECT_NE(N, DIImportedEntity::get(Context, Tag, Scope, getCompositeType(), + Line, Name)); + EXPECT_NE(N, + DIImportedEntity::get(Context, Tag, Scope, Entity, Line + 1, Name)); + EXPECT_NE(N, + DIImportedEntity::get(Context, Tag, Scope, Entity, Line, "other")); + + TempDIImportedEntity Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + +typedef MetadataTest MetadataAsValueTest; + +TEST_F(MetadataAsValueTest, MDNode) { + MDNode *N = MDNode::get(Context, None); + auto *V = MetadataAsValue::get(Context, N); + EXPECT_TRUE(V->getType()->isMetadataTy()); + EXPECT_EQ(N, V->getMetadata()); + + auto *V2 = MetadataAsValue::get(Context, N); + EXPECT_EQ(V, V2); +} + +TEST_F(MetadataAsValueTest, MDNodeMDNode) { + MDNode *N = MDNode::get(Context, None); + Metadata *Ops[] = {N}; + MDNode *N2 = MDNode::get(Context, Ops); + auto *V = MetadataAsValue::get(Context, N2); + EXPECT_TRUE(V->getType()->isMetadataTy()); + EXPECT_EQ(N2, V->getMetadata()); + + auto *V2 = MetadataAsValue::get(Context, N2); + EXPECT_EQ(V, V2); + + auto *V3 = MetadataAsValue::get(Context, N); + EXPECT_TRUE(V3->getType()->isMetadataTy()); + EXPECT_NE(V, V3); + EXPECT_EQ(N, V3->getMetadata()); +} + +TEST_F(MetadataAsValueTest, MDNodeConstant) { + auto *C = ConstantInt::getTrue(Context); + auto *MD = ConstantAsMetadata::get(C); + Metadata *Ops[] = {MD}; + auto *N = MDNode::get(Context, Ops); + + auto *V = MetadataAsValue::get(Context, MD); + EXPECT_TRUE(V->getType()->isMetadataTy()); + EXPECT_EQ(MD, V->getMetadata()); + + auto *V2 = MetadataAsValue::get(Context, N); + EXPECT_EQ(MD, V2->getMetadata()); + EXPECT_EQ(V, V2); +} + +typedef MetadataTest ValueAsMetadataTest; + +TEST_F(ValueAsMetadataTest, UpdatesOnRAUW) { + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr<GlobalVariable> GV0( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + auto *MD = ValueAsMetadata::get(GV0.get()); + EXPECT_TRUE(MD->getValue() == GV0.get()); + ASSERT_TRUE(GV0->use_empty()); + + std::unique_ptr<GlobalVariable> GV1( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + GV0->replaceAllUsesWith(GV1.get()); + EXPECT_TRUE(MD->getValue() == GV1.get()); +} + +TEST_F(ValueAsMetadataTest, CollidingDoubleUpdates) { + // Create a constant. + ConstantAsMetadata *CI = ConstantAsMetadata::get( + ConstantInt::get(getGlobalContext(), APInt(8, 0))); + + // Create a temporary to prevent nodes from resolving. + auto Temp = MDTuple::getTemporary(Context, None); + + // When the first operand of N1 gets reset to nullptr, it'll collide with N2. + Metadata *Ops1[] = {CI, CI, Temp.get()}; + Metadata *Ops2[] = {nullptr, CI, Temp.get()}; + + auto *N1 = MDTuple::get(Context, Ops1); + auto *N2 = MDTuple::get(Context, Ops2); + ASSERT_NE(N1, N2); + + // Tell metadata that the constant is getting deleted. + // + // After this, N1 will be invalid, so don't touch it. + ValueAsMetadata::handleDeletion(CI->getValue()); + EXPECT_EQ(nullptr, N2->getOperand(0)); + EXPECT_EQ(nullptr, N2->getOperand(1)); + EXPECT_EQ(Temp.get(), N2->getOperand(2)); + + // Clean up Temp for teardown. + Temp->replaceAllUsesWith(nullptr); +} + +typedef MetadataTest TrackingMDRefTest; + +TEST_F(TrackingMDRefTest, UpdatesOnRAUW) { + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr<GlobalVariable> GV0( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(GV0.get())); + EXPECT_TRUE(MD->getValue() == GV0.get()); + ASSERT_TRUE(GV0->use_empty()); + + std::unique_ptr<GlobalVariable> GV1( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + GV0->replaceAllUsesWith(GV1.get()); + EXPECT_TRUE(MD->getValue() == GV1.get()); + + // Reset it, so we don't inadvertently test deletion. + MD.reset(); +} + +TEST_F(TrackingMDRefTest, UpdatesOnDeletion) { + Type *Ty = Type::getInt1PtrTy(Context); + std::unique_ptr<GlobalVariable> GV( + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + TypedTrackingMDRef<ValueAsMetadata> MD(ValueAsMetadata::get(GV.get())); + EXPECT_TRUE(MD->getValue() == GV.get()); + ASSERT_TRUE(GV->use_empty()); + + GV.reset(); + EXPECT_TRUE(!MD); +} + +TEST(NamedMDNodeTest, Search) { + LLVMContext Context; + ConstantAsMetadata *C = + ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Context), 1)); + ConstantAsMetadata *C2 = + ConstantAsMetadata::get(ConstantInt::get(Type::getInt32Ty(Context), 2)); + + Metadata *const V = C; + Metadata *const V2 = C2; + MDNode *n = MDNode::get(Context, V); + MDNode *n2 = MDNode::get(Context, V2); + + Module M("MyModule", Context); + const char *Name = "llvm.NMD1"; + NamedMDNode *NMD = M.getOrInsertNamedMetadata(Name); + NMD->addOperand(n); + NMD->addOperand(n2); + + std::string Str; + raw_string_ostream oss(Str); + NMD->print(oss); + EXPECT_STREQ("!llvm.NMD1 = !{!0, !1}\n", + oss.str().c_str()); +} + +typedef MetadataTest FunctionAttachmentTest; +TEST_F(FunctionAttachmentTest, setMetadata) { + Function *F = getFunction("foo"); + ASSERT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + DISubprogram *SP1 = getSubprogram(); + DISubprogram *SP2 = getSubprogram(); + ASSERT_NE(SP1, SP2); + + F->setMetadata("dbg", SP1); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(SP1, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(SP1, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + F->setMetadata(LLVMContext::MD_dbg, SP2); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(SP2, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(SP2, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + F->setMetadata("dbg", nullptr); + EXPECT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + EXPECT_EQ(nullptr, F->getMetadata("other")); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + ASSERT_NE(T1, T2); + + F->setMetadata("other1", T1); + F->setMetadata("other2", T2); + EXPECT_TRUE(F->hasMetadata()); + EXPECT_EQ(T1, F->getMetadata("other1")); + EXPECT_EQ(T2, F->getMetadata("other2")); + EXPECT_EQ(nullptr, F->getMetadata("dbg")); + + F->setMetadata("other1", T2); + F->setMetadata("other2", T1); + EXPECT_EQ(T2, F->getMetadata("other1")); + EXPECT_EQ(T1, F->getMetadata("other2")); + + F->setMetadata("other1", nullptr); + F->setMetadata("other2", nullptr); + EXPECT_FALSE(F->hasMetadata()); + EXPECT_EQ(nullptr, F->getMetadata("other1")); + EXPECT_EQ(nullptr, F->getMetadata("other2")); +} + +TEST_F(FunctionAttachmentTest, getAll) { + Function *F = getFunction("foo"); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + MDTuple *P = getTuple(); + DISubprogram *SP = getSubprogram(); + + F->setMetadata("other1", T2); + F->setMetadata(LLVMContext::MD_dbg, SP); + F->setMetadata("other2", T1); + F->setMetadata(LLVMContext::MD_prof, P); + F->setMetadata("other2", T2); + F->setMetadata("other1", T1); + + SmallVector<std::pair<unsigned, MDNode *>, 4> MDs; + F->getAllMetadata(MDs); + ASSERT_EQ(4u, MDs.size()); + EXPECT_EQ(LLVMContext::MD_dbg, MDs[0].first); + EXPECT_EQ(LLVMContext::MD_prof, MDs[1].first); + EXPECT_EQ(Context.getMDKindID("other1"), MDs[2].first); + EXPECT_EQ(Context.getMDKindID("other2"), MDs[3].first); + EXPECT_EQ(SP, MDs[0].second); + EXPECT_EQ(P, MDs[1].second); + EXPECT_EQ(T1, MDs[2].second); + EXPECT_EQ(T2, MDs[3].second); +} + +TEST_F(FunctionAttachmentTest, dropUnknownMetadata) { + Function *F = getFunction("foo"); + + MDTuple *T1 = getTuple(); + MDTuple *T2 = getTuple(); + MDTuple *P = getTuple(); + DISubprogram *SP = getSubprogram(); + + F->setMetadata("other1", T1); + F->setMetadata(LLVMContext::MD_dbg, SP); + F->setMetadata("other2", T2); + F->setMetadata(LLVMContext::MD_prof, P); + + unsigned Known[] = {Context.getMDKindID("other2"), LLVMContext::MD_prof}; + F->dropUnknownMetadata(Known); + + EXPECT_EQ(T2, F->getMetadata("other2")); + EXPECT_EQ(P, F->getMetadata(LLVMContext::MD_prof)); + EXPECT_EQ(nullptr, F->getMetadata("other1")); + EXPECT_EQ(nullptr, F->getMetadata(LLVMContext::MD_dbg)); + + F->setMetadata("other2", nullptr); + F->setMetadata(LLVMContext::MD_prof, nullptr); + EXPECT_FALSE(F->hasMetadata()); +} + +TEST_F(FunctionAttachmentTest, Verifier) { + Function *F = getFunction("foo"); + F->setMetadata("attach", getTuple()); + + // Confirm this has no body. + ASSERT_TRUE(F->empty()); + + // Functions without a body cannot have metadata attachments (they also can't + // be verified directly, so check that the module fails to verify). + EXPECT_TRUE(verifyModule(*F->getParent())); + + // Functions with a body can. + (void)new UnreachableInst(Context, BasicBlock::Create(Context, "bb", F)); + EXPECT_FALSE(verifyModule(*F->getParent())); + EXPECT_FALSE(verifyFunction(*F)); +} + +TEST_F(FunctionAttachmentTest, EntryCount) { + Function *F = getFunction("foo"); + EXPECT_FALSE(F->getEntryCount().hasValue()); + F->setEntryCount(12304); + EXPECT_TRUE(F->getEntryCount().hasValue()); + EXPECT_EQ(12304u, *F->getEntryCount()); +} + +TEST_F(FunctionAttachmentTest, SubprogramAttachment) { + Function *F = getFunction("foo"); + DISubprogram *SP = getSubprogram(); + F->setSubprogram(SP); + + // Note that the static_cast confirms that F->getSubprogram() actually + // returns an DISubprogram. + EXPECT_EQ(SP, static_cast<DISubprogram *>(F->getSubprogram())); + EXPECT_EQ(SP, F->getMetadata("dbg")); + EXPECT_EQ(SP, F->getMetadata(LLVMContext::MD_dbg)); +} + +} diff --git a/gnu/llvm/unittests/IR/PassManagerTest.cpp b/gnu/llvm/unittests/IR/PassManagerTest.cpp new file mode 100644 index 00000000000..41af0b0bd25 --- /dev/null +++ b/gnu/llvm/unittests/IR/PassManagerTest.cpp @@ -0,0 +1,349 @@ +//===- llvm/unittest/IR/PassManager.cpp - PassManager tests ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class TestFunctionAnalysis { +public: + struct Result { + Result(int Count) : InstructionCount(Count) {} + int InstructionCount; + }; + + /// \brief Returns an opaque, unique ID for this pass type. + static void *ID() { return (void *)&PassID; } + + /// \brief Returns the name of the analysis. + static StringRef name() { return "TestFunctionAnalysis"; } + + TestFunctionAnalysis(int &Runs) : Runs(Runs) {} + + /// \brief Run the analysis pass over the function and return a result. + Result run(Function &F, FunctionAnalysisManager *AM) { + ++Runs; + int Count = 0; + for (Function::iterator BBI = F.begin(), BBE = F.end(); BBI != BBE; ++BBI) + for (BasicBlock::iterator II = BBI->begin(), IE = BBI->end(); II != IE; + ++II) + ++Count; + return Result(Count); + } + +private: + /// \brief Private static data to provide unique ID. + static char PassID; + + int &Runs; +}; + +char TestFunctionAnalysis::PassID; + +class TestModuleAnalysis { +public: + struct Result { + Result(int Count) : FunctionCount(Count) {} + int FunctionCount; + }; + + static void *ID() { return (void *)&PassID; } + + static StringRef name() { return "TestModuleAnalysis"; } + + TestModuleAnalysis(int &Runs) : Runs(Runs) {} + + Result run(Module &M, ModuleAnalysisManager *AM) { + ++Runs; + int Count = 0; + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) + ++Count; + return Result(Count); + } + +private: + static char PassID; + + int &Runs; +}; + +char TestModuleAnalysis::PassID; + +struct TestModulePass { + TestModulePass(int &RunCount) : RunCount(RunCount) {} + + PreservedAnalyses run(Module &M) { + ++RunCount; + return PreservedAnalyses::none(); + } + + static StringRef name() { return "TestModulePass"; } + + int &RunCount; +}; + +struct TestPreservingModulePass { + PreservedAnalyses run(Module &M) { return PreservedAnalyses::all(); } + + static StringRef name() { return "TestPreservingModulePass"; } +}; + +struct TestMinPreservingModulePass { + PreservedAnalyses run(Module &M, ModuleAnalysisManager *AM) { + PreservedAnalyses PA; + + // Force running an analysis. + (void)AM->getResult<TestModuleAnalysis>(M); + + PA.preserve<FunctionAnalysisManagerModuleProxy>(); + return PA; + } + + static StringRef name() { return "TestMinPreservingModulePass"; } +}; + +struct TestFunctionPass { + TestFunctionPass(int &RunCount, int &AnalyzedInstrCount, + int &AnalyzedFunctionCount, + bool OnlyUseCachedResults = false) + : RunCount(RunCount), AnalyzedInstrCount(AnalyzedInstrCount), + AnalyzedFunctionCount(AnalyzedFunctionCount), + OnlyUseCachedResults(OnlyUseCachedResults) {} + + PreservedAnalyses run(Function &F, FunctionAnalysisManager *AM) { + ++RunCount; + + const ModuleAnalysisManager &MAM = + AM->getResult<ModuleAnalysisManagerFunctionProxy>(F).getManager(); + if (TestModuleAnalysis::Result *TMA = + MAM.getCachedResult<TestModuleAnalysis>(*F.getParent())) + AnalyzedFunctionCount += TMA->FunctionCount; + + if (OnlyUseCachedResults) { + // Hack to force the use of the cached interface. + if (TestFunctionAnalysis::Result *AR = + AM->getCachedResult<TestFunctionAnalysis>(F)) + AnalyzedInstrCount += AR->InstructionCount; + } else { + // Typical path just runs the analysis as needed. + TestFunctionAnalysis::Result &AR = AM->getResult<TestFunctionAnalysis>(F); + AnalyzedInstrCount += AR.InstructionCount; + } + + return PreservedAnalyses::all(); + } + + static StringRef name() { return "TestFunctionPass"; } + + int &RunCount; + int &AnalyzedInstrCount; + int &AnalyzedFunctionCount; + bool OnlyUseCachedResults; +}; + +// A test function pass that invalidates all function analyses for a function +// with a specific name. +struct TestInvalidationFunctionPass { + TestInvalidationFunctionPass(StringRef FunctionName) : Name(FunctionName) {} + + PreservedAnalyses run(Function &F) { + return F.getName() == Name ? PreservedAnalyses::none() + : PreservedAnalyses::all(); + } + + static StringRef name() { return "TestInvalidationFunctionPass"; } + + StringRef Name; +}; + +std::unique_ptr<Module> parseIR(const char *IR) { + LLVMContext &C = getGlobalContext(); + SMDiagnostic Err; + return parseAssemblyString(IR, Err, C); +} + +class PassManagerTest : public ::testing::Test { +protected: + std::unique_ptr<Module> M; + +public: + PassManagerTest() + : M(parseIR("define void @f() {\n" + "entry:\n" + " call void @g()\n" + " call void @h()\n" + " ret void\n" + "}\n" + "define void @g() {\n" + " ret void\n" + "}\n" + "define void @h() {\n" + " ret void\n" + "}\n")) {} +}; + +TEST_F(PassManagerTest, BasicPreservedAnalyses) { + PreservedAnalyses PA1 = PreservedAnalyses(); + EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>()); + PreservedAnalyses PA2 = PreservedAnalyses::none(); + EXPECT_FALSE(PA2.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA2.preserved<TestModuleAnalysis>()); + PreservedAnalyses PA3 = PreservedAnalyses::all(); + EXPECT_TRUE(PA3.preserved<TestFunctionAnalysis>()); + EXPECT_TRUE(PA3.preserved<TestModuleAnalysis>()); + PreservedAnalyses PA4 = PA1; + EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>()); + PA4 = PA3; + EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>()); + EXPECT_TRUE(PA4.preserved<TestModuleAnalysis>()); + PA4 = std::move(PA2); + EXPECT_FALSE(PA4.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>()); + PA4.preserve<TestFunctionAnalysis>(); + EXPECT_TRUE(PA4.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA4.preserved<TestModuleAnalysis>()); + PA1.preserve<TestModuleAnalysis>(); + EXPECT_FALSE(PA1.preserved<TestFunctionAnalysis>()); + EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>()); + PA1.preserve<TestFunctionAnalysis>(); + EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>()); + EXPECT_TRUE(PA1.preserved<TestModuleAnalysis>()); + PA1.intersect(PA4); + EXPECT_TRUE(PA1.preserved<TestFunctionAnalysis>()); + EXPECT_FALSE(PA1.preserved<TestModuleAnalysis>()); +} + +TEST_F(PassManagerTest, Basic) { + FunctionAnalysisManager FAM; + int FunctionAnalysisRuns = 0; + FAM.registerPass(TestFunctionAnalysis(FunctionAnalysisRuns)); + + ModuleAnalysisManager MAM; + int ModuleAnalysisRuns = 0; + MAM.registerPass(TestModuleAnalysis(ModuleAnalysisRuns)); + MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); + FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); + + ModulePassManager MPM; + + // Count the runs over a Function. + int FunctionPassRunCount1 = 0; + int AnalyzedInstrCount1 = 0; + int AnalyzedFunctionCount1 = 0; + { + // Pointless scoped copy to test move assignment. + ModulePassManager NestedMPM; + FunctionPassManager FPM; + { + // Pointless scope to test move assignment. + FunctionPassManager NestedFPM; + NestedFPM.addPass(TestFunctionPass(FunctionPassRunCount1, AnalyzedInstrCount1, + AnalyzedFunctionCount1)); + FPM = std::move(NestedFPM); + } + NestedMPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + MPM = std::move(NestedMPM); + } + + // Count the runs over a module. + int ModulePassRunCount = 0; + MPM.addPass(TestModulePass(ModulePassRunCount)); + + // Count the runs over a Function in a separate manager. + int FunctionPassRunCount2 = 0; + int AnalyzedInstrCount2 = 0; + int AnalyzedFunctionCount2 = 0; + { + FunctionPassManager FPM; + FPM.addPass(TestFunctionPass(FunctionPassRunCount2, AnalyzedInstrCount2, + AnalyzedFunctionCount2)); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + // A third function pass manager but with only preserving intervening passes + // and with a function pass that invalidates exactly one analysis. + MPM.addPass(TestPreservingModulePass()); + int FunctionPassRunCount3 = 0; + int AnalyzedInstrCount3 = 0; + int AnalyzedFunctionCount3 = 0; + { + FunctionPassManager FPM; + FPM.addPass(TestFunctionPass(FunctionPassRunCount3, AnalyzedInstrCount3, + AnalyzedFunctionCount3)); + FPM.addPass(TestInvalidationFunctionPass("f")); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + // A fourth function pass manager but with a minimal intervening passes. + MPM.addPass(TestMinPreservingModulePass()); + int FunctionPassRunCount4 = 0; + int AnalyzedInstrCount4 = 0; + int AnalyzedFunctionCount4 = 0; + { + FunctionPassManager FPM; + FPM.addPass(TestFunctionPass(FunctionPassRunCount4, AnalyzedInstrCount4, + AnalyzedFunctionCount4)); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + // A fifth function pass manager but which uses only cached results. + int FunctionPassRunCount5 = 0; + int AnalyzedInstrCount5 = 0; + int AnalyzedFunctionCount5 = 0; + { + FunctionPassManager FPM; + FPM.addPass(TestInvalidationFunctionPass("f")); + FPM.addPass(TestFunctionPass(FunctionPassRunCount5, AnalyzedInstrCount5, + AnalyzedFunctionCount5, + /*OnlyUseCachedResults=*/true)); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + } + + MPM.run(*M, &MAM); + + // Validate module pass counters. + EXPECT_EQ(1, ModulePassRunCount); + + // Validate all function pass counter sets are the same. + EXPECT_EQ(3, FunctionPassRunCount1); + EXPECT_EQ(5, AnalyzedInstrCount1); + EXPECT_EQ(0, AnalyzedFunctionCount1); + EXPECT_EQ(3, FunctionPassRunCount2); + EXPECT_EQ(5, AnalyzedInstrCount2); + EXPECT_EQ(0, AnalyzedFunctionCount2); + EXPECT_EQ(3, FunctionPassRunCount3); + EXPECT_EQ(5, AnalyzedInstrCount3); + EXPECT_EQ(0, AnalyzedFunctionCount3); + EXPECT_EQ(3, FunctionPassRunCount4); + EXPECT_EQ(5, AnalyzedInstrCount4); + EXPECT_EQ(0, AnalyzedFunctionCount4); + EXPECT_EQ(3, FunctionPassRunCount5); + EXPECT_EQ(2, AnalyzedInstrCount5); // Only 'g' and 'h' were cached. + EXPECT_EQ(0, AnalyzedFunctionCount5); + + // Validate the analysis counters: + // first run over 3 functions, then module pass invalidates + // second run over 3 functions, nothing invalidates + // third run over 0 functions, but 1 function invalidated + // fourth run over 1 function + EXPECT_EQ(7, FunctionAnalysisRuns); + + EXPECT_EQ(1, ModuleAnalysisRuns); +} +} diff --git a/gnu/llvm/unittests/IR/PatternMatch.cpp b/gnu/llvm/unittests/IR/PatternMatch.cpp new file mode 100644 index 00000000000..f3a27b8d250 --- /dev/null +++ b/gnu/llvm/unittests/IR/PatternMatch.cpp @@ -0,0 +1,298 @@ +//===---- llvm/unittest/IR/PatternMatch.cpp - PatternMatch unit tests ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/NoFolder.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/IR/Type.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::PatternMatch; + +namespace { + +struct PatternMatchTest : ::testing::Test { + LLVMContext Ctx; + std::unique_ptr<Module> M; + Function *F; + BasicBlock *BB; + IRBuilder<true, NoFolder> IRB; + + PatternMatchTest() + : M(new Module("PatternMatchTestModule", Ctx)), + F(Function::Create( + FunctionType::get(Type::getVoidTy(Ctx), /* IsVarArg */ false), + Function::ExternalLinkage, "f", M.get())), + BB(BasicBlock::Create(Ctx, "entry", F)), IRB(BB) {} +}; + +TEST_F(PatternMatchTest, OneUse) { + // Build up a little tree of values: + // + // One = (1 + 2) + 42 + // Two = One + 42 + // Leaf = (Two + 8) + (Two + 13) + Value *One = IRB.CreateAdd(IRB.CreateAdd(IRB.getInt32(1), IRB.getInt32(2)), + IRB.getInt32(42)); + Value *Two = IRB.CreateAdd(One, IRB.getInt32(42)); + Value *Leaf = IRB.CreateAdd(IRB.CreateAdd(Two, IRB.getInt32(8)), + IRB.CreateAdd(Two, IRB.getInt32(13))); + Value *V; + + EXPECT_TRUE(m_OneUse(m_Value(V)).match(One)); + EXPECT_EQ(One, V); + + EXPECT_FALSE(m_OneUse(m_Value()).match(Two)); + EXPECT_FALSE(m_OneUse(m_Value()).match(Leaf)); +} + +TEST_F(PatternMatchTest, FloatingPointOrderedMin) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test OLT. + EXPECT_TRUE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test OLE. + EXPECT_TRUE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on OGE. + EXPECT_FALSE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), L, R))); + + // Test no match on OGT. + EXPECT_FALSE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), L, R))); + + // Test match on OGE with inverted select. + EXPECT_TRUE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test match on OGT with inverted select. + EXPECT_TRUE(m_OrdFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + +TEST_F(PatternMatchTest, FloatingPointOrderedMax) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test OGT. + EXPECT_TRUE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test OGE. + EXPECT_TRUE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on OLE. + EXPECT_FALSE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), L, R))); + + // Test no match on OLT. + EXPECT_FALSE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), L, R))); + + // Test match on OLE with inverted select. + EXPECT_TRUE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test match on OLT with inverted select. + EXPECT_TRUE(m_OrdFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + +TEST_F(PatternMatchTest, FloatingPointUnorderedMin) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test ULT. + EXPECT_TRUE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test ULE. + EXPECT_TRUE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on UGE. + EXPECT_FALSE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), L, R))); + + // Test no match on UGT. + EXPECT_FALSE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), L, R))); + + // Test match on UGE with inverted select. + EXPECT_TRUE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test match on UGT with inverted select. + EXPECT_TRUE(m_UnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + +TEST_F(PatternMatchTest, FloatingPointUnorderedMax) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test UGT. + EXPECT_TRUE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test UGE. + EXPECT_TRUE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on ULE. + EXPECT_FALSE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), L, R))); + + // Test no match on ULT. + EXPECT_FALSE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), L, R))); + + // Test match on ULE with inverted select. + EXPECT_TRUE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test match on ULT with inverted select. + EXPECT_TRUE(m_UnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + +TEST_F(PatternMatchTest, OverflowingBinOps) { + Value *L = IRB.getInt32(1); + Value *R = IRB.getInt32(2); + Value *MatchL, *MatchR; + + EXPECT_TRUE( + m_NSWAdd(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWAdd(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE( + m_NSWSub(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWSub(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE( + m_NSWMul(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNSWMul(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE(m_NSWShl(m_Value(MatchL), m_Value(MatchR)).match( + IRB.CreateShl(L, R, "", /* NUW */ false, /* NSW */ true))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_TRUE( + m_NUWAdd(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWAdd(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE( + m_NUWSub(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWSub(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE( + m_NUWMul(m_Value(MatchL), m_Value(MatchR)).match(IRB.CreateNUWMul(L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + MatchL = MatchR = nullptr; + EXPECT_TRUE(m_NUWShl(m_Value(MatchL), m_Value(MatchR)).match( + IRB.CreateShl(L, R, "", /* NUW */ true, /* NSW */ false))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateAdd(L, R))); + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NSWAdd(m_Value(), m_Value()).match(IRB.CreateNSWSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateNUWSub(L, R))); + EXPECT_FALSE(m_NSWSub(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateMul(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateNUWMul(L, R))); + EXPECT_FALSE(m_NSWMul(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match(IRB.CreateShl(L, R))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match( + IRB.CreateShl(L, R, "", /* NUW */ true, /* NSW */ false))); + EXPECT_FALSE(m_NSWShl(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateAdd(L, R))); + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateNSWAdd(L, R))); + EXPECT_FALSE(m_NUWAdd(m_Value(), m_Value()).match(IRB.CreateNUWSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateNSWSub(L, R))); + EXPECT_FALSE(m_NUWSub(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateMul(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateNSWMul(L, R))); + EXPECT_FALSE(m_NUWMul(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match(IRB.CreateShl(L, R))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match( + IRB.CreateShl(L, R, "", /* NUW */ false, /* NSW */ true))); + EXPECT_FALSE(m_NUWShl(m_Value(), m_Value()).match(IRB.CreateNUWAdd(L, R))); +} + +} // anonymous namespace. diff --git a/gnu/llvm/unittests/IR/TypeBuilderTest.cpp b/gnu/llvm/unittests/IR/TypeBuilderTest.cpp new file mode 100644 index 00000000000..b7b3e45e35e --- /dev/null +++ b/gnu/llvm/unittests/IR/TypeBuilderTest.cpp @@ -0,0 +1,253 @@ +//===- llvm/unittest/TypeBuilderTest.cpp - TypeBuilder tests --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/TypeBuilder.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(TypeBuilderTest, Void) { + EXPECT_EQ(Type::getVoidTy(getGlobalContext()), (TypeBuilder<void, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getVoidTy(getGlobalContext()), (TypeBuilder<void, false>::get(getGlobalContext()))); + // Special cases for C compatibility: + EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), + (TypeBuilder<void*, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), + (TypeBuilder<const void*, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), + (TypeBuilder<volatile void*, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), + (TypeBuilder<const volatile void*, false>::get( + getGlobalContext()))); +} + +TEST(TypeBuilderTest, HostIntegers) { + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), (TypeBuilder<int8_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), (TypeBuilder<uint8_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt16Ty(getGlobalContext()), (TypeBuilder<int16_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt16Ty(getGlobalContext()), (TypeBuilder<uint16_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (TypeBuilder<int32_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (TypeBuilder<uint32_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt64Ty(getGlobalContext()), (TypeBuilder<int64_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt64Ty(getGlobalContext()), (TypeBuilder<uint64_t, false>::get(getGlobalContext()))); + + EXPECT_EQ(IntegerType::get(getGlobalContext(), sizeof(size_t) * CHAR_BIT), + (TypeBuilder<size_t, false>::get(getGlobalContext()))); + EXPECT_EQ(IntegerType::get(getGlobalContext(), sizeof(ptrdiff_t) * CHAR_BIT), + (TypeBuilder<ptrdiff_t, false>::get(getGlobalContext()))); +} + +TEST(TypeBuilderTest, CrossCompilableIntegers) { + EXPECT_EQ(IntegerType::get(getGlobalContext(), 1), (TypeBuilder<types::i<1>, true>::get(getGlobalContext()))); + EXPECT_EQ(IntegerType::get(getGlobalContext(), 1), (TypeBuilder<types::i<1>, false>::get(getGlobalContext()))); + EXPECT_EQ(IntegerType::get(getGlobalContext(), 72), (TypeBuilder<types::i<72>, true>::get(getGlobalContext()))); + EXPECT_EQ(IntegerType::get(getGlobalContext(), 72), (TypeBuilder<types::i<72>, false>::get(getGlobalContext()))); +} + +TEST(TypeBuilderTest, Float) { + EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder<float, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder<double, false>::get(getGlobalContext()))); + // long double isn't supported yet. + EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder<types::ieee_float, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getFloatTy(getGlobalContext()), (TypeBuilder<types::ieee_float, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder<types::ieee_double, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getDoubleTy(getGlobalContext()), (TypeBuilder<types::ieee_double, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getX86_FP80Ty(getGlobalContext()), (TypeBuilder<types::x86_fp80, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getX86_FP80Ty(getGlobalContext()), (TypeBuilder<types::x86_fp80, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getFP128Ty(getGlobalContext()), (TypeBuilder<types::fp128, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getFP128Ty(getGlobalContext()), (TypeBuilder<types::fp128, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getPPC_FP128Ty(getGlobalContext()), (TypeBuilder<types::ppc_fp128, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getPPC_FP128Ty(getGlobalContext()), (TypeBuilder<types::ppc_fp128, false>::get(getGlobalContext()))); +} + +TEST(TypeBuilderTest, Derived) { + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), + (TypeBuilder<int8_t**, false>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), + (TypeBuilder<int8_t[7], false>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), + (TypeBuilder<int8_t[], false>::get(getGlobalContext()))); + + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), + (TypeBuilder<types::i<8>**, false>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), + (TypeBuilder<types::i<8>[7], false>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), + (TypeBuilder<types::i<8>[], false>::get(getGlobalContext()))); + + EXPECT_EQ(PointerType::getUnqual(Type::getInt8PtrTy(getGlobalContext())), + (TypeBuilder<types::i<8>**, true>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 7), + (TypeBuilder<types::i<8>[7], true>::get(getGlobalContext()))); + EXPECT_EQ(ArrayType::get(Type::getInt8Ty(getGlobalContext()), 0), + (TypeBuilder<types::i<8>[], true>::get(getGlobalContext()))); + + + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const int8_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<volatile int8_t, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const volatile int8_t, false>::get(getGlobalContext()))); + + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const types::i<8>, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<volatile types::i<8>, false>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const volatile types::i<8>, false>::get(getGlobalContext()))); + + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const types::i<8>, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<volatile types::i<8>, true>::get(getGlobalContext()))); + EXPECT_EQ(Type::getInt8Ty(getGlobalContext()), + (TypeBuilder<const volatile types::i<8>, true>::get(getGlobalContext()))); + + EXPECT_EQ(Type::getInt8PtrTy(getGlobalContext()), + (TypeBuilder<const volatile int8_t*const volatile, false>::get(getGlobalContext()))); +} + +TEST(TypeBuilderTest, Functions) { + std::vector<Type*> params; + EXPECT_EQ(FunctionType::get(Type::getVoidTy(getGlobalContext()), params, false), + (TypeBuilder<void(), true>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(...), false>::get(getGlobalContext()))); + params.push_back(TypeBuilder<int32_t*, false>::get(getGlobalContext())); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), + (TypeBuilder<int8_t(const int32_t*), false>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(const int32_t*, ...), false>::get(getGlobalContext()))); + params.push_back(TypeBuilder<char*, false>::get(getGlobalContext())); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), + (TypeBuilder<int8_t(int32_t*, void*), false>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(int32_t*, char*, ...), false>::get(getGlobalContext()))); + params.push_back(TypeBuilder<char, false>::get(getGlobalContext())); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), + (TypeBuilder<int8_t(int32_t*, void*, char), false>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(int32_t*, char*, char, ...), false>::get(getGlobalContext()))); + params.push_back(TypeBuilder<char, false>::get(getGlobalContext())); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), + (TypeBuilder<int8_t(int32_t*, void*, char, char), false>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(int32_t*, char*, char, char, ...), + false>::get(getGlobalContext()))); + params.push_back(TypeBuilder<char, false>::get(getGlobalContext())); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, false), + (TypeBuilder<int8_t(int32_t*, void*, char, char, char), + false>::get(getGlobalContext()))); + EXPECT_EQ(FunctionType::get(Type::getInt8Ty(getGlobalContext()), params, true), + (TypeBuilder<int8_t(int32_t*, char*, char, char, char, ...), + false>::get(getGlobalContext()))); +} + +TEST(TypeBuilderTest, Context) { + // We used to cache TypeBuilder results in static local variables. This + // produced the same type for different contexts, which of course broke + // things. + LLVMContext context1; + EXPECT_EQ(&context1, + &(TypeBuilder<types::i<1>, true>::get(context1))->getContext()); + LLVMContext context2; + EXPECT_EQ(&context2, + &(TypeBuilder<types::i<1>, true>::get(context2))->getContext()); +} + +struct MyType { + int a; + int *b; + void *array[1]; +}; + +struct MyPortableType { + int32_t a; + int32_t *b; + void *array[1]; +}; + +} // anonymous namespace + +namespace llvm { +template<bool cross> class TypeBuilder<MyType, cross> { +public: + static StructType *get(LLVMContext &Context) { + // Using the static result variable ensures that the type is + // only looked up once. + std::vector<Type*> st; + st.push_back(TypeBuilder<int, cross>::get(Context)); + st.push_back(TypeBuilder<int*, cross>::get(Context)); + st.push_back(TypeBuilder<void*[], cross>::get(Context)); + static StructType *const result = StructType::get(Context, st); + return result; + } + + // You may find this a convenient place to put some constants + // to help with getelementptr. They don't have any effect on + // the operation of TypeBuilder. + enum Fields { + FIELD_A, + FIELD_B, + FIELD_ARRAY + }; +}; + +template<bool cross> class TypeBuilder<MyPortableType, cross> { +public: + static StructType *get(LLVMContext &Context) { + // Using the static result variable ensures that the type is + // only looked up once. + std::vector<Type*> st; + st.push_back(TypeBuilder<types::i<32>, cross>::get(Context)); + st.push_back(TypeBuilder<types::i<32>*, cross>::get(Context)); + st.push_back(TypeBuilder<types::i<8>*[], cross>::get(Context)); + static StructType *const result = StructType::get(Context, st); + return result; + } + + // You may find this a convenient place to put some constants + // to help with getelementptr. They don't have any effect on + // the operation of TypeBuilder. + enum Fields { + FIELD_A, + FIELD_B, + FIELD_ARRAY + }; +}; +} // namespace llvm +namespace { + +TEST(TypeBuilderTest, Extensions) { + EXPECT_EQ(PointerType::getUnqual(StructType::get( + TypeBuilder<int, false>::get(getGlobalContext()), + TypeBuilder<int*, false>::get(getGlobalContext()), + TypeBuilder<void*[], false>::get(getGlobalContext()), + (void*)nullptr)), + (TypeBuilder<MyType*, false>::get(getGlobalContext()))); + EXPECT_EQ(PointerType::getUnqual(StructType::get( + TypeBuilder<types::i<32>, false>::get(getGlobalContext()), + TypeBuilder<types::i<32>*, false>::get(getGlobalContext()), + TypeBuilder<types::i<8>*[], false>::get(getGlobalContext()), + (void*)nullptr)), + (TypeBuilder<MyPortableType*, false>::get(getGlobalContext()))); + EXPECT_EQ(PointerType::getUnqual(StructType::get( + TypeBuilder<types::i<32>, false>::get(getGlobalContext()), + TypeBuilder<types::i<32>*, false>::get(getGlobalContext()), + TypeBuilder<types::i<8>*[], false>::get(getGlobalContext()), + (void*)nullptr)), + (TypeBuilder<MyPortableType*, true>::get(getGlobalContext()))); +} + +} // anonymous namespace diff --git a/gnu/llvm/unittests/IR/TypesTest.cpp b/gnu/llvm/unittests/IR/TypesTest.cpp new file mode 100644 index 00000000000..f006db51de5 --- /dev/null +++ b/gnu/llvm/unittests/IR/TypesTest.cpp @@ -0,0 +1,38 @@ +//===- llvm/unittest/IR/TypesTest.cpp - Type unit tests -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(TypesTest, StructType) { + LLVMContext C; + + // PR13522 + StructType *Struct = StructType::create(C, "FooBar"); + EXPECT_EQ("FooBar", Struct->getName()); + Struct->setName(Struct->getName().substr(0, 3)); + EXPECT_EQ("Foo", Struct->getName()); + Struct->setName(""); + EXPECT_TRUE(Struct->getName().empty()); + EXPECT_FALSE(Struct->hasName()); +} + +TEST(TypesTest, LayoutIdenticalEmptyStructs) { + LLVMContext C; + + StructType *Foo = StructType::create(C, "Foo"); + StructType *Bar = StructType::create(C, "Bar"); + EXPECT_TRUE(Foo->isLayoutIdentical(Bar)); +} + +} // end anonymous namespace diff --git a/gnu/llvm/unittests/IR/UseTest.cpp b/gnu/llvm/unittests/IR/UseTest.cpp new file mode 100644 index 00000000000..d9d20af941d --- /dev/null +++ b/gnu/llvm/unittests/IR/UseTest.cpp @@ -0,0 +1,112 @@ +//===- llvm/unittest/IR/UseTest.cpp - Use unit tests ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/User.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +TEST(UseTest, sort) { + LLVMContext C; + + const char *ModuleString = "define void @f(i32 %x) {\n" + "entry:\n" + " %v0 = add i32 %x, 0\n" + " %v2 = add i32 %x, 2\n" + " %v5 = add i32 %x, 5\n" + " %v1 = add i32 %x, 1\n" + " %v3 = add i32 %x, 3\n" + " %v7 = add i32 %x, 7\n" + " %v6 = add i32 %x, 6\n" + " %v4 = add i32 %x, 4\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + char vnbuf[8]; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + Function *F = M->getFunction("f"); + ASSERT_TRUE(F); + ASSERT_TRUE(F->arg_begin() != F->arg_end()); + Argument &X = *F->arg_begin(); + ASSERT_EQ("x", X.getName()); + + X.sortUseList([](const Use &L, const Use &R) { + return L.getUser()->getName() < R.getUser()->getName(); + }); + unsigned I = 0; + for (User *U : X.users()) { + format("v%u", I++).snprint(vnbuf, sizeof(vnbuf)); + EXPECT_EQ(vnbuf, U->getName()); + } + ASSERT_EQ(8u, I); + + X.sortUseList([](const Use &L, const Use &R) { + return L.getUser()->getName() > R.getUser()->getName(); + }); + I = 0; + for (User *U : X.users()) { + format("v%u", (7 - I++)).snprint(vnbuf, sizeof(vnbuf)); + EXPECT_EQ(vnbuf, U->getName()); + } + ASSERT_EQ(8u, I); +} + +TEST(UseTest, reverse) { + LLVMContext C; + + const char *ModuleString = "define void @f(i32 %x) {\n" + "entry:\n" + " %v0 = add i32 %x, 0\n" + " %v2 = add i32 %x, 2\n" + " %v5 = add i32 %x, 5\n" + " %v1 = add i32 %x, 1\n" + " %v3 = add i32 %x, 3\n" + " %v7 = add i32 %x, 7\n" + " %v6 = add i32 %x, 6\n" + " %v4 = add i32 %x, 4\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + char vnbuf[8]; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + Function *F = M->getFunction("f"); + ASSERT_TRUE(F); + ASSERT_TRUE(F->arg_begin() != F->arg_end()); + Argument &X = *F->arg_begin(); + ASSERT_EQ("x", X.getName()); + + X.sortUseList([](const Use &L, const Use &R) { + return L.getUser()->getName() < R.getUser()->getName(); + }); + unsigned I = 0; + for (User *U : X.users()) { + format("v%u", I++).snprint(vnbuf, sizeof(vnbuf)); + EXPECT_EQ(vnbuf, U->getName()); + } + ASSERT_EQ(8u, I); + + X.reverseUseList(); + I = 0; + for (User *U : X.users()) { + format("v%u", (7 - I++)).snprint(vnbuf, sizeof(vnbuf)); + EXPECT_EQ(vnbuf, U->getName()); + } + ASSERT_EQ(8u, I); +} + +} // end anonymous namespace diff --git a/gnu/llvm/unittests/IR/UserTest.cpp b/gnu/llvm/unittests/IR/UserTest.cpp new file mode 100644 index 00000000000..8d488389448 --- /dev/null +++ b/gnu/llvm/unittests/IR/UserTest.cpp @@ -0,0 +1,120 @@ +//===- llvm/unittest/IR/UserTest.cpp - User unit tests --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/User.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(UserTest, ValueOpIteration) { + LLVMContext C; + + const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" + "entry:\n" + " switch i32 undef, label %s0\n" + " [ i32 1, label %s1\n" + " i32 2, label %s2\n" + " i32 3, label %s3\n" + " i32 4, label %s4\n" + " i32 5, label %s5\n" + " i32 6, label %s6\n" + " i32 7, label %s7\n" + " i32 8, label %s8\n" + " i32 9, label %s9 ]\n" + "\n" + "s0:\n" + " br label %exit\n" + "s1:\n" + " br label %exit\n" + "s2:\n" + " br label %exit\n" + "s3:\n" + " br label %exit\n" + "s4:\n" + " br label %exit\n" + "s5:\n" + " br label %exit\n" + "s6:\n" + " br label %exit\n" + "s7:\n" + " br label %exit\n" + "s8:\n" + " br label %exit\n" + "s9:\n" + " br label %exit\n" + "\n" + "exit:\n" + " %phi = phi i32 [ 0, %s0 ], [ 1, %s1 ],\n" + " [ 2, %s2 ], [ 3, %s3 ],\n" + " [ 4, %s4 ], [ 5, %s5 ],\n" + " [ 6, %s6 ], [ 7, %s7 ],\n" + " [ 8, %s8 ], [ 9, %s9 ]\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + BasicBlock &ExitBB = F->back(); + PHINode &P = cast<PHINode>(ExitBB.front()); + EXPECT_TRUE(P.value_op_begin() == P.value_op_begin()); + EXPECT_FALSE(P.value_op_begin() == P.value_op_end()); + EXPECT_TRUE(P.value_op_begin() != P.value_op_end()); + EXPECT_FALSE(P.value_op_end() != P.value_op_end()); + EXPECT_TRUE(P.value_op_begin() < P.value_op_end()); + EXPECT_FALSE(P.value_op_begin() < P.value_op_begin()); + EXPECT_TRUE(P.value_op_end() > P.value_op_begin()); + EXPECT_FALSE(P.value_op_begin() > P.value_op_begin()); + EXPECT_TRUE(P.value_op_begin() <= P.value_op_begin()); + EXPECT_FALSE(P.value_op_end() <= P.value_op_begin()); + EXPECT_TRUE(P.value_op_begin() >= P.value_op_begin()); + EXPECT_FALSE(P.value_op_begin() >= P.value_op_end()); + EXPECT_EQ(10, std::distance(P.value_op_begin(), P.value_op_end())); + + User::value_op_iterator I = P.value_op_begin(); + I += 3; + EXPECT_EQ(std::next(P.value_op_begin(), 3), I); + EXPECT_EQ(P.getOperand(3), *I); + I++; + EXPECT_EQ(P.getOperand(6), I[2]); + EXPECT_EQ(P.value_op_end(), (I - 2) + 8); +} + +TEST(UserTest, PersonalityUser) { + Module M("", getGlobalContext()); + FunctionType *RetVoidTy = + FunctionType::get(Type::getVoidTy(getGlobalContext()), false); + Function *PersonalityF = Function::Create( + RetVoidTy, GlobalValue::ExternalLinkage, "PersonalityFn", &M); + Function *TestF = + Function::Create(RetVoidTy, GlobalValue::ExternalLinkage, "TestFn", &M); + + // Set up the personality function + TestF->setPersonalityFn(PersonalityF); + auto PersonalityUsers = PersonalityF->user_begin(); + + // One user and that user is the Test function + EXPECT_EQ(*PersonalityUsers, TestF); + EXPECT_EQ(++PersonalityUsers, PersonalityF->user_end()); + + // Reset the personality function + TestF->setPersonalityFn(nullptr); + + // No users should remain + EXPECT_TRUE(TestF->user_empty()); +} + +} // end anonymous namespace diff --git a/gnu/llvm/unittests/IR/ValueHandleTest.cpp b/gnu/llvm/unittests/IR/ValueHandleTest.cpp new file mode 100644 index 00000000000..e1d598bbc58 --- /dev/null +++ b/gnu/llvm/unittests/IR/ValueHandleTest.cpp @@ -0,0 +1,413 @@ +//===- ValueHandleTest.cpp - ValueHandle tests ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ValueHandle.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" +#include <memory> + +using namespace llvm; + +namespace { + +class ValueHandle : public testing::Test { +protected: + Constant *ConstantV; + std::unique_ptr<BitCastInst> BitcastV; + + ValueHandle() : + ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))) { + } +}; + +class ConcreteCallbackVH final : public CallbackVH { +public: + ConcreteCallbackVH(Value *V) : CallbackVH(V) {} +}; + +TEST_F(ValueHandle, WeakVH_BasicOperation) { + WeakVH WVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), WVH); + WVH = ConstantV; + EXPECT_EQ(ConstantV, WVH); + + // Make sure I can call a method on the underlying Value. It + // doesn't matter which method. + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), WVH->getType()); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*WVH).getType()); +} + +TEST_F(ValueHandle, WeakVH_Comparisons) { + WeakVH BitcastWVH(BitcastV.get()); + WeakVH ConstantWVH(ConstantV); + + EXPECT_TRUE(BitcastWVH == BitcastWVH); + EXPECT_TRUE(BitcastV.get() == BitcastWVH); + EXPECT_TRUE(BitcastWVH == BitcastV.get()); + EXPECT_FALSE(BitcastWVH == ConstantWVH); + + EXPECT_TRUE(BitcastWVH != ConstantWVH); + EXPECT_TRUE(BitcastV.get() != ConstantWVH); + EXPECT_TRUE(BitcastWVH != ConstantV); + EXPECT_FALSE(BitcastWVH != BitcastWVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH); + EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH); + EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH); + EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH); + + EXPECT_EQ(BV < CV, BitcastWVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastWVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV); +} + +TEST_F(ValueHandle, WeakVH_FollowsRAUW) { + WeakVH WVH(BitcastV.get()); + WeakVH WVH_Copy(WVH); + WeakVH WVH_Recreated(BitcastV.get()); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(ConstantV, WVH); + EXPECT_EQ(ConstantV, WVH_Copy); + EXPECT_EQ(ConstantV, WVH_Recreated); +} + +TEST_F(ValueHandle, WeakVH_NullOnDeletion) { + WeakVH WVH(BitcastV.get()); + WeakVH WVH_Copy(WVH); + WeakVH WVH_Recreated(BitcastV.get()); + BitcastV.reset(); + Value *null_value = nullptr; + EXPECT_EQ(null_value, WVH); + EXPECT_EQ(null_value, WVH_Copy); + EXPECT_EQ(null_value, WVH_Recreated); +} + + +TEST_F(ValueHandle, AssertingVH_BasicOperation) { + AssertingVH<CastInst> AVH(BitcastV.get()); + CastInst *implicit_to_exact_type = AVH; + (void)implicit_to_exact_type; // Avoid warning. + + AssertingVH<Value> GenericAVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), GenericAVH); + GenericAVH = ConstantV; + EXPECT_EQ(ConstantV, GenericAVH); + + // Make sure I can call a method on the underlying CastInst. It + // doesn't matter which method. + EXPECT_FALSE(AVH->mayWriteToMemory()); + EXPECT_FALSE((*AVH).mayWriteToMemory()); +} + +TEST_F(ValueHandle, AssertingVH_Const) { + const CastInst *ConstBitcast = BitcastV.get(); + AssertingVH<const CastInst> AVH(ConstBitcast); + const CastInst *implicit_to_exact_type = AVH; + (void)implicit_to_exact_type; // Avoid warning. +} + +TEST_F(ValueHandle, AssertingVH_Comparisons) { + AssertingVH<Value> BitcastAVH(BitcastV.get()); + AssertingVH<Value> ConstantAVH(ConstantV); + + EXPECT_TRUE(BitcastAVH == BitcastAVH); + EXPECT_TRUE(BitcastV.get() == BitcastAVH); + EXPECT_TRUE(BitcastAVH == BitcastV.get()); + EXPECT_FALSE(BitcastAVH == ConstantAVH); + + EXPECT_TRUE(BitcastAVH != ConstantAVH); + EXPECT_TRUE(BitcastV.get() != ConstantAVH); + EXPECT_TRUE(BitcastAVH != ConstantV); + EXPECT_FALSE(BitcastAVH != BitcastAVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH); + EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH); + EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH); + EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH); + + EXPECT_EQ(BV < CV, BitcastAVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastAVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV); +} + +TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) { + AssertingVH<Value> AVH(BitcastV.get()); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(BitcastV.get(), AVH); +} + +#ifdef NDEBUG + +TEST_F(ValueHandle, AssertingVH_ReducesToPointer) { + EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH<CastInst>)); +} + +#else // !NDEBUG + +#ifdef GTEST_HAS_DEATH_TEST + +TEST_F(ValueHandle, AssertingVH_Asserts) { + AssertingVH<Value> AVH(BitcastV.get()); + EXPECT_DEATH({BitcastV.reset();}, + "An asserting value handle still pointed to this value!"); + AssertingVH<Value> Copy(AVH); + AVH = nullptr; + EXPECT_DEATH({BitcastV.reset();}, + "An asserting value handle still pointed to this value!"); + Copy = nullptr; + BitcastV.reset(); +} + +#endif // GTEST_HAS_DEATH_TEST + +#endif // NDEBUG + +TEST_F(ValueHandle, CallbackVH_BasicOperation) { + ConcreteCallbackVH CVH(BitcastV.get()); + EXPECT_EQ(BitcastV.get(), CVH); + CVH = ConstantV; + EXPECT_EQ(ConstantV, CVH); + + // Make sure I can call a method on the underlying Value. It + // doesn't matter which method. + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), CVH->getType()); + EXPECT_EQ(Type::getInt32Ty(getGlobalContext()), (*CVH).getType()); +} + +TEST_F(ValueHandle, CallbackVH_Comparisons) { + ConcreteCallbackVH BitcastCVH(BitcastV.get()); + ConcreteCallbackVH ConstantCVH(ConstantV); + + EXPECT_TRUE(BitcastCVH == BitcastCVH); + EXPECT_TRUE(BitcastV.get() == BitcastCVH); + EXPECT_TRUE(BitcastCVH == BitcastV.get()); + EXPECT_FALSE(BitcastCVH == ConstantCVH); + + EXPECT_TRUE(BitcastCVH != ConstantCVH); + EXPECT_TRUE(BitcastV.get() != ConstantCVH); + EXPECT_TRUE(BitcastCVH != ConstantV); + EXPECT_FALSE(BitcastCVH != BitcastCVH); + + // Cast to Value* so comparisons work. + Value *BV = BitcastV.get(); + Value *CV = ConstantV; + EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH); + EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH); + EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH); + EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH); + + EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH); + EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH); + EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH); + EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH); + + EXPECT_EQ(BV < CV, BitcastCVH < ConstantV); + EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV); + EXPECT_EQ(BV > CV, BitcastCVH > ConstantV); + EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV); +} + +TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) { + class RecordingVH final : public CallbackVH { + public: + int DeletedCalls; + int AURWCalls; + + RecordingVH() : DeletedCalls(0), AURWCalls(0) {} + RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {} + + private: + void deleted() override { + DeletedCalls++; + CallbackVH::deleted(); + } + void allUsesReplacedWith(Value *) override { AURWCalls++; } + }; + + RecordingVH RVH; + RVH = BitcastV.get(); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(0, RVH.AURWCalls); + BitcastV.reset(); + EXPECT_EQ(1, RVH.DeletedCalls); + EXPECT_EQ(0, RVH.AURWCalls); +} + +TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) { + class RecordingVH final : public CallbackVH { + public: + int DeletedCalls; + Value *AURWArgument; + + RecordingVH() : DeletedCalls(0), AURWArgument(nullptr) {} + RecordingVH(Value *V) + : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr) {} + + private: + void deleted() override { + DeletedCalls++; + CallbackVH::deleted(); + } + void allUsesReplacedWith(Value *new_value) override { + EXPECT_EQ(nullptr, AURWArgument); + AURWArgument = new_value; + } + }; + + RecordingVH RVH; + RVH = BitcastV.get(); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(nullptr, RVH.AURWArgument); + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(0, RVH.DeletedCalls); + EXPECT_EQ(ConstantV, RVH.AURWArgument); +} + +TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) { + class RecoveringVH final : public CallbackVH { + public: + int DeletedCalls; + Value *AURWArgument; + LLVMContext *Context; + + RecoveringVH() : DeletedCalls(0), AURWArgument(nullptr), + Context(&getGlobalContext()) {} + RecoveringVH(Value *V) + : CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr), + Context(&getGlobalContext()) {} + + private: + void deleted() override { + getValPtr()->replaceAllUsesWith(Constant::getNullValue(Type::getInt32Ty(getGlobalContext()))); + setValPtr(nullptr); + } + void allUsesReplacedWith(Value *new_value) override { + ASSERT_TRUE(nullptr != getValPtr()); + EXPECT_EQ(1U, getValPtr()->getNumUses()); + EXPECT_EQ(nullptr, AURWArgument); + AURWArgument = new_value; + } + }; + + // Normally, if a value has uses, deleting it will crash. However, we can use + // a CallbackVH to remove the uses before the check for no uses. + RecoveringVH RVH; + RVH = BitcastV.get(); + std::unique_ptr<BinaryOperator> BitcastUser( + BinaryOperator::CreateAdd(RVH, + Constant::getNullValue(Type::getInt32Ty(getGlobalContext())))); + EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0)); + BitcastV.reset(); // Would crash without the ValueHandler. + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), RVH.AURWArgument); + EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(getGlobalContext())), + BitcastUser->getOperand(0)); +} + +TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) { + // When a CallbackVH modifies other ValueHandles in its callbacks, + // that shouldn't interfere with non-modified ValueHandles receiving + // their appropriate callbacks. + // + // We create the active CallbackVH in the middle of a palindromic + // arrangement of other VHs so that the bad behavior would be + // triggered in whichever order callbacks run. + + class DestroyingVH final : public CallbackVH { + public: + std::unique_ptr<WeakVH> ToClear[2]; + DestroyingVH(Value *V) { + ToClear[0].reset(new WeakVH(V)); + setValPtr(V); + ToClear[1].reset(new WeakVH(V)); + } + void deleted() override { + ToClear[0].reset(); + ToClear[1].reset(); + CallbackVH::deleted(); + } + void allUsesReplacedWith(Value *) override { + ToClear[0].reset(); + ToClear[1].reset(); + } + }; + + { + WeakVH ShouldBeVisited1(BitcastV.get()); + DestroyingVH C(BitcastV.get()); + WeakVH ShouldBeVisited2(BitcastV.get()); + + BitcastV->replaceAllUsesWith(ConstantV); + EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited1)); + EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited2)); + } + + { + WeakVH ShouldBeVisited1(BitcastV.get()); + DestroyingVH C(BitcastV.get()); + WeakVH ShouldBeVisited2(BitcastV.get()); + + BitcastV.reset(); + EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited1)); + EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited2)); + } +} + +TEST_F(ValueHandle, AssertingVHCheckedLast) { + // If a CallbackVH exists to clear out a group of AssertingVHs on + // Value deletion, the CallbackVH should get a chance to do so + // before the AssertingVHs assert. + + class ClearingVH final : public CallbackVH { + public: + AssertingVH<Value> *ToClear[2]; + ClearingVH(Value *V, + AssertingVH<Value> &A0, AssertingVH<Value> &A1) + : CallbackVH(V) { + ToClear[0] = &A0; + ToClear[1] = &A1; + } + + void deleted() override { + *ToClear[0] = nullptr; + *ToClear[1] = nullptr; + CallbackVH::deleted(); + } + }; + + AssertingVH<Value> A1, A2; + A1 = BitcastV.get(); + ClearingVH C(BitcastV.get(), A1, A2); + A2 = BitcastV.get(); + // C.deleted() should run first, clearing the two AssertingVHs, + // which should prevent them from asserting. + BitcastV.reset(); +} + +} diff --git a/gnu/llvm/unittests/IR/ValueMapTest.cpp b/gnu/llvm/unittests/IR/ValueMapTest.cpp new file mode 100644 index 00000000000..1431a8d87de --- /dev/null +++ b/gnu/llvm/unittests/IR/ValueMapTest.cpp @@ -0,0 +1,295 @@ +//===- llvm/unittest/ADT/ValueMapTest.cpp - ValueMap unit tests -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/ValueMap.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +// Test fixture +template<typename T> +class ValueMapTest : public testing::Test { +protected: + Constant *ConstantV; + std::unique_ptr<BitCastInst> BitcastV; + std::unique_ptr<BinaryOperator> AddV; + + ValueMapTest() : + ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)), + BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))), + AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) { + } +}; + +// Run everything on Value*, a subtype to make sure that casting works as +// expected, and a const subtype to make sure we cast const correctly. +typedef ::testing::Types<Value, Instruction, const Instruction> KeyTypes; +TYPED_TEST_CASE(ValueMapTest, KeyTypes); + +TYPED_TEST(ValueMapTest, Null) { + ValueMap<TypeParam*, int> VM1; + VM1[nullptr] = 7; + EXPECT_EQ(7, VM1.lookup(nullptr)); +} + +TYPED_TEST(ValueMapTest, FollowsValue) { + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 7; + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0u, VM.count(this->AddV.get())); + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(7, VM.lookup(this->AddV.get())); + EXPECT_EQ(0u, VM.count(this->BitcastV.get())); + this->AddV.reset(); + EXPECT_EQ(0u, VM.count(this->AddV.get())); + EXPECT_EQ(0u, VM.count(this->BitcastV.get())); + EXPECT_EQ(0U, VM.size()); +} + +TYPED_TEST(ValueMapTest, OperationsWork) { + ValueMap<TypeParam*, int> VM; + ValueMap<TypeParam*, int> VM2(16); (void)VM2; + typename ValueMapConfig<TypeParam*>::ExtraData Data; + ValueMap<TypeParam*, int> VM3(Data, 16); (void)VM3; + EXPECT_TRUE(VM.empty()); + + VM[this->BitcastV.get()] = 7; + + // Find: + typename ValueMap<TypeParam*, int>::iterator I = + VM.find(this->BitcastV.get()); + ASSERT_TRUE(I != VM.end()); + EXPECT_EQ(this->BitcastV.get(), I->first); + EXPECT_EQ(7, I->second); + EXPECT_TRUE(VM.find(this->AddV.get()) == VM.end()); + + // Const find: + const ValueMap<TypeParam*, int> &CVM = VM; + typename ValueMap<TypeParam*, int>::const_iterator CI = + CVM.find(this->BitcastV.get()); + ASSERT_TRUE(CI != CVM.end()); + EXPECT_EQ(this->BitcastV.get(), CI->first); + EXPECT_EQ(7, CI->second); + EXPECT_TRUE(CVM.find(this->AddV.get()) == CVM.end()); + + // Insert: + std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult1 = + VM.insert(std::make_pair(this->AddV.get(), 3)); + EXPECT_EQ(this->AddV.get(), InsertResult1.first->first); + EXPECT_EQ(3, InsertResult1.first->second); + EXPECT_TRUE(InsertResult1.second); + EXPECT_EQ(1u, VM.count(this->AddV.get())); + std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult2 = + VM.insert(std::make_pair(this->AddV.get(), 5)); + EXPECT_EQ(this->AddV.get(), InsertResult2.first->first); + EXPECT_EQ(3, InsertResult2.first->second); + EXPECT_FALSE(InsertResult2.second); + + // Erase: + VM.erase(InsertResult2.first); + EXPECT_EQ(0U, VM.count(this->AddV.get())); + EXPECT_EQ(1U, VM.count(this->BitcastV.get())); + VM.erase(this->BitcastV.get()); + EXPECT_EQ(0U, VM.count(this->BitcastV.get())); + EXPECT_EQ(0U, VM.size()); + + // Range insert: + SmallVector<std::pair<Instruction*, int>, 2> Elems; + Elems.push_back(std::make_pair(this->AddV.get(), 1)); + Elems.push_back(std::make_pair(this->BitcastV.get(), 2)); + VM.insert(Elems.begin(), Elems.end()); + EXPECT_EQ(1, VM.lookup(this->AddV.get())); + EXPECT_EQ(2, VM.lookup(this->BitcastV.get())); +} + +template<typename ExpectedType, typename VarType> +void CompileAssertHasType(VarType) { + static_assert(std::is_same<ExpectedType, VarType>::value, + "Not the same type"); +} + +TYPED_TEST(ValueMapTest, Iteration) { + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 2; + VM[this->AddV.get()] = 3; + size_t size = 0; + for (typename ValueMap<TypeParam*, int>::iterator I = VM.begin(), E = VM.end(); + I != E; ++I) { + ++size; + std::pair<TypeParam*, int> value = *I; (void)value; + CompileAssertHasType<TypeParam*>(I->first); + if (I->second == 2) { + EXPECT_EQ(this->BitcastV.get(), I->first); + I->second = 5; + } else if (I->second == 3) { + EXPECT_EQ(this->AddV.get(), I->first); + I->second = 6; + } else { + ADD_FAILURE() << "Iterated through an extra value."; + } + } + EXPECT_EQ(2U, size); + EXPECT_EQ(5, VM[this->BitcastV.get()]); + EXPECT_EQ(6, VM[this->AddV.get()]); + + size = 0; + // Cast to const ValueMap to avoid a bug in DenseMap's iterators. + const ValueMap<TypeParam*, int>& CVM = VM; + for (typename ValueMap<TypeParam*, int>::const_iterator I = CVM.begin(), + E = CVM.end(); I != E; ++I) { + ++size; + std::pair<TypeParam*, int> value = *I; (void)value; + CompileAssertHasType<TypeParam*>(I->first); + if (I->second == 5) { + EXPECT_EQ(this->BitcastV.get(), I->first); + } else if (I->second == 6) { + EXPECT_EQ(this->AddV.get(), I->first); + } else { + ADD_FAILURE() << "Iterated through an extra value."; + } + } + EXPECT_EQ(2U, size); +} + +TYPED_TEST(ValueMapTest, DefaultCollisionBehavior) { + // By default, we overwrite the old value with the replaced value. + ValueMap<TypeParam*, int> VM; + VM[this->BitcastV.get()] = 7; + VM[this->AddV.get()] = 9; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(0u, VM.count(this->BitcastV.get())); + EXPECT_EQ(9, VM.lookup(this->AddV.get())); +} + +TYPED_TEST(ValueMapTest, ConfiguredCollisionBehavior) { + // TODO: Implement this when someone needs it. +} + +template<typename KeyT, typename MutexT> +struct LockMutex : ValueMapConfig<KeyT, MutexT> { + struct ExtraData { + MutexT *M; + bool *CalledRAUW; + bool *CalledDeleted; + }; + static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) { + *Data.CalledRAUW = true; + EXPECT_FALSE(Data.M->try_lock()) << "Mutex should already be locked."; + } + static void onDelete(const ExtraData &Data, KeyT Old) { + *Data.CalledDeleted = true; + EXPECT_FALSE(Data.M->try_lock()) << "Mutex should already be locked."; + } + static MutexT *getMutex(const ExtraData &Data) { return Data.M; } +}; +// FIXME: These tests started failing on Windows. +#if LLVM_ENABLE_THREADS && !defined(LLVM_ON_WIN32) +TYPED_TEST(ValueMapTest, LocksMutex) { + sys::Mutex M(false); // Not recursive. + bool CalledRAUW = false, CalledDeleted = false; + typedef LockMutex<TypeParam*, sys::Mutex> ConfigType; + typename ConfigType::ExtraData Data = {&M, &CalledRAUW, &CalledDeleted}; + ValueMap<TypeParam*, int, ConfigType> VM(Data); + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + this->AddV.reset(); + EXPECT_TRUE(CalledRAUW); + EXPECT_TRUE(CalledDeleted); +} +#endif + +template<typename KeyT> +struct NoFollow : ValueMapConfig<KeyT> { + enum { FollowRAUW = false }; +}; + +TYPED_TEST(ValueMapTest, NoFollowRAUW) { + ValueMap<TypeParam*, int, NoFollow<TypeParam*> > VM; + VM[this->BitcastV.get()] = 7; + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0u, VM.count(this->AddV.get())); + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + this->AddV.reset(); + EXPECT_EQ(7, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + this->BitcastV.reset(); + EXPECT_EQ(0, VM.lookup(this->BitcastV.get())); + EXPECT_EQ(0, VM.lookup(this->AddV.get())); + EXPECT_EQ(0U, VM.size()); +} + +template<typename KeyT> +struct CountOps : ValueMapConfig<KeyT> { + struct ExtraData { + int *Deletions; + int *RAUWs; + }; + + static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) { + ++*Data.RAUWs; + } + static void onDelete(const ExtraData &Data, KeyT Old) { + ++*Data.Deletions; + } +}; + +TYPED_TEST(ValueMapTest, CallsConfig) { + int Deletions = 0, RAUWs = 0; + typename CountOps<TypeParam*>::ExtraData Data = {&Deletions, &RAUWs}; + ValueMap<TypeParam*, int, CountOps<TypeParam*> > VM(Data); + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(0, Deletions); + EXPECT_EQ(1, RAUWs); + this->AddV.reset(); + EXPECT_EQ(1, Deletions); + EXPECT_EQ(1, RAUWs); + this->BitcastV.reset(); + EXPECT_EQ(1, Deletions); + EXPECT_EQ(1, RAUWs); +} + +template<typename KeyT> +struct ModifyingConfig : ValueMapConfig<KeyT> { + // We'll put a pointer here back to the ValueMap this key is in, so + // that we can modify it (and clobber *this) before the ValueMap + // tries to do the same modification. In previous versions of + // ValueMap, that exploded. + typedef ValueMap<KeyT, int, ModifyingConfig<KeyT> > **ExtraData; + + static void onRAUW(ExtraData Map, KeyT Old, KeyT New) { + (*Map)->erase(Old); + } + static void onDelete(ExtraData Map, KeyT Old) { + (*Map)->erase(Old); + } +}; +TYPED_TEST(ValueMapTest, SurvivesModificationByConfig) { + ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > *MapAddress; + ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > VM(&MapAddress); + MapAddress = &VM; + // Now the ModifyingConfig can modify the Map inside a callback. + VM[this->BitcastV.get()] = 7; + this->BitcastV->replaceAllUsesWith(this->AddV.get()); + EXPECT_EQ(0u, VM.count(this->BitcastV.get())); + EXPECT_EQ(0u, VM.count(this->AddV.get())); + VM[this->AddV.get()] = 7; + this->AddV.reset(); + EXPECT_EQ(0u, VM.count(this->AddV.get())); +} + +} diff --git a/gnu/llvm/unittests/IR/ValueTest.cpp b/gnu/llvm/unittests/IR/ValueTest.cpp new file mode 100644 index 00000000000..9cf1306dae6 --- /dev/null +++ b/gnu/llvm/unittests/IR/ValueTest.cpp @@ -0,0 +1,238 @@ +//===- llvm/unittest/IR/ValueTest.cpp - Value unit tests ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ModuleSlotTracker.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/SourceMgr.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { + +TEST(ValueTest, UsedInBasicBlock) { + LLVMContext C; + + const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" + "bb0:\n" + " %y1 = add i32 %y, 1\n" + " %y2 = add i32 %y, 1\n" + " %y3 = add i32 %y, 1\n" + " %y4 = add i32 %y, 1\n" + " %y5 = add i32 %y, 1\n" + " %y6 = add i32 %y, 1\n" + " %y7 = add i32 %y, 1\n" + " %y8 = add i32 %x, 1\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + + EXPECT_FALSE(F->isUsedInBasicBlock(&F->front())); + EXPECT_TRUE((++F->arg_begin())->isUsedInBasicBlock(&F->front())); + EXPECT_TRUE(F->arg_begin()->isUsedInBasicBlock(&F->front())); +} + +TEST(GlobalTest, CreateAddressSpace) { + LLVMContext &Ctx = getGlobalContext(); + std::unique_ptr<Module> M(new Module("TestModule", Ctx)); + Type *Int8Ty = Type::getInt8Ty(Ctx); + Type *Int32Ty = Type::getInt32Ty(Ctx); + + GlobalVariable *Dummy0 + = new GlobalVariable(*M, + Int32Ty, + true, + GlobalValue::ExternalLinkage, + Constant::getAllOnesValue(Int32Ty), + "dummy", + nullptr, + GlobalVariable::NotThreadLocal, + 1); + + EXPECT_TRUE(Value::MaximumAlignment == 536870912U); + Dummy0->setAlignment(536870912U); + EXPECT_EQ(Dummy0->getAlignment(), 536870912U); + + // Make sure the address space isn't dropped when returning this. + Constant *Dummy1 = M->getOrInsertGlobal("dummy", Int32Ty); + EXPECT_EQ(Dummy0, Dummy1); + EXPECT_EQ(1u, Dummy1->getType()->getPointerAddressSpace()); + + + // This one requires a bitcast, but the address space must also stay the same. + GlobalVariable *DummyCast0 + = new GlobalVariable(*M, + Int32Ty, + true, + GlobalValue::ExternalLinkage, + Constant::getAllOnesValue(Int32Ty), + "dummy_cast", + nullptr, + GlobalVariable::NotThreadLocal, + 1); + + // Make sure the address space isn't dropped when returning this. + Constant *DummyCast1 = M->getOrInsertGlobal("dummy_cast", Int8Ty); + EXPECT_EQ(1u, DummyCast1->getType()->getPointerAddressSpace()); + EXPECT_NE(DummyCast0, DummyCast1) << *DummyCast1; +} + +#ifdef GTEST_HAS_DEATH_TEST +#ifndef NDEBUG +TEST(GlobalTest, AlignDeath) { + LLVMContext &Ctx = getGlobalContext(); + std::unique_ptr<Module> M(new Module("TestModule", Ctx)); + Type *Int32Ty = Type::getInt32Ty(Ctx); + GlobalVariable *Var = + new GlobalVariable(*M, Int32Ty, true, GlobalValue::ExternalLinkage, + Constant::getAllOnesValue(Int32Ty), "var", nullptr, + GlobalVariable::NotThreadLocal, 1); + + EXPECT_DEATH(Var->setAlignment(536870913U), "Alignment is not a power of 2"); + EXPECT_DEATH(Var->setAlignment(1073741824U), + "Alignment is greater than MaximumAlignment"); +} +#endif +#endif + +TEST(ValueTest, printSlots) { + // Check that Value::print() and Value::printAsOperand() work with and + // without a slot tracker. + LLVMContext C; + + const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" + "entry:\n" + " %0 = add i32 %y, 1\n" + " %1 = add i32 %y, 1\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + ASSERT_TRUE(F); + ASSERT_FALSE(F->empty()); + BasicBlock &BB = F->getEntryBlock(); + ASSERT_EQ(3u, BB.size()); + + Instruction *I0 = &*BB.begin(); + ASSERT_TRUE(I0); + Instruction *I1 = &*++BB.begin(); + ASSERT_TRUE(I1); + + ModuleSlotTracker MST(M.get()); + +#define CHECK_PRINT(INST, STR) \ + do { \ + { \ + std::string S; \ + raw_string_ostream OS(S); \ + INST->print(OS); \ + EXPECT_EQ(STR, OS.str()); \ + } \ + { \ + std::string S; \ + raw_string_ostream OS(S); \ + INST->print(OS, MST); \ + EXPECT_EQ(STR, OS.str()); \ + } \ + } while (false) + CHECK_PRINT(I0, " %0 = add i32 %y, 1"); + CHECK_PRINT(I1, " %1 = add i32 %y, 1"); +#undef CHECK_PRINT + +#define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \ + do { \ + { \ + std::string S; \ + raw_string_ostream OS(S); \ + INST->printAsOperand(OS, TYPE); \ + EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \ + } \ + { \ + std::string S; \ + raw_string_ostream OS(S); \ + INST->printAsOperand(OS, TYPE, MST); \ + EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \ + } \ + } while (false) + CHECK_PRINT_AS_OPERAND(I0, false, "%0"); + CHECK_PRINT_AS_OPERAND(I1, false, "%1"); + CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0"); + CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1"); +#undef CHECK_PRINT_AS_OPERAND +} + +TEST(ValueTest, getLocalSlots) { + // Verify that the getLocalSlot method returns the correct slot numbers. + LLVMContext C; + const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" + "entry:\n" + " %0 = add i32 %y, 1\n" + " %1 = add i32 %y, 1\n" + " br label %2\n" + "\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + ASSERT_TRUE(F); + ASSERT_FALSE(F->empty()); + BasicBlock &EntryBB = F->getEntryBlock(); + ASSERT_EQ(3u, EntryBB.size()); + BasicBlock *BB2 = &*++F->begin(); + ASSERT_TRUE(BB2); + + Instruction *I0 = &*EntryBB.begin(); + ASSERT_TRUE(I0); + Instruction *I1 = &*++EntryBB.begin(); + ASSERT_TRUE(I1); + + ModuleSlotTracker MST(M.get()); + MST.incorporateFunction(*F); + EXPECT_EQ(MST.getLocalSlot(I0), 0); + EXPECT_EQ(MST.getLocalSlot(I1), 1); + EXPECT_EQ(MST.getLocalSlot(&EntryBB), -1); + EXPECT_EQ(MST.getLocalSlot(BB2), 2); +} + +#if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG) +TEST(ValueTest, getLocalSlotDeath) { + LLVMContext C; + const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n" + "entry:\n" + " %0 = add i32 %y, 1\n" + " %1 = add i32 %y, 1\n" + " br label %2\n" + "\n" + " ret void\n" + "}\n"; + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C); + + Function *F = M->getFunction("f"); + ASSERT_TRUE(F); + ASSERT_FALSE(F->empty()); + BasicBlock *BB2 = &*++F->begin(); + ASSERT_TRUE(BB2); + + ModuleSlotTracker MST(M.get()); + EXPECT_DEATH(MST.getLocalSlot(BB2), "No function incorporated"); +} +#endif + +} // end anonymous namespace diff --git a/gnu/llvm/unittests/IR/VerifierTest.cpp b/gnu/llvm/unittests/IR/VerifierTest.cpp new file mode 100644 index 00000000000..4e94b4375f9 --- /dev/null +++ b/gnu/llvm/unittests/IR/VerifierTest.cpp @@ -0,0 +1,111 @@ +//===- llvm/unittest/IR/VerifierTest.cpp - Verifier unit tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/Verifier.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "gtest/gtest.h" + +namespace llvm { +namespace { + +TEST(VerifierTest, Branch_i1) { + LLVMContext &C = getGlobalContext(); + Module M("M", C); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); + Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy)); + BasicBlock *Entry = BasicBlock::Create(C, "entry", F); + BasicBlock *Exit = BasicBlock::Create(C, "exit", F); + ReturnInst::Create(C, Exit); + + // To avoid triggering an assertion in BranchInst::Create, we first create + // a branch with an 'i1' condition ... + + Constant *False = ConstantInt::getFalse(C); + BranchInst *BI = BranchInst::Create(Exit, Exit, False, Entry); + + // ... then use setOperand to redirect it to a value of different type. + + Constant *Zero32 = ConstantInt::get(IntegerType::get(C, 32), 0); + BI->setOperand(0, Zero32); + + EXPECT_TRUE(verifyFunction(*F)); +} + +TEST(VerifierTest, InvalidRetAttribute) { + LLVMContext &C = getGlobalContext(); + Module M("M", C); + FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false); + Function *F = cast<Function>(M.getOrInsertFunction("foo", FTy)); + AttributeSet AS = F->getAttributes(); + F->setAttributes(AS.addAttribute(C, AttributeSet::ReturnIndex, + Attribute::UWTable)); + + std::string Error; + raw_string_ostream ErrorOS(Error); + EXPECT_TRUE(verifyModule(M, &ErrorOS)); + EXPECT_TRUE(StringRef(ErrorOS.str()).startswith( + "Attribute 'uwtable' only applies to functions!")); +} + +TEST(VerifierTest, CrossModuleRef) { + LLVMContext &C = getGlobalContext(); + Module M1("M1", C); + Module M2("M2", C); + Module M3("M2", C); + FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false); + Function *F1 = cast<Function>(M1.getOrInsertFunction("foo1", FTy)); + Function *F2 = cast<Function>(M2.getOrInsertFunction("foo2", FTy)); + Function *F3 = cast<Function>(M3.getOrInsertFunction("foo3", FTy)); + + BasicBlock *Entry1 = BasicBlock::Create(C, "entry", F1); + BasicBlock *Entry3 = BasicBlock::Create(C, "entry", F3); + + // BAD: Referencing function in another module + CallInst::Create(F2,"call",Entry1); + + // BAD: Referencing personality routine in another module + F3->setPersonalityFn(F2); + + // Fill in the body + Constant *ConstZero = ConstantInt::get(Type::getInt32Ty(C), 0); + ReturnInst::Create(C, ConstZero, Entry1); + ReturnInst::Create(C, ConstZero, Entry3); + + std::string Error; + raw_string_ostream ErrorOS(Error); + EXPECT_FALSE(verifyModule(M2, &ErrorOS)); + EXPECT_TRUE(verifyModule(M1, &ErrorOS)); + EXPECT_TRUE(StringRef(ErrorOS.str()).equals( + "Referencing function in another module!\n" + " %call = call i32 @foo2()\n" + "; ModuleID = 'M1'\n" + "i32 ()* @foo2\n" + "; ModuleID = 'M2'\n")); + + Error.clear(); + EXPECT_TRUE(verifyModule(M3, &ErrorOS)); + EXPECT_TRUE(StringRef(ErrorOS.str()).startswith( + "Referencing personality function in another module!")); + + // Erase bad methods to avoid triggering an assertion failure on destruction + F1->eraseFromParent(); + F3->eraseFromParent(); +} + + + +} +} diff --git a/gnu/llvm/unittests/IR/WaymarkTest.cpp b/gnu/llvm/unittests/IR/WaymarkTest.cpp new file mode 100644 index 00000000000..a8924efed3f --- /dev/null +++ b/gnu/llvm/unittests/IR/WaymarkTest.cpp @@ -0,0 +1,58 @@ +//===- llvm/unittest/IR/WaymarkTest.cpp - getUser() unit tests ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// we perform white-box tests +// +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "gtest/gtest.h" +#include <algorithm> + +namespace llvm { +namespace { + +Constant *char2constant(char c) { + return ConstantInt::get(Type::getInt8Ty(getGlobalContext()), c); +} + + +TEST(WaymarkTest, NativeArray) { + static uint8_t tail[22] = "s02s33s30y2y0s1x0syxS"; + Value * values[22]; + std::transform(tail, tail + 22, values, char2constant); + FunctionType *FT = FunctionType::get(Type::getVoidTy(getGlobalContext()), true); + std::unique_ptr<Function> F( + Function::Create(FT, GlobalValue::ExternalLinkage)); + const CallInst *A = CallInst::Create(F.get(), makeArrayRef(values)); + ASSERT_NE(A, (const CallInst*)nullptr); + ASSERT_EQ(1U + 22, A->getNumOperands()); + const Use *U = &A->getOperandUse(0); + const Use *Ue = &A->getOperandUse(22); + for (; U != Ue; ++U) + { + EXPECT_EQ(A, U->getUser()); + } + delete A; +} + +TEST(WaymarkTest, TwoBit) { + Use* many = (Use*)calloc(sizeof(Use), 8212 + 1); + ASSERT_TRUE(many); + Use::initTags(many, many + 8212); + for (Use *U = many, *Ue = many + 8212 - 1; U != Ue; ++U) + { + EXPECT_EQ(reinterpret_cast<User *>(Ue + 1), U->getUser()); + } + free(many); +} + +} // end anonymous namespace +} // end namespace llvm |