165b40f27SMatt Arsenault //===- MLRegAllocDevelopmentFeatures.cpp - test dev MLRegAlloc features ---===// 265b40f27SMatt Arsenault // 365b40f27SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 465b40f27SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information. 565b40f27SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 665b40f27SMatt Arsenault // 765b40f27SMatt Arsenault //===----------------------------------------------------------------------===// 865b40f27SMatt Arsenault 965b40f27SMatt Arsenault #include "../../lib/CodeGen/MLRegAllocEvictAdvisor.h" 1065b40f27SMatt Arsenault #include "llvm/Analysis/NoInferenceModelRunner.h" 11*bb3f5e1fSMatin Raayai #include "llvm/CodeGen/CodeGenTargetMachineImpl.h" 1265b40f27SMatt Arsenault #include "llvm/CodeGen/MachineBasicBlock.h" 1365b40f27SMatt Arsenault #include "llvm/CodeGen/MachineFunction.h" 1465b40f27SMatt Arsenault #include "llvm/CodeGen/MachineModuleInfo.h" 1565b40f27SMatt Arsenault #include "llvm/CodeGen/SlotIndexes.h" 1665b40f27SMatt Arsenault #include "llvm/CodeGen/TargetFrameLowering.h" 1765b40f27SMatt Arsenault #include "llvm/CodeGen/TargetInstrInfo.h" 1865b40f27SMatt Arsenault #include "llvm/CodeGen/TargetLowering.h" 1965b40f27SMatt Arsenault #include "llvm/IR/LLVMContext.h" 204169338eSNikita Popov #include "llvm/IR/Module.h" 2165b40f27SMatt Arsenault #include "llvm/MC/TargetRegistry.h" 2265b40f27SMatt Arsenault #include "llvm/Support/Allocator.h" 2365b40f27SMatt Arsenault #include "llvm/Support/CodeGen.h" 2465b40f27SMatt Arsenault #include "llvm/Support/TargetSelect.h" 2565b40f27SMatt Arsenault #include "llvm/Target/TargetOptions.h" 2665b40f27SMatt Arsenault #include "llvm/TargetParser/Triple.h" 2765b40f27SMatt Arsenault #include "gmock/gmock.h" 2865b40f27SMatt Arsenault #include "gtest/gtest.h" 2965b40f27SMatt Arsenault 3065b40f27SMatt Arsenault #include <string> 3165b40f27SMatt Arsenault #include <vector> 3265b40f27SMatt Arsenault 331753008bSRahul Joshi using namespace llvm; 3465b40f27SMatt Arsenault using testing::ContainerEq; 3565b40f27SMatt Arsenault using testing::Test; 3665b40f27SMatt Arsenault 3765b40f27SMatt Arsenault namespace { 3865b40f27SMatt Arsenault 3965b40f27SMatt Arsenault #include "MFCommon.inc" 4065b40f27SMatt Arsenault 4165b40f27SMatt Arsenault struct LRPosInfoIndexes { 4265b40f27SMatt Arsenault size_t StartIndex; 4365b40f27SMatt Arsenault size_t EndIndex; 4465b40f27SMatt Arsenault size_t PhysReg; 4565b40f27SMatt Arsenault }; 4665b40f27SMatt Arsenault 4765b40f27SMatt Arsenault class RegAllocDevelopmentFeaturesTest : public ::Test { 4865b40f27SMatt Arsenault protected: 4965b40f27SMatt Arsenault SmallVector<LRStartEndInfo> 5065b40f27SMatt Arsenault setupOverlapProblem(const SmallVectorImpl<LRPosInfoIndexes> &Segments, 51d6f906eaSJay Foad simple_ilist<IndexListEntry> &IndexList) { 5265b40f27SMatt Arsenault SmallVector<LRStartEndInfo> PositionsToReturn; 5365b40f27SMatt Arsenault PositionsToReturn.reserve(Segments.size()); 5465b40f27SMatt Arsenault for (auto CurrentPosIndexInfo : Segments) { 5565b40f27SMatt Arsenault LRStartEndInfo CurrentPosInfo = {}; 5665b40f27SMatt Arsenault CurrentPosInfo.Pos = CurrentPosIndexInfo.PhysReg; 5765b40f27SMatt Arsenault PositionsToReturn.push_back(CurrentPosInfo); 5865b40f27SMatt Arsenault } 5965b40f27SMatt Arsenault size_t CurrentSegmentIndex = 0; 6065b40f27SMatt Arsenault size_t CurrentIndex = 0; 6165b40f27SMatt Arsenault while (CurrentSegmentIndex < Segments.size()) { 6265b40f27SMatt Arsenault auto *CurrentLEMem = static_cast<IndexListEntry *>( 6365b40f27SMatt Arsenault Allocator.Allocate(sizeof(IndexListEntry), alignof(IndexListEntry))); 6465b40f27SMatt Arsenault auto *CurrentListEntry = 6565b40f27SMatt Arsenault new (CurrentLEMem) IndexListEntry(nullptr, CurrentIndex); 66d6f906eaSJay Foad IndexList.push_back(*CurrentListEntry); 6765b40f27SMatt Arsenault for (size_t CurrentPosInfoIndex = 0; 6865b40f27SMatt Arsenault CurrentPosInfoIndex < Segments.size(); ++CurrentPosInfoIndex) { 6965b40f27SMatt Arsenault if ((CurrentIndex / SlotIndex::InstrDist) == 7065b40f27SMatt Arsenault Segments[CurrentPosInfoIndex].StartIndex) { 7165b40f27SMatt Arsenault PositionsToReturn[CurrentPosInfoIndex].Begin = 7265b40f27SMatt Arsenault SlotIndex(CurrentListEntry, 0); 7365b40f27SMatt Arsenault } else if ((CurrentIndex / SlotIndex::InstrDist) == 7465b40f27SMatt Arsenault Segments[CurrentPosInfoIndex].EndIndex) { 7565b40f27SMatt Arsenault PositionsToReturn[CurrentPosInfoIndex].End = 7665b40f27SMatt Arsenault SlotIndex(CurrentListEntry, 0); 7765b40f27SMatt Arsenault ++CurrentSegmentIndex; 7865b40f27SMatt Arsenault } 7965b40f27SMatt Arsenault } 8065b40f27SMatt Arsenault CurrentIndex += SlotIndex::InstrDist; 8165b40f27SMatt Arsenault } 8265b40f27SMatt Arsenault return PositionsToReturn; 8365b40f27SMatt Arsenault } 8465b40f27SMatt Arsenault 8565b40f27SMatt Arsenault NoInferenceModelRunner setupModelRunner() { 8665b40f27SMatt Arsenault const std::vector<TensorSpec> Inputs{ 8765b40f27SMatt Arsenault TensorSpec::createSpec<int64_t>("instructions", InstructionsShape), 8865b40f27SMatt Arsenault TensorSpec::createSpec<int64_t>("instructions_mapping", 8965b40f27SMatt Arsenault InstructionsMappingShape), 9065b40f27SMatt Arsenault TensorSpec::createSpec<float>("mbb_frequencies", MBBFrequencyShape), 9165b40f27SMatt Arsenault TensorSpec::createSpec<int64_t>("mbb_mapping", InstructionsShape)}; 9265b40f27SMatt Arsenault LLVMContext Ctx; 9365b40f27SMatt Arsenault return NoInferenceModelRunner(Ctx, Inputs); 9465b40f27SMatt Arsenault } 9565b40f27SMatt Arsenault 9665b40f27SMatt Arsenault std::vector<int64_t> 9765b40f27SMatt Arsenault getExpectedMappingMatrix(SmallVectorImpl<LRPosInfoIndexes> &OverlapSetup) { 9865b40f27SMatt Arsenault std::vector<int64_t> ExpectedMappingMatrix( 9965b40f27SMatt Arsenault NumberOfInterferences * ModelMaxSupportedInstructionCount, 0); 10065b40f27SMatt Arsenault for (auto NewSegment : OverlapSetup) { 10165b40f27SMatt Arsenault for (size_t CurrentIndex = NewSegment.StartIndex; 10265b40f27SMatt Arsenault CurrentIndex <= NewSegment.EndIndex; ++CurrentIndex) { 10365b40f27SMatt Arsenault ExpectedMappingMatrix[NewSegment.PhysReg * 10465b40f27SMatt Arsenault ModelMaxSupportedInstructionCount + 10565b40f27SMatt Arsenault CurrentIndex] = 1; 10665b40f27SMatt Arsenault } 10765b40f27SMatt Arsenault } 10865b40f27SMatt Arsenault return ExpectedMappingMatrix; 10965b40f27SMatt Arsenault } 11065b40f27SMatt Arsenault 11165b40f27SMatt Arsenault void runOverlapTest(SmallVectorImpl<LRPosInfoIndexes> &OverlapSetup) { 112d6f906eaSJay Foad simple_ilist<IndexListEntry> IndexList; 11365b40f27SMatt Arsenault auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList); 11465b40f27SMatt Arsenault NoInferenceModelRunner ModelRunner = setupModelRunner(); 11565b40f27SMatt Arsenault size_t MaxIndex = 0; 11665b40f27SMatt Arsenault for (size_t CurrentOverlap = 0; CurrentOverlap < OverlapSetup.size(); 11765b40f27SMatt Arsenault ++CurrentOverlap) { 11865b40f27SMatt Arsenault if (OverlapSetup[CurrentOverlap].EndIndex > 11965b40f27SMatt Arsenault OverlapSetup[MaxIndex].EndIndex) { 12065b40f27SMatt Arsenault MaxIndex = CurrentOverlap; 12165b40f27SMatt Arsenault } 12265b40f27SMatt Arsenault } 12365b40f27SMatt Arsenault SlotIndex LastIndex = OverlapProblem[MaxIndex].End; 12465b40f27SMatt Arsenault extractInstructionFeatures( 12565b40f27SMatt Arsenault OverlapProblem, &ModelRunner, 12665b40f27SMatt Arsenault [](SlotIndex InputSlot) -> int { return 0; }, 12765b40f27SMatt Arsenault [](SlotIndex InputSlot) -> float { return 0.0f; }, 12865b40f27SMatt Arsenault [](SlotIndex InputSlot) -> MachineBasicBlock * { return nullptr; }, 0, 12965b40f27SMatt Arsenault 1, 2, 3, LastIndex); 13065b40f27SMatt Arsenault std::vector<int64_t> MappingMatrix( 13165b40f27SMatt Arsenault ModelRunner.getTensor<int64_t>(1), 13265b40f27SMatt Arsenault ModelRunner.getTensor<int64_t>(1) + 13365b40f27SMatt Arsenault NumberOfInterferences * ModelMaxSupportedInstructionCount); 13465b40f27SMatt Arsenault ASSERT_THAT(MappingMatrix, 13565b40f27SMatt Arsenault ContainerEq(getExpectedMappingMatrix(OverlapSetup))); 136d6f906eaSJay Foad IndexList.clear(); 13765b40f27SMatt Arsenault } 13865b40f27SMatt Arsenault 13965b40f27SMatt Arsenault BumpPtrAllocator Allocator; 14065b40f27SMatt Arsenault }; 14165b40f27SMatt Arsenault 14265b40f27SMatt Arsenault // meta tests to ensure that test setup works correctly 14365b40f27SMatt Arsenault 14465b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, 14565b40f27SMatt Arsenault MetaOverlapInstructionDistancesAreCorrect) { 14665b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 2> OverlapSetup; 14765b40f27SMatt Arsenault OverlapSetup.push_back({0, 5, 0}); 14865b40f27SMatt Arsenault OverlapSetup.push_back({5, 10, 0}); 149d6f906eaSJay Foad simple_ilist<IndexListEntry> IndexList; 15065b40f27SMatt Arsenault auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList); 15165b40f27SMatt Arsenault ASSERT_EQ(OverlapProblem[0].End.distance(OverlapProblem[1].End), 15265b40f27SMatt Arsenault 5 * SlotIndex::InstrDist); 15365b40f27SMatt Arsenault ASSERT_EQ(OverlapProblem[0].End.distance(OverlapProblem[1].Begin), 0); 15465b40f27SMatt Arsenault } 15565b40f27SMatt Arsenault 15665b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, MetaSlotIndicesAreValid) { 15765b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 1> OverlapSetup; 15865b40f27SMatt Arsenault OverlapSetup.push_back({0, 10, 0}); 159d6f906eaSJay Foad simple_ilist<IndexListEntry> IndexList; 16065b40f27SMatt Arsenault auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList); 16165b40f27SMatt Arsenault ASSERT_TRUE(OverlapProblem[0].Begin.isValid()); 16265b40f27SMatt Arsenault ASSERT_TRUE(OverlapProblem[0].End.isValid()); 16365b40f27SMatt Arsenault } 16465b40f27SMatt Arsenault 16565b40f27SMatt Arsenault // Testing of feature extraction for per-instruction features 16665b40f27SMatt Arsenault 16765b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, InstructionOpcodesAreCorrect) { 16865b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 1> OverlapSetup; 16965b40f27SMatt Arsenault OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0}); 170d6f906eaSJay Foad simple_ilist<IndexListEntry> IndexList; 17165b40f27SMatt Arsenault auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList); 17265b40f27SMatt Arsenault NoInferenceModelRunner ModelRunner = setupModelRunner(); 17365b40f27SMatt Arsenault SlotIndex LastIndex = OverlapProblem[0].End; 17465b40f27SMatt Arsenault SlotIndex FirstIndex = OverlapProblem[0].Begin; 17565b40f27SMatt Arsenault extractInstructionFeatures( 17665b40f27SMatt Arsenault OverlapProblem, &ModelRunner, 17765b40f27SMatt Arsenault [FirstIndex](SlotIndex InputSlot) -> int { 17865b40f27SMatt Arsenault return FirstIndex.distance(InputSlot) / SlotIndex::InstrDist; 17965b40f27SMatt Arsenault }, 18065b40f27SMatt Arsenault [](SlotIndex InputSlot) -> float { return 0.0f; }, 18165b40f27SMatt Arsenault [](SlotIndex InputSlot) -> MachineBasicBlock * { return nullptr; }, 0, 1, 18265b40f27SMatt Arsenault 2, 3, LastIndex); 18365b40f27SMatt Arsenault for (size_t CurrentInstructionIndex = 0; 18465b40f27SMatt Arsenault CurrentInstructionIndex < ModelMaxSupportedInstructionCount; 18565b40f27SMatt Arsenault ++CurrentInstructionIndex) { 18665b40f27SMatt Arsenault ASSERT_EQ( 18765b40f27SMatt Arsenault (size_t)ModelRunner.getTensor<int64_t>(0)[CurrentInstructionIndex], 18865b40f27SMatt Arsenault CurrentInstructionIndex); 18965b40f27SMatt Arsenault } 19065b40f27SMatt Arsenault } 19165b40f27SMatt Arsenault 19265b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, FullOverlap) { 19365b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 2> OverlapSetup; 19465b40f27SMatt Arsenault OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0}); 19565b40f27SMatt Arsenault OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 1}); 19665b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 19765b40f27SMatt Arsenault } 19865b40f27SMatt Arsenault 19965b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, PartialOverlap) { 20065b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 2> OverlapSetup; 20165b40f27SMatt Arsenault OverlapSetup.push_back({0, 20, 0}); 20265b40f27SMatt Arsenault OverlapSetup.push_back({15, 30, 1}); 20365b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 20465b40f27SMatt Arsenault } 20565b40f27SMatt Arsenault 20665b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, PartialOverlapOpposite) { 20765b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 2> OverlapSetup; 20865b40f27SMatt Arsenault OverlapSetup.push_back({15, 30, 1}); 20965b40f27SMatt Arsenault OverlapSetup.push_back({0, 20, 0}); 21065b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 21165b40f27SMatt Arsenault } 21265b40f27SMatt Arsenault 21365b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, InternalOverlap) { 21465b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 2> OverlapSetup; 21565b40f27SMatt Arsenault OverlapSetup.push_back({0, 30, 0}); 21665b40f27SMatt Arsenault OverlapSetup.push_back({10, 20, 1}); 21765b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 21865b40f27SMatt Arsenault } 21965b40f27SMatt Arsenault 22065b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, TripleInternalOverlap) { 22165b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 3> OverlapSetup; 22265b40f27SMatt Arsenault OverlapSetup.push_back({0, 30, 0}); 22365b40f27SMatt Arsenault OverlapSetup.push_back({10, 25, 1}); 22465b40f27SMatt Arsenault OverlapSetup.push_back({15, 20, 2}); 22565b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 22665b40f27SMatt Arsenault } 22765b40f27SMatt Arsenault 22865b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, InternalMultiOverlap) { 22965b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 3> OverlapSetup; 23065b40f27SMatt Arsenault OverlapSetup.push_back({0, 45, 0}); 23165b40f27SMatt Arsenault OverlapSetup.push_back({30, 40, 1}); 23265b40f27SMatt Arsenault OverlapSetup.push_back({35, 60, 2}); 23365b40f27SMatt Arsenault runOverlapTest(OverlapSetup); 23465b40f27SMatt Arsenault } 23565b40f27SMatt Arsenault 23665b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, SingleMBBTest) { 23765b40f27SMatt Arsenault NoInferenceModelRunner ModelRunner = setupModelRunner(); 23865b40f27SMatt Arsenault SlotIndex CurrentIndex; 23965b40f27SMatt Arsenault // set index to 1 so we can ensure that the mapping actually get set 24065b40f27SMatt Arsenault std::map<MachineBasicBlock *, size_t> VisitedMBBs = {{nullptr, 1}}; 24165b40f27SMatt Arsenault extractMBBFrequency( 24265b40f27SMatt Arsenault CurrentIndex, 0, VisitedMBBs, 24365b40f27SMatt Arsenault [](SlotIndex InputSlot) -> float { return 1.0f; }, nullptr, &ModelRunner, 24465b40f27SMatt Arsenault 2, 3); 24565b40f27SMatt Arsenault ASSERT_FLOAT_EQ(ModelRunner.getTensor<float>(2)[1], 1.0f); 24665b40f27SMatt Arsenault ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[0], 1); 24765b40f27SMatt Arsenault } 24865b40f27SMatt Arsenault 24965b40f27SMatt Arsenault TEST_F(RegAllocDevelopmentFeaturesTest, MBBFullTruncated) { 25065b40f27SMatt Arsenault SmallVector<LRPosInfoIndexes, 1> OverlapSetup; 25165b40f27SMatt Arsenault OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0}); 252d6f906eaSJay Foad simple_ilist<IndexListEntry> IndexList; 25365b40f27SMatt Arsenault auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList); 25465b40f27SMatt Arsenault NoInferenceModelRunner ModelRunner = setupModelRunner(); 25565b40f27SMatt Arsenault SlotIndex LastIndex = OverlapProblem[0].End; 25665b40f27SMatt Arsenault SlotIndex FirstIndex = OverlapProblem[0].Begin; 25765b40f27SMatt Arsenault 25865b40f27SMatt Arsenault LLVMContext Ctx; 25965b40f27SMatt Arsenault Module Mod("Module", Ctx); 26065b40f27SMatt Arsenault auto MF = createMachineFunction(Ctx, Mod); 26165b40f27SMatt Arsenault std::array<MachineBasicBlock *, ModelMaxSupportedInstructionCount> 26265b40f27SMatt Arsenault MBBsForTest; 26365b40f27SMatt Arsenault for (size_t I = 0; I < ModelMaxSupportedInstructionCount; ++I) { 26465b40f27SMatt Arsenault MBBsForTest[I] = MF->CreateMachineBasicBlock(); 26565b40f27SMatt Arsenault } 26665b40f27SMatt Arsenault 26765b40f27SMatt Arsenault extractInstructionFeatures( 26865b40f27SMatt Arsenault OverlapProblem, &ModelRunner, 26965b40f27SMatt Arsenault [](SlotIndex InputSlot) -> int { return 0; }, 27065b40f27SMatt Arsenault [FirstIndex](SlotIndex InputSlot) -> float { 27165b40f27SMatt Arsenault return static_cast<float>(FirstIndex.distance(InputSlot) / 27265b40f27SMatt Arsenault SlotIndex::InstrDist); 27365b40f27SMatt Arsenault }, 27465b40f27SMatt Arsenault [FirstIndex, MBBsForTest](SlotIndex InputSlot) -> MachineBasicBlock * { 27565b40f27SMatt Arsenault return MBBsForTest[FirstIndex.distance(InputSlot) / 27665b40f27SMatt Arsenault SlotIndex::InstrDist]; 27765b40f27SMatt Arsenault }, 27865b40f27SMatt Arsenault 0, 1, 2, 3, LastIndex); 27965b40f27SMatt Arsenault for (size_t MBBIndex = 0; MBBIndex < ModelMaxSupportedMBBCount; ++MBBIndex) { 28065b40f27SMatt Arsenault ASSERT_FLOAT_EQ(ModelRunner.getTensor<float>(2)[MBBIndex], 28165b40f27SMatt Arsenault static_cast<float>(MBBIndex)); 28265b40f27SMatt Arsenault ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[MBBIndex], 28365b40f27SMatt Arsenault static_cast<int64_t>(MBBIndex)); 28465b40f27SMatt Arsenault } 28565b40f27SMatt Arsenault // the rest of the mapping values should be zero (truncated to 100 MBBs) 28665b40f27SMatt Arsenault for (size_t MBBIndex = ModelMaxSupportedMBBCount; 28765b40f27SMatt Arsenault MBBIndex < ModelMaxSupportedInstructionCount; ++MBBIndex) { 28865b40f27SMatt Arsenault ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[MBBIndex], 28965b40f27SMatt Arsenault static_cast<int64_t>(0)); 29065b40f27SMatt Arsenault } 29165b40f27SMatt Arsenault } 29265b40f27SMatt Arsenault 29365b40f27SMatt Arsenault } // end namespace 294