forked from OSchip/llvm-project
llvm-reduce: Support multiple MachineFunctions
The current testcase I'm trying to reduce only reproduces with IPRA enabled and requires handling multiple functions. The only real difference vs. the IR is the extra indirect to look for the underlying MachineFunction, so treat the ReduceWorkItem as the module instead of the function. The ugliest piece of this is really the ugliness of MachineModuleInfo. It not only tracks actual module state, but has a number of transient fields used for isel and/or the asm printer. These shouldn't do any harm for the use here, though they should be separated out.
This commit is contained in:
parent
49c7534587
commit
7c2db66632
|
@ -163,6 +163,9 @@ public:
|
|||
/// Machine Function map.
|
||||
void deleteMachineFunctionFor(Function &F);
|
||||
|
||||
/// Add an externally created MachineFunction \p MF for \p F.
|
||||
void insertFunction(const Function &F, std::unique_ptr<MachineFunction> &&MF);
|
||||
|
||||
/// Keep track of various per-module pieces of information for backends
|
||||
/// that would like to do so.
|
||||
template<typename Ty>
|
||||
|
|
|
@ -141,6 +141,13 @@ void MachineModuleInfo::deleteMachineFunctionFor(Function &F) {
|
|||
LastResult = nullptr;
|
||||
}
|
||||
|
||||
void MachineModuleInfo::insertFunction(const Function &F,
|
||||
std::unique_ptr<MachineFunction> &&MF) {
|
||||
auto I = MachineFunctions.insert(std::make_pair(&F, std::move(MF)));
|
||||
assert(I.second && "machine function already mapped");
|
||||
(void)I;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// This pass frees the MachineFunction object associated with a Function.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# REQUIRES: amdgpu-registered-target
|
||||
# RUN: llvm-reduce -simplify-mir -mtriple=amdgcn-amd-amdhsa --test FileCheck --test-arg --check-prefix=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t 2> %t.log
|
||||
# RUN: FileCheck --check-prefix=RESULT %s < %t
|
||||
|
||||
# CHECK-INTERESTINGNESS: S_NOP 0
|
||||
|
||||
# RESULT: name: func0
|
||||
# RESULT: S_NOP 0
|
||||
|
||||
# RESULT: name: func1
|
||||
# RESULT-NOT: S_NOP
|
||||
|
||||
--- |
|
||||
define void @func0() {
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @func1() {
|
||||
ret void
|
||||
}
|
||||
|
||||
...
|
||||
---
|
||||
name: func0
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
S_WAITCNT 0
|
||||
S_NOP 0
|
||||
%0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
|
||||
INLINEASM &"", 1 /* sideeffect attdialect */
|
||||
S_ENDPGM 0, implicit %0
|
||||
...
|
||||
|
||||
---
|
||||
name: func1
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
S_WAITCNT 0
|
||||
S_NOP 1
|
||||
%0:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
|
||||
INLINEASM &"", 1 /* sideeffect attdialect */
|
||||
S_ENDPGM 0, implicit %0
|
||||
...
|
|
@ -127,10 +127,11 @@ static void cloneFrameInfo(
|
|||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF) {
|
||||
static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF,
|
||||
MachineModuleInfo &DestMMI) {
|
||||
auto DstMF = std::make_unique<MachineFunction>(
|
||||
SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
|
||||
SrcMF->getFunctionNumber(), SrcMF->getMMI());
|
||||
SrcMF->getFunctionNumber(), DestMMI);
|
||||
DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
|
||||
|
||||
auto *SrcMRI = &SrcMF->getRegInfo();
|
||||
|
@ -292,7 +293,7 @@ static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF) {
|
|||
std::unique_ptr<ReducerWorkItem>
|
||||
parseReducerWorkItem(const char *ToolName, StringRef Filename,
|
||||
LLVMContext &Ctxt, std::unique_ptr<TargetMachine> &TM,
|
||||
std::unique_ptr<MachineModuleInfo> &MMI, bool IsMIR) {
|
||||
bool IsMIR) {
|
||||
Triple TheTriple;
|
||||
|
||||
auto MMM = std::make_unique<ReducerWorkItem>();
|
||||
|
@ -336,23 +337,9 @@ parseReducerWorkItem(const char *ToolName, StringRef Filename,
|
|||
std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
|
||||
LLVMTargetMachine *LLVMTM = static_cast<LLVMTargetMachine *>(TM.get());
|
||||
|
||||
MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
|
||||
MParser->parseMachineFunctions(*M, *MMI);
|
||||
MachineFunction *MF = nullptr;
|
||||
for (auto &F : *M) {
|
||||
if (auto *MF4F = MMI->getMachineFunction(F)) {
|
||||
// XXX: Maybe it would not be a lot of effort to handle multiple MFs by
|
||||
// simply storing them in a ReducerWorkItem::SmallVector or similar. The
|
||||
// single MF use-case seems a lot more common though so that will do for
|
||||
// now.
|
||||
assert(!MF && "Only single MF supported!");
|
||||
MF = MF4F;
|
||||
}
|
||||
}
|
||||
assert(MF && "No MF found!");
|
||||
|
||||
MMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
|
||||
MParser->parseMachineFunctions(*M, *MMM->MMI);
|
||||
MMM->M = std::move(M);
|
||||
MMM->MF = cloneMF(MF);
|
||||
} else {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
|
||||
|
@ -371,16 +358,24 @@ parseReducerWorkItem(const char *ToolName, StringRef Filename,
|
|||
}
|
||||
|
||||
std::unique_ptr<ReducerWorkItem>
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM) {
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM) {
|
||||
auto CloneMMM = std::make_unique<ReducerWorkItem>();
|
||||
if (MMM.MF) {
|
||||
// Note that we cannot clone the Module as then we would need a way to
|
||||
// updated the cloned MachineFunction's IR references.
|
||||
// XXX: Actually have a look at
|
||||
// std::unique_ptr<Module> CloneModule(const Module &M, ValueToValueMapTy
|
||||
// &VMap);
|
||||
if (TM) {
|
||||
// We're assuming the Module IR contents are always unchanged by MIR
|
||||
// reductions, and can share it as a constant.
|
||||
CloneMMM->M = MMM.M;
|
||||
CloneMMM->MF = cloneMF(MMM.MF.get());
|
||||
|
||||
// MachineModuleInfo contains a lot of other state used during codegen which
|
||||
// we won't be using here, but we should be able to ignore it (although this
|
||||
// is pretty ugly).
|
||||
const LLVMTargetMachine *LLVMTM =
|
||||
static_cast<const LLVMTargetMachine *>(TM);
|
||||
CloneMMM->MMI = std::make_unique<MachineModuleInfo>(LLVMTM);
|
||||
|
||||
for (const Function &F : MMM.getModule()) {
|
||||
if (auto *MF = MMM.MMI->getMachineFunction(F))
|
||||
CloneMMM->MMI->insertFunction(F, cloneMF(MF, *CloneMMM->MMI));
|
||||
}
|
||||
} else {
|
||||
CloneMMM->M = CloneModule(*MMM.M);
|
||||
}
|
||||
|
@ -390,15 +385,27 @@ cloneReducerWorkItem(const ReducerWorkItem &MMM) {
|
|||
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
|
||||
if (verifyModule(*MMM.M, OS))
|
||||
return true;
|
||||
if (MMM.MF && !MMM.MF->verify(nullptr, "", /*AbortOnError=*/false))
|
||||
|
||||
if (!MMM.MMI)
|
||||
return false;
|
||||
|
||||
for (const Function &F : MMM.getModule()) {
|
||||
if (const MachineFunction *MF = MMM.MMI->getMachineFunction(F)) {
|
||||
if (!MF->verify(nullptr, "", /*AbortOnError=*/false))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
|
||||
if (MF) {
|
||||
if (MMI) {
|
||||
printMIR(ROS, *M);
|
||||
for (Function &F : *M) {
|
||||
if (auto *MF = MMI->getMachineFunction(F))
|
||||
printMIR(ROS, *MF);
|
||||
}
|
||||
} else {
|
||||
M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,
|
||||
/*ShouldPreserveUseListOrder=*/true);
|
||||
|
|
|
@ -19,20 +19,23 @@ using namespace llvm;
|
|||
class ReducerWorkItem {
|
||||
public:
|
||||
std::shared_ptr<Module> M;
|
||||
std::unique_ptr<MachineFunction> MF;
|
||||
std::unique_ptr<MachineModuleInfo> MMI;
|
||||
|
||||
bool isMIR() const { return MMI != nullptr; }
|
||||
|
||||
const Module &getModule() const { return *M; }
|
||||
|
||||
void print(raw_ostream &ROS, void *p = nullptr) const;
|
||||
bool isMIR() { return MF != nullptr; }
|
||||
operator Module &() const { return *M; }
|
||||
operator MachineFunction &() const { return *MF; }
|
||||
};
|
||||
|
||||
std::unique_ptr<ReducerWorkItem>
|
||||
parseReducerWorkItem(const char *ToolName, StringRef Filename,
|
||||
LLVMContext &Ctxt, std::unique_ptr<TargetMachine> &TM,
|
||||
std::unique_ptr<MachineModuleInfo> &MMI, bool IsMIR);
|
||||
bool IsMIR);
|
||||
|
||||
std::unique_ptr<ReducerWorkItem>
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM);
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM, const TargetMachine *TM);
|
||||
|
||||
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS);
|
||||
|
||||
|
|
|
@ -12,8 +12,10 @@ using namespace llvm;
|
|||
|
||||
TestRunner::TestRunner(StringRef TestName,
|
||||
const std::vector<std::string> &TestArgs,
|
||||
std::unique_ptr<ReducerWorkItem> Program)
|
||||
: TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) {
|
||||
std::unique_ptr<ReducerWorkItem> Program,
|
||||
std::unique_ptr<TargetMachine> TM)
|
||||
: TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)),
|
||||
TM(std::move(TM)) {
|
||||
assert(this->Program && "Initialized with null program?");
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
@ -26,7 +27,8 @@ namespace llvm {
|
|||
class TestRunner {
|
||||
public:
|
||||
TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs,
|
||||
std::unique_ptr<ReducerWorkItem> Program);
|
||||
std::unique_ptr<ReducerWorkItem> Program,
|
||||
std::unique_ptr<TargetMachine> TM);
|
||||
|
||||
/// Runs the interesting-ness test for the specified file
|
||||
/// @returns 0 if test was successful, 1 if otherwise
|
||||
|
@ -40,10 +42,13 @@ public:
|
|||
Program = std::move(P);
|
||||
}
|
||||
|
||||
const TargetMachine *getTargetMachine() const { return TM.get(); }
|
||||
|
||||
private:
|
||||
StringRef TestName;
|
||||
const std::vector<std::string> &TestArgs;
|
||||
std::unique_ptr<ReducerWorkItem> Program;
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -132,13 +132,14 @@ static bool increaseGranularity(std::vector<Chunk> &Chunks) {
|
|||
}
|
||||
return SplitOne;
|
||||
}
|
||||
|
||||
// Check if \p ChunkToCheckForUninterestingness is interesting. Returns the
|
||||
// modified module if the chunk resulted in a reduction.
|
||||
template <typename T>
|
||||
template <typename FuncType>
|
||||
static std::unique_ptr<ReducerWorkItem>
|
||||
CheckChunk(Chunk &ChunkToCheckForUninterestingness,
|
||||
std::unique_ptr<ReducerWorkItem> Clone, TestRunner &Test,
|
||||
function_ref<void(Oracle &, T &)> ExtractChunksFromModule,
|
||||
FuncType ExtractChunksFromModule,
|
||||
std::set<Chunk> &UninterestingChunks,
|
||||
std::vector<Chunk> &ChunksStillConsideredInteresting) {
|
||||
// Take all of ChunksStillConsideredInteresting chunks, except those we've
|
||||
|
@ -183,11 +184,10 @@ CheckChunk(Chunk &ChunkToCheckForUninterestingness,
|
|||
return Clone;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename FuncType>
|
||||
SmallString<0> ProcessChunkFromSerializedBitcode(
|
||||
Chunk &ChunkToCheckForUninterestingness, TestRunner &Test,
|
||||
function_ref<void(Oracle &, T &)> ExtractChunksFromModule,
|
||||
std::set<Chunk> &UninterestingChunks,
|
||||
FuncType ExtractChunksFromModule, std::set<Chunk> &UninterestingChunks,
|
||||
std::vector<Chunk> &ChunksStillConsideredInteresting,
|
||||
SmallString<0> &OriginalBC, std::atomic<bool> &AnyReduced) {
|
||||
LLVMContext Ctx;
|
||||
|
@ -217,10 +217,8 @@ SmallString<0> ProcessChunkFromSerializedBitcode(
|
|||
/// reduces the amount of chunks that are considered interesting by the
|
||||
/// given test. The number of chunks is determined by a preliminary run of the
|
||||
/// reduction pass where no change must be made to the module.
|
||||
template <typename T>
|
||||
void runDeltaPassInt(
|
||||
TestRunner &Test,
|
||||
function_ref<void(Oracle &, T &)> ExtractChunksFromModule) {
|
||||
void llvm::runDeltaPass(TestRunner &Test,
|
||||
ReductionFunc ExtractChunksFromModule) {
|
||||
assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
|
||||
"input module is broken before making changes");
|
||||
|
||||
|
@ -250,7 +248,7 @@ void runDeltaPassInt(
|
|||
std::vector<Chunk> NoChunks;
|
||||
Oracle NoChunksCounter(NoChunks);
|
||||
std::unique_ptr<ReducerWorkItem> Clone =
|
||||
cloneReducerWorkItem(Test.getProgram());
|
||||
cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine());
|
||||
ExtractChunksFromModule(NoChunksCounter, *Clone);
|
||||
assert(Targets == NoChunksCounter.count() &&
|
||||
"number of chunks changes when reducing");
|
||||
|
@ -365,8 +363,10 @@ void runDeltaPassInt(
|
|||
// Forward I to the last chunk processed in parallel.
|
||||
I += NumChunksProcessed - 1;
|
||||
} else {
|
||||
Result = CheckChunk(*I, cloneReducerWorkItem(Test.getProgram()), Test,
|
||||
ExtractChunksFromModule, UninterestingChunks,
|
||||
Result = CheckChunk(
|
||||
*I,
|
||||
cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()),
|
||||
Test, ExtractChunksFromModule, UninterestingChunks,
|
||||
ChunksStillConsideredInteresting);
|
||||
}
|
||||
|
||||
|
@ -394,15 +394,3 @@ void runDeltaPassInt(
|
|||
Test.setProgram(std::move(ReducedProgram));
|
||||
errs() << "Couldn't increase anymore.\n";
|
||||
}
|
||||
|
||||
void llvm::runDeltaPass(
|
||||
TestRunner &Test,
|
||||
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
|
||||
runDeltaPassInt<Module>(Test, ExtractChunksFromModule);
|
||||
}
|
||||
|
||||
void llvm::runDeltaPass(
|
||||
TestRunner &Test,
|
||||
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule) {
|
||||
runDeltaPassInt<MachineFunction>(Test, ExtractChunksFromModule);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,8 @@ public:
|
|||
int count() { return Index; }
|
||||
};
|
||||
|
||||
using ReductionFunc = function_ref<void(Oracle &, ReducerWorkItem &)>;
|
||||
|
||||
/// This function implements the Delta Debugging algorithm, it receives a
|
||||
/// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and
|
||||
/// splits them in half; these chunks of targets are then tested while ignoring
|
||||
|
@ -103,12 +105,7 @@ public:
|
|||
///
|
||||
/// Other implementations of the Delta Debugging algorithm can also be found in
|
||||
/// the CReduce, Delta, and Lithium projects.
|
||||
void runDeltaPass(
|
||||
TestRunner &Test,
|
||||
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule);
|
||||
void runDeltaPass(
|
||||
TestRunner &Test,
|
||||
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule);
|
||||
void runDeltaPass(TestRunner &Test, ReductionFunc ExtractChunksFromModule);
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,7 +45,7 @@ static Register getPrevDefOfRCInMBB(MachineBasicBlock &MBB,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
|
||||
static void extractInstrFromFunction(Oracle &O, MachineFunction &MF) {
|
||||
MachineDominatorTree MDT;
|
||||
MDT.runOnMachineFunction(MF);
|
||||
|
||||
|
@ -129,6 +129,13 @@ static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
|
|||
MI->eraseFromParent();
|
||||
}
|
||||
|
||||
static void extractInstrFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
|
||||
for (const Function &F : WorkItem.getModule()) {
|
||||
if (MachineFunction *MF = WorkItem.MMI->getMachineFunction(F))
|
||||
extractInstrFromFunction(O, *MF);
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Instructions...\n";
|
||||
runDeltaPass(Test, extractInstrFromModule);
|
||||
|
|
|
@ -138,16 +138,16 @@ int main(int Argc, char **Argv) {
|
|||
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
std::unique_ptr<MachineModuleInfo> MMI;
|
||||
|
||||
std::unique_ptr<ReducerWorkItem> OriginalProgram = parseReducerWorkItem(
|
||||
Argv[0], InputFilename, Context, TM, MMI, ReduceModeMIR);
|
||||
std::unique_ptr<ReducerWorkItem> OriginalProgram =
|
||||
parseReducerWorkItem(Argv[0], InputFilename, Context, TM, ReduceModeMIR);
|
||||
if (!OriginalProgram) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize test environment
|
||||
TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram));
|
||||
TestRunner Tester(TestFilename, TestArguments, std::move(OriginalProgram),
|
||||
std::move(TM));
|
||||
|
||||
// Try to reduce code
|
||||
runDeltaPasses(Tester, MaxPassIterations);
|
||||
|
|
Loading…
Reference in New Issue