void deadVariableElimination(FnSymbol* fn) { Vec<Symbol*> symSet; Vec<SymExpr*> symExprs; collectSymbolSetSymExprVec(fn, symSet, symExprs); Map<Symbol*,Vec<SymExpr*>*> defMap; Map<Symbol*,Vec<SymExpr*>*> useMap; buildDefUseMaps(symSet, symExprs, defMap, useMap); forv_Vec(Symbol, sym, symSet) { // We're interested only in VarSymbols. if (!isVarSymbol(sym)) continue; // A method must have a _this symbol, even if it is not used. if (sym == fn->_this) continue; if (isDeadVariable(sym, defMap, useMap)) { for_defs(se, defMap, sym) { CallExpr* call = toCallExpr(se->parentExpr); INT_ASSERT(call && (call->isPrimitive(PRIM_MOVE) || call->isPrimitive(PRIM_ASSIGN))); Expr* rhs = call->get(2)->remove(); if (!isSymExpr(rhs)) call->replace(rhs); else call->remove(); } sym->defPoint->remove(); } }
/* * Returns true if `e` has no side effects. Checked side effects are: * - Read/write to a global * - Is/contains essential primitive * - If it's a call to functions with ref arguments * - If the LHS of a PRIM_MOVE appears in the exprToMove * * For now, this is a very conservative analysis. A more precise analysis * could distinguish between reads and writes to memory and to take into * account alias analysis. */ bool SafeExprAnalysis::exprHasNoSideEffects(Expr* e, Expr* exprToMove) { if(safeExprCache.count(e) > 0) { return safeExprCache[e]; } if(CallExpr* ce = toCallExpr(e)) { if(!ce->isPrimitive()) { FnSymbol* fnSym = ce->theFnSymbol(); const bool cachedSafeFn = safeFnCache.count(fnSym); if(!cachedSafeFn) { const bool retval = fnHasNoSideEffects(fnSym); safeFnCache[fnSym] = retval; return retval; } return safeFnCache[fnSym]; } else { //primitive if(! isSafePrimitive(ce)){ safeExprCache[e] = false; return false; } else if (exprToMove != NULL) { // // Exposed by AST pattern like this: // |---|------- `exprToMove` // (move T (+ A B)) // (move A B) -------- `ce` // (move B T) // // Without this check could turn into: // // (move A B) // (move B (+ A B)) // // Which is incorrect. // if (ce->isPrimitive(PRIM_MOVE)) { INT_ASSERT(isSymExpr(ce->get(1))); std::vector<SymExpr*> syms; collectSymExprs(exprToMove, syms); for_vector(SymExpr, s, syms) { if (s->symbol() == toSymExpr(ce->get(1))->symbol()) { safeExprCache[e] = false; return false; } } } } } }
void BlockStmt::verify() { Expr::verify(); if (astTag != E_BlockStmt) { INT_FATAL(this, "BlockStmt::verify. Bad astTag"); } if (body.parent != this) INT_FATAL(this, "BlockStmt::verify. Bad body.parent"); for_alist(expr, body) { if (expr->parentExpr != this) INT_FATAL(this, "BlockStmt::verify. Bad body.expr->parentExpr"); } if (blockInfo != NULL && blockInfo->parentExpr != this) { INT_FATAL(this, "BlockStmt::verify. Bad blockInfo->parentExpr"); } if (useList != NULL && useList->parentExpr != this) { INT_FATAL(this, "BlockStmt::verify. Bad useList->parentExpr"); } if (byrefVars) { if (byrefVars->parentExpr != this) { INT_FATAL(this, "BlockStmt::verify. Bad byrefVars->parentExpr"); } if (!byrefVars->isPrimitive(PRIM_ACTUALS_LIST)) { INT_FATAL(this, "BlockStmt::byrefVars not PRIM_ACTUALS_LIST"); } for_actuals(varExp, byrefVars) { if (!isSymExpr(varExp) && !isUnresolvedSymExpr(varExp)) { INT_FATAL(this, "BlockStmt::verify. Bad expression kind in byrefVars"); } } } verifyNotOnList(useList); verifyNotOnList(byrefVars); verifyNotOnList(blockInfo); }