Skip to content

Commit

Permalink
Merge pull request #35 from 01org/develop
Browse files Browse the repository at this point in the history
Merge from the development branch. Major changes include sub-blocks and default args.
  • Loading branch information
chuckyount authored Apr 12, 2017
2 parents 8ba75b0 + 1022751 commit d9acd6a
Show file tree
Hide file tree
Showing 31 changed files with 2,310 additions and 1,984 deletions.
467 changes: 275 additions & 192 deletions Makefile

Large diffs are not rendered by default.

Binary file modified docs/YASK-intro.pdf
Binary file not shown.
122 changes: 61 additions & 61 deletions gen-loops.pl
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,16 @@ BEGIN
# Globals.
my %OPT; # cmd-line options.
my @dims; # names of dimensions.
my @results; # names of result buffers.
my $genericCache = "L#"; # a string placeholder for L1 or L2.

# loop-feature bit fields.
my $bSerp = 0x1; # serpentine path
my $bSquare = 0x2; # square_wave path
my $bGroup = 0x4; # group path
my $bGroup = 0x4; # group path
my $bSimd = 0x8; # simd prefix
my $bPrefetchL1 = 0x10; # prefetch L1
my $bPrefetchL2 = 0x20; # prefetch L2
my $bPipe = 0x40; # pipeline
my $bPipe = 0x100; # pipeline

##########
# Function to make names of variables based on dimension string(s).
Expand Down Expand Up @@ -851,6 +850,7 @@ ($)
my $ucDir = uc($innerDim);
my $pfd = "PFD$genericCache";
my $nVar = numItersVar(@loopDims);
my $doSplitL2 = ($features & $bPrefetchL2) && $OPT{splitL2};

# declare pipeline vars.
push @code, " // Pipeline accumulators.", " MAKE_PIPE_$ucDir;"
Expand Down Expand Up @@ -902,7 +902,7 @@ ($)
}

# midpoint calculation for L2 prefetch only.
if ($features & $bPrefetchL2) {
if ($doSplitL2) {
my $ofs = ($features & $bPrefetchL1) ? "(PFDL2-PFDL1)" : "PFDL2";
push @code, " // Point where L2-prefetch policy changes.";
push @code, " // This covers all L1 fetches, even unneeded one(s) beyond end."
Expand All @@ -917,7 +917,7 @@ ($)
# loop 1: w/o L2 prefetch from midpoint to end.
# if no L2 prefetch:
# loop 0: no L2 prefetch from start to end.
my $lastLoop = ($features & $bPrefetchL2) ? 1 : 0;
my $lastLoop = $doSplitL2 ? 1 : 0;
for my $loop (0 .. $lastLoop) {

my $name = "Computation";
Expand All @@ -929,6 +929,7 @@ ($)
my $comment = " // $name loop.";
$comment .= " Same as previous loop, except no L2 prefetch." if $loop==1;
push @code, $comment;
push @code, $OPT{innerMod};
beginLoop(\@code, \@loopDims, \@loopPrefix,
$beginVal, $endVal, $features, \@loopStack);

Expand Down Expand Up @@ -1041,64 +1042,63 @@ ($)
# Parse arguments and emit code.
sub main() {

my(@KNOBS) =
( # knob, description, optional default
[ "dims=s", "Comma-separated names of dimensions (in order passed via calls).", 'v,x,y,z'],
[ "comArgs=s", "Common arguments to all calls (after L1/L2 for prefetch).", ''],
[ "resultBlks=s", "Comma-separated name of block-sized buffers that hold inter-loop values and/or final result at 'save' command.", 'result'],
[ "calcPrefix=s", "Prefix for calculation call.", 'calc_'],
[ "primePrefix=s", "Prefix for pipeline-priming call.", 'prime_'],
[ "pipePrefix=s", "Additional prefix for pipeline call.", 'pipe_'],
[ "pfPrefix=s", "Prefix for prefetch call.", 'prefetch_'],
[ "ompConstruct=s", "Pragma to use before 'omp' loop(s).", "omp parallel for"],
[ "output=s", "Name of output file.", 'loops.h'],
);
my($command_line) = process_command_line(\%OPT, \@KNOBS);
print "$command_line\n" if $OPT{verbose};

my $script = basename($0);
if (!$command_line || $OPT{help} || @ARGV < 1) {
print "Outputs C++ code for a loop block.\n",
"Usage: $script [options] <loop-code-string>\n",
"Examples:\n",
" $script -dims x,y 'loop(x,y) { calc(f); }'\n",
" $script -dims x,y,z 'omp loop(x,y) { loop(z) { calc(f); } }'\n",
" $script -dims x,y,z 'omp loop(x,y) { prefetch loop(z) { calc(f); } }'\n",
#" $script -dims x,y,z 'omp loop(x,y) { pipeline loop(z) { calc(f); } }'\n",
" $script -dims x,y,z 'grouped omp loop(x,y,z) { calc(f); }'\n",
" $script -dims x,y,z 'omp loop(x) { serpentine loop(y,z) { calc(f); } }'\n",
" $script -dims x,y,z 'omp loop(x) { crew loop(y) { loop(z) { calc(f); } } }'\n",
"Inner loops should contain calc statements that generate calls to calculation functions.\n",
"A loop statement with more than one argument will generate a single collapsed loop.\n",
"Optional loop modifiers:\n",
" omp: generate an OpenMP for loop (distribute work across SW threads).\n",
" crew: generate an Intel crew loop (distribute work across HW threads).\n",
" prefetch: generate calls to SW L1 & L2 prefetch functions in addition to calc functions.\n",
" prefetch(L1,L2): generate calls to SW L1 & L2 prefetch functions in addition to calc functions.\n",
" prefetch(L1): generate calls to SW L1 prefetch functions in addition to calc functions.\n",
" prefetch(L2): generate calls to SW L2 prefetch functions in addition to calc functions.\n",
" grouped: generate grouped path within a collapsed loop.\n",
" serpentine: generate reverse path when enclosing loop dimension is odd.\n",
" square_wave: generate 2D square-wave path for two innermost dimensions of a collapsed loop.\n",
#" pipeline: generate calls to pipeline versions of calculation functions (deprecated).\n",
"For each dim D in dims, loops are generated from begin_D to end_D-1 by step_D;\n",
" if grouping is used, groups are of size group_size_D;\n",
" these vars must be defined *outside* of the generated code.\n",
"Each iteration will cover values from start_D to stop_D-1;\n",
" these vars will be defined in the generated code.\n",
"Options:\n";
print_options_help(\@KNOBS);
exit 1;
}

@dims = split(/\s*,\s*/, $OPT{dims});
@results = split(/\s*,\s*/, $OPT{resultBlks});
my(@KNOBS) = (
# knob, description, optional default
[ "dims=s", "Comma-separated names of dimensions (in order passed via calls).", 'v,x,y,z'],
[ "comArgs=s", "Common arguments to all calls (after L1/L2 for prefetch).", ''],
[ "calcPrefix=s", "Prefix for calculation call.", 'calc_'],
[ "primePrefix=s", "Prefix for pipeline-priming call.", 'prime_'],
[ "pipePrefix=s", "Additional prefix for pipeline call.", 'pipe_'],
[ "pfPrefix=s", "Prefix for prefetch call.", 'prefetch_'],
[ "ompConstruct=s", "Pragma to use before 'omp' loop(s).", "omp parallel for"],
[ "innerMod=s", "Code to insert before inner computation loops.",
'_Pragma("nounroll_and_jam") _Pragma("nofusion")'],
[ "splitL2!", "Split inner loops with L2 prefetching.", 0],
[ "output=s", "Name of output file.", 'loops.h'],
);
my($command_line) = process_command_line(\%OPT, \@KNOBS);
print "$command_line\n" if $OPT{verbose};

my $script = basename($0);
if (!$command_line || $OPT{help} || @ARGV < 1) {
print "Outputs C++ code for a loop block.\n",
"Usage: $script [options] <loop-code-string>\n",
"Examples:\n",
" $script -dims x,y 'loop(x,y) { calc(f); }'\n",
" $script -dims x,y,z 'omp loop(x,y) { loop(z) { calc(f); } }'\n",
" $script -dims x,y,z 'omp loop(x,y) { prefetch loop(z) { calc(f); } }'\n",
#" $script -dims x,y,z 'omp loop(x,y) { pipeline loop(z) { calc(f); } }'\n",
" $script -dims x,y,z 'grouped omp loop(x,y,z) { calc(f); }'\n",
" $script -dims x,y,z 'omp loop(x) { serpentine loop(y,z) { calc(f); } }'\n",
" $script -dims x,y,z 'omp loop(x) { crew loop(y) { loop(z) { calc(f); } } }'\n",
"Inner loops should contain calc statements that generate calls to calculation functions.\n",
"A loop statement with more than one argument will generate a single collapsed loop.\n",
"Optional loop modifiers:\n",
" omp: generate an OpenMP for loop (distribute work across SW threads).\n",
" crew: generate an Intel crew loop (distribute work across HW threads).\n",
" prefetch: generate calls to SW L1 & L2 prefetch functions in addition to calc functions.\n",
" prefetch(L1,L2): generate calls to SW L1 & L2 prefetch functions in addition to calc functions.\n",
" prefetch(L1): generate calls to SW L1 prefetch functions in addition to calc functions.\n",
" prefetch(L2): generate calls to SW L2 prefetch functions in addition to calc functions.\n",
" grouped: generate grouped path within a collapsed loop.\n",
" serpentine: generate reverse path when enclosing loop dimension is odd.\n",
" square_wave: generate 2D square-wave path for two innermost dimensions of a collapsed loop.\n",
#" pipeline: generate calls to pipeline versions of calculation functions (deprecated).\n",
"For each dim D in dims, loops are generated from begin_D to end_D-1 by step_D;\n",
" if grouping is used, groups are of size group_size_D;\n",
" these vars must be defined *outside* of the generated code.\n",
"Each iteration will cover values from start_D to stop_D-1;\n",
" these vars will be defined in the generated code.\n",
"Options:\n";
print_options_help(\@KNOBS);
exit 1;
}

warn "info: generating ".scalar(@dims)."-D loop code with ".
scalar(@results)." output(s).\n";
@dims = split(/\s*,\s*/, $OPT{dims});
warn "info: generating ".scalar(@dims)."-D loop code...\n";

my $codeString = join(' ', @ARGV);
processCode($codeString);
my $codeString = join(' ', @ARGV);
processCode($codeString);
}

main();
21 changes: 17 additions & 4 deletions src/foldBuilder/Cpp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class CppPrintHelper : public PrintHelper {

// Return a parameter reference.
virtual string readFromParam(ostream& os, const GridPoint& pp) {
string str = "(*context." + pp.getName() + ")(" + pp.makeValStr() + ")";
string str = "(*_context->" + pp.getName() + ")(" + pp.makeValStr() + ")";
return str;
}

Expand All @@ -73,7 +73,7 @@ class CppPrintHelper : public PrintHelper {
virtual string makePointCall(const GridPoint& gp,
const string& fname, string optArg = "") const {
ostringstream oss;
oss << "context." << gp.getName() << "->" << fname << "(";
oss << "_context->" << gp.getName() << "->" << fname << "(";
if (optArg.length()) oss << optArg << ", ";
oss << gp.makeDimValOffsetStr() << ", __LINE__)";
return oss.str();
Expand Down Expand Up @@ -120,7 +120,7 @@ class CppVecPrintHelper : public VecPrintHelper {

// Return a parameter reference.
virtual string readFromParam(ostream& os, const GridPoint& pp) {
string str = "(*context." + pp.getName() + ")(" + pp.makeValStr() + ")";
string str = "(*_context->" + pp.getName() + ")(" + pp.makeValStr() + ")";
return str;
}

Expand All @@ -140,7 +140,7 @@ class CppVecPrintHelper : public VecPrintHelper {
const string& firstArg,
const string& lastArg,
bool isNorm) const {
os << " context." << gp.getName() << "->" << funcName << "(";
os << " _context->" << gp.getName() << "->" << funcName << "(";
if (firstArg.length())
os << firstArg << ", ";
if (isNorm)
Expand Down Expand Up @@ -300,6 +300,8 @@ class YASKCppPrinter : public PrinterBase {
Dimensions& _dims;
YASKCppSettings& _settings;
string _context, _context_base;
IntTuple _yask_dims; // spatial dims in yask.
string _yask_step; // step dim in yask.

// Print an expression as a one-line C++ comment.
void addComment(ostream& os, EqGroup& eq) {
Expand Down Expand Up @@ -333,12 +335,23 @@ class YASKCppPrinter : public PrinterBase {
// name of C++ struct.
_context = "StencilContext_" + _stencil.getName();
_context_base = _context + "_data";

// YASK dims are hard-coded.
// TODO: fix YASK.
_yask_step = "t";
_yask_dims.addDimBack("w", 1);
_yask_dims.addDimBack("x", 1);
_yask_dims.addDimBack("y", 1);
_yask_dims.addDimBack("z", 1);
}
virtual ~YASKCppPrinter() { }

virtual void printMacros(ostream& os);
virtual void printGrids(ostream& os);
virtual void printCode(ostream& os);
virtual void printShim(ostream& os, const string& fname,
bool use_template = false,
const string& dim = "");
};

#endif
16 changes: 8 additions & 8 deletions src/foldBuilder/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ IfExprPtr operator IF_OPER(EqualsExprPtr expr, const BoolExprPtr cond) {
}

// Define the value of a grid point.
EqualsExprPtr operator EQUIV_OPER(GridPointPtr gpp, const NumExprPtr rhs) {
EqualsExprPtr operator EQUALS_OPER(GridPointPtr gpp, const NumExprPtr rhs) {

// Get grid referenced by the expr.
assert(gpp);
Expand All @@ -220,8 +220,8 @@ EqualsExprPtr operator EQUIV_OPER(GridPointPtr gpp, const NumExprPtr rhs) {

return expr;
}
EqualsExprPtr operator EQUIV_OPER(GridPointPtr gpp, double rhs) {
return gpp EQUIV_OPER constNum(rhs);
EqualsExprPtr operator EQUALS_OPER(GridPointPtr gpp, double rhs) {
return gpp EQUALS_OPER constNum(rhs);
}

// Visitor acceptors.
Expand Down Expand Up @@ -684,7 +684,7 @@ void Grids::findDeps(IntTuple& pts,
assert(outGrids.count(eq1p));
assert(inGrids.count(eq1p));
auto& og1 = outGrids.at(eq1p);
auto& ig1 = inGrids.at(eq1p);
//auto& ig1 = inGrids.at(eq1p);
auto& op1 = outPts.at(eq1p);
auto& ip1 = inPts.at(eq1p);
auto cond1 = g1->getCond(eq1p);
Expand Down Expand Up @@ -744,7 +744,7 @@ void Grids::findDeps(IntTuple& pts,
// All eqs in grid g2.
for (auto eq2 : g2->getEqs()) {
auto* eq2p = eq2.get();
auto& og2 = outGrids.at(eq2p);
//auto& og2 = outGrids.at(eq2p);
auto& ig2 = inGrids.at(eq2p);
auto& op2 = outPts.at(eq2p);
auto& ip2 = inPts.at(eq2p);
Expand Down Expand Up @@ -807,8 +807,8 @@ void Grids::findDeps(IntTuple& pts,
// may or may not be legal.
//
// Example:
// eq1: a(t+1, x, ...) IS_EQUIV_TO ... IF ...
// eq2: b(t+1, x, ...) IS_EQUIV_TO a(t+1, x+5, ...) ... IF ...
// eq1: a(t+1, x, ...) EQUALS ... IF ...
// eq2: b(t+1, x, ...) EQUALS a(t+1, x+5, ...) ... IF ...
//
// TODO: be much smarter about this and find only real
// dependencies--use a polyhedral library?
Expand Down Expand Up @@ -1168,7 +1168,7 @@ void EqGroups::findEqGroups(Grids& allGrids,
IntTuple& pts,
EqDepMap& eq_deps)
{
auto& stepDim = _dims->_stepDim;
//auto& stepDim = _dims->_stepDim;

// Map to track indices per eq-group name.
map<string, int> indices;
Expand Down
29 changes: 16 additions & 13 deletions src/foldBuilder/Expr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,12 @@ void operator/=(NumExprPtr& lhs, const NumExprPtr rhs);
void operator/=(NumExprPtr& lhs, double rhs);

// The '==' operator used for defining a grid value.
#define EQUIV_OPER ==
EqualsExprPtr operator EQUIV_OPER(GridPointPtr gpp, const NumExprPtr rhs);
EqualsExprPtr operator EQUIV_OPER(GridPointPtr gpp, double rhs);
#define IS_EQUIV_TO EQUIV_OPER
#define IS_EQUIVALENT_TO EQUIV_OPER
#define EQUALS_OPER ==
EqualsExprPtr operator EQUALS_OPER(GridPointPtr gpp, const NumExprPtr rhs);
EqualsExprPtr operator EQUALS_OPER(GridPointPtr gpp, double rhs);
#define EQUALS EQUALS_OPER
#define IS_EQUIV_TO EQUALS_OPER
#define IS_EQUIVALENT_TO EQUALS_OPER

// The '==' operator for comparing values.
BoolExprPtr operator==(const NumExprPtr lhs, const NumExprPtr rhs);
Expand Down Expand Up @@ -878,7 +879,7 @@ class EqDeps {

// Check whether eq a depends on b.
virtual bool is_dep_on(EqualsExprPtr a, EqualsExprPtr b) const {
assert(_done);
assert(_done || _deps.size() == 0);
return _full_deps.count(a) && _full_deps.at(a).count(b) > 0;
}

Expand Down Expand Up @@ -1142,7 +1143,7 @@ class Grids : public vector_set<Grid*> {

// Aliases for parameters.
// Even though these are just typedefs for now, don't interchange them.
// TODO: enforce the difference between grids and parameters.
// TODO: make params just a special case of grids.
typedef Grid Param;
typedef Grids Params;

Expand Down Expand Up @@ -1324,9 +1325,11 @@ class EqGroups : public vector<EqGroup> {
EqDepMap& eq_deps);
void findEqGroups(Grids& grids,
const string& targets,
IntTuple& pts) {
IntTuple& pts,
bool find_deps) {
EqDepMap eq_deps;
grids.findDeps(pts, _dims->_stepDim, &eq_deps);
if (find_deps)
grids.findDeps(pts, _dims->_stepDim, &eq_deps);
findEqGroups(grids, targets, pts, eq_deps);
}

Expand Down Expand Up @@ -1429,14 +1432,14 @@ typedef NumExprPtr GridValue;
// of the local var must be evaluated and inserted in the expr.
// Example code:
// GridValue v;
// SET_VALUE_FROM_EXPR(v =, "context.temp * " << 0.2);
// SET_VALUE_FROM_EXPR(v +=, "context.coeff[" << r << "]");
// SET_VALUE_FROM_EXPR(v =, "_context->temp * " << 0.2);
// SET_VALUE_FROM_EXPR(v +=, "_context->coeff[" << r << "]");
// This example would generate the following partial expression (when r=9):
// (context.temp * 2.00000000000000000e-01) + (context.coeff[9])
// (_context->temp * 2.00000000000000000e-01) + (_context->coeff[9])
#define SET_VALUE_FROM_EXPR(lhs, rhs) do { \
ostringstream oss; \
oss << setprecision(17) << scientific; \
oss << "(" << rhs << ")"; \
oss << "(" << rhs << ")"; \
lhs make_shared<CodeExpr>(oss.str()); \
} while(0)

Expand Down
1 change: 1 addition & 0 deletions src/foldBuilder/ExprUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ class TrackingVisitor : public ExprVisitor {
map<Expr*, int> _counts;
int _visits;

// Visits are considered unique by address, not semantic equivalence.
virtual bool alreadyVisited(Expr* ep) {
#if DEBUG_TRACKING >= 1
cout << "- tracking '" << ep->makeStr() << "'@" << ep << endl;
Expand Down
Loading

0 comments on commit d9acd6a

Please sign in to comment.