forked from OSchip/llvm-project
[CodeGen] Print executed statement instances at runtime.
Add the options -polly-codegen-trace-stmts and -polly-codegen-trace-scalars. When enabled, adds a call to the beginning of every generated statement that prints the executed statement instance. With -polly-codegen-trace-scalars, it also prints the value of all scalars that are used in the statement, and PHIs defined in the beginning of the statement. Differential Revision: https://reviews.llvm.org/D45743 llvm-svn: 330864
This commit is contained in:
parent
152060275f
commit
e819fffee3
|
@ -329,6 +329,25 @@ protected:
|
|||
ValueMapT &BBMap,
|
||||
__isl_keep isl_id_to_ast_expr *NewAccesses);
|
||||
|
||||
/// When statement tracing is enable, build the print instructions for
|
||||
/// printing the current statement instance and its input scalars.
|
||||
///
|
||||
/// The printed output looks like:
|
||||
///
|
||||
/// Stmt1(0)
|
||||
///
|
||||
/// If printing of scalars is enabled, it also appends the value of each
|
||||
/// scalar to the line:
|
||||
///
|
||||
/// Stmt1(0) %i=1 %sum=5
|
||||
///
|
||||
/// @param Stmt The statement we generate code for.
|
||||
/// @param LTS A mapping from loops virtual canonical induction
|
||||
/// variable to their new values.
|
||||
/// @param BBMap A mapping from old values to their new values in this block.
|
||||
void generateBeginStmtTrace(ScopStmt &Stmt, LoopToScevMapT <S,
|
||||
ValueMapT &BBMap);
|
||||
|
||||
/// Generate instructions that compute whether one instance of @p Set is
|
||||
/// executed.
|
||||
///
|
||||
|
|
|
@ -30,6 +30,28 @@ namespace polly {
|
|||
/// run time.
|
||||
struct RuntimeDebugBuilder {
|
||||
|
||||
/// Generate a constant string into the builder's llvm::Module which can be
|
||||
/// passed to createGPUPrinter() or createGPUPrinter().
|
||||
///
|
||||
/// @param Builder The builder used to emit the printer calls.
|
||||
/// @param Str The string to be printed.
|
||||
|
||||
/// @return A global containing @p Str.
|
||||
static llvm::Value *getPrintableString(PollyIRBuilder &Builder,
|
||||
llvm::StringRef Str) {
|
||||
// TODO: Get rid of magic number 4. It it NVPTX's constant address space and
|
||||
// works on X86 (CPU) only because its backend ignores the address space.
|
||||
return Builder.CreateGlobalStringPtr(Str, "", 4);
|
||||
}
|
||||
|
||||
/// Return whether an llvm::Value of the type @p Ty is printable for
|
||||
/// debugging.
|
||||
///
|
||||
/// That is, whether such a value can be passed to createGPUPrinter() or
|
||||
/// createGPUPrinter() to be dumped as runtime. If false is returned, those
|
||||
/// functions will fail.
|
||||
static bool isPrintable(llvm::Type *Ty);
|
||||
|
||||
/// Print a set of LLVM-IR Values or StringRefs via printf
|
||||
///
|
||||
/// This function emits a call to printf that will print the given arguments.
|
||||
|
@ -78,7 +100,7 @@ private:
|
|||
static void createPrinter(PollyIRBuilder &Builder, bool UseGPU,
|
||||
std::vector<llvm::Value *> &Values,
|
||||
llvm::StringRef String, Args... args) {
|
||||
Values.push_back(Builder.CreateGlobalStringPtr(String, "", 4));
|
||||
Values.push_back(getPrintableString(Builder, String));
|
||||
createPrinter(Builder, UseGPU, Values, args...);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,17 @@ static cl::opt<bool, true> DebugPrintingX(
|
|||
cl::location(PollyDebugPrinting), cl::Hidden, cl::init(false),
|
||||
cl::ZeroOrMore, cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> TraceStmts(
|
||||
"polly-codegen-trace-stmts",
|
||||
cl::desc("Add printf calls that print the statement being executed"),
|
||||
cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> TraceScalars(
|
||||
"polly-codegen-trace-scalars",
|
||||
cl::desc("Add printf calls that print the values of all scalar values "
|
||||
"used in a statement. Requires -polly-codegen-trace-stmts."),
|
||||
cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
|
||||
|
||||
BlockGenerator::BlockGenerator(
|
||||
PollyIRBuilder &B, LoopInfo &LI, ScalarEvolution &SE, DominatorTree &DT,
|
||||
AllocaMapTy &ScalarMap, EscapeUsersAllocaMapTy &EscapeMap,
|
||||
|
@ -436,6 +447,7 @@ BasicBlock *BlockGenerator::copyBB(ScopStmt &Stmt, BasicBlock *BB,
|
|||
BasicBlock *CopyBB = splitBB(BB);
|
||||
Builder.SetInsertPoint(&CopyBB->front());
|
||||
generateScalarLoads(Stmt, LTS, BBMap, NewAccesses);
|
||||
generateBeginStmtTrace(Stmt, LTS, BBMap);
|
||||
|
||||
copyBB(Stmt, BB, CopyBB, BBMap, LTS, NewAccesses);
|
||||
|
||||
|
@ -647,6 +659,108 @@ void BlockGenerator::generateConditionalExecution(
|
|||
Builder.SetInsertPoint(TailBlock, TailBlock->getFirstInsertionPt());
|
||||
}
|
||||
|
||||
static std::string getInstName(Value *Val) {
|
||||
std::string Result;
|
||||
raw_string_ostream OS(Result);
|
||||
Val->printAsOperand(OS, false);
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
void BlockGenerator::generateBeginStmtTrace(ScopStmt &Stmt, LoopToScevMapT <S,
|
||||
ValueMapT &BBMap) {
|
||||
if (!TraceStmts)
|
||||
return;
|
||||
|
||||
Scop *S = Stmt.getParent();
|
||||
const char *BaseName = Stmt.getBaseName();
|
||||
|
||||
isl::ast_build AstBuild = Stmt.getAstBuild();
|
||||
isl::set Domain = Stmt.getDomain();
|
||||
|
||||
isl::union_map USchedule = AstBuild.get_schedule().intersect_domain(Domain);
|
||||
isl::map Schedule = isl::map::from_union_map(USchedule);
|
||||
assert(Schedule.is_empty().is_false() &&
|
||||
"The stmt must have a valid instance");
|
||||
|
||||
isl::multi_pw_aff ScheduleMultiPwAff =
|
||||
isl::pw_multi_aff::from_map(Schedule.reverse());
|
||||
isl::ast_build RestrictedBuild = AstBuild.restrict(Schedule.range());
|
||||
|
||||
// Sequence of strings to print.
|
||||
SmallVector<llvm::Value *, 8> Values;
|
||||
|
||||
// Print the name of the statement.
|
||||
// TODO: Indent by the depth of the statement instance in the schedule tree.
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, BaseName));
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, "("));
|
||||
|
||||
// Add the coordinate of the statement instance.
|
||||
int DomDims = ScheduleMultiPwAff.dim(isl::dim::out);
|
||||
for (int i = 0; i < DomDims; i += 1) {
|
||||
if (i > 0)
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, ","));
|
||||
|
||||
isl::ast_expr IsInSet =
|
||||
RestrictedBuild.expr_from(ScheduleMultiPwAff.get_pw_aff(i));
|
||||
Values.push_back(ExprBuilder->create(IsInSet.copy()));
|
||||
}
|
||||
|
||||
if (TraceScalars) {
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, ")"));
|
||||
DenseSet<Instruction *> Encountered;
|
||||
|
||||
// Add the value of each scalar (and the result of PHIs) used in the
|
||||
// statement.
|
||||
// TODO: Values used in region-statements.
|
||||
for (Instruction *Inst : Stmt.insts()) {
|
||||
if (!RuntimeDebugBuilder::isPrintable(Inst->getType()))
|
||||
continue;
|
||||
|
||||
if (isa<PHINode>(Inst)) {
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, " "));
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(
|
||||
Builder, getInstName(Inst)));
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, "="));
|
||||
Values.push_back(getNewValue(Stmt, Inst, BBMap, LTS,
|
||||
LI.getLoopFor(Inst->getParent())));
|
||||
} else {
|
||||
for (Value *Op : Inst->operand_values()) {
|
||||
// Do not print values that cannot change during the execution of the
|
||||
// SCoP.
|
||||
auto *OpInst = dyn_cast<Instruction>(Op);
|
||||
if (!OpInst)
|
||||
continue;
|
||||
if (!S->contains(OpInst))
|
||||
continue;
|
||||
|
||||
// Print each scalar at most once, and exclude values defined in the
|
||||
// statement itself.
|
||||
if (Encountered.count(OpInst))
|
||||
continue;
|
||||
|
||||
Values.push_back(
|
||||
RuntimeDebugBuilder::getPrintableString(Builder, " "));
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(
|
||||
Builder, getInstName(OpInst)));
|
||||
Values.push_back(
|
||||
RuntimeDebugBuilder::getPrintableString(Builder, "="));
|
||||
Values.push_back(getNewValue(Stmt, OpInst, BBMap, LTS,
|
||||
LI.getLoopFor(Inst->getParent())));
|
||||
Encountered.insert(OpInst);
|
||||
}
|
||||
}
|
||||
|
||||
Encountered.insert(Inst);
|
||||
}
|
||||
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, "\n"));
|
||||
} else {
|
||||
Values.push_back(RuntimeDebugBuilder::getPrintableString(Builder, ")\n"));
|
||||
}
|
||||
|
||||
RuntimeDebugBuilder::createCPUPrinter(Builder, ArrayRef<Value *>(Values));
|
||||
}
|
||||
|
||||
void BlockGenerator::generateScalarStores(
|
||||
ScopStmt &Stmt, LoopToScevMapT <S, ValueMapT &BBMap,
|
||||
__isl_keep isl_id_to_ast_expr *NewAccesses) {
|
||||
|
@ -1375,6 +1489,7 @@ void RegionGenerator::copyStmt(ScopStmt &Stmt, LoopToScevMapT <S,
|
|||
|
||||
ValueMapT &EntryBBMap = RegionMaps[EntryBBCopy];
|
||||
generateScalarLoads(Stmt, LTS, EntryBBMap, IdToAstExp);
|
||||
generateBeginStmtTrace(Stmt, LTS, EntryBBMap);
|
||||
|
||||
for (auto PI = pred_begin(EntryBB), PE = pred_end(EntryBB); PI != PE; ++PI)
|
||||
if (!R->contains(*PI)) {
|
||||
|
|
|
@ -103,6 +103,19 @@ void RuntimeDebugBuilder::createPrinter(PollyIRBuilder &Builder, bool IsGPU,
|
|||
createCPUPrinterT(Builder, Values);
|
||||
}
|
||||
|
||||
bool RuntimeDebugBuilder::isPrintable(Type *Ty) {
|
||||
if (Ty->isFloatingPointTy())
|
||||
return true;
|
||||
|
||||
if (Ty->isIntegerTy())
|
||||
return Ty->getIntegerBitWidth() <= 64;
|
||||
|
||||
if (isa<PointerType>(Ty))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::tuple<std::string, std::vector<Value *>>
|
||||
prepareValuesForPrinting(PollyIRBuilder &Builder, ArrayRef<Value *> Values) {
|
||||
std::string FormatString;
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
; RUN: opt %loadPolly -polly-codegen-trace-stmts -polly-codegen-trace-scalars -polly-codegen -S < %s | FileCheck %s
|
||||
;
|
||||
|
||||
define void @func(i32 %n, double* %A) {
|
||||
entry:
|
||||
br label %for
|
||||
|
||||
for:
|
||||
%j = phi i32 [0, %entry], [%j.inc, %inc]
|
||||
%j.cmp = icmp slt i32 %j, %n
|
||||
br i1 %j.cmp, label %body, label %exit
|
||||
|
||||
body:
|
||||
%A_idx = getelementptr inbounds double, double* %A, i32 %j
|
||||
store double 0.0, double* %A_idx
|
||||
br label %inc
|
||||
|
||||
inc:
|
||||
%j.inc = add nuw nsw i32 %j, 1
|
||||
br label %for
|
||||
|
||||
exit:
|
||||
br label %return
|
||||
|
||||
return:
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; CHECK: @0 = private unnamed_addr addrspace(4) constant [10 x i8] c"Stmt_body\00"
|
||||
; CHECK: @1 = private unnamed_addr addrspace(4) constant [2 x i8] c"(\00"
|
||||
; CHECK: @2 = private unnamed_addr addrspace(4) constant [2 x i8] c")\00"
|
||||
; CHECK: @3 = private unnamed_addr addrspace(4) constant [2 x i8] c"\0A\00"
|
||||
; CHECK: @4 = private unnamed_addr constant [12 x i8] c"%s%s%ld%s%s\00"
|
||||
|
||||
; CHECK: polly.stmt.body:
|
||||
; CHECK: call i32 (...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @4, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([10 x i8], [10 x i8] addrspace(4)* @0, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @1, i32 0, i32 0), i64 %polly.indvar, i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @2, i32 0, i32 0), i8 addrspace(4)* getelementptr inbounds ([2 x i8], [2 x i8] addrspace(4)* @3, i32 0, i32 0))
|
||||
; CHECK-NEXT: call i32 @fflush(i8* null)
|
Loading…
Reference in New Issue