diff options
Diffstat (limited to 'llvm/unittests')
20 files changed, 1063 insertions, 77 deletions
diff --git a/llvm/unittests/ADT/BitFieldsTest.cpp b/llvm/unittests/ADT/BitFieldsTest.cpp index 3062d5d..ae541fe 100644 --- a/llvm/unittests/ADT/BitFieldsTest.cpp +++ b/llvm/unittests/ADT/BitFieldsTest.cpp @@ -247,8 +247,8 @@ TEST(BitfieldsTest, ValueTooBigBounded) { Bitfield::set<A>(Storage, 0); Bitfield::set<A>(Storage, -1); Bitfield::set<A>(Storage, -2); - EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is too big"); - EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -3), "value is too small"); + EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, 2), "value is out of range"); + EXPECT_DEBUG_DEATH(Bitfield::set<A>(Storage, -3), "value is out of range"); } #endif diff --git a/llvm/unittests/ADT/StringExtrasTest.cpp b/llvm/unittests/ADT/StringExtrasTest.cpp index fbaed38..af88f889 100644 --- a/llvm/unittests/ADT/StringExtrasTest.cpp +++ b/llvm/unittests/ADT/StringExtrasTest.cpp @@ -290,6 +290,12 @@ TEST(StringExtrasTest, ListSeparator) { EXPECT_EQ(S, ""); S = LS2; EXPECT_EQ(S, " "); + + ListSeparator LS3(",", "{"); + S = LS3; + EXPECT_EQ(S, "{"); + S = LS3; + EXPECT_EQ(S, ","); } TEST(StringExtrasTest, toStringAPInt) { diff --git a/llvm/unittests/ADT/StringSwitchTest.cpp b/llvm/unittests/ADT/StringSwitchTest.cpp index bcb1521..0fbf371 100644 --- a/llvm/unittests/ADT/StringSwitchTest.cpp +++ b/llvm/unittests/ADT/StringSwitchTest.cpp @@ -153,13 +153,14 @@ TEST(StringSwitchTest, EndsWithLower) { } TEST(StringSwitchTest, Cases) { - enum class OSType { Windows, Linux, Unknown }; + enum class OSType { Windows, Linux, MacOS, Unknown }; auto Translate = [](StringRef S) { return llvm::StringSwitch<OSType>(S) .Cases(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt", OSType::Windows) .Cases("linux", "unix", "*nix", "posix", OSType::Linux) + .Cases({"macos", "osx"}, OSType::MacOS) .Default(OSType::Unknown); }; @@ -172,21 +173,26 @@ TEST(StringSwitchTest, Cases) { EXPECT_EQ(OSType::Linux, Translate("*nix")); EXPECT_EQ(OSType::Linux, Translate("posix")); + EXPECT_EQ(OSType::MacOS, Translate("macos")); + EXPECT_EQ(OSType::MacOS, Translate("osx")); + // Note that the whole null-terminator embedded string is required for the // case to match. EXPECT_EQ(OSType::Unknown, Translate("wind")); EXPECT_EQ(OSType::Unknown, Translate("Windows")); + EXPECT_EQ(OSType::Unknown, Translate("MacOS")); EXPECT_EQ(OSType::Unknown, Translate("")); } TEST(StringSwitchTest, CasesLower) { - enum class OSType { Windows, Linux, Unknown }; + enum class OSType { Windows, Linux, MacOS, Unknown }; auto Translate = [](StringRef S) { return llvm::StringSwitch<OSType>(S) .CasesLower(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt", OSType::Windows) .CasesLower("linux", "unix", "*nix", "posix", OSType::Linux) + .CasesLower({"macos", "osx"}, OSType::MacOS) .Default(OSType::Unknown); }; @@ -202,6 +208,9 @@ TEST(StringSwitchTest, CasesLower) { EXPECT_EQ(OSType::Windows, Translate(llvm::StringRef("wind\0ws", 7))); EXPECT_EQ(OSType::Linux, Translate("linux")); + EXPECT_EQ(OSType::MacOS, Translate("macOS")); + EXPECT_EQ(OSType::MacOS, Translate("OSX")); + EXPECT_EQ(OSType::Unknown, Translate("wind")); EXPECT_EQ(OSType::Unknown, Translate("")); } diff --git a/llvm/unittests/ADT/TypeTraitsTest.cpp b/llvm/unittests/ADT/TypeTraitsTest.cpp index a56aa7e..f9b8d6d 100644 --- a/llvm/unittests/ADT/TypeTraitsTest.cpp +++ b/llvm/unittests/ADT/TypeTraitsTest.cpp @@ -40,9 +40,7 @@ struct Foo { struct CheckMethodPointer : CheckFunctionTraits<decltype(&Foo::func)> {}; /// Test lambda references. -LLVM_ATTRIBUTE_UNUSED auto lambdaFunc = [](const int &v) -> bool { - return true; -}; +[[maybe_unused]] auto lambdaFunc = [](const int &v) -> bool { return true; }; struct CheckLambda : CheckFunctionTraits<decltype(lambdaFunc)> {}; } // end anonymous namespace diff --git a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp index 1a68823..5d7eded 100644 --- a/llvm/unittests/Analysis/ScalarEvolutionTest.cpp +++ b/llvm/unittests/Analysis/ScalarEvolutionTest.cpp @@ -11,6 +11,7 @@ #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/ScalarEvolutionNormalization.h" +#include "llvm/Analysis/ScalarEvolutionPatternMatch.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Constants.h" @@ -26,6 +27,8 @@ namespace llvm { +using namespace SCEVPatternMatch; + // We use this fixture to ensure that we clean up ScalarEvolution before // deleting the PassManager. class ScalarEvolutionsTest : public testing::Test { @@ -64,11 +67,6 @@ static std::optional<APInt> computeConstantDifference(ScalarEvolution &SE, return SE.computeConstantDifference(LHS, RHS); } - static bool matchURem(ScalarEvolution &SE, const SCEV *Expr, const SCEV *&LHS, - const SCEV *&RHS) { - return SE.matchURem(Expr, LHS, RHS); - } - static bool isImpliedCond( ScalarEvolution &SE, ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, ICmpInst::Predicate FoundPred, const SCEV *FoundLHS, @@ -1524,7 +1522,7 @@ TEST_F(ScalarEvolutionsTest, MatchURem) { auto *URemI = getInstructionByName(F, N); auto *S = SE.getSCEV(URemI); const SCEV *LHS, *RHS; - EXPECT_TRUE(matchURem(SE, S, LHS, RHS)); + EXPECT_TRUE(match(S, m_scev_URem(m_SCEV(LHS), m_SCEV(RHS), SE))); EXPECT_EQ(LHS, SE.getSCEV(URemI->getOperand(0))); EXPECT_EQ(RHS, SE.getSCEV(URemI->getOperand(1))); EXPECT_EQ(LHS->getType(), S->getType()); @@ -1537,7 +1535,7 @@ TEST_F(ScalarEvolutionsTest, MatchURem) { auto *URem1 = getInstructionByName(F, "rem4"); auto *S = SE.getSCEV(Ext); const SCEV *LHS, *RHS; - EXPECT_TRUE(matchURem(SE, S, LHS, RHS)); + EXPECT_TRUE(match(S, m_scev_URem(m_SCEV(LHS), m_SCEV(RHS), SE))); EXPECT_NE(LHS, SE.getSCEV(URem1->getOperand(0))); // RHS and URem1->getOperand(1) have different widths, so compare the // integer values. diff --git a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp index 33f53de..d560073 100644 --- a/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp +++ b/llvm/unittests/DebugInfo/GSYM/GSYMTest.cpp @@ -4899,3 +4899,189 @@ TEST(GSYMTest, TestLookupsOfOverlappingAndUnequalRanges) { for (const auto &Line : ExpectedDumpLines) EXPECT_TRUE(DumpStr.find(Line) != std::string::npos); } + +TEST(GSYMTest, TestUnableToLocateDWO) { + // Test that llvm-gsymutil will not produce "uanble to locate DWO file" for + // Apple binaries. Apple uses DW_AT_GNU_dwo_id for non split DWARF purposes + // and this makes llvm-gsymutil create warnings and errors. + // + // 0x0000000b: DW_TAG_compile_unit + // DW_AT_name ("main.cpp") + // DW_AT_language (DW_LANG_C) + // DW_AT_GNU_dwo_id (0xfffffffe) + StringRef yamldata = R"( + debug_str: + - '' + - main.cpp + debug_abbrev: + - ID: 0 + Table: + - Code: 0x1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_language + Form: DW_FORM_udata + - Attribute: DW_AT_GNU_dwo_id + Form: DW_FORM_data4 + debug_info: + - Length: 0x11 + Version: 4 + AbbrevTableID: 0 + AbbrOffset: 0x0 + AddrSize: 8 + Entries: + - AbbrCode: 0x1 + Values: + - Value: 0x1 + - Value: 0x2 + - Value: 0xFFFFFFFE + )"; + auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); + ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); + std::unique_ptr<DWARFContext> DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + ASSERT_TRUE(DwarfContext.get() != nullptr); + std::string errors; + raw_string_ostream OS(errors); + OutputAggregator OSAgg(&OS); + GsymCreator GC; + // Make a DWARF transformer that is MachO (Apple) to avoid warnings about + // not finding DWO files. + DwarfTransformer DT(*DwarfContext, GC, /*LDCS=*/false, /*MachO*/ true); + const uint32_t ThreadCount = 1; + ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); + ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); + + // Make sure this warning is not in the binary + std::string warn("warning: Unable to retrieve DWO .debug_info section for"); + EXPECT_TRUE(errors.find(warn) == std::string::npos); +} + +TEST(GSYMTest, TestDWARFTransformNoErrorForMissingFileDecl) { + // Test that if llvm-gsymutil finds a line table for a compile unit and if + // there are no matching entries for a function in that compile unit, that + // it doesn't print out a error saying that a DIE has an invalid file index + // if there is no DW_AT_decl_file attribute. + // + // 0x0000000b: DW_TAG_compile_unit + // DW_AT_name ("main.cpp") + // DW_AT_language (DW_LANG_C) + // DW_AT_stmt_list (0x00000000) + // + // 0x00000015: DW_TAG_subprogram + // DW_AT_name ("foo") + // DW_AT_low_pc (0x0000000000001000) + // DW_AT_high_pc (0x0000000000001050) + // + // 0x0000002a: NULL + // + // Line table that has entries, but none that match "foo": + // + // Address Line Column File ISA Discriminator OpIndex Flags + // ------------------ ------ ------ ------ --- ------------- ------- ----- + // 0x0000000000002000 10 0 1 0 0 0 is_stmt + // 0x0000000000002050 13 0 1 0 0 0 is_stmt + + StringRef yamldata = R"( + debug_str: + - '' + - main.cpp + debug_abbrev: + - ID: 0 + Table: + - Code: 0x1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_language + Form: DW_FORM_udata + - Attribute: DW_AT_stmt_list + Form: DW_FORM_sec_offset + - Code: 0x2 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_string + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_addr + debug_info: + - Length: 0x27 + Version: 4 + AbbrevTableID: 0 + AbbrOffset: 0x0 + AddrSize: 8 + Entries: + - AbbrCode: 0x1 + Values: + - Value: 0x1 + - Value: 0x2 + - Value: 0x0 + - AbbrCode: 0x2 + Values: + - Value: 0xDEADBEEFDEADBEEF + CStr: foo + - Value: 0x1000 + - Value: 0x1050 + - AbbrCode: 0x0 + debug_line: + - Length: 58 + Version: 2 + PrologueLength: 31 + MinInstLength: 1 + DefaultIsStmt: 1 + LineBase: 251 + LineRange: 14 + OpcodeBase: 13 + StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] + Files: + - Name: main.cpp + DirIdx: 0 + ModTime: 0 + Length: 0 + Opcodes: + - Opcode: DW_LNS_extended_op + ExtLen: 9 + SubOpcode: DW_LNE_set_address + Data: 8192 + - Opcode: DW_LNS_advance_line + SData: 9 + Data: 0 + - Opcode: DW_LNS_copy + Data: 0 + - Opcode: DW_LNS_advance_pc + Data: 80 + - Opcode: DW_LNS_advance_line + SData: 3 + Data: 0 + - Opcode: DW_LNS_extended_op + ExtLen: 1 + SubOpcode: DW_LNE_end_sequence + Data: 0 + )"; + auto ErrOrSections = DWARFYAML::emitDebugSections(yamldata); + ASSERT_THAT_EXPECTED(ErrOrSections, Succeeded()); + std::unique_ptr<DWARFContext> DwarfContext = + DWARFContext::create(*ErrOrSections, 8); + ASSERT_TRUE(DwarfContext.get() != nullptr); + std::string errors; + raw_string_ostream OS(errors); + OutputAggregator OSAgg(&OS); + GsymCreator GC; + DwarfTransformer DT(*DwarfContext, GC); + const uint32_t ThreadCount = 1; + ASSERT_THAT_ERROR(DT.convert(ThreadCount, OSAgg), Succeeded()); + ASSERT_THAT_ERROR(GC.finalize(OSAgg), Succeeded()); + + // Make sure this warning is not in the binary + std::string error_str("error: function DIE at 0x00000015 has an invalid file " + "index 4294967295 in its DW_AT_decl_file attribute"); + EXPECT_TRUE(errors.find(error_str) == std::string::npos); +} diff --git a/llvm/unittests/ExecutionEngine/Orc/ExecutorAddressTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ExecutorAddressTest.cpp index ae9db14..9a37980 100644 --- a/llvm/unittests/ExecutionEngine/Orc/ExecutorAddressTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/ExecutorAddressTest.cpp @@ -97,10 +97,16 @@ TEST(ExecutorAddrTest, AddrRanges) { EXPECT_FALSE(R1.contains(A0)); EXPECT_FALSE(R1.contains(A2)); + EXPECT_TRUE(R3.contains(R0)); // True for singleton range at start. + EXPECT_TRUE(R3.contains(R1)); // True for singleton range at end. + EXPECT_FALSE(R3.contains(R2)); // False for non-overlaping singleton range. + EXPECT_FALSE(R3.contains(R4)); // False for overlapping, uncontained range. + EXPECT_FALSE(R1.overlaps(R0)); EXPECT_FALSE(R1.overlaps(R2)); EXPECT_TRUE(R1.overlaps(R3)); EXPECT_TRUE(R1.overlaps(R4)); + EXPECT_TRUE(R3.overlaps(R4)); EXPECT_LE(R0, R0); EXPECT_LT(R0, R1); diff --git a/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp index c5e9d43..a5269f7 100644 --- a/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp @@ -39,8 +39,8 @@ public: return Mapper->initialize(AI, std::move(OnInitialized)); } - char *prepare(ExecutorAddr Addr, size_t ContentSize) override { - return Mapper->prepare(Addr, ContentSize); + char *prepare(LinkGraph &G, ExecutorAddr Addr, size_t ContentSize) override { + return Mapper->prepare(G, Addr, ContentSize); } void deinitialize(ArrayRef<ExecutorAddr> Allocations, diff --git a/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp index fea9eab..1174493 100644 --- a/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" +#include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/Support/Process.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" @@ -66,6 +67,9 @@ TEST(MemoryMapperTest, InitializeDeinitialize) { { std::unique_ptr<MemoryMapper> Mapper = cantFail(InProcessMemoryMapper::Create()); + jitlink::LinkGraph G("G", std::make_shared<SymbolStringPool>(), + Triple("x86_64-apple-darwin"), SubtargetFeatures(), + jitlink::getGenericEdgeKindName); // We will do two separate allocations auto PageSize = Mapper->getPageSize(); @@ -80,7 +84,7 @@ TEST(MemoryMapperTest, InitializeDeinitialize) { { // Provide working memory - char *WA1 = Mapper->prepare(Mem1->Start, HW.size() + 1); + char *WA1 = Mapper->prepare(G, Mem1->Start, HW.size() + 1); std::strcpy(WA1, HW.c_str()); } @@ -105,7 +109,7 @@ TEST(MemoryMapperTest, InitializeDeinitialize) { } { - char *WA2 = Mapper->prepare(Mem1->Start + PageSize, HW.size() + 1); + char *WA2 = Mapper->prepare(G, Mem1->Start + PageSize, HW.size() + 1); std::strcpy(WA2, HW.c_str()); } @@ -158,7 +162,7 @@ TEST(MemoryMapperTest, InitializeDeinitialize) { auto Mem2 = reserve(*Mapper, PageSize); EXPECT_THAT_ERROR(Mem2.takeError(), Succeeded()); - char *WA = Mapper->prepare(Mem2->Start, HW.size() + 1); + char *WA = Mapper->prepare(G, Mem2->Start, HW.size() + 1); std::strcpy(WA, HW.c_str()); MemoryMapper::AllocInfo Alloc3; diff --git a/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp index 700500f..7775f3c 100644 --- a/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp +++ b/llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp @@ -8,6 +8,7 @@ #include "OrcTestCommon.h" #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX +#include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/Orc/MemoryMapper.h" #include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h" #include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" @@ -67,12 +68,16 @@ TEST(SharedMemoryMapperTest, MemReserveInitializeDeinitializeRelease) { auto PageSize = Mapper->getPageSize(); size_t ReqSize = PageSize; + jitlink::LinkGraph G("G", std::make_shared<SymbolStringPool>(), + Triple("x86_64-apple-darwin"), SubtargetFeatures(), + jitlink::getGenericEdgeKindName); Mapper->reserve(ReqSize, [&](Expected<ExecutorAddrRange> Result) { EXPECT_THAT_ERROR(Result.takeError(), Succeeded()); auto Reservation = std::move(*Result); { - char *Addr = Mapper->prepare(Reservation.Start, TestString.size() + 1); + char *Addr = + Mapper->prepare(G, Reservation.Start, TestString.size() + 1); std::strcpy(Addr, TestString.c_str()); } MemoryMapper::AllocInfo AI; diff --git a/llvm/unittests/IR/ConstantFPRangeTest.cpp b/llvm/unittests/IR/ConstantFPRangeTest.cpp index cf9b31c..67fee96 100644 --- a/llvm/unittests/IR/ConstantFPRangeTest.cpp +++ b/llvm/unittests/IR/ConstantFPRangeTest.cpp @@ -8,6 +8,7 @@ #include "llvm/IR/ConstantFPRange.h" #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/FloatingPointMode.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Operator.h" #include "gtest/gtest.h" @@ -1065,4 +1066,179 @@ TEST_F(ConstantFPRangeTest, sub) { #endif } +TEST_F(ConstantFPRangeTest, mul) { + EXPECT_EQ(Full.mul(Full), NonNaN.unionWith(QNaN)); + EXPECT_EQ(Full.mul(Empty), Empty); + EXPECT_EQ(Empty.mul(Full), Empty); + EXPECT_EQ(Empty.mul(Empty), Empty); + EXPECT_EQ(One.mul(One), ConstantFPRange(APFloat(1.0))); + EXPECT_EQ(Some.mul(Some), + ConstantFPRange::getNonNaN(APFloat(-9.0), APFloat(9.0))); + EXPECT_EQ(SomePos.mul(SomeNeg), + ConstantFPRange::getNonNaN(APFloat(-9.0), APFloat(-0.0))); + EXPECT_EQ(PosInf.mul(PosInf), PosInf); + EXPECT_EQ(NegInf.mul(NegInf), PosInf); + EXPECT_EQ(PosInf.mul(Finite), NonNaN.unionWith(QNaN)); + EXPECT_EQ(NegInf.mul(Finite), NonNaN.unionWith(QNaN)); + EXPECT_EQ(PosInf.mul(NegInf), NegInf); + EXPECT_EQ(NegInf.mul(PosInf), NegInf); + EXPECT_EQ(PosZero.mul(NegZero), NegZero); + EXPECT_EQ(PosZero.mul(Zero), Zero); + EXPECT_EQ(NegZero.mul(NegZero), PosZero); + EXPECT_EQ(NegZero.mul(Zero), Zero); + EXPECT_EQ(NaN.mul(NaN), QNaN); + EXPECT_EQ(NaN.mul(Finite), QNaN); + +#if defined(EXPENSIVE_CHECKS) + EnumerateTwoInterestingConstantFPRanges( + [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) { + ConstantFPRange Res = LHS.mul(RHS); + ConstantFPRange Expected = + ConstantFPRange::getEmpty(LHS.getSemantics()); + EnumerateValuesInConstantFPRange( + LHS, + [&](const APFloat &LHSC) { + EnumerateValuesInConstantFPRange( + RHS, + [&](const APFloat &RHSC) { + APFloat Prod = LHSC * RHSC; + EXPECT_TRUE(Res.contains(Prod)) + << "Wrong result for " << LHS << " * " << RHS + << ". The result " << Res << " should contain " << Prod; + if (!Expected.contains(Prod)) + Expected = Expected.unionWith(ConstantFPRange(Prod)); + }, + /*IgnoreNaNPayload=*/true); + }, + /*IgnoreNaNPayload=*/true); + EXPECT_EQ(Res, Expected) + << "Suboptimal result for " << LHS << " * " << RHS << ". Expected " + << Expected << ", but got " << Res; + }, + SparseLevel::SpecialValuesOnly); +#endif +} + +TEST_F(ConstantFPRangeTest, div) { + EXPECT_EQ(Full.div(Full), NonNaN.unionWith(QNaN)); + EXPECT_EQ(Full.div(Empty), Empty); + EXPECT_EQ(Empty.div(Full), Empty); + EXPECT_EQ(Empty.div(Empty), Empty); + EXPECT_EQ(One.div(One), ConstantFPRange(APFloat(1.0))); + EXPECT_EQ(Some.div(Some), NonNaN.unionWith(QNaN)); + EXPECT_EQ(SomePos.div(SomeNeg), + ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/true), + APFloat::getZero(Sem, /*Negative=*/true), + /*MayBeQNaN=*/true, /*MayBeSNaN=*/false)); + EXPECT_EQ(PosInf.div(PosInf), QNaN); + EXPECT_EQ(NegInf.div(NegInf), QNaN); + EXPECT_EQ(PosInf.div(Finite), NonNaN); + EXPECT_EQ(NegInf.div(Finite), NonNaN); + EXPECT_EQ(PosInf.div(NegInf), QNaN); + EXPECT_EQ(NegInf.div(PosInf), QNaN); + EXPECT_EQ(Zero.div(Zero), QNaN); + EXPECT_EQ(SomePos.div(PosInf), PosZero); + EXPECT_EQ(SomeNeg.div(PosInf), NegZero); + EXPECT_EQ(PosInf.div(SomePos), PosInf); + EXPECT_EQ(NegInf.div(SomeNeg), PosInf); + EXPECT_EQ(NegInf.div(Some), NonNaN); + EXPECT_EQ(NaN.div(NaN), QNaN); + EXPECT_EQ(NaN.div(Finite), QNaN); + +#if defined(EXPENSIVE_CHECKS) + EnumerateTwoInterestingConstantFPRanges( + [](const ConstantFPRange &LHS, const ConstantFPRange &RHS) { + ConstantFPRange Res = LHS.div(RHS); + ConstantFPRange Expected = + ConstantFPRange::getEmpty(LHS.getSemantics()); + EnumerateValuesInConstantFPRange( + LHS, + [&](const APFloat &LHSC) { + EnumerateValuesInConstantFPRange( + RHS, + [&](const APFloat &RHSC) { + APFloat Val = LHSC / RHSC; + EXPECT_TRUE(Res.contains(Val)) + << "Wrong result for " << LHS << " / " << RHS + << ". The result " << Res << " should contain " << Val; + if (!Expected.contains(Val)) + Expected = Expected.unionWith(ConstantFPRange(Val)); + }, + /*IgnoreNaNPayload=*/true); + }, + /*IgnoreNaNPayload=*/true); + EXPECT_EQ(Res, Expected) + << "Suboptimal result for " << LHS << " / " << RHS << ". Expected " + << Expected << ", but got " << Res; + }, + SparseLevel::SpecialValuesOnly); +#endif +} + +TEST_F(ConstantFPRangeTest, flushDenormals) { + const fltSemantics &FP8Sem = APFloat::Float8E4M3(); + APFloat NormalVal = APFloat::getSmallestNormalized(FP8Sem); + APFloat Subnormal1 = NormalVal; + Subnormal1.next(/*nextDown=*/true); + APFloat Subnormal2 = APFloat::getSmallest(FP8Sem); + APFloat ZeroVal = APFloat::getZero(FP8Sem); + APFloat EdgeValues[8] = {-NormalVal, -Subnormal1, -Subnormal2, -ZeroVal, + ZeroVal, Subnormal2, Subnormal1, NormalVal}; + constexpr DenormalMode::DenormalModeKind Modes[4] = { + DenormalMode::IEEE, DenormalMode::PreserveSign, + DenormalMode::PositiveZero, DenormalMode::Dynamic}; + for (uint32_t I = 0; I != 8; ++I) { + for (uint32_t J = I; J != 8; ++J) { + ConstantFPRange OriginCR = + ConstantFPRange::getNonNaN(EdgeValues[I], EdgeValues[J]); + for (auto Mode : Modes) { + StringRef ModeName = denormalModeKindName(Mode); + ConstantFPRange FlushedCR = OriginCR; + FlushedCR.flushDenormals(Mode); + + ConstantFPRange Expected = ConstantFPRange::getEmpty(FP8Sem); + auto CheckFlushedV = [&](const APFloat &V, const APFloat &FlushedV) { + EXPECT_TRUE(FlushedCR.contains(FlushedV)) + << "Wrong result for flushDenormal(" << V << ", " << ModeName + << "). The result " << FlushedCR << " should contain " + << FlushedV; + if (!Expected.contains(FlushedV)) + Expected = Expected.unionWith(ConstantFPRange(FlushedV)); + }; + EnumerateValuesInConstantFPRange( + OriginCR, + [&](const APFloat &V) { + if (V.isDenormal()) { + switch (Mode) { + case DenormalMode::IEEE: + break; + case DenormalMode::PreserveSign: + CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative())); + break; + case DenormalMode::PositiveZero: + CheckFlushedV(V, APFloat::getZero(FP8Sem)); + break; + case DenormalMode::Dynamic: + // PreserveSign + CheckFlushedV(V, APFloat::getZero(FP8Sem, V.isNegative())); + // PositiveZero + CheckFlushedV(V, APFloat::getZero(FP8Sem)); + break; + default: + llvm_unreachable("unknown denormal mode"); + } + } + // It is not mandated that flushing to zero occurs. + CheckFlushedV(V, V); + }, + /*IgnoreNaNPayload=*/true); + EXPECT_EQ(FlushedCR, Expected) + << "Suboptimal result for flushDenormal(" << OriginCR << ", " + << ModeName << "). Expected " << Expected << ", but got " + << FlushedCR; + } + } + } +} + } // anonymous namespace diff --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp index 54c7ddd..6376165 100644 --- a/llvm/unittests/IR/ConstantsTest.cpp +++ b/llvm/unittests/IR/ConstantsTest.cpp @@ -564,13 +564,17 @@ TEST(ConstantsTest, FoldGlobalVariablePtr) { Global->setAlignment(Align(4)); - ConstantInt *TheConstant(ConstantInt::get(IntType, 2)); + ConstantInt *TheConstant = ConstantInt::get(IntType, 2); - Constant *TheConstantExpr(ConstantExpr::getPtrToInt(Global.get(), IntType)); + Constant *PtrToInt = ConstantExpr::getPtrToInt(Global.get(), IntType); + ASSERT_TRUE( + ConstantFoldBinaryInstruction(Instruction::And, PtrToInt, TheConstant) + ->isNullValue()); - ASSERT_TRUE(ConstantFoldBinaryInstruction(Instruction::And, TheConstantExpr, - TheConstant) - ->isNullValue()); + Constant *PtrToAddr = ConstantExpr::getPtrToAddr(Global.get(), IntType); + ASSERT_TRUE( + ConstantFoldBinaryInstruction(Instruction::And, PtrToAddr, TheConstant) + ->isNullValue()); } // Check that containsUndefOrPoisonElement and containsPoisonElement is working diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp index fe9e7e8..f4693bf 100644 --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -606,12 +606,14 @@ TEST(InstructionTest, ConstrainedTrans) { TEST(InstructionsTest, isEliminableCastPair) { LLVMContext C; - DataLayout DL1("p1:32:32"); + DataLayout DL1("p1:32:32-p2:64:64:64:32"); Type *Int16Ty = Type::getInt16Ty(C); + Type *Int32Ty = Type::getInt32Ty(C); Type *Int64Ty = Type::getInt64Ty(C); Type *PtrTy64 = PointerType::get(C, 0); Type *PtrTy32 = PointerType::get(C, 1); + Type *PtrTy64_32 = PointerType::get(C, 2); // Source and destination pointers have same size -> bitcast. EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::PtrToInt, @@ -637,6 +639,42 @@ TEST(InstructionsTest, isEliminableCastPair) { Int64Ty, &DL1), 0U); + // Destination larger than source. Pointer type same as destination. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, Int16Ty, PtrTy64, + Int64Ty, &DL1), + CastInst::ZExt); + + // Destination larger than source. Pointer type different from destination. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, Int16Ty, PtrTy32, + Int64Ty, &DL1), + CastInst::ZExt); + + // Destination smaller than source. Pointer type same as source. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, Int64Ty, PtrTy64, + Int16Ty, &DL1), + CastInst::Trunc); + + // Destination smaller than source. Pointer type different from source. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToInt, Int64Ty, PtrTy32, + Int16Ty, &DL1), + CastInst::Trunc); + + // ptrtoaddr with address size != pointer size. Truncating case. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToAddr, Int64Ty, + PtrTy64_32, Int32Ty, &DL1), + CastInst::Trunc); + + // ptrtoaddr with address size != pointer size. Non-truncating case. + EXPECT_EQ(CastInst::isEliminableCastPair(CastInst::IntToPtr, + CastInst::PtrToAddr, Int32Ty, + PtrTy64_32, Int32Ty, &DL1), + CastInst::BitCast); + // Test that we don't eliminate bitcasts between different address spaces, // or if we don't have available pointer size information. DataLayout DL2("e-p:32:32:32-p1:16:16:16-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16" diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp index 17d9f50..d6a3ca5 100644 --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -531,7 +531,7 @@ Sections: // Check that we can detect unsupported versions. SmallString<128> UnsupportedVersionYamlString(CommonYamlString); UnsupportedVersionYamlString += R"( - - Version: 4 + - Version: 5 BBRanges: - BaseAddress: 0x11111 BBEntries: @@ -543,7 +543,7 @@ Sections: { SCOPED_TRACE("unsupported version"); DoCheck(UnsupportedVersionYamlString, - "unsupported SHT_LLVM_BB_ADDR_MAP version: 4"); + "unsupported SHT_LLVM_BB_ADDR_MAP version: 5"); } SmallString<128> ZeroBBRangesYamlString(CommonYamlString); @@ -761,14 +761,14 @@ Sections: BBAddrMap E1 = { {{0x11111, - {{1, 0x0, 0x3, {false, true, false, false, false}, {0x1, 0x2}}}}}}; + {{1, 0x0, 0x3, {false, true, false, false, false}, {0x1, 0x2}, 0}}}}}; BBAddrMap E2 = { - {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}, - {0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}, {}}}}}}; + {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}, 0}}}, + {0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}, {}, 0}}}}}; BBAddrMap E3 = { - {{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}, {}}}}}}; + {{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}, {}, 0}}}}}; BBAddrMap E4 = { - {{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}, {}}}}}}; + {{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}, {}, 0}}}}}; std::vector<BBAddrMap> Section0BBAddrMaps = {E4}; std::vector<BBAddrMap> Section1BBAddrMaps = {E3}; @@ -988,6 +988,123 @@ Sections: } } +// Test for the ELFObjectFile::readBBAddrMap API with BBHash. +TEST(ELFObjectFileTest, ReadBBHash) { + StringRef CommonYamlString(R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .llvm_bb_addr_map_1 + Type: SHT_LLVM_BB_ADDR_MAP + Link: 1 + Entries: + - Version: 4 + Feature: 0x60 + BBRanges: + - BaseAddress: 0x11111 + BBEntries: + - ID: 1 + AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x2 + CallsiteEndOffsets: [ 0x1 , 0x1 ] + Hash: 0x1 + - Name: .llvm_bb_addr_map_2 + Type: SHT_LLVM_BB_ADDR_MAP + Link: 1 + Entries: + - Version: 4 + Feature: 0x48 + BBRanges: + - BaseAddress: 0x22222 + BBEntries: + - ID: 2 + AddressOffset: 0x0 + Size: 0x2 + Metadata: 0x4 + Hash: 0x2 + - BaseAddress: 0xFFFFF + BBEntries: + - ID: 15 + AddressOffset: 0xF0 + Size: 0xF1 + Metadata: 0x1F + Hash: 0xF + - Name: .llvm_bb_addr_map_3 + Type: SHT_LLVM_BB_ADDR_MAP + Link: 2 + Entries: + - Version: 4 + Feature: 0x40 + BBRanges: + - BaseAddress: 0x33333 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x3 + Metadata: 0x6 + Hash: 0x3 + - Name: .llvm_bb_addr_map_4 + Type: SHT_LLVM_BB_ADDR_MAP + # Link: 0 (by default, can be overriden) + Entries: + - Version: 4 + Feature: 0x40 + BBRanges: + - BaseAddress: 0x44444 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x4 + Metadata: 0x18 + Hash: 0x4 +)"); + + BBAddrMap E1 = { + {{0x11111, + {{1, 0x0, 0x3, {false, true, false, false, false}, {0x1, 0x2}, 0x1}}}}}; + BBAddrMap E2 = { + {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}, 0x2}}}, + {0xFFFFF, {{15, 0xF0, 0xF1, {true, true, true, true, true}, {}, 0xF}}}}}; + BBAddrMap E3 = { + {{0x33333, {{0, 0x0, 0x3, {false, true, true, false, false}, {}, 0x3}}}}}; + BBAddrMap E4 = { + {{0x44444, {{0, 0x0, 0x4, {false, false, false, true, true}, {}, 0x4}}}}}; + + std::vector<BBAddrMap> Section0BBAddrMaps = {E4}; + std::vector<BBAddrMap> Section1BBAddrMaps = {E3}; + std::vector<BBAddrMap> Section2BBAddrMaps = {E1, E2}; + std::vector<BBAddrMap> AllBBAddrMaps = {E1, E2, E3, E4}; + + auto DoCheckSucceeds = [&](StringRef YamlString, + std::optional<unsigned> TextSectionIndex, + std::vector<BBAddrMap> ExpectedResult) { + SCOPED_TRACE("for TextSectionIndex: " + + (TextSectionIndex ? llvm::Twine(*TextSectionIndex) : "{}") + + " and object yaml:\n" + YamlString); + SmallString<0> Storage; + Expected<ELFObjectFile<ELF64LE>> ElfOrErr = + toBinary<ELF64LE>(Storage, YamlString); + ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded()); + + Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr = + ElfOrErr->getELFFile().getSection(1); + ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded()); + auto BBAddrMaps = ElfOrErr->readBBAddrMap(TextSectionIndex); + ASSERT_THAT_EXPECTED(BBAddrMaps, Succeeded()); + EXPECT_EQ(*BBAddrMaps, ExpectedResult); + }; + + DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/std::nullopt, + AllBBAddrMaps); + DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/0, Section0BBAddrMaps); + DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/2, Section1BBAddrMaps); + DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/1, Section2BBAddrMaps); +} + // Test for the ELFObjectFile::readBBAddrMap API with PGOAnalysisMap. TEST(ELFObjectFileTest, ReadPGOAnalysisMap) { StringRef CommonYamlString(R"( @@ -1159,29 +1276,32 @@ Sections: )"); BBAddrMap E1 = { - {{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}, {}}}}}}; - PGOAnalysisMap P1 = {892, {}, {true, false, false, false, false, false}}; + {{0x11111, {{1, 0x0, 0x1, {false, true, false, false, false}, {}, 0}}}}}; + PGOAnalysisMap P1 = { + 892, {}, {true, false, false, false, false, false, false}}; BBAddrMap E2 = { - {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}}; + {{0x22222, {{2, 0x0, 0x2, {false, false, true, false, false}, {}, 0}}}}}; PGOAnalysisMap P2 = {{}, {{BlockFrequency(343), {}}}, - {false, true, false, false, false, false}}; - BBAddrMap E3 = {{{0x33333, - {{0, 0x0, 0x3, {false, true, true, false, false}, {}}, - {1, 0x3, 0x3, {false, false, true, false, false}, {}}, - {2, 0x6, 0x3, {false, false, false, false, false}, {}}}}}}; + {false, true, false, false, false, false, false}}; + BBAddrMap E3 = { + {{0x33333, + {{0, 0x0, 0x3, {false, true, true, false, false}, {}, 0}, + {1, 0x3, 0x3, {false, false, true, false, false}, {}, 0}, + {2, 0x6, 0x3, {false, false, false, false, false}, {}, 0}}}}}; PGOAnalysisMap P3 = {{}, {{{}, {{1, BranchProbability::getRaw(0x1111'1111)}, {2, BranchProbability::getRaw(0xeeee'eeee)}}}, {{}, {{2, BranchProbability::getRaw(0xffff'ffff)}}}, {{}, {}}}, - {false, false, true, false, false, false}}; - BBAddrMap E4 = {{{0x44444, - {{0, 0x0, 0x4, {false, false, false, true, true}, {}}, - {1, 0x4, 0x4, {false, false, false, false, false}, {}}, - {2, 0x8, 0x4, {false, false, false, false, false}, {}}, - {3, 0xc, 0x4, {false, false, false, false, false}, {}}}}}}; + {false, false, true, false, false, false, false}}; + BBAddrMap E4 = { + {{0x44444, + {{0, 0x0, 0x4, {false, false, false, true, true}, {}, 0}, + {1, 0x4, 0x4, {false, false, false, false, false}, {}, 0}, + {2, 0x8, 0x4, {false, false, false, false, false}, {}, 0}, + {3, 0xc, 0x4, {false, false, false, false, false}, {}, 0}}}}}; PGOAnalysisMap P4 = { 1000, {{BlockFrequency(1000), @@ -1193,22 +1313,24 @@ Sections: {3, BranchProbability::getRaw(0xeeee'eeee)}}}, {BlockFrequency(18), {{3, BranchProbability::getRaw(0xffff'ffff)}}}, {BlockFrequency(1000), {}}}, - {true, true, true, false, false, false}}; + {true, true, true, false, false, false, false}}; BBAddrMap E5 = { - {{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}, {}}}}}}; - PGOAnalysisMap P5 = {{}, {}, {false, false, false, false, false, false}}; + {{0x55555, {{2, 0x0, 0x2, {false, false, true, false, false}, {}, 0}}}}}; + PGOAnalysisMap P5 = { + {}, {}, {false, false, false, false, false, false, false}}; BBAddrMap E6 = { {{0x66666, - {{0, 0x0, 0x6, {false, true, true, false, false}, {}}, - {1, 0x6, 0x6, {false, false, true, false, false}, {}}}}, - {0x666661, {{2, 0x0, 0x6, {false, false, false, false, false}, {}}}}}}; + {{0, 0x0, 0x6, {false, true, true, false, false}, {}, 0}, + {1, 0x6, 0x6, {false, false, true, false, false}, {}, 0}}}, + {0x666661, + {{2, 0x0, 0x6, {false, false, false, false, false}, {}, 0}}}}}; PGOAnalysisMap P6 = {{}, {{{}, {{1, BranchProbability::getRaw(0x2222'2222)}, {2, BranchProbability::getRaw(0xcccc'cccc)}}}, {{}, {{2, BranchProbability::getRaw(0x8888'8888)}}}, {{}, {}}}, - {false, false, true, true, false, false}}; + {false, false, true, true, false, false, false}}; std::vector<BBAddrMap> Section0BBAddrMaps = {E4, E5, E6}; std::vector<BBAddrMap> Section1BBAddrMaps = {E3}; diff --git a/llvm/unittests/Object/ELFTypesTest.cpp b/llvm/unittests/Object/ELFTypesTest.cpp index f88931b5f..1765e15 100644 --- a/llvm/unittests/Object/ELFTypesTest.cpp +++ b/llvm/unittests/Object/ELFTypesTest.cpp @@ -101,21 +101,22 @@ static_assert( "PGOAnalysisMap should use the same type for basic block ID as BBAddrMap"); TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) { - const std::array<BBAddrMap::Features, 11> Decoded = { - {{false, false, false, false, false, false}, - {true, false, false, false, false, false}, - {false, true, false, false, false, false}, - {false, false, true, false, false, false}, - {false, false, false, true, false, false}, - {true, true, false, false, false, false}, - {false, true, true, false, false, false}, - {false, true, true, true, false, false}, - {true, true, true, true, false, false}, - {false, false, false, false, true, false}, - {false, false, false, false, false, true}}}; - const std::array<uint8_t, 11> Encoded = {{0b0000, 0b0001, 0b0010, 0b0100, - 0b1000, 0b0011, 0b0110, 0b1110, - 0b1111, 0b1'0000, 0b10'0000}}; + const std::array<BBAddrMap::Features, 12> Decoded = { + {{false, false, false, false, false, false, false}, + {true, false, false, false, false, false, false}, + {false, true, false, false, false, false, false}, + {false, false, true, false, false, false, false}, + {false, false, false, true, false, false, false}, + {true, true, false, false, false, false, false}, + {false, true, true, false, false, false, false}, + {false, true, true, true, false, false, false}, + {true, true, true, true, false, false, false}, + {false, false, false, false, true, false, false}, + {false, false, false, false, false, true, false}, + {false, false, false, false, false, false, true}}}; + const std::array<uint8_t, 12> Encoded = { + {0b0000, 0b0001, 0b0010, 0b0100, 0b1000, 0b0011, 0b0110, 0b1110, 0b1111, + 0b1'0000, 0b10'0000, 0b100'0000}}; for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded)) EXPECT_EQ(Feat.encode(), EncodedVal); for (const auto &[Feat, EncodedVal] : llvm::zip(Decoded, Encoded)) { @@ -128,9 +129,9 @@ TEST(ELFTypesTest, BBAddrMapFeaturesEncodingTest) { TEST(ELFTypesTest, BBAddrMapFeaturesInvalidEncodingTest) { const std::array<std::string, 2> Errors = { - "invalid encoding for BBAddrMap::Features: 0x40", + "invalid encoding for BBAddrMap::Features: 0x80", "invalid encoding for BBAddrMap::Features: 0xf0"}; - const std::array<uint8_t, 2> Values = {{0b100'0000, 0b1111'0000}}; + const std::array<uint8_t, 2> Values = {{0b1000'0000, 0b1111'0000}}; for (const auto &[Val, Error] : llvm::zip(Values, Errors)) { EXPECT_THAT_ERROR(BBAddrMap::Features::decode(Val).takeError(), FailedWithMessage(Error)); diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index 25efa00..21f10eb 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -44,6 +44,7 @@ add_llvm_unittest(SupportTests ExtensibleRTTITest.cpp FileCollectorTest.cpp FileOutputBufferTest.cpp + Format.cpp FormatVariadicTest.cpp FSUniqueIDTest.cpp GenericDomTreeTest.cpp diff --git a/llvm/unittests/Support/Format.cpp b/llvm/unittests/Support/Format.cpp new file mode 100644 index 0000000..c4e421f --- /dev/null +++ b/llvm/unittests/Support/Format.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Format.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +template <typename FormatTy> +std::string printToString(unsigned MaxN, FormatTy &&Fmt) { + std::vector<char> Dst(MaxN + 2); + int N = Fmt.snprint(Dst.data(), Dst.size()); + Dst.back() = 0; + return N < 0 ? "" : Dst.data(); +} + +template <typename Expected, typename Arg> +constexpr bool checkDecayTypeEq(const Arg &arg) { + return std::is_same_v<detail::decay_if_c_char_array_t<Arg>, Expected>; +} + +TEST(Format, DecayIfCCharArray) { + char Array[] = "Array"; + const char ConstArray[] = "ConstArray"; + char PtrBuf[] = "Ptr"; + char *Ptr = PtrBuf; + const char *PtrToConst = "PtrToConst"; + + EXPECT_EQ(" Literal", printToString(20, format("%15s", "Literal"))); + EXPECT_EQ(" Array", printToString(20, format("%15s", Array))); + EXPECT_EQ(" ConstArray", printToString(20, format("%15s", ConstArray))); + EXPECT_EQ(" Ptr", printToString(20, format("%15s", Ptr))); + EXPECT_EQ(" PtrToConst", printToString(20, format("%15s", PtrToConst))); + + EXPECT_TRUE(checkDecayTypeEq<const char *>("Literal")); + EXPECT_TRUE(checkDecayTypeEq<const char *>(Array)); + EXPECT_TRUE(checkDecayTypeEq<const char *>(ConstArray)); + EXPECT_TRUE(checkDecayTypeEq<char *>(Ptr)); + EXPECT_TRUE(checkDecayTypeEq<const char *>(PtrToConst)); + EXPECT_TRUE(checkDecayTypeEq<char>(PtrToConst[0])); + EXPECT_TRUE( + checkDecayTypeEq<const char *>(static_cast<const char *>("Literal"))); + + wchar_t WCharArray[] = L"WCharArray"; + EXPECT_TRUE(checkDecayTypeEq<wchar_t[11]>(WCharArray)); + EXPECT_TRUE(checkDecayTypeEq<wchar_t>(WCharArray[0])); +} + +} // namespace diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index c74d157..809960d 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -177,6 +177,165 @@ TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_VASHR) { EXPECT_EQ(DAG->ComputeNumSignBits(Fr2), 5u); } +TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SUB) { + SDLoc Loc; + auto IntVT = EVT::getIntegerVT(Context, 8); + auto N0 = DAG->getConstant(0x00, Loc, IntVT); + auto N1 = DAG->getConstant(0x01, Loc, IntVT); + auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); + auto UnknownOp = DAG->getRegister(0, IntVT); + auto Mask = DAG->getConstant(0x1e, Loc, IntVT); + auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); + // RHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpRhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, Nsign1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); + + // Neg 0 + // N0 = 00000000 + auto OpNegZero = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N0); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); + + // Neg 1 + // N0 = 00000000 + // N1 = 00000001 + auto OpNegOne = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + + // Neg 5 + // N0 = 00000000 + // N5 = 00000101 + auto OpNegFive = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegFive), 5u); + + // Non negative + // N0 = 00000000 + // Nsign3 = 000????0 + auto OpNonNeg = DAG->getNode(ISD::SUB, Loc, IntVT, N0, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); + + // LHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpLhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign1, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); + + // Nsign3 = 000????0 + // N5 = 00000101 + auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); +} + +TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) { + SDLoc Loc; + auto IntVT = EVT::getIntegerVT(Context, 8); + auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); + auto N0 = DAG->getConstant(0x00, Loc, IntVT); + auto N1 = DAG->getConstant(0x01, Loc, IntVT); + auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto N8 = DAG->getConstant(0x08, Loc, IntVT); + auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); + auto UnknownOp = DAG->getRegister(0, IntVT); + auto Mask = DAG->getConstant(0x1e, Loc, IntVT); + auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); + // RHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpRhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nsign1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); + + // ADD 0 -1 + // N0 = 00000000 + // Nneg1 = 11111111 + auto OpNegZero = DAG->getNode(ISD::ADD, Loc, IntVT, N0, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); + + // ADD 1 -1 + // N1 = 00000001 + // Nneg1 = 11111111 + auto OpNegOne = DAG->getNode(ISD::ADD, Loc, IntVT, N1, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + + // ADD 8 -1 + // N8 = 00001000 + // Nneg1 = 11111111 + auto OpSeven = DAG->getNode(ISD::ADD, Loc, IntVT, N8, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 5u); + + // Non negative + // Nsign3 = 000????0 + // Nneg1 = 11111111 + auto OpNonNeg = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); + + // LHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpLhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign1, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); + + // Nsign3 = 000????0 + // N5 = 00000101 + auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); +} + +TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) { + SDLoc Loc; + auto IntVT = EVT::getIntegerVT(Context, 8); + auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); + auto N0 = DAG->getConstant(0x00, Loc, IntVT); + auto N1 = DAG->getConstant(0x01, Loc, IntVT); + auto N5 = DAG->getConstant(0x05, Loc, IntVT); + auto N8 = DAG->getConstant(0x08, Loc, IntVT); + auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); + auto UnknownOp = DAG->getRegister(0, IntVT); + auto Mask = DAG->getConstant(0x1e, Loc, IntVT); + auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); + // RHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpRhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nsign1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); + + // ADD 0 -1 + // N0 = 00000000 + // Nneg1 = 11111111 + auto OpNegZero = DAG->getNode(ISD::ADDC, Loc, IntVT, N0, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); + + // ADD 1 -1 + // N1 = 00000001 + // Nneg1 = 11111111 + auto OpNegOne = DAG->getNode(ISD::ADDC, Loc, IntVT, N1, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); + + // ADD 8 -1 + // N8 = 00001000 + // Nneg1 = 11111111 + auto OpSeven = DAG->getNode(ISD::ADDC, Loc, IntVT, N8, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 4u); + + // Non negative + // Nsign3 = 000????0 + // Nneg1 = 11111111 + auto OpNonNeg = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nneg1); + EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); + + // LHS early out + // Nsign1 = 01010101 + // Nsign3 = 000????0 + auto OpLhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign1, Nsign3); + EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); + + // Nsign3 = 000????0 + // N5 = 00000101 + auto Op = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, N5); + EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); +} + TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) { TargetLowering TL(*TM); diff --git a/llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp b/llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp index 841f44c..716f5f2 100644 --- a/llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp +++ b/llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp @@ -308,3 +308,223 @@ TEST(SSAUpdaterBulk, TwoBBLoop) { EXPECT_EQ(Phi->getIncomingValueForBlock(Entry), ConstantInt::get(I32Ty, 0)); EXPECT_EQ(Phi->getIncomingValueForBlock(Loop), I); } + +TEST(SSAUpdaterBulk, SimplifyPHIs) { + const char *IR = R"( + define void @main(i32 %val, i1 %cond) { + entry: + br i1 %cond, label %left, label %right + left: + %add = add i32 %val, 1 + br label %exit + right: + %sub = sub i32 %val, 1 + br label %exit + exit: + %phi = phi i32 [ %sub, %right ], [ %add, %left ] + %cmp = icmp slt i32 0, 42 + ret void + } + )"; + + llvm::LLVMContext Context; + llvm::SMDiagnostic Err; + std::unique_ptr<llvm::Module> M = llvm::parseAssemblyString(IR, Err, Context); + ASSERT_NE(M, nullptr) << "Failed to parse IR: " << Err.getMessage(); + + Function *F = M->getFunction("main"); + auto *Entry = &F->getEntryBlock(); + auto *Left = Entry->getTerminator()->getSuccessor(0); + auto *Right = Entry->getTerminator()->getSuccessor(1); + auto *Exit = Left->getSingleSuccessor(); + auto *Val = &*F->arg_begin(); + auto *Phi = &Exit->front(); + auto *Cmp = &*std::next(Exit->begin()); + auto *Add = &Left->front(); + auto *Sub = &Right->front(); + + SSAUpdaterBulk Updater; + Type *I32Ty = Type::getInt32Ty(Context); + + // Use %val directly instead of creating a phi. + unsigned ValVar = Updater.AddVariable("Val", I32Ty); + Updater.AddAvailableValue(ValVar, Left, Val); + Updater.AddAvailableValue(ValVar, Right, Val); + Updater.AddUse(ValVar, &Cmp->getOperandUse(0)); + + // Use existing %phi for %add and %sub values. + unsigned AddSubVar = Updater.AddVariable("AddSub", I32Ty); + Updater.AddAvailableValue(AddSubVar, Left, Add); + Updater.AddAvailableValue(AddSubVar, Right, Sub); + Updater.AddUse(AddSubVar, &Cmp->getOperandUse(1)); + + auto ExitSizeBefore = Exit->size(); + DominatorTree DT(*F); + Updater.RewriteAndOptimizeAllUses(DT); + + // Output for Exit->dump(): + // exit: ; preds = %right, %left + // %phi = phi i32 [ %sub, %right ], [ %add, %left ] + // %cmp = icmp slt i32 %val, %phi + // ret void + + ASSERT_EQ(Exit->size(), ExitSizeBefore); + ASSERT_EQ(&Exit->front(), Phi); + EXPECT_EQ(Val, Cmp->getOperand(0)); + EXPECT_EQ(Phi, Cmp->getOperand(1)); +} + +bool EliminateNewDuplicatePHINodes(BasicBlock *BB, + BasicBlock::phi_iterator FirstExistingPN); + +// Helper to run both versions on the same input. +static void RunEliminateNewDuplicatePHINode( + const char *AsmText, + std::function<void(BasicBlock &, + bool(BasicBlock *BB, BasicBlock::phi_iterator))> + Check) { + LLVMContext C; + + SMDiagnostic Err; + std::unique_ptr<Module> M = parseAssemblyString(AsmText, Err, C); + if (!M) { + Err.print("UtilsTests", errs()); + return; + } + + Function *F = M->getFunction("main"); + auto BBIt = std::find_if(F->begin(), F->end(), [](const BasicBlock &Block) { + return Block.getName() == "testbb"; + }); + ASSERT_NE(BBIt, F->end()); + Check(*BBIt, EliminateNewDuplicatePHINodes); +} + +static BasicBlock::phi_iterator getPhiIt(BasicBlock &BB, unsigned Idx) { + return std::next(BB.phis().begin(), Idx); +} + +static PHINode *getPhi(BasicBlock &BB, unsigned Idx) { + return &*getPhiIt(BB, Idx); +} + +static int getNumPHIs(BasicBlock &BB) { + return std::distance(BB.phis().begin(), BB.phis().end()); +} + +TEST(SSAUpdaterBulk, EliminateNewDuplicatePHINodes_OrderExisting) { + RunEliminateNewDuplicatePHINode(R"( + define void @main() { + entry: + br label %testbb + testbb: + %np0 = phi i32 [ 1, %entry ] + %np1 = phi i32 [ 1, %entry ] + %ep0 = phi i32 [ 1, %entry ] + %ep1 = phi i32 [ 1, %entry ] + %u = add i32 %np0, %np1 + ret void + } + )", [](BasicBlock &BB, auto *ENDPN) { + AssertingVH<PHINode> EP0 = getPhi(BB, 2); + AssertingVH<PHINode> EP1 = getPhi(BB, 3); + EXPECT_TRUE(ENDPN(&BB, getPhiIt(BB, 2))); + // Expected: + // %ep0 = phi i32 [ 1, %entry ] + // %ep1 = phi i32 [ 1, %entry ] + // %u = add i32 %ep0, %ep0 + EXPECT_EQ(getNumPHIs(BB), 2); + Instruction &Add = *BB.getFirstNonPHIIt(); + EXPECT_EQ(Add.getOperand(0), EP0); + EXPECT_EQ(Add.getOperand(1), EP0); + (void)EP1; // Avoid "unused" warning. + }); +} + +TEST(SSAUpdaterBulk, EliminateNewDuplicatePHINodes_OrderNew) { + RunEliminateNewDuplicatePHINode(R"( + define void @main() { + entry: + br label %testbb + testbb: + %np0 = phi i32 [ 1, %entry ] + %np1 = phi i32 [ 1, %entry ] + %ep0 = phi i32 [ 2, %entry ] + %ep1 = phi i32 [ 2, %entry ] + %u = add i32 %np0, %np1 + ret void + } + )", [](BasicBlock &BB, auto *ENDPN) { + AssertingVH<PHINode> NP0 = getPhi(BB, 0); + AssertingVH<PHINode> EP0 = getPhi(BB, 2); + AssertingVH<PHINode> EP1 = getPhi(BB, 3); + EXPECT_TRUE(ENDPN(&BB, getPhiIt(BB, 2))); + // Expected: + // %np0 = phi i32 [ 1, %entry ] + // %ep0 = phi i32 [ 2, %entry ] + // %ep1 = phi i32 [ 2, %entry ] + // %u = add i32 %np0, %np0 + EXPECT_EQ(getNumPHIs(BB), 3); + Instruction &Add = *BB.getFirstNonPHIIt(); + EXPECT_EQ(Add.getOperand(0), NP0); + EXPECT_EQ(Add.getOperand(1), NP0); + (void)EP0; + (void)EP1; // Avoid "unused" warning. + }); +} + +TEST(SSAUpdaterBulk, EliminateNewDuplicatePHINodes_NewRefExisting) { + RunEliminateNewDuplicatePHINode(R"( + define void @main() { + entry: + br label %testbb + testbb: + %np0 = phi i32 [ 1, %entry ], [ %ep0, %testbb ] + %np1 = phi i32 [ 1, %entry ], [ %ep1, %testbb ] + %ep0 = phi i32 [ 1, %entry ], [ %ep0, %testbb ] + %ep1 = phi i32 [ 1, %entry ], [ %ep1, %testbb ] + %u = add i32 %np0, %np1 + br label %testbb + } + )", [](BasicBlock &BB, auto *ENDPN) { + AssertingVH<PHINode> EP0 = getPhi(BB, 2); + AssertingVH<PHINode> EP1 = getPhi(BB, 3); + EXPECT_TRUE(ENDPN(&BB, getPhiIt(BB, 2))); + // Expected: + // %ep0 = phi i32 [ 1, %entry ], [ %ep0, %testbb ] + // %ep1 = phi i32 [ 1, %entry ], [ %ep1, %testbb ] + // %u = add i32 %ep0, %ep1 + EXPECT_EQ(getNumPHIs(BB), 2); + Instruction &Add = *BB.getFirstNonPHIIt(); + EXPECT_EQ(Add.getOperand(0), EP0); + EXPECT_EQ(Add.getOperand(1), EP1); + }); +} + +TEST(SSAUpdaterBulk, EliminateNewDuplicatePHINodes_ExistingRefNew) { + RunEliminateNewDuplicatePHINode(R"( + define void @main() { + entry: + br label %testbb + testbb: + %np0 = phi i32 [ 1, %entry ], [ %np0, %testbb ] + %np1 = phi i32 [ 1, %entry ], [ %np1, %testbb ] + %ep0 = phi i32 [ 1, %entry ], [ %np0, %testbb ] + %ep1 = phi i32 [ 1, %entry ], [ %np1, %testbb ] + %u = add i32 %np0, %np1 + br label %testbb + } + )", [](BasicBlock &BB, auto *ENDPN) { + AssertingVH<PHINode> EP0 = getPhi(BB, 2); + AssertingVH<PHINode> EP1 = getPhi(BB, 3); + EXPECT_TRUE(ENDPN(&BB, getPhiIt(BB, 2))); + // Expected: + // %ep0 = phi i32 [ 1, %entry ], [ %ep0, %testbb ] + // %ep1 = phi i32 [ 1, %entry ], [ %ep1, %testbb ] + // %u = add i32 %ep0, %ep1 + EXPECT_EQ(getNumPHIs(BB), 2); + Instruction &Add = *BB.getFirstNonPHIIt(); + EXPECT_EQ(Add.getOperand(0), EP0); + EXPECT_EQ(Add.getOperand(1), EP1); + }); +} diff --git a/llvm/unittests/Transforms/Vectorize/VPDomTreeTest.cpp b/llvm/unittests/Transforms/Vectorize/VPDomTreeTest.cpp index 55b68f5..2a0f500 100644 --- a/llvm/unittests/Transforms/Vectorize/VPDomTreeTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPDomTreeTest.cpp @@ -45,8 +45,7 @@ TEST_F(VPDominatorTreeTest, DominanceNoRegionsTest) { VPBlockUtils::connectBlocks(R1, Plan.getScalarHeader()); - VPDominatorTree VPDT; - VPDT.recalculate(Plan); + VPDominatorTree VPDT(Plan); EXPECT_TRUE(VPDT.dominates(VPBB1, VPBB4)); EXPECT_FALSE(VPDT.dominates(VPBB4, VPBB1)); @@ -118,8 +117,7 @@ TEST_F(VPDominatorTreeTest, DominanceRegionsTest) { VPBlockUtils::connectBlocks(R1, R2); VPBlockUtils::connectBlocks(R2, Plan.getScalarHeader()); - VPDominatorTree VPDT; - VPDT.recalculate(Plan); + VPDominatorTree VPDT(Plan); checkDomChildren(VPDT, R1, {R1BB1}); checkDomChildren(VPDT, R1BB1, {R1BB2, R1BB4, R1BB3}); @@ -197,8 +195,7 @@ TEST_F(VPDominatorTreeTest, DominanceRegionsTest) { VPBlockUtils::connectBlocks(R1, VPBB2); VPBlockUtils::connectBlocks(VPBB2, Plan.getScalarHeader()); - VPDominatorTree VPDT; - VPDT.recalculate(Plan); + VPDominatorTree VPDT(Plan); checkDomChildren(VPDT, VPBB1, {R1}); checkDomChildren(VPDT, R1, {R1BB1}); |