Add __foreach_active statement to loop over active prog. instances.
For now this has the __ prefix, as an experimental feature currently only used in the standard library implementation. It's probably worth making something along these lines an official feature, but I'm not sure if this in its current form is quite the right thing.
This commit is contained in:
78
stmt.cpp
78
stmt.cpp
@@ -2721,3 +2721,81 @@ int
|
||||
DeleteStmt::EstimateCost() const {
|
||||
return COST_DELETE;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** This generates AST nodes for an __foreach_active statement. This
|
||||
construct can be synthesized ouf of the existing ForStmt (and other AST
|
||||
nodes), so here we just build up the AST that we need rather than
|
||||
having a new Stmt implementation for __foreach_active.
|
||||
|
||||
@param iterSym Symbol for the iteration variable (e.g. "i" in
|
||||
__foreach_active (i) { .. .}
|
||||
@param stmts Statements to execute each time through the loop, for
|
||||
each active program instance.
|
||||
@param pos Position of the __foreach_active statement in the source
|
||||
file.
|
||||
*/
|
||||
Stmt *
|
||||
CreateForeachActiveStmt(Symbol *iterSym, Stmt *stmts, SourcePos pos) {
|
||||
if (iterSym == NULL) {
|
||||
Assert(m->errorCount > 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// loop initializer: set iter = 0
|
||||
std::vector<VariableDeclaration> var;
|
||||
ConstExpr *zeroExpr = new ConstExpr(AtomicType::UniformInt32, 0,
|
||||
iterSym->pos);
|
||||
var.push_back(VariableDeclaration(iterSym, zeroExpr));
|
||||
Stmt *initStmt = new DeclStmt(var, iterSym->pos);
|
||||
|
||||
// loop test: (iter < programCount)
|
||||
ConstExpr *progCountExpr =
|
||||
new ConstExpr(AtomicType::UniformInt32, g->target.vectorWidth,
|
||||
pos);
|
||||
SymbolExpr *symExpr = new SymbolExpr(iterSym, iterSym->pos);
|
||||
Expr *testExpr = new BinaryExpr(BinaryExpr::Lt, symExpr, progCountExpr,
|
||||
pos);
|
||||
|
||||
// loop step: ++iterSym
|
||||
UnaryExpr *incExpr = new UnaryExpr(UnaryExpr::PreInc, symExpr, pos);
|
||||
Stmt *stepStmt = new ExprStmt(incExpr, pos);
|
||||
|
||||
// loop body
|
||||
// First, call __movmsk(__mask)) to get the mask as a set of bits.
|
||||
// This should be hoisted out of the loop
|
||||
Symbol *maskSym = m->symbolTable->LookupVariable("__mask");
|
||||
Assert(maskSym != NULL);
|
||||
Expr *maskVecExpr = new SymbolExpr(maskSym, pos);
|
||||
std::vector<Symbol *> mmFuns;
|
||||
m->symbolTable->LookupFunction("__movmsk", &mmFuns);
|
||||
Assert(mmFuns.size() == 2);
|
||||
FunctionSymbolExpr *movmskFunc = new FunctionSymbolExpr("__movmsk", mmFuns,
|
||||
pos);
|
||||
ExprList *movmskArgs = new ExprList(maskVecExpr, pos);
|
||||
FunctionCallExpr *movmskExpr = new FunctionCallExpr(movmskFunc, movmskArgs,
|
||||
pos);
|
||||
|
||||
// Compute the per lane mask to test the mask bits against: (1 << iter)
|
||||
ConstExpr *oneExpr = new ConstExpr(AtomicType::UniformInt32, 1,
|
||||
iterSym->pos);
|
||||
Expr *shiftLaneExpr = new BinaryExpr(BinaryExpr::Shl, oneExpr, symExpr,
|
||||
pos);
|
||||
|
||||
// Compute the AND: movmsk & (1 << iter)
|
||||
Expr *maskAndLaneExpr = new BinaryExpr(BinaryExpr::BitAnd, movmskExpr,
|
||||
shiftLaneExpr, pos);
|
||||
// Test to see if it's non-zero: (mask & (1 << iter)) != 0
|
||||
Expr *ifTestExpr = new BinaryExpr(BinaryExpr::NotEqual, maskAndLaneExpr,
|
||||
zeroExpr, pos);
|
||||
|
||||
// Now, enclose the provided statements in an if test such that they
|
||||
// only run if the mask is non-zero for the lane we're currently
|
||||
// handling in the loop.
|
||||
IfStmt *laneCheckIf = new IfStmt(ifTestExpr, stmts, NULL, false, pos);
|
||||
|
||||
// And return a for loop that wires it all together.
|
||||
return new ForStmt(initStmt, testExpr, stepStmt, laneCheckIf, false, pos);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user