/// 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>
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.
--- /dev/null
+# 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
+...
}
}
-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();
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>();
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);
}
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);
}
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))
- return true;
+
+ 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);
- printMIR(ROS, *MF);
+ for (Function &F : *M) {
+ if (auto *MF = MMI->getMachineFunction(F))
+ printMIR(ROS, *MF);
+ }
} else {
M->print(ROS, /*AssemblyAnnotationWriter=*/nullptr,
/*ShouldPreserveUseListOrder=*/true);
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);
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?");
}
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
+#include "llvm/Target/TargetMachine.h"
#include <vector>
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
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
}
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
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;
/// 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");
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");
// Forward I to the last chunk processed in parallel.
I += NumChunksProcessed - 1;
} else {
- Result = CheckChunk(*I, cloneReducerWorkItem(Test.getProgram()), Test,
- ExtractChunksFromModule, UninterestingChunks,
- ChunksStillConsideredInteresting);
+ Result = CheckChunk(
+ *I,
+ cloneReducerWorkItem(Test.getProgram(), Test.getTargetMachine()),
+ Test, ExtractChunksFromModule, UninterestingChunks,
+ ChunksStillConsideredInteresting);
}
if (!Result)
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);
-}
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
///
/// 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
return 0;
}
-static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
+static void extractInstrFromFunction(Oracle &O, MachineFunction &MF) {
MachineDominatorTree MDT;
MDT.runOnMachineFunction(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);
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);