diff options
Diffstat (limited to 'llvm/unittests')
-rw-r--r-- | llvm/unittests/ADT/StringSwitchTest.cpp | 13 | ||||
-rw-r--r-- | llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp | 4 | ||||
-rw-r--r-- | llvm/unittests/ExecutionEngine/Orc/MemoryMapperTest.cpp | 10 | ||||
-rw-r--r-- | llvm/unittests/ExecutionEngine/Orc/SharedMemoryMapperTest.cpp | 7 | ||||
-rw-r--r-- | llvm/unittests/IR/ConstantFPRangeTest.cpp | 67 | ||||
-rw-r--r-- | llvm/unittests/IR/InstructionsTest.cpp | 40 | ||||
-rw-r--r-- | llvm/unittests/Support/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/unittests/Support/Format.cpp | 56 | ||||
-rw-r--r-- | llvm/unittests/Support/JobserverTest.cpp | 1 | ||||
-rw-r--r-- | llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp | 51 | ||||
-rw-r--r-- | llvm/unittests/Transforms/Utils/SSAUpdaterBulkTest.cpp | 220 | ||||
-rw-r--r-- | llvm/unittests/Transforms/Vectorize/VPDomTreeTest.cpp | 9 |
12 files changed, 464 insertions, 15 deletions
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/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..2431db9 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,70 @@ TEST_F(ConstantFPRangeTest, sub) { #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/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/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/Support/JobserverTest.cpp b/llvm/unittests/Support/JobserverTest.cpp index ddee023..d274458 100644 --- a/llvm/unittests/Support/JobserverTest.cpp +++ b/llvm/unittests/Support/JobserverTest.cpp @@ -355,6 +355,7 @@ TEST_F(JobserverStrategyTest, ThreadPoolConcurrencyIsLimited) { int CurrentActive = ++ActiveTasks; LLVM_DEBUG(dbgs() << "Task " << i << ": Active tasks: " << CurrentActive << "\n"); + (void)i; int OldMax = MaxActiveTasks.load(); while (CurrentActive > OldMax) MaxActiveTasks.compare_exchange_weak(OldMax, CurrentActive); diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp index c74d157..5ac4c53 100644 --- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp +++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp @@ -177,6 +177,57 @@ 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, 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}); |