Merge pull request #559 from ifilippov/debug_phases

Supporting dumping, switching off and debug printing of optimization phases.
This commit is contained in:
Dmitry Babokin
2013-08-01 14:55:07 -07:00
4 changed files with 191 additions and 30 deletions

View File

@@ -774,6 +774,7 @@ Globals::Globals() {
includeStdlib = true;
runCPP = true;
debugPrint = false;
debugIR = -1;
disableWarnings = false;
warningsAsErrors = false;
quiet = false;

14
ispc.h
View File

@@ -59,6 +59,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <set>
#include <string>
/** @def ISPC_MAX_NVEC maximum vector size of any of the compliation
@@ -66,6 +67,9 @@
*/
#define ISPC_MAX_NVEC 64
// Number of final optimization phase
#define LAST_OPT_NUMBER 1000
// Forward declarations of a number of widely-used LLVM types
namespace llvm {
class AttributeSet;
@@ -494,6 +498,16 @@ struct Globals {
ispc's execution. */
bool debugPrint;
/** Indicates which stages of optimization we want to dump. */
std::set<int> debug_stages;
/** Indicates after which optimization we want to generate
DebugIR information. */
int debugIR;
/** Indicates which phases of optimization we want to switch off. */
std::set<int> off_stages;
/** Indicates whether all warning messages should be surpressed. */
bool disableWarnings;

View File

@@ -156,6 +156,11 @@ devUsage(int ret) {
printf(" disable-uniform-control-flow\t\tDisable uniform control flow optimizations\n");
printf(" disable-uniform-memory-optimizations\tDisable uniform-based coherent memory access\n");
printf(" [--yydebug]\t\t\t\tPrint debugging information during parsing\n");
printf(" [--debug-phase=<value>]\t\tSet optimization phases to dump. --debug-phase=first,210:220,300,305,310:last\n");
#ifdef LLVM_3_4
printf(" [--debug-ir=<value>]\t\tSet optimization phase to generate debugIR after it\n");
#endif
printf(" [--off-phase=<value>]\t\tSwitch off optimization phases. --off-phase=first,210:220,300,305,310:last\n");
exit(ret);
}
@@ -212,6 +217,47 @@ lSignal(void *) {
}
static int ParsingPhaseName(char * stage) {
if (strncmp(stage, "first", 5) == 0) {
return 0;
}
else if (strncmp(stage, "last", 4) == 0) {
return LAST_OPT_NUMBER;
}
else {
int t = atoi(stage);
if (t < 0 || t > LAST_OPT_NUMBER) {
fprintf(stderr, "Phases must be from 0 to %d. %s is incorrect.\n", LAST_OPT_NUMBER, stage);
exit(0);
}
else {
return t;
}
}
}
static std::set<int> ParsingPhases(char * stages) {
std::set<int> phases;
int begin = ParsingPhaseName(stages);
int end = begin;
for (unsigned i = 0; i < strlen(stages); i++) {
if ((stages[i] == ',') || (i == strlen(stages) - 1)) {
for (int j = begin; j < end + 1; j++) {
phases.insert(j);
}
begin = ParsingPhaseName(stages + i + 1);
end = begin;
}
else if (stages[i] == ':') {
end = ParsingPhaseName(stages + i + 1);
}
}
return phases;
}
static void
lParseInclude(const char *path) {
#ifdef ISPC_IS_WINDOWS
@@ -489,6 +535,20 @@ int main(int Argc, char *Argv[]) {
}
hostStubFileName = argv[i];
}
else if (strncmp(argv[i], "--debug-phase=", 14) == 0) {
fprintf(stderr, "WARNING: Adding debug phases may change the way PassManager"
"handles the phases and it may possibly make some bugs go"
"away or introduce the new ones.\n");
g->debug_stages = ParsingPhases(argv[i] + strlen("--debug-phase="));
}
#ifdef LLVM_3_4
else if (strncmp(argv[i], "--debug-ir=", 11) == 0) {
g->debugIR = ParsingPhaseName(argv[i] + strlen("--debug-ir="));
}
#endif
else if (strncmp(argv[i], "--off-phase=", 12) == 0) {
g->off_stages = ParsingPhases(argv[i] + strlen("--off-phase="));
}
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
lPrintVersion();
return 0;

146
opt.cpp
View File

@@ -63,6 +63,9 @@
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Constants.h>
#endif
#if defined (LLVM_3_4)
#include <llvm/Transforms/Instrumentation.h>
#endif
#include <llvm/PassManager.h>
#include <llvm/PassRegistry.h>
#include <llvm/Assembly/PrintModulePass.h>
@@ -117,6 +120,8 @@ static llvm::Pass *CreateReplacePseudoMemoryOpsPass();
static llvm::Pass *CreateIsCompileTimeConstantPass(bool isLastTry);
static llvm::Pass *CreateMakeInternalFuncsStaticPass();
static llvm::Pass *CreateDebugPass(char * output);
#define DEBUG_START_PASS(NAME) \
if (g->debugPrint && \
(getenv("FUNC") == NULL || \
@@ -393,6 +398,54 @@ lGetMaskStatus(llvm::Value *mask, int vecWidth = -1) {
}
///////////////////////////////////////////////////////////////////////////
// This is a wrap over class llvm::PassManager. This duplicates PassManager function run()
// and change PassManager function add by adding some checks and debug passes.
// This wrap can control:
// - If we want to switch off optimization with given number.
// - If we want to dump LLVM IR after optimization with given number.
// - If we want to generate LLVM IR debug for gdb after optimization with given number.
class DebugPassManager {
public:
DebugPassManager():number(0){}
void add(llvm::Pass * P, int stage);
bool run(llvm::Module& M) {return PM.run(M);}
llvm::PassManager& getPM() {return PM;}
private:
llvm::PassManager PM;
int number;
};
void
DebugPassManager::add(llvm::Pass * P, int stage = -1) {
// taking number of optimization
if (stage == -1) {
number++;
}
else {
number = stage;
}
if (g->off_stages.find(number) == g->off_stages.end()) {
// adding optimization (not switched off)
PM.add(P);
if (g->debug_stages.find(number) != g->debug_stages.end()) {
// adding dump of LLVM IR after optimization
char buf[100];
sprintf(buf, "\n\n*****LLVM IR after phase %d: %s*****\n\n",
number, P->getPassName());
PM.add(CreateDebugPass(buf));
}
#ifdef LLVM_3_4
if (g->debugIR == number) {
// adding generating of LLVM IR debug after optimization
char buf[100];
sprintf(buf, "Debug_IR_after_%d_phase.bc", number);
PM.add(llvm::createDebugIRPass(true, true, ".", buf));
}
#endif
}
}
///////////////////////////////////////////////////////////////////////////
void
@@ -401,14 +454,8 @@ Optimize(llvm::Module *module, int optLevel) {
printf("*** Code going into optimization ***\n");
module->dump();
}
llvm::PassManager optPM;
optPM.add(llvm::createVerifierPass());
#if 0
std::string err;
optPM.add(llvm::createPrintModulePass(new llvm::raw_fd_ostream("-", err)));
#endif
DebugPassManager optPM;
optPM.add(llvm::createVerifierPass(),0);
llvm::TargetLibraryInfo *targetLibraryInfo =
new llvm::TargetLibraryInfo(llvm::Triple(module->getTargetTriple()));
@@ -425,7 +472,7 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(new llvm::TargetTransformInfo(targetMachine->getScalarTargetTransformInfo(),
targetMachine->getVectorTargetTransformInfo()));
#else // LLVM 3.3+
targetMachine->addAnalysisPasses(optPM);
targetMachine->addAnalysisPasses(optPM.getPM());
#endif
#endif
@@ -437,11 +484,11 @@ Optimize(llvm::Module *module, int optLevel) {
// run absolutely no optimizations, since the front-end needs us to
// take the various __pseudo_* functions it has emitted and turn
// them into something that can actually execute.
optPM.add(CreateImproveMemoryOpsPass());
optPM.add(CreateImproveMemoryOpsPass(), 100);
if (g->opt.disableHandlePseudoMemoryOps == false)
optPM.add(CreateReplacePseudoMemoryOpsPass());
optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateIntrinsicsOptPass(), 102);
optPM.add(CreateIsCompileTimeConstantPass(true));
optPM.add(llvm::createFunctionInliningPass());
optPM.add(CreateMakeInternalFuncsStaticPass());
@@ -460,7 +507,7 @@ Optimize(llvm::Module *module, int optLevel) {
llvm::initializeInstrumentation(*registry);
llvm::initializeTarget(*registry);
optPM.add(llvm::createGlobalDCEPass());
optPM.add(llvm::createGlobalDCEPass(), 200);
// Early optimizations to try to reduce the total amount of code to
// work with if we can
@@ -471,14 +518,14 @@ Optimize(llvm::Module *module, int optLevel) {
if (g->opt.disableGatherScatterOptimizations == false &&
g->target->getVectorWidth() > 1) {
optPM.add(llvm::createInstructionCombiningPass());
optPM.add(llvm::createInstructionCombiningPass(), 210);
optPM.add(CreateImproveMemoryOpsPass());
}
if (!g->opt.disableMaskAllOnOptimizations) {
optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateIntrinsicsOptPass(), 215);
optPM.add(CreateVSelMovmskOptPass());
}
optPM.add(llvm::createDeadInstEliminationPass());
optPM.add(llvm::createDeadInstEliminationPass(), 220);
// Max struct size threshold for scalar replacement is
// 1) 4 fields (r,g,b,w)
@@ -508,9 +555,9 @@ Optimize(llvm::Module *module, int optLevel) {
#if defined(LLVM_3_1) || defined(LLVM_3_2) || defined(LLVM_3_3)
// Starting from 3.4 this functionality was moved to
// InstructionCombiningPass. See r184459 for details.
optPM.add(llvm::createSimplifyLibCallsPass());
optPM.add(llvm::createSimplifyLibCallsPass(), 240);
#endif
optPM.add(llvm::createInstructionCombiningPass());
optPM.add(llvm::createInstructionCombiningPass(), 241);
optPM.add(llvm::createJumpThreadingPass());
optPM.add(llvm::createCFGSimplificationPass());
optPM.add(llvm::createScalarReplAggregatesPass(sr_threshold));
@@ -518,43 +565,45 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(llvm::createTailCallEliminationPass());
if (!g->opt.disableMaskAllOnOptimizations) {
optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateIntrinsicsOptPass(), 250);
optPM.add(CreateVSelMovmskOptPass());
}
if (g->opt.disableGatherScatterOptimizations == false &&
g->target->getVectorWidth() > 1) {
optPM.add(llvm::createInstructionCombiningPass());
optPM.add(llvm::createInstructionCombiningPass(), 255);
optPM.add(CreateImproveMemoryOpsPass());
if (g->opt.disableCoalescing == false &&
g->target->getISA() != Target::GENERIC) {
// It is important to run this here to make it easier to
// finding matching gathers we can coalesce..
optPM.add(llvm::createEarlyCSEPass());
optPM.add(llvm::createEarlyCSEPass(), 260);
optPM.add(CreateGatherCoalescePass());
}
}
optPM.add(llvm::createFunctionInliningPass());
optPM.add(llvm::createFunctionInliningPass(), 265);
optPM.add(llvm::createConstantPropagationPass());
optPM.add(CreateIntrinsicsOptPass());
optPM.add(CreateVSelMovmskOptPass());
if (g->opt.disableGatherScatterOptimizations == false &&
g->target->getVectorWidth() > 1) {
optPM.add(llvm::createInstructionCombiningPass());
optPM.add(llvm::createInstructionCombiningPass(), 270);
optPM.add(CreateImproveMemoryOpsPass());
}
optPM.add(llvm::createIPSCCPPass());
optPM.add(llvm::createIPSCCPPass(), 275);
optPM.add(llvm::createDeadArgEliminationPass());
optPM.add(llvm::createInstructionCombiningPass());
optPM.add(llvm::createCFGSimplificationPass());
if (g->opt.disableHandlePseudoMemoryOps == false)
optPM.add(CreateReplacePseudoMemoryOpsPass());
optPM.add(CreateIntrinsicsOptPass());
if (g->opt.disableHandlePseudoMemoryOps == false) {
optPM.add(CreateReplacePseudoMemoryOpsPass(),280);
}
optPM.add(CreateIntrinsicsOptPass(),281);
optPM.add(CreateVSelMovmskOptPass());
optPM.add(llvm::createFunctionInliningPass());
@@ -570,9 +619,10 @@ Optimize(llvm::Module *module, int optLevel) {
optPM.add(llvm::createIndVarSimplifyPass());
optPM.add(llvm::createLoopIdiomPass());
optPM.add(llvm::createLoopDeletionPass());
if (g->opt.unrollLoops)
optPM.add(llvm::createLoopUnrollPass());
optPM.add(llvm::createGVNPass());
if (g->opt.unrollLoops) {
optPM.add(llvm::createLoopUnrollPass(), 300);
}
optPM.add(llvm::createGVNPass(), 301);
optPM.add(CreateIsCompileTimeConstantPass(true));
optPM.add(CreateIntrinsicsOptPass());
@@ -595,7 +645,7 @@ Optimize(llvm::Module *module, int optLevel) {
// Finish up by making sure we didn't mess anything up in the IR along
// the way.
optPM.add(llvm::createVerifierPass());
optPM.add(llvm::createVerifierPass(), LAST_OPT_NUMBER);
optPM.run(*module);
if (g->debugPrint) {
@@ -4240,6 +4290,42 @@ CreateIsCompileTimeConstantPass(bool isLastTry) {
return new IsCompileTimeConstantPass(isLastTry);
}
//////////////////////////////////////////////////////////////////////////
// DebugPass
/** This pass is added in list of passes after optimizations which
we want to debug and print dump of LLVM IR in stderr. Also it
prints name and number of previous optimization.
*/
class DebugPass : public llvm::ModulePass {
public:
static char ID;
DebugPass(char * output) : ModulePass(ID) {
sprintf(str_output, "%s", output);
}
const char *getPassName() const { return "Dump LLVM IR"; }
bool runOnModule(llvm::Module &m);
private:
char str_output[100];
};
char DebugPass::ID = 0;
bool
DebugPass::runOnModule(llvm::Module &module) {
fprintf(stderr, "%s", str_output);
fflush(stderr);
module.dump();
return true;
}
static llvm::Pass *
CreateDebugPass(char * output) {
return new DebugPass(output);
}
///////////////////////////////////////////////////////////////////////////
// MakeInternalFuncsStaticPass