[llvm] d9eebe3 - [DebugInfo][InstrRef] Add unit tests for transfer-function building
Jeremy Morse via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 22 10:29:27 PDT 2021
Author: Jeremy Morse
Date: 2021-10-22T18:29:03+01:00
New Revision: d9eebe3cd7832b69471b27e68f0ee6f1374ed759
URL: https://github.com/llvm/llvm-project/commit/d9eebe3cd7832b69471b27e68f0ee6f1374ed759
DIFF: https://github.com/llvm/llvm-project/commit/d9eebe3cd7832b69471b27e68f0ee6f1374ed759.diff
LOG: [DebugInfo][InstrRef] Add unit tests for transfer-function building
This patch adds some unit tests for the machine-location transfer-function
building parts of InstrRefBasedLDV: i.e., test that if we feed some MIR
into the transfer-function building code, does it create the correct
transfer function.
There are a number of minor defects that get corrected in the process:
* The unit test was selecting the x86 (i.e. 32 bit) backend rather than
x86_64's 64 bit backend,
* COPY instructions weren't actually having their subregister values
correctly represented in the transfer function. Subregisters were being
defined by the COPY, rather than taking the value in the source register.
* SP aliases were at risk of being clobbered, if an SP subregister was
clobbered.
Differential Revision: https://reviews.llvm.org/D112006
Added:
Modified:
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
llvm/unittests/CodeGen/InstrRefLDVTest.cpp
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
index d286aa903547..4f151d721f1d 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
@@ -362,7 +362,7 @@ class TransferTracker {
// instruction or similar with an instruction number, where it doesn't
// actually define a new value, instead it moves a value. In case this
// happens, discard.
- if (MTracker->LocIdxToIDNum[L] != Use.ID)
+ if (MTracker->readMLoc(L) != Use.ID)
continue;
// If a
diff erent debug instruction defined the variable value / location
@@ -493,12 +493,12 @@ class TransferTracker {
// Check whether our local copy of values-by-location in #VarLocs is out of
// date. Wipe old tracking data for the location if it's been clobbered in
// the meantime.
- if (MTracker->getNumAtPos(NewLoc) != VarLocs[NewLoc.asU64()]) {
+ if (MTracker->readMLoc(NewLoc) != VarLocs[NewLoc.asU64()]) {
for (auto &P : ActiveMLocs[NewLoc]) {
ActiveVLocs.erase(P);
}
ActiveMLocs[NewLoc.asU64()].clear();
- VarLocs[NewLoc.asU64()] = MTracker->getNumAtPos(NewLoc);
+ VarLocs[NewLoc.asU64()] = MTracker->readMLoc(NewLoc);
}
ActiveMLocs[NewLoc].insert(Var);
@@ -586,7 +586,7 @@ class TransferTracker {
void transferMlocs(LocIdx Src, LocIdx Dst, MachineBasicBlock::iterator Pos) {
// Does Src still contain the value num we expect? If not, it's been
// clobbered in the meantime, and our variable locations are stale.
- if (VarLocs[Src.asU64()] != MTracker->getNumAtPos(Src))
+ if (VarLocs[Src.asU64()] != MTracker->readMLoc(Src))
return;
// assert(ActiveMLocs[Dst].size() == 0);
@@ -1066,7 +1066,7 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI,
Optional<LocIdx> FoundLoc = None;
for (auto Location : MTracker->locations()) {
LocIdx CurL = Location.Idx;
- ValueIDNum ID = MTracker->LocIdxToIDNum[CurL];
+ ValueIDNum ID = MTracker->readMLoc(CurL);
if (NewID && ID == NewID) {
// If this is the first location with that value, pick it. Otherwise,
// consider whether it's a "longer term" location.
@@ -1176,10 +1176,6 @@ void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) {
} else if (MI.isMetaInstruction())
return;
- MachineFunction *MF = MI.getMF();
- const TargetLowering *TLI = MF->getSubtarget().getTargetLowering();
- Register SP = TLI->getStackPointerRegisterToSaveRestore();
-
// Find the regs killed by MI, and find regmasks of preserved regs.
// Max out the number of statically allocated elements in `DeadRegs`, as this
// prevents fallback to std::set::count() operations.
@@ -1190,7 +1186,7 @@ void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) {
// Determine whether the operand is a register def.
if (MO.isReg() && MO.isDef() && MO.getReg() &&
Register::isPhysicalRegister(MO.getReg()) &&
- !(MI.isCall() && MO.getReg() == SP)) {
+ !(MI.isCall() && MTracker->SPAliases.count(MO.getReg()))) {
// Remove ranges of all aliased registers.
for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI)
// FIXME: Can we break out of this loop early if no insertion occurs?
@@ -1236,29 +1232,14 @@ void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) {
}
void InstrRefBasedLDV::performCopy(Register SrcRegNum, Register DstRegNum) {
- ValueIDNum SrcValue = MTracker->readReg(SrcRegNum);
+ // In all circumstances, re-def all aliases. It's definitely a new value now.
+ for (MCRegAliasIterator RAI(DstRegNum, TRI, true); RAI.isValid(); ++RAI)
+ MTracker->defReg(*RAI, CurBB, CurInst);
+ ValueIDNum SrcValue = MTracker->readReg(SrcRegNum);
MTracker->setReg(DstRegNum, SrcValue);
- // In all circumstances, re-def the super registers. It's definitely a new
- // value now. This doesn't uniquely identify the composition of subregs, for
- // example, two identical values in subregisters composed in
diff erent
- // places would not get equal value numbers.
- for (MCSuperRegIterator SRI(DstRegNum, TRI); SRI.isValid(); ++SRI)
- MTracker->defReg(*SRI, CurBB, CurInst);
-
- // If we're emulating VarLocBasedImpl, just define all the subregisters.
- // DBG_VALUEs of them will expect to be tracked from the DBG_VALUE, not
- // through prior copies.
- if (EmulateOldLDV) {
- for (MCSubRegIndexIterator DRI(DstRegNum, TRI); DRI.isValid(); ++DRI)
- MTracker->defReg(DRI.getSubReg(), CurBB, CurInst);
- return;
- }
-
- // Otherwise, actually copy subregisters from one location to another.
- // XXX: in addition, any subregisters of DstRegNum that don't line up with
- // the source register should be def'd.
+ // Copy subregisters from one location to another.
for (MCSubRegIndexIterator SRI(SrcRegNum, TRI); SRI.isValid(); ++SRI) {
unsigned SrcSubReg = SRI.getSubReg();
unsigned SubRegIdx = SRI.getSubRegIndex();
@@ -1269,15 +1250,13 @@ void InstrRefBasedLDV::performCopy(Register SrcRegNum, Register DstRegNum) {
// Do copy. There are two matching subregisters, the source value should
// have been def'd when the super-reg was, the latter might not be tracked
// yet.
- // This will force SrcSubReg to be tracked, if it isn't yet.
- (void)MTracker->readReg(SrcSubReg);
- LocIdx SrcL = MTracker->getRegMLoc(SrcSubReg);
- assert(SrcL.asU64());
- (void)MTracker->readReg(DstSubReg);
- LocIdx DstL = MTracker->getRegMLoc(DstSubReg);
- assert(DstL.asU64());
+ // This will force SrcSubReg to be tracked, if it isn't yet. Will read
+ // mphi values if it wasn't tracked.
+ LocIdx SrcL = MTracker->lookupOrTrackRegister(SrcSubReg);
+ LocIdx DstL = MTracker->lookupOrTrackRegister(DstSubReg);
+ (void)SrcL;
(void)DstL;
- ValueIDNum CpyValue = {SrcValue.getBlock(), SrcValue.getInst(), SrcL};
+ ValueIDNum CpyValue = MTracker->readReg(SrcSubReg);
MTracker->setReg(DstSubReg, CpyValue);
}
@@ -1911,7 +1890,7 @@ void InstrRefBasedLDV::buildMLocValueMap(
for (auto &P : MLocTransfer[CurBB]) {
if (P.second.getBlock() == CurBB && P.second.isPHI()) {
// This is a movement of whatever was live in. Read it.
- ValueIDNum NewID = MTracker->getNumAtPos(P.second.getLoc());
+ ValueIDNum NewID = MTracker->readMLoc(P.second.getLoc());
ToRemap.push_back(std::make_pair(P.first, NewID));
} else {
// It's a def. Just set it.
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
index 0de8ed5fc352..b211154489f4 100644
--- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
+++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h
@@ -380,12 +380,6 @@ class MLocTracker {
return (isSpill) ? RegOrSpill.id() + NumRegs - 1 : RegOrSpill.id();
}
- /// Accessor for reading the value at Idx.
- ValueIDNum getNumAtPos(LocIdx Idx) const {
- assert(Idx.asU64() < LocIdxToIDNum.size());
- return LocIdxToIDNum[Idx];
- }
-
unsigned getNumLocs(void) const { return LocIdxToIDNum.size(); }
/// Reset all locations to contain a PHI value at the designated block. Used
@@ -435,6 +429,12 @@ class MLocTracker {
LocIdxToIDNum[L] = Num;
}
+ /// Read the value of a particular location
+ ValueIDNum readMLoc(LocIdx L) {
+ assert(L.asU64() < LocIdxToIDNum.size());
+ return LocIdxToIDNum[L];
+ }
+
/// Create a LocIdx for an untracked register ID. Initialize it to either an
/// mphi value representing a live-in, or a recent register mask clobber.
LocIdx trackRegister(unsigned ID);
@@ -664,7 +664,7 @@ class InstrRefBasedLDV : public LDVImpl {
/// Object to track machine locations as we step through a block. Could
/// probably be a field rather than a pointer, as it's always used.
- MLocTracker *MTracker;
+ MLocTracker *MTracker = nullptr;
/// Number of the current block LiveDebugValues is stepping through.
unsigned CurBB;
@@ -675,12 +675,12 @@ class InstrRefBasedLDV : public LDVImpl {
/// Variable tracker -- listens to DBG_VALUEs occurring as InstrRefBasedImpl
/// steps through a block. Reads the values at each location from the
/// MLocTracker object.
- VLocTracker *VTracker;
+ VLocTracker *VTracker = nullptr;
/// Tracker for transfers, listens to DBG_VALUEs and transfers of values
/// between locations during stepping, creates new DBG_VALUEs when values move
/// location.
- TransferTracker *TTracker;
+ TransferTracker *TTracker = nullptr;
/// Blocks which are artificial, i.e. blocks which exclusively contain
/// instructions without DebugLocs, or with line 0 locations.
diff --git a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
index c6420b5b5a02..79043205112d 100644
--- a/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
+++ b/llvm/unittests/CodeGen/InstrRefLDVTest.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
@@ -13,6 +14,7 @@
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -33,10 +35,11 @@ class InstrRefLDVTest : public testing::Test {
using MLocTransferMap = InstrRefBasedLDV::MLocTransferMap;
LLVMContext Ctx;
- Module Mod;
+ std::unique_ptr<Module> Mod;
std::unique_ptr<TargetMachine> Machine;
std::unique_ptr<MachineFunction> MF;
std::unique_ptr<MachineDominatorTree> DomTree;
+ std::unique_ptr<MachineModuleInfo> MMI;
DICompileUnit *OurCU;
DIFile *OurFile;
DISubprogram *OurFunc;
@@ -55,13 +58,15 @@ class InstrRefLDVTest : public testing::Test {
std::unique_ptr<MLocTracker> MTracker;
std::unique_ptr<VLocTracker> VTracker;
- InstrRefLDVTest() : Ctx(), Mod("beehives", Ctx) {
- }
+ SmallString<256> MIRStr;
+
+ InstrRefLDVTest() : Ctx(), Mod(std::make_unique<Module>("beehives", Ctx)) {}
void SetUp() {
// Boilerplate that creates a MachineFunction and associated blocks.
- Mod.setDataLayout("e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128");
+ Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-"
+ "n8:16:32:64-S128");
Triple TargetTriple("x86_64--");
std::string Error;
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
@@ -69,21 +74,24 @@ class InstrRefLDVTest : public testing::Test {
GTEST_SKIP();
TargetOptions Options;
- Machine = std::unique_ptr<TargetMachine>(T->createTargetMachine(
- "X86", "", "", Options, None, None, CodeGenOpt::Aggressive));
+ Machine = std::unique_ptr<TargetMachine>(
+ T->createTargetMachine(Triple::normalize("x86_64--"), "", "", Options,
+ None, None, CodeGenOpt::Aggressive));
auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
- auto F = Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &Mod);
+ auto F =
+ Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &*Mod);
unsigned FunctionNum = 42;
- MachineModuleInfo MMI((LLVMTargetMachine*)&*Machine);
+ MMI = std::make_unique<MachineModuleInfo>((LLVMTargetMachine *)&*Machine);
const TargetSubtargetInfo &STI = *Machine->getSubtargetImpl(*F);
- MF = std::make_unique<MachineFunction>(*F, (LLVMTargetMachine&)*Machine, STI, FunctionNum, MMI);
+ MF = std::make_unique<MachineFunction>(*F, (LLVMTargetMachine &)*Machine,
+ STI, FunctionNum, *MMI);
// Create metadata: CU, subprogram, some blocks and an inline function
// scope.
- DIBuilder DIB(Mod);
+ DIBuilder DIB(*Mod);
OurFile = DIB.createFile("xyzzy.c", "/cave");
OurCU =
DIB.createCompileUnit(dwarf::DW_LANG_C99, OurFile, "nou", false, "", 0);
@@ -126,7 +134,7 @@ class InstrRefLDVTest : public testing::Test {
llvm_unreachable("Can't find register by name");
}
- InstrRefBasedLDV *setupLDVObj() {
+ InstrRefBasedLDV *setupLDVObj(MachineFunction *MF) {
// Create a new LDV object, and plug some relevant object ptrs into it.
LDV = std::make_unique<InstrRefBasedLDV>();
const TargetSubtargetInfo &STI = MF->getSubtarget();
@@ -144,12 +152,11 @@ class InstrRefLDVTest : public testing::Test {
// mappings.
LDV->initialSetup(*MF);
LDV->LS.initialize(*MF);
- addMTracker();
- addVTracker();
+ addMTracker(MF);
return &*LDV;
}
- void addMTracker() {
+ void addMTracker(MachineFunction *MF) {
ASSERT_TRUE(LDV);
// Add a machine-location-tracking object to LDV. Don't initialize any
// register locations within it though.
@@ -212,7 +219,7 @@ class InstrRefLDVTest : public testing::Test {
MF->insert(MF->end(), MBB0);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
}
void setupDiamondBlocks() {
@@ -245,7 +252,7 @@ class InstrRefLDVTest : public testing::Test {
MBB2->addSuccessor(MBB3);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
}
void setupSimpleLoop() {
@@ -275,7 +282,7 @@ class InstrRefLDVTest : public testing::Test {
MBB1->addSuccessor(MBB1);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
}
void setupNestedLoops() {
@@ -320,7 +327,7 @@ class InstrRefLDVTest : public testing::Test {
MBB3->addSuccessor(MBB4);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
}
void setupNoDominatingLoop() {
@@ -365,7 +372,7 @@ class InstrRefLDVTest : public testing::Test {
MBB3->addSuccessor(MBB4);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
}
void setupBadlyNestedLoops() {
@@ -416,10 +423,307 @@ class InstrRefLDVTest : public testing::Test {
MBB3->addSuccessor(MBB4);
MF->RenumberBlocks();
- setupLDVObj();
+ setupLDVObj(&*MF);
+ }
+
+ MachineFunction *readMIRBlock(const char *Input) {
+ MIRStr.clear();
+ StringRef S = Twine(Twine(R"MIR(
+--- |
+ target triple = "x86_64-unknown-linux-gnu"
+ define void @test() { ret void }
+...
+---
+name: test
+tracksRegLiveness: true
+stack:
+ - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
+ stack-id: default, callee-saved-register: '', callee-saved-restored: true,
+ debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
+body: |
+ bb.0:
+ liveins: $rdi, $rsi
+)MIR") + Twine(Input) + Twine("...\n"))
+ .toNullTerminatedStringRef(MIRStr);
+ ;
+
+ // Clear the "test" function from MMI if it's still present.
+ if (Function *Fn = Mod->getFunction("test"))
+ MMI->deleteMachineFunctionFor(*Fn);
+
+ auto MemBuf = MemoryBuffer::getMemBuffer(S, "<input>");
+ auto MIRParse = createMIRParser(std::move(MemBuf), Ctx);
+ Mod = MIRParse->parseIRModule();
+ assert(Mod);
+ Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-"
+ "n8:16:32:64-S128");
+
+ bool Result = MIRParse->parseMachineFunctions(*Mod, *MMI);
+ assert(!Result && "Failed to parse unit test machine function?");
+ (void)Result;
+
+ Function *Fn = Mod->getFunction("test");
+ assert(Fn && "Failed to parse a unit test module string?");
+ Fn->setSubprogram(OurFunc);
+ return MMI->getMachineFunction(*Fn);
+ }
+
+ void
+ produceMLocTransferFunction(MachineFunction &MF,
+ SmallVectorImpl<MLocTransferMap> &MLocTransfer,
+ unsigned MaxNumBlocks) {
+ LDV->produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks);
}
};
+TEST_F(InstrRefLDVTest, MTransferDefs) {
+ MachineFunction *MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " RETQ $rax\n");
+ setupLDVObj(MF);
+
+ // We should start with only SP tracked.
+ EXPECT_TRUE(MTracker->getNumLocs() == 1);
+
+ SmallVector<MLocTransferMap, 1> TransferMap;
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ // Code contains only one register write: that should assign to each of the
+ // aliasing registers. Test that all of them get locations, and have a
+ // corresponding def at the first instr in the function.
+ const char *RegNames[] = {"RAX", "HAX", "EAX", "AX", "AH", "AL"};
+ EXPECT_TRUE(MTracker->getNumLocs() == 7);
+ for (const char *RegName : RegNames) {
+ Register R = getRegByName(RegName);
+ ASSERT_TRUE(MTracker->isRegisterTracked(R));
+ LocIdx L = MTracker->getRegMLoc(R);
+ ValueIDNum V = MTracker->readReg(R);
+ // Value of this register should be: block zero, instruction 1, and the
+ // location it's defined in is itself.
+ ValueIDNum ToCmp(0, 1, L);
+ EXPECT_EQ(V, ToCmp);
+ }
+
+ // Do the same again, but with an aliasing write. This should write to all
+ // the same registers again, except $ah and $hax (the upper 8 bits of $ax
+ // and 32 bits of $rax resp.).
+ MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " $al = MOV8ri 0\n"
+ " RETQ $rax\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ auto TestRegSetSite = [&](const char *Name, unsigned InstrNum) {
+ Register R = getRegByName(Name);
+ ASSERT_TRUE(MTracker->isRegisterTracked(R));
+ LocIdx L = MTracker->getRegMLoc(R);
+ ValueIDNum V = MTracker->readMLoc(L);
+ ValueIDNum ToCmp(0, InstrNum, L);
+ EXPECT_EQ(V, ToCmp);
+ };
+
+ TestRegSetSite("AL", 2);
+ TestRegSetSite("AH", 1);
+ TestRegSetSite("AX", 2);
+ TestRegSetSite("EAX", 2);
+ TestRegSetSite("HAX", 1);
+ TestRegSetSite("RAX", 2);
+
+ // This call should:
+ // * Def rax via the implicit-def,
+ // * Clobber rsi/rdi and all their subregs, via the register mask
+ // * Same for rcx, despite it not being a use in the instr, it's in the mask
+ // * NOT clobber $rsp / $esp $ sp, LiveDebugValues deliberately ignores
+ // these.
+ // * NOT clobber $rbx, because it's non-volatile
+ // * Not track every other register in the machine, only those needed.
+ MF = readMIRBlock(
+ " $rax = MOV64ri 0\n" // instr 1
+ " $rbx = MOV64ri 0\n" // instr 2
+ " $rcx = MOV64ri 0\n" // instr 3
+ " $rdi = MOV64ri 0\n" // instr 4
+ " $rsi = MOV64ri 0\n" // instr 5
+ " CALL64r $rax, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, implicit-def $esp, implicit-def $sp\n\n\n\n" // instr 6
+ " RETQ $rax\n"); // instr 7
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ const char *RegsSetInCall[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX",
+ "DIL", "DIH", "DI", "EDI", "HDI", "RDI",
+ "SIL", "SIH", "SI", "ESI", "HSI", "RSI",
+ "CL", "CH", "CX", "ECX", "HCX", "RCX"};
+ for (const char *RegSetInCall : RegsSetInCall)
+ TestRegSetSite(RegSetInCall, 6);
+
+ const char *RegsLeftAlone[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
+ for (const char *RegLeftAlone : RegsLeftAlone)
+ TestRegSetSite(RegLeftAlone, 2);
+
+ // Stack pointer should be the live-in to the function, instruction zero.
+ TestRegSetSite("RSP", 0);
+ // These stack regs should not be tracked either. Nor the (fake) subregs.
+ EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("ESP")));
+ EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SP")));
+ EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPL")));
+ EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPH")));
+ EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("HSP")));
+
+ // Should only be tracking: 6 x {A, B, C, DI, SI} registers = 30,
+ // Plus RSP, SSP = 32.
+ EXPECT_EQ(32u, MTracker->getNumLocs());
+
+
+ // When we DBG_PHI something, we should track all its subregs.
+ MF = readMIRBlock(
+ " DBG_PHI $rdi, 0\n"
+ " RETQ\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ // All DI regs and RSP tracked.
+ EXPECT_EQ(7u, MTracker->getNumLocs());
+
+ // All the DI registers should have block live-in values, i.e. the argument
+ // to the function.
+ const char *DIRegs[] = {"DIL", "DIH", "DI", "EDI", "HDI", "RDI"};
+ for (const char *DIReg : DIRegs)
+ TestRegSetSite(DIReg, 0);
+}
+
+TEST_F(InstrRefLDVTest, MTransferMeta) {
+ // Meta instructions should not have any effect on register values.
+ SmallVector<MLocTransferMap, 1> TransferMap;
+ MachineFunction *MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " $rax = IMPLICIT_DEF\n"
+ " $rax = KILL killed $rax\n"
+ " RETQ $rax\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ LocIdx RaxLoc = MTracker->getRegMLoc(getRegByName("RAX"));
+ ValueIDNum V = MTracker->readMLoc(RaxLoc);
+ // Def of rax should be from instruction 1, i.e., unmodified.
+ ValueIDNum Cmp(0, 1, RaxLoc);
+ EXPECT_EQ(Cmp, V);
+}
+
+TEST_F(InstrRefLDVTest, MTransferCopies) {
+ SmallVector<MLocTransferMap, 1> TransferMap;
+ // This memory spill should be recognised, and a spill slot created.
+ MachineFunction *MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
+ " RETQ $rax\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ // Check that the spill location contains the value defined in rax by
+ // instruction 1. The MIR header says -16 offset, but it's stored as -8;
+ // it's not completely clear why, but here we only care about correctly
+ // identifying the slot, not that all the surrounding data is correct.
+ SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
+ Optional<ValueIDNum> V = MTracker->readSpill(L);
+ ASSERT_TRUE(V);
+ Register RAX = getRegByName("RAX");
+ LocIdx RaxLoc = MTracker->getRegMLoc(RAX);
+ ValueIDNum Cmp(0, 1, RaxLoc);
+ EXPECT_EQ(*V, Cmp);
+
+ // A spill and restore should be recognised.
+ MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
+ " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
+ " RETQ\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ // Test that rbx contains rax from instruction 1.
+ RAX = getRegByName("RAX");
+ RaxLoc = MTracker->getRegMLoc(RAX);
+ Register RBX = getRegByName("RBX");
+ LocIdx RbxLoc = MTracker->getRegMLoc(RBX);
+ Cmp = ValueIDNum(0, 1, RaxLoc);
+ ValueIDNum RbxVal = MTracker->readMLoc(RbxLoc);
+ EXPECT_EQ(RbxVal, Cmp);
+
+ // FIXME: future work, make sure all the subregisters are transferred too.
+
+ // Copies and x86 movs should be recognised and honoured. In addition, all
+ // of the subregisters should be copied across too.
+ MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " $rcx = COPY $rax\n"
+ " $rbx = MOV64rr $rcx\n"
+ " RETQ\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
+ const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
+ const char *CRegs[] = {"CL", "CH", "CX", "ECX", "HCX", "RCX"};
+ auto CheckReg = [&](unsigned int I) {
+ LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
+ LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
+ LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
+ ValueIDNum ARefVal(0, 1, A);
+ ValueIDNum AVal = MTracker->readMLoc(A);
+ ValueIDNum BVal = MTracker->readMLoc(B);
+ ValueIDNum CVal = MTracker->readMLoc(C);
+ EXPECT_EQ(ARefVal, AVal);
+ EXPECT_EQ(ARefVal, BVal);
+ EXPECT_EQ(ARefVal, CVal);
+ };
+
+ for (unsigned int I = 0; I < 6; ++I)
+ CheckReg(I);
+
+ // When we copy to a subregister, the super-register should be def'd too: it's
+ // value will have changed.
+ MF = readMIRBlock(
+ " $rax = MOV64ri 0\n"
+ " $ecx = COPY $eax\n"
+ " RETQ\n");
+ setupLDVObj(MF);
+ TransferMap.clear();
+ TransferMap.resize(1);
+ produceMLocTransferFunction(*MF, TransferMap, 1);
+
+ // First four regs [al, ah, ax, eax] should be copied to *cx.
+ for (unsigned int I = 0; I < 4; ++I) {
+ LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
+ LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
+ ValueIDNum ARefVal(0, 1, A);
+ ValueIDNum AVal = MTracker->readMLoc(A);
+ ValueIDNum CVal = MTracker->readMLoc(C);
+ EXPECT_EQ(ARefVal, AVal);
+ EXPECT_EQ(ARefVal, CVal);
+ }
+
+ // But rcx should contain a value defined by the COPY.
+ LocIdx RcxLoc = MTracker->getRegMLoc(getRegByName("RCX"));
+ ValueIDNum RcxVal = MTracker->readMLoc(RcxLoc);
+ ValueIDNum RcxDefVal(0, 2, RcxLoc); // instr 2 -> the copy
+ EXPECT_EQ(RcxVal, RcxDefVal);
+}
+
TEST_F(InstrRefLDVTest, MLocSingleBlock) {
// Test some very simple properties about interpreting the transfer function.
setupSingleBlock();
More information about the llvm-commits
mailing list