292 lines
11 KiB
C++
292 lines
11 KiB
C++
//===- MLRegAllocDevelopmentFeatures.cpp - test dev MLRegalloc features ---===//
|
|
//
|
|
// 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 "../../lib/CodeGen/MLRegallocEvictAdvisor.h"
|
|
#include "llvm/ADT/Triple.h"
|
|
#include "llvm/Analysis/NoInferenceModelRunner.h"
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/CodeGen/SlotIndexes.h"
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
#include "llvm/CodeGen/TargetLowering.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include "llvm/Support/Allocator.h"
|
|
#include "llvm/Support/CodeGen.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using testing::ContainerEq;
|
|
using testing::Test;
|
|
|
|
namespace {
|
|
|
|
#include "MFCommon.inc"
|
|
|
|
struct LRPosInfoIndexes {
|
|
size_t StartIndex;
|
|
size_t EndIndex;
|
|
size_t PhysReg;
|
|
};
|
|
|
|
class RegallocDevelopmentFeaturesTest : public ::Test {
|
|
protected:
|
|
SmallVector<LRStartEndInfo>
|
|
setupOverlapProblem(const SmallVectorImpl<LRPosInfoIndexes> &Segments,
|
|
ilist<IndexListEntry> &IndexList) {
|
|
SmallVector<LRStartEndInfo> PositionsToReturn;
|
|
PositionsToReturn.reserve(Segments.size());
|
|
for (auto CurrentPosIndexInfo : Segments) {
|
|
LRStartEndInfo CurrentPosInfo = {};
|
|
CurrentPosInfo.Pos = CurrentPosIndexInfo.PhysReg;
|
|
PositionsToReturn.push_back(CurrentPosInfo);
|
|
}
|
|
size_t CurrentSegmentIndex = 0;
|
|
size_t CurrentIndex = 0;
|
|
while (CurrentSegmentIndex < Segments.size()) {
|
|
auto *CurrentLEMem = static_cast<IndexListEntry *>(
|
|
Allocator.Allocate(sizeof(IndexListEntry), alignof(IndexListEntry)));
|
|
auto *CurrentListEntry =
|
|
new (CurrentLEMem) IndexListEntry(nullptr, CurrentIndex);
|
|
IndexList.push_back(CurrentListEntry);
|
|
for (size_t CurrentPosInfoIndex = 0;
|
|
CurrentPosInfoIndex < Segments.size(); ++CurrentPosInfoIndex) {
|
|
if ((CurrentIndex / SlotIndex::InstrDist) ==
|
|
Segments[CurrentPosInfoIndex].StartIndex) {
|
|
PositionsToReturn[CurrentPosInfoIndex].Begin =
|
|
SlotIndex(CurrentListEntry, 0);
|
|
} else if ((CurrentIndex / SlotIndex::InstrDist) ==
|
|
Segments[CurrentPosInfoIndex].EndIndex) {
|
|
PositionsToReturn[CurrentPosInfoIndex].End =
|
|
SlotIndex(CurrentListEntry, 0);
|
|
++CurrentSegmentIndex;
|
|
}
|
|
}
|
|
CurrentIndex += SlotIndex::InstrDist;
|
|
}
|
|
return PositionsToReturn;
|
|
}
|
|
|
|
NoInferenceModelRunner setupModelRunner() {
|
|
const std::vector<TensorSpec> Inputs{
|
|
TensorSpec::createSpec<int64_t>("instructions", InstructionsShape),
|
|
TensorSpec::createSpec<int64_t>("instructions_mapping",
|
|
InstructionsMappingShape),
|
|
TensorSpec::createSpec<float>("mbb_frequencies", MBBFrequencyShape),
|
|
TensorSpec::createSpec<int64_t>("mbb_mapping", InstructionsShape)};
|
|
LLVMContext Ctx;
|
|
return NoInferenceModelRunner(Ctx, Inputs);
|
|
}
|
|
|
|
std::vector<int64_t>
|
|
getExpectedMappingMatrix(SmallVectorImpl<LRPosInfoIndexes> &OverlapSetup) {
|
|
std::vector<int64_t> ExpectedMappingMatrix(
|
|
NumberOfInterferences * ModelMaxSupportedInstructionCount, 0);
|
|
for (auto NewSegment : OverlapSetup) {
|
|
for (size_t CurrentIndex = NewSegment.StartIndex;
|
|
CurrentIndex <= NewSegment.EndIndex; ++CurrentIndex) {
|
|
ExpectedMappingMatrix[NewSegment.PhysReg *
|
|
ModelMaxSupportedInstructionCount +
|
|
CurrentIndex] = 1;
|
|
}
|
|
}
|
|
return ExpectedMappingMatrix;
|
|
}
|
|
|
|
void runOverlapTest(SmallVectorImpl<LRPosInfoIndexes> &OverlapSetup) {
|
|
ilist<IndexListEntry> IndexList;
|
|
auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList);
|
|
NoInferenceModelRunner ModelRunner = setupModelRunner();
|
|
size_t MaxIndex = 0;
|
|
for (size_t CurrentOverlap = 0; CurrentOverlap < OverlapSetup.size();
|
|
++CurrentOverlap) {
|
|
if (OverlapSetup[CurrentOverlap].EndIndex >
|
|
OverlapSetup[MaxIndex].EndIndex) {
|
|
MaxIndex = CurrentOverlap;
|
|
}
|
|
}
|
|
SlotIndex LastIndex = OverlapProblem[MaxIndex].End;
|
|
extractInstructionFeatures(
|
|
OverlapProblem, &ModelRunner,
|
|
[](SlotIndex InputSlot) -> int { return 0; },
|
|
[](SlotIndex InputSlot) -> float { return 0.0f; },
|
|
[](SlotIndex InputSlot) -> MachineBasicBlock * { return nullptr; }, 0,
|
|
1, 2, 3, LastIndex);
|
|
std::vector<int64_t> MappingMatrix(
|
|
ModelRunner.getTensor<int64_t>(1),
|
|
ModelRunner.getTensor<int64_t>(1) +
|
|
NumberOfInterferences * ModelMaxSupportedInstructionCount);
|
|
ASSERT_THAT(MappingMatrix,
|
|
ContainerEq(getExpectedMappingMatrix(OverlapSetup)));
|
|
IndexList.clearAndLeakNodesUnsafely();
|
|
}
|
|
|
|
BumpPtrAllocator Allocator;
|
|
};
|
|
|
|
// meta tests to ensure that test setup works correctly
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest,
|
|
MetaOverlapInstructionDistancesAreCorrect) {
|
|
SmallVector<LRPosInfoIndexes, 2> OverlapSetup;
|
|
OverlapSetup.push_back({0, 5, 0});
|
|
OverlapSetup.push_back({5, 10, 0});
|
|
ilist<IndexListEntry> IndexList;
|
|
auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList);
|
|
ASSERT_EQ(OverlapProblem[0].End.distance(OverlapProblem[1].End),
|
|
5 * SlotIndex::InstrDist);
|
|
ASSERT_EQ(OverlapProblem[0].End.distance(OverlapProblem[1].Begin), 0);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, MetaSlotIndicesAreValid) {
|
|
SmallVector<LRPosInfoIndexes, 1> OverlapSetup;
|
|
OverlapSetup.push_back({0, 10, 0});
|
|
ilist<IndexListEntry> IndexList;
|
|
auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList);
|
|
ASSERT_TRUE(OverlapProblem[0].Begin.isValid());
|
|
ASSERT_TRUE(OverlapProblem[0].End.isValid());
|
|
}
|
|
|
|
// Testing of feature extraction for per-instruction features
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, InstructionOpcodesAreCorrect) {
|
|
SmallVector<LRPosInfoIndexes, 1> OverlapSetup;
|
|
OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0});
|
|
ilist<IndexListEntry> IndexList;
|
|
auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList);
|
|
NoInferenceModelRunner ModelRunner = setupModelRunner();
|
|
SlotIndex LastIndex = OverlapProblem[0].End;
|
|
SlotIndex FirstIndex = OverlapProblem[0].Begin;
|
|
extractInstructionFeatures(
|
|
OverlapProblem, &ModelRunner,
|
|
[FirstIndex](SlotIndex InputSlot) -> int {
|
|
return FirstIndex.distance(InputSlot) / SlotIndex::InstrDist;
|
|
},
|
|
[](SlotIndex InputSlot) -> float { return 0.0f; },
|
|
[](SlotIndex InputSlot) -> MachineBasicBlock * { return nullptr; }, 0, 1,
|
|
2, 3, LastIndex);
|
|
for (size_t CurrentInstructionIndex = 0;
|
|
CurrentInstructionIndex < ModelMaxSupportedInstructionCount;
|
|
++CurrentInstructionIndex) {
|
|
ASSERT_EQ(
|
|
(size_t)ModelRunner.getTensor<int64_t>(0)[CurrentInstructionIndex],
|
|
CurrentInstructionIndex);
|
|
}
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, FullOverlap) {
|
|
SmallVector<LRPosInfoIndexes, 2> OverlapSetup;
|
|
OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0});
|
|
OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 1});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, PartialOverlap) {
|
|
SmallVector<LRPosInfoIndexes, 2> OverlapSetup;
|
|
OverlapSetup.push_back({0, 20, 0});
|
|
OverlapSetup.push_back({15, 30, 1});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, PartialOverlapOpposite) {
|
|
SmallVector<LRPosInfoIndexes, 2> OverlapSetup;
|
|
OverlapSetup.push_back({15, 30, 1});
|
|
OverlapSetup.push_back({0, 20, 0});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, InternalOverlap) {
|
|
SmallVector<LRPosInfoIndexes, 2> OverlapSetup;
|
|
OverlapSetup.push_back({0, 30, 0});
|
|
OverlapSetup.push_back({10, 20, 1});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, TripleInternalOverlap) {
|
|
SmallVector<LRPosInfoIndexes, 3> OverlapSetup;
|
|
OverlapSetup.push_back({0, 30, 0});
|
|
OverlapSetup.push_back({10, 25, 1});
|
|
OverlapSetup.push_back({15, 20, 2});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, InternalMultiOverlap) {
|
|
SmallVector<LRPosInfoIndexes, 3> OverlapSetup;
|
|
OverlapSetup.push_back({0, 45, 0});
|
|
OverlapSetup.push_back({30, 40, 1});
|
|
OverlapSetup.push_back({35, 60, 2});
|
|
runOverlapTest(OverlapSetup);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, SingleMBBTest) {
|
|
NoInferenceModelRunner ModelRunner = setupModelRunner();
|
|
SlotIndex CurrentIndex;
|
|
// set index to 1 so we can ensure that the mapping actually get set
|
|
std::map<MachineBasicBlock *, size_t> VisitedMBBs = {{nullptr, 1}};
|
|
extractMBBFrequency(
|
|
CurrentIndex, 0, VisitedMBBs,
|
|
[](SlotIndex InputSlot) -> float { return 1.0f; }, nullptr, &ModelRunner,
|
|
2, 3);
|
|
ASSERT_FLOAT_EQ(ModelRunner.getTensor<float>(2)[1], 1.0f);
|
|
ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[0], 1);
|
|
}
|
|
|
|
TEST_F(RegallocDevelopmentFeaturesTest, MBBFullTruncated) {
|
|
SmallVector<LRPosInfoIndexes, 1> OverlapSetup;
|
|
OverlapSetup.push_back({0, ModelMaxSupportedInstructionCount - 1, 0});
|
|
ilist<IndexListEntry> IndexList;
|
|
auto OverlapProblem = setupOverlapProblem(OverlapSetup, IndexList);
|
|
NoInferenceModelRunner ModelRunner = setupModelRunner();
|
|
SlotIndex LastIndex = OverlapProblem[0].End;
|
|
SlotIndex FirstIndex = OverlapProblem[0].Begin;
|
|
|
|
LLVMContext Ctx;
|
|
Module Mod("Module", Ctx);
|
|
auto MF = createMachineFunction(Ctx, Mod);
|
|
std::array<MachineBasicBlock *, ModelMaxSupportedInstructionCount>
|
|
MBBsForTest;
|
|
for (size_t I = 0; I < ModelMaxSupportedInstructionCount; ++I) {
|
|
MBBsForTest[I] = MF->CreateMachineBasicBlock();
|
|
}
|
|
|
|
extractInstructionFeatures(
|
|
OverlapProblem, &ModelRunner,
|
|
[](SlotIndex InputSlot) -> int { return 0; },
|
|
[FirstIndex](SlotIndex InputSlot) -> float {
|
|
return static_cast<float>(FirstIndex.distance(InputSlot) /
|
|
SlotIndex::InstrDist);
|
|
},
|
|
[FirstIndex, MBBsForTest](SlotIndex InputSlot) -> MachineBasicBlock * {
|
|
return MBBsForTest[FirstIndex.distance(InputSlot) /
|
|
SlotIndex::InstrDist];
|
|
},
|
|
0, 1, 2, 3, LastIndex);
|
|
for (size_t MBBIndex = 0; MBBIndex < ModelMaxSupportedMBBCount; ++MBBIndex) {
|
|
ASSERT_FLOAT_EQ(ModelRunner.getTensor<float>(2)[MBBIndex],
|
|
static_cast<float>(MBBIndex));
|
|
ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[MBBIndex],
|
|
static_cast<int64_t>(MBBIndex));
|
|
}
|
|
// the rest of the mapping values should be zero (truncated to 100 MBBs)
|
|
for (size_t MBBIndex = ModelMaxSupportedMBBCount;
|
|
MBBIndex < ModelMaxSupportedInstructionCount; ++MBBIndex) {
|
|
ASSERT_EQ(ModelRunner.getTensor<int64_t>(3)[MBBIndex],
|
|
static_cast<int64_t>(0));
|
|
}
|
|
}
|
|
|
|
} // end namespace
|