Recommit "[llvm-reduce] Add MIR support"
(Second try. Need to link against CodeGen and MC libs.) The llvm-reduce tool has been extended to operate on MIR (import, clone and export). Current limitation is that only a single machine function is supported. A single reducer pass that operates on machine instructions (while on SSA-form) has been added. Additional MIR specific reducer passes can be added later as needed. Differential Revision: https://reviews.llvm.org/D110527
This commit is contained in:
parent
cd2e66efa6
commit
fd41738e2c
|
@ -0,0 +1,30 @@
|
|||
# RUN: llvm-reduce -mtriple=riscv32 --test %python --test-arg %p/instr-reduce.py %s -o %t
|
||||
# RUN: cat %t | FileCheck --match-full-lines %s
|
||||
|
||||
# REQUIRES: riscv-registered-target
|
||||
|
||||
# Verify that after reduction the following instruction sequence remains. The
|
||||
# interestingness-test 'instr-reduce.py' matches a '%[0-9]+:gpr = ADDI %[0-9]+, 5'
|
||||
# pattern in the output and that combined with that the MIR has to be valid
|
||||
# (pass verify) results in the given sequence.
|
||||
|
||||
# CHECK: %0:gpr = COPY $x10
|
||||
# CHECK-NEXT: %2:gpr = ADDI %0, 5
|
||||
# CHECK-NEXT: PseudoRET implicit $x10
|
||||
|
||||
...
|
||||
---
|
||||
name: f
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x10
|
||||
|
||||
%10:gpr = COPY $x10
|
||||
%20:gpr = ADDI %10, 1
|
||||
%30:gpr = ADDI %20, 5
|
||||
%40:gpr = ADDI %30, 9
|
||||
$x10 = COPY %40
|
||||
PseudoRET implicit $x10
|
||||
...
|
||||
---
|
|
@ -0,0 +1,16 @@
|
|||
from subprocess import run, PIPE
|
||||
import re
|
||||
import sys
|
||||
|
||||
llc = run( [ 'llc', '-disable-symbolication','-verify-machineinstrs', '-mtriple=riscv32', '-run-pass=none', '-o', '-', sys.argv[1]], stdout=PIPE, stderr=PIPE )
|
||||
|
||||
stdout = llc.stdout.decode()
|
||||
|
||||
p = re.compile(r'^\s*%[0-9]+:gpr = ADDI %[0-9]+, 5$', flags=re.MULTILINE)
|
||||
|
||||
if (llc.returncode == 0 and p.search(stdout)):
|
||||
print('This is interesting!')
|
||||
sys.exit(0)
|
||||
else:
|
||||
print('This is NOT interesting!')
|
||||
sys.exit(1)
|
|
@ -3,8 +3,11 @@ set(LLVM_LINK_COMPONENTS
|
|||
AllTargetsCodeGens
|
||||
AllTargetsDescs
|
||||
AllTargetsInfos
|
||||
CodeGen
|
||||
Core
|
||||
IRReader
|
||||
MC
|
||||
MIRParser
|
||||
Support
|
||||
Target
|
||||
TransformUtils
|
||||
|
@ -12,6 +15,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
|
||||
add_llvm_tool(llvm-reduce
|
||||
DeltaManager.cpp
|
||||
ReducerWorkItem.cpp
|
||||
TestRunner.cpp
|
||||
deltas/Delta.cpp
|
||||
deltas/ReduceAliases.cpp
|
||||
|
@ -30,6 +34,7 @@ add_llvm_tool(llvm-reduce
|
|||
deltas/ReduceSpecialGlobals.cpp
|
||||
deltas/ReduceOperands.cpp
|
||||
deltas/ReduceOperandsToArgs.cpp
|
||||
deltas/ReduceInstructionsMIR.cpp
|
||||
llvm-reduce.cpp
|
||||
|
||||
DEPENDS
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "deltas/ReduceGlobalVarInitializers.h"
|
||||
#include "deltas/ReduceGlobalVars.h"
|
||||
#include "deltas/ReduceInstructions.h"
|
||||
#include "deltas/ReduceInstructionsMIR.h"
|
||||
#include "deltas/ReduceMetadata.h"
|
||||
#include "deltas/ReduceModuleData.h"
|
||||
#include "deltas/ReduceOperandBundles.h"
|
||||
|
@ -59,9 +60,16 @@ static cl::opt<std::string>
|
|||
DELTA_PASS("attributes", reduceAttributesDeltaPass) \
|
||||
DELTA_PASS("module-data", reduceModuleDataDeltaPass)
|
||||
|
||||
#define DELTA_PASSES_MIR \
|
||||
DELTA_PASS("instructions", reduceInstructionsMIRDeltaPass)
|
||||
|
||||
static void runAllDeltaPasses(TestRunner &Tester) {
|
||||
#define DELTA_PASS(NAME, FUNC) FUNC(Tester);
|
||||
DELTA_PASSES
|
||||
if (Tester.getProgram().isMIR()) {
|
||||
DELTA_PASSES_MIR
|
||||
} else {
|
||||
DELTA_PASSES
|
||||
}
|
||||
#undef DELTA_PASS
|
||||
}
|
||||
|
||||
|
@ -71,7 +79,11 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
|
|||
FUNC(Tester); \
|
||||
return; \
|
||||
}
|
||||
DELTA_PASSES
|
||||
if (Tester.getProgram().isMIR()) {
|
||||
DELTA_PASSES_MIR
|
||||
} else {
|
||||
DELTA_PASSES
|
||||
}
|
||||
#undef DELTA_PASS
|
||||
errs() << "unknown pass \"" << PassName << "\"";
|
||||
exit(1);
|
||||
|
@ -80,7 +92,10 @@ static void runDeltaPassName(TestRunner &Tester, StringRef PassName) {
|
|||
void llvm::printDeltaPasses(raw_ostream &OS) {
|
||||
OS << "Delta passes (pass to `--delta-passes=` as a comma separated list):\n";
|
||||
#define DELTA_PASS(NAME, FUNC) OS << " " << NAME << "\n";
|
||||
OS << " IR:\n";
|
||||
DELTA_PASSES
|
||||
OS << " MIR:\n";
|
||||
DELTA_PASSES_MIR
|
||||
#undef DELTA_PASS
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
//===- ReducerWorkItem.cpp - Wrapper for Module and MachineFunction -------===//
|
||||
//
|
||||
// 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 "ReducerWorkItem.h"
|
||||
#include "llvm/CodeGen/MIRParser/MIRParser.h"
|
||||
#include "llvm/CodeGen/MIRPrinter.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
static std::unique_ptr<MachineFunction> cloneMF(MachineFunction *SrcMF) {
|
||||
auto DstMF = std::make_unique<MachineFunction>(
|
||||
SrcMF->getFunction(), SrcMF->getTarget(), SrcMF->getSubtarget(),
|
||||
SrcMF->getFunctionNumber(), SrcMF->getMMI());
|
||||
DenseMap<MachineBasicBlock *, MachineBasicBlock *> Src2DstMBB;
|
||||
DenseMap<Register, Register> Src2DstReg;
|
||||
|
||||
auto *SrcMRI = &SrcMF->getRegInfo();
|
||||
auto *DstMRI = &DstMF->getRegInfo();
|
||||
|
||||
// Create vregs.
|
||||
for (auto &SrcMBB : *SrcMF) {
|
||||
for (auto &SrcMI : SrcMBB) {
|
||||
for (unsigned I = 0, E = SrcMI.getNumOperands(); I < E; ++I) {
|
||||
auto &DMO = SrcMI.getOperand(I);
|
||||
if (!DMO.isReg() || !DMO.isDef())
|
||||
continue;
|
||||
Register SrcReg = DMO.getReg();
|
||||
if (Register::isPhysicalRegister(SrcReg))
|
||||
continue;
|
||||
auto SrcRC = SrcMRI->getRegClass(SrcReg);
|
||||
auto DstReg = DstMRI->createVirtualRegister(SrcRC);
|
||||
Src2DstReg[SrcReg] = DstReg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone blocks.
|
||||
for (auto &SrcMBB : *SrcMF)
|
||||
Src2DstMBB[&SrcMBB] = DstMF->CreateMachineBasicBlock();
|
||||
// Link blocks.
|
||||
for (auto &SrcMBB : *SrcMF) {
|
||||
auto *DstMBB = Src2DstMBB[&SrcMBB];
|
||||
DstMF->push_back(DstMBB);
|
||||
for (auto It = SrcMBB.succ_begin(), IterEnd = SrcMBB.succ_end();
|
||||
It != IterEnd; ++It) {
|
||||
auto *SrcSuccMBB = *It;
|
||||
auto *DstSuccMBB = Src2DstMBB[SrcSuccMBB];
|
||||
DstMBB->addSuccessor(DstSuccMBB);
|
||||
}
|
||||
for (auto &LI : SrcMBB.liveins())
|
||||
DstMBB->addLiveIn(LI);
|
||||
}
|
||||
// Clone instructions.
|
||||
for (auto &SrcMBB : *SrcMF) {
|
||||
auto *DstMBB = Src2DstMBB[&SrcMBB];
|
||||
for (auto &SrcMI : SrcMBB) {
|
||||
const auto &MCID =
|
||||
DstMF->getSubtarget().getInstrInfo()->get(SrcMI.getOpcode());
|
||||
auto *DstMI = DstMF->CreateMachineInstr(MCID, SrcMI.getDebugLoc(),
|
||||
/*NoImplicit=*/true);
|
||||
DstMBB->push_back(DstMI);
|
||||
for (auto &SrcMO : SrcMI.operands()) {
|
||||
MachineOperand DstMO(SrcMO);
|
||||
DstMO.clearParent();
|
||||
// Update vreg.
|
||||
if (DstMO.isReg() && Src2DstReg.count(DstMO.getReg())) {
|
||||
DstMO.setReg(Src2DstReg[DstMO.getReg()]);
|
||||
}
|
||||
// Update MBB.
|
||||
if (DstMO.isMBB()) {
|
||||
DstMO.setMBB(Src2DstMBB[DstMO.getMBB()]);
|
||||
}
|
||||
DstMI->addOperand(DstMO);
|
||||
}
|
||||
DstMI->setMemRefs(*DstMF, SrcMI.memoperands());
|
||||
}
|
||||
}
|
||||
|
||||
DstMF->verify(nullptr, "", /*AbortOnErrors=*/true);
|
||||
return DstMF;
|
||||
}
|
||||
|
||||
std::unique_ptr<ReducerWorkItem> parseReducerWorkItem(StringRef Filename,
|
||||
LLVMContext &Ctxt,
|
||||
MachineModuleInfo *MMI) {
|
||||
auto MMM = std::make_unique<ReducerWorkItem>();
|
||||
if (MMI) {
|
||||
auto FileOrErr = MemoryBuffer::getFileOrSTDIN(Filename, /*IsText=*/true);
|
||||
std::unique_ptr<MIRParser> MParser =
|
||||
createMIRParser(std::move(FileOrErr.get()), Ctxt);
|
||||
|
||||
auto SetDataLayout =
|
||||
[&](StringRef DataLayoutTargetTriple) -> Optional<std::string> {
|
||||
return MMI->getTarget().createDataLayout().getStringRepresentation();
|
||||
};
|
||||
|
||||
std::unique_ptr<Module> M = MParser->parseIRModule(SetDataLayout);
|
||||
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->M = std::move(M);
|
||||
MMM->MF = cloneMF(MF);
|
||||
} else {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
|
||||
if (!Result) {
|
||||
Err.print("llvm-reduce", errs());
|
||||
return std::unique_ptr<ReducerWorkItem>();
|
||||
}
|
||||
MMM->M = std::move(Result);
|
||||
}
|
||||
if (verifyReducerWorkItem(*MMM, &errs())) {
|
||||
errs() << "Error: " << Filename << " - input module is broken!\n";
|
||||
return std::unique_ptr<ReducerWorkItem>();
|
||||
}
|
||||
return MMM;
|
||||
}
|
||||
|
||||
std::unique_ptr<ReducerWorkItem>
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM) {
|
||||
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);
|
||||
CloneMMM->M = MMM.M;
|
||||
CloneMMM->MF = cloneMF(MMM.MF.get());
|
||||
} else {
|
||||
CloneMMM->M = CloneModule(*MMM.M);
|
||||
}
|
||||
return CloneMMM;
|
||||
}
|
||||
|
||||
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS) {
|
||||
if (verifyModule(*MMM.M, OS))
|
||||
return true;
|
||||
if (MMM.MF && !MMM.MF->verify(nullptr, "", /*AbortOnErrors=*/false))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReducerWorkItem::print(raw_ostream &ROS, void *p) const {
|
||||
if (MF) {
|
||||
printMIR(ROS, *M);
|
||||
printMIR(ROS, *MF);
|
||||
} else {
|
||||
M->print(ROS, nullptr);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//===- ReducerWorkItem.h - Wrapper for Module and MachineFunction ---------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
|
||||
#define LLVM_TOOLS_LLVM_REDUCE_REDUCERWORKITEM_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
class ReducerWorkItem {
|
||||
public:
|
||||
std::shared_ptr<Module> M;
|
||||
std::unique_ptr<MachineFunction> MF;
|
||||
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(StringRef Filename,
|
||||
LLVMContext &Ctxt,
|
||||
MachineModuleInfo *MMI);
|
||||
|
||||
std::unique_ptr<ReducerWorkItem>
|
||||
cloneReducerWorkItem(const ReducerWorkItem &MMM);
|
||||
|
||||
bool verifyReducerWorkItem(const ReducerWorkItem &MMM, raw_fd_ostream *OS);
|
||||
|
||||
#endif
|
|
@ -12,7 +12,7 @@ using namespace llvm;
|
|||
|
||||
TestRunner::TestRunner(StringRef TestName,
|
||||
const std::vector<std::string> &TestArgs,
|
||||
std::unique_ptr<Module> Program)
|
||||
std::unique_ptr<ReducerWorkItem> Program)
|
||||
: TestName(TestName), TestArgs(TestArgs), Program(std::move(Program)) {
|
||||
assert(this->Program && "Initialized with null program?");
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#ifndef LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
|
||||
#define LLVM_TOOLS_LLVM_REDUCE_TESTRUNNER_H
|
||||
|
||||
#include "ReducerWorkItem.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
@ -25,16 +26,16 @@ namespace llvm {
|
|||
class TestRunner {
|
||||
public:
|
||||
TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs,
|
||||
std::unique_ptr<Module> Program);
|
||||
std::unique_ptr<ReducerWorkItem> Program);
|
||||
|
||||
/// Runs the interesting-ness test for the specified file
|
||||
/// @returns 0 if test was successful, 1 if otherwise
|
||||
int run(StringRef Filename);
|
||||
|
||||
/// Returns the most reduced version of the original testcase
|
||||
Module &getProgram() const { return *Program; }
|
||||
ReducerWorkItem &getProgram() const { return *Program; }
|
||||
|
||||
void setProgram(std::unique_ptr<Module> P) {
|
||||
void setProgram(std::unique_ptr<ReducerWorkItem> P) {
|
||||
assert(P && "Setting null program?");
|
||||
Program = std::move(P);
|
||||
}
|
||||
|
@ -42,7 +43,7 @@ public:
|
|||
private:
|
||||
StringRef TestName;
|
||||
const std::vector<std::string> &TestArgs;
|
||||
std::unique_ptr<Module> Program;
|
||||
std::unique_ptr<ReducerWorkItem> Program;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
|
|
@ -13,11 +13,11 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "ReducerWorkItem.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
|
@ -27,13 +27,14 @@ static cl::opt<bool> AbortOnInvalidReduction(
|
|||
"abort-on-invalid-reduction",
|
||||
cl::desc("Abort if any reduction results in invalid IR"));
|
||||
|
||||
void writeOutput(llvm::Module &M, llvm::StringRef Message);
|
||||
void writeOutput(ReducerWorkItem &M, llvm::StringRef Message);
|
||||
|
||||
bool isReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) {
|
||||
// Write Module to tmp file
|
||||
bool isReduced(ReducerWorkItem &M, TestRunner &Test,
|
||||
SmallString<128> &CurrentFilepath) {
|
||||
// Write ReducerWorkItem to tmp file
|
||||
int FD;
|
||||
std::error_code EC =
|
||||
sys::fs::createTemporaryFile("llvm-reduce", "ll", FD, CurrentFilepath);
|
||||
std::error_code EC = sys::fs::createTemporaryFile(
|
||||
"llvm-reduce", M.isMIR() ? "mir" : "ll", FD, CurrentFilepath);
|
||||
if (EC) {
|
||||
errs() << "Error making unique filename: " << EC.message() << "!\n";
|
||||
exit(1);
|
||||
|
@ -95,9 +96,10 @@ static bool increaseGranularity(std::vector<Chunk> &Chunks) {
|
|||
/// Runs the Delta Debugging algorithm, splits the code into chunks and
|
||||
/// reduces the amount of chunks that are considered interesting by the
|
||||
/// given test.
|
||||
void llvm::runDeltaPass(
|
||||
template <typename T>
|
||||
void runDeltaPassInt(
|
||||
TestRunner &Test, int Targets,
|
||||
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
|
||||
function_ref<void(Oracle &, T &)> ExtractChunksFromModule) {
|
||||
assert(Targets >= 0);
|
||||
if (!Targets) {
|
||||
errs() << "\nNothing to reduce\n";
|
||||
|
@ -110,11 +112,11 @@ void llvm::runDeltaPass(
|
|||
exit(1);
|
||||
}
|
||||
|
||||
assert(!verifyModule(Test.getProgram(), &errs()) &&
|
||||
assert(!verifyReducerWorkItem(Test.getProgram(), &errs()) &&
|
||||
"input module is broken before making changes");
|
||||
|
||||
std::vector<Chunk> ChunksStillConsideredInteresting = {{1, Targets}};
|
||||
std::unique_ptr<Module> ReducedProgram;
|
||||
std::unique_ptr<ReducerWorkItem> ReducedProgram;
|
||||
|
||||
bool FoundAtLeastOneNewUninterestingChunkWithCurrentGranularity;
|
||||
do {
|
||||
|
@ -137,13 +139,14 @@ void llvm::runDeltaPass(
|
|||
});
|
||||
|
||||
// Clone module before hacking it up..
|
||||
std::unique_ptr<Module> Clone = CloneModule(Test.getProgram());
|
||||
std::unique_ptr<ReducerWorkItem> Clone =
|
||||
cloneReducerWorkItem(Test.getProgram());
|
||||
// Generate Module with only Targets inside Current Chunks
|
||||
Oracle O(CurrentChunks);
|
||||
ExtractChunksFromModule(O, *Clone);
|
||||
|
||||
// Some reductions may result in invalid IR. Skip such reductions.
|
||||
if (verifyModule(*Clone, &errs())) {
|
||||
if (verifyReducerWorkItem(*Clone, &errs())) {
|
||||
if (AbortOnInvalidReduction) {
|
||||
errs() << "Invalid reduction\n";
|
||||
exit(1);
|
||||
|
@ -185,3 +188,15 @@ void llvm::runDeltaPass(
|
|||
Test.setProgram(std::move(ReducedProgram));
|
||||
errs() << "Couldn't increase anymore.\n";
|
||||
}
|
||||
|
||||
void llvm::runDeltaPass(
|
||||
TestRunner &Test, int Targets,
|
||||
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule) {
|
||||
runDeltaPassInt<Module>(Test, Targets, ExtractChunksFromModule);
|
||||
}
|
||||
|
||||
void llvm::runDeltaPass(
|
||||
TestRunner &Test, int Targets,
|
||||
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule) {
|
||||
runDeltaPassInt<MachineFunction>(Test, Targets, ExtractChunksFromModule);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,9 @@ public:
|
|||
void runDeltaPass(
|
||||
TestRunner &Test, int Targets,
|
||||
function_ref<void(Oracle &, Module &)> ExtractChunksFromModule);
|
||||
void runDeltaPass(
|
||||
TestRunner &Test, int Targets,
|
||||
function_ref<void(Oracle &, MachineFunction &)> ExtractChunksFromModule);
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
//===- ReduceInstructionsMIR.cpp - Specialized Delta Pass -----------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting MachineInstr from the MachineFunction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceInstructionsMIR.h"
|
||||
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static Register getPrevDefOfRCInMBB(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::reverse_iterator &RI,
|
||||
const TargetRegisterClass *RC,
|
||||
SetVector<MachineInstr *> &ExcludeMIs) {
|
||||
auto MRI = &MBB.getParent()->getRegInfo();
|
||||
for (MachineBasicBlock::reverse_instr_iterator E = MBB.instr_rend(); RI != E;
|
||||
++RI) {
|
||||
auto &MI = *RI;
|
||||
// All Def operands explicit and implicit.
|
||||
for (auto &MO : MI.operands()) {
|
||||
if (!MO.isReg() || !MO.isDef())
|
||||
continue;
|
||||
auto Reg = MO.getReg();
|
||||
if (Register::isPhysicalRegister(Reg))
|
||||
continue;
|
||||
|
||||
if (MRI->getRegClass(Reg) == RC && !ExcludeMIs.count(MO.getParent()))
|
||||
return Reg;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned countInstructions(MachineFunction &MF) {
|
||||
unsigned Count = 0;
|
||||
MachineInstr *TopMI = nullptr;
|
||||
for (auto &MBB : MF) {
|
||||
for (auto &MI : MBB) {
|
||||
if (MI.isTerminator())
|
||||
continue;
|
||||
if (MBB.isEntryBlock() && !TopMI) {
|
||||
TopMI = &MI;
|
||||
continue;
|
||||
}
|
||||
Count++;
|
||||
}
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
static void extractInstrFromModule(Oracle &O, MachineFunction &MF) {
|
||||
MachineDominatorTree MDT;
|
||||
MDT.runOnMachineFunction(MF);
|
||||
|
||||
auto MRI = &MF.getRegInfo();
|
||||
SetVector<MachineInstr *> ToDelete;
|
||||
|
||||
MachineInstr *TopMI = nullptr;
|
||||
|
||||
// Mark MIs for deletion according to some criteria.
|
||||
for (auto &MBB : MF) {
|
||||
for (auto &MI : MBB) {
|
||||
if (MI.isTerminator())
|
||||
continue;
|
||||
if (MBB.isEntryBlock() && !TopMI) {
|
||||
TopMI = &MI;
|
||||
continue;
|
||||
}
|
||||
if (!O.shouldKeep())
|
||||
ToDelete.insert(&MI);
|
||||
}
|
||||
}
|
||||
|
||||
// For each MI to be deleted update users of regs defined by that MI to use
|
||||
// some other dominating definition (that is not to be deleted).
|
||||
for (auto *MI : ToDelete) {
|
||||
for (auto &MO : MI->operands()) {
|
||||
if (!MO.isReg() || !MO.isDef())
|
||||
continue;
|
||||
auto Reg = MO.getReg();
|
||||
if (Register::isPhysicalRegister(Reg))
|
||||
continue;
|
||||
auto UI = MRI->use_begin(Reg);
|
||||
auto UE = MRI->use_end();
|
||||
|
||||
auto RegRC = MRI->getRegClass(Reg);
|
||||
Register NewReg = 0;
|
||||
// If this is not a physical register and there are some uses.
|
||||
if (UI != UE) {
|
||||
MachineBasicBlock::reverse_iterator RI(*MI);
|
||||
MachineBasicBlock *BB = MI->getParent();
|
||||
++RI;
|
||||
while (NewReg == 0 && BB) {
|
||||
NewReg = getPrevDefOfRCInMBB(*BB, RI, RegRC, ToDelete);
|
||||
// Prepare for idom(BB).
|
||||
if (auto *IDM = MDT.getNode(BB)->getIDom()) {
|
||||
BB = IDM->getBlock();
|
||||
RI = BB->rbegin();
|
||||
} else {
|
||||
BB = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no dominating definition was found then add an implicit one to the
|
||||
// first instruction in the entry block.
|
||||
if (!NewReg && TopMI) {
|
||||
NewReg = MRI->createVirtualRegister(RegRC);
|
||||
TopMI->addOperand(MachineOperand::CreateReg(
|
||||
NewReg, true /*IsDef*/, true /*IsImp*/, false /*IsKill*/));
|
||||
}
|
||||
|
||||
// Update all uses.
|
||||
while (UI != UE) {
|
||||
auto &UMO = *UI++;
|
||||
UMO.setReg(NewReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally delete the MIs.
|
||||
for (auto *MI : ToDelete)
|
||||
MI->eraseFromParent();
|
||||
}
|
||||
|
||||
void llvm::reduceInstructionsMIRDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Instructions...\n";
|
||||
unsigned InstCount = countInstructions(Test.getProgram());
|
||||
runDeltaPass(Test, InstCount, extractInstrFromModule);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
//===- ReduceInstructionsMIR.h - Specialized Delta Pass ------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting MachineInstr from the MachineFunction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONS_MIR_H
|
||||
#define LLVM_TOOLS_LLVM_REDUCE_DELTAS_REDUCEINSTRUCTIONS_MIR_H
|
||||
|
||||
#include "Delta.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceInstructionsMIRDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
|
@ -15,15 +15,21 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DeltaManager.h"
|
||||
#include "ReducerWorkItem.h"
|
||||
#include "TestRunner.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/CodeGen/CommandFlags.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
|
@ -39,7 +45,8 @@ static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden,
|
|||
static cl::opt<bool>
|
||||
PrintDeltaPasses("print-delta-passes",
|
||||
cl::desc("Print list of delta passes, passable to "
|
||||
"--delta-passes as a comma separated list"));
|
||||
"--delta-passes as a comma separated list"),
|
||||
cl::cat(Options));
|
||||
|
||||
static cl::opt<std::string> InputFilename(cl::Positional, cl::Required,
|
||||
cl::desc("<input llvm ll/bc file>"),
|
||||
|
@ -55,9 +62,8 @@ static cl::list<std::string>
|
|||
cl::desc("Arguments passed onto the interesting-ness test"),
|
||||
cl::cat(Options));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("output",
|
||||
cl::desc("Specify the output file. default: reduced.ll"));
|
||||
static cl::opt<std::string> OutputFilename(
|
||||
"output", cl::desc("Specify the output file. default: reduced.ll|mir"));
|
||||
static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
|
||||
cl::aliasopt(OutputFilename),
|
||||
cl::cat(Options));
|
||||
|
@ -68,30 +74,27 @@ static cl::opt<bool>
|
|||
"with the reduced version!"),
|
||||
cl::cat(Options));
|
||||
|
||||
// Parses IR into a Module and verifies it
|
||||
static std::unique_ptr<Module> parseInputFile(StringRef Filename,
|
||||
LLVMContext &Ctxt) {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
|
||||
if (!Result) {
|
||||
Err.print("llvm-reduce", errs());
|
||||
return Result;
|
||||
}
|
||||
enum class InputLanguages { None, IR, MIR };
|
||||
|
||||
if (verifyModule(*Result, &errs())) {
|
||||
errs() << "Error: " << Filename << " - input module is broken!\n";
|
||||
return std::unique_ptr<Module>();
|
||||
}
|
||||
static cl::opt<InputLanguages>
|
||||
InputLanguage("x", cl::ValueOptional,
|
||||
cl::desc("Input language ('ir' or 'mir')"),
|
||||
cl::init(InputLanguages::None),
|
||||
cl::values(clEnumValN(InputLanguages::IR, "ir", ""),
|
||||
clEnumValN(InputLanguages::MIR, "mir", "")),
|
||||
cl::cat(Options));
|
||||
|
||||
return Result;
|
||||
}
|
||||
static cl::opt<std::string> TargetTriple("mtriple",
|
||||
cl::desc("Set the target triple"),
|
||||
cl::cat(Options));
|
||||
|
||||
void writeOutput(Module &M, StringRef Message) {
|
||||
static codegen::RegisterCodeGenFlags CGF;
|
||||
|
||||
void writeOutput(ReducerWorkItem &M, StringRef Message) {
|
||||
if (ReplaceInput) // In-place
|
||||
OutputFilename = InputFilename.c_str();
|
||||
else if (OutputFilename.empty() || OutputFilename == "-")
|
||||
OutputFilename = "reduced.ll";
|
||||
|
||||
OutputFilename = M.isMIR() ? "reduced.mir" : "reduced.ll";
|
||||
std::error_code EC;
|
||||
raw_fd_ostream Out(OutputFilename, EC);
|
||||
if (EC) {
|
||||
|
@ -102,21 +105,54 @@ void writeOutput(Module &M, StringRef Message) {
|
|||
errs() << Message << OutputFilename << "\n";
|
||||
}
|
||||
|
||||
static std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmPrinters();
|
||||
InitializeAllAsmParsers();
|
||||
|
||||
if (TargetTriple == "")
|
||||
TargetTriple = sys::getDefaultTargetTriple();
|
||||
auto TT(Triple::normalize(TargetTriple));
|
||||
std::string CPU(codegen::getCPUStr());
|
||||
std::string FS(codegen::getFeaturesStr());
|
||||
|
||||
std::string Error;
|
||||
const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
|
||||
|
||||
return std::unique_ptr<LLVMTargetMachine>(
|
||||
static_cast<LLVMTargetMachine *>(TheTarget->createTargetMachine(
|
||||
TT, CPU, FS, TargetOptions(), None, None, CodeGenOpt::Default)));
|
||||
}
|
||||
|
||||
int main(int Argc, char **Argv) {
|
||||
InitLLVM X(Argc, Argv);
|
||||
|
||||
cl::HideUnrelatedOptions({&Options, &getColorCategory()});
|
||||
cl::ParseCommandLineOptions(Argc, Argv, "LLVM automatic testcase reducer.\n");
|
||||
|
||||
bool ReduceModeMIR = false;
|
||||
if (InputLanguage != InputLanguages::None) {
|
||||
if (InputLanguage == InputLanguages::MIR)
|
||||
ReduceModeMIR = true;
|
||||
} else if (StringRef(InputFilename).endswith(".mir")) {
|
||||
ReduceModeMIR = true;
|
||||
}
|
||||
|
||||
if (PrintDeltaPasses) {
|
||||
printDeltaPasses(errs());
|
||||
return 0;
|
||||
}
|
||||
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<Module> OriginalProgram =
|
||||
parseInputFile(InputFilename, Context);
|
||||
|
||||
std::unique_ptr<LLVMTargetMachine> TM;
|
||||
std::unique_ptr<MachineModuleInfo> MMI;
|
||||
std::unique_ptr<ReducerWorkItem> OriginalProgram;
|
||||
if (ReduceModeMIR) {
|
||||
TM = createTargetMachine();
|
||||
MMI = std::make_unique<MachineModuleInfo>(TM.get());
|
||||
}
|
||||
OriginalProgram = parseReducerWorkItem(InputFilename, Context, MMI.get());
|
||||
if (!OriginalProgram) {
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue