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(); } }
// Mark the variables listed in 'with' clauses, if any, with tiMark markers. // Same as markOuterVarsWithIntents() in implementForallIntents.cpp, // except uses byrefVars instead of forallIntents. static void markOuterVarsWithIntents(CallExpr* byrefVars, SymbolMap& uses) { if (!byrefVars) return; Symbol* marker = NULL; // Keep in sync with setupForallIntents() - the actuals alternate: // (tiMark arg | reduce opExpr), task-intent variable [, repeat] for_actuals(actual, byrefVars) { SymExpr* se = toSymExpr(actual); INT_ASSERT(se); // comes as an UnresolvedSymExpr from the parser, // should have been resolved in ScopeResolve // or it is a SymExpr over a tiMark ArgSymbol // or over chpl__reduceGlob Symbol* var = se->symbol(); if (marker) { SymbolMapElem* elem = uses.get_record(var); if (elem) { elem->value = marker; } else { if (isVarSymbol(marker)) { // this is a globalOp created in setupOneReduceIntent() INT_ASSERT(!strcmp(marker->name, "chpl__reduceGlob")); USR_WARN(byrefVars, "the variable '%s' is given a reduce intent and not mentioned in the loop body - it will have the unit value after the loop", var->name); } } marker = NULL; } else { marker = var; INT_ASSERT(marker); // otherwise the alternation logic will not work } }
GenRet BlockStmt::codegen() { GenInfo* info = gGenInfo; FILE* outfile = info->cfile; GenRet ret; codegenStmt(this); if( outfile ) { if (blockInfo) { if (blockInfo->isPrimitive(PRIM_BLOCK_WHILEDO_LOOP)) { std::string hdr = "while (" + codegenValue(blockInfo->get(1)).c + ") "; info->cStatements.push_back(hdr); } else if (blockInfo->isPrimitive(PRIM_BLOCK_DOWHILE_LOOP)) { info->cStatements.push_back("do "); } else if (blockInfo->isPrimitive(PRIM_BLOCK_FOR_LOOP)) { std::string hdr = "for (;" + codegenValue(blockInfo->get(1)).c + ";) "; info->cStatements.push_back(hdr); } else if (blockInfo->isPrimitive(PRIM_BLOCK_XMT_PRAGMA_FORALL_I_IN_N)) { std::string hdr = "_Pragma(\"mta for all streams "; hdr += codegenValue(blockInfo->get(1)).c; hdr += " of "; hdr += codegenValue(blockInfo->get(2)).c; hdr += "\")\n"; info->cStatements.push_back(hdr); } } if (this != getFunction()->body) info->cStatements.push_back("{\n"); if (!(fNoRepositionDefExpr)) { Vec<BaseAST*> asts; collect_top_asts(this, asts); forv_Vec(BaseAST, ast, asts) { if (DefExpr* def = toDefExpr(ast)) { if (def->parentExpr == this) { if (!toTypeSymbol(def->sym)) { if (fGenIDS && isVarSymbol(def->sym)) info->cStatements.push_back("/* " + numToString(def->sym->id) + " */ "); def->sym->codegenDef(); } } } } } body.codegen(""); if (blockInfo && blockInfo->isPrimitive(PRIM_BLOCK_DOWHILE_LOOP)) { std::string ftr = "} while (" + codegenValue(blockInfo->get(1)).c + ");\n"; info->cStatements.push_back(ftr); } else if (this != getFunction()->body) { std::string end = "}"; CondStmt* cond = toCondStmt(parentExpr); if (!cond || !(cond->thenStmt == this && cond->elseStmt)) end += "\n"; info->cStatements.push_back(end); } } else {
for_fields(field, at) { if (!field->hasFlag(FLAG_IMPLICIT_ALIAS_FIELD)) { if (isVarSymbol(field)) { if (strcmp(field->name, "_promotionType")) { build_accessors(at, field); } } else if (isEnumType(field->type)) { build_accessors(at, field); } } }
// Build a map from Symbols to ConstInfo. This is somewhat like // buildDefUseMaps, except we don't want to put defs and uses in different // lists (for simplicity). // // TODO: Can we use for_SymbolSymExprs here instead? forv_Vec(SymExpr, se, gSymExprs) { if (!(isVarSymbol(se->symbol()) || isArgSymbol(se->symbol()))) continue; // TODO: BHARSH: Skip classes for now. Not sure how to deal with aliasing if (!se->isRef() && isClass(se->typeInfo())) continue; ConstInfo* info = NULL; ConstInfoIter it = infoMap.find(se->symbol()); if (it == infoMap.end()) { info = new ConstInfo(se->symbol()); infoMap[se->symbol()] = info; } else { info = it->second; } info->todo.push_back(se); }
void ForallIntents::verifyFI(BlockStmt* parentB) { Expr* parentE = (Expr*)parentB; int nv = numVars(); INT_ASSERT((int)(fiVars.size()) == nv); INT_ASSERT((int)(fIntents.size()) == nv); INT_ASSERT((int)(riSpecs.size()) == nv); for (int i = 0; i < nv; i++) { Expr* fiVar = fiVars[i]; if (SymExpr* fiVarSE = toSymExpr(fiVar)) { INT_ASSERT(isVarSymbol(fiVarSE->symbol()) || isArgSymbol(fiVarSE->symbol())); // no modules, fns, etc. } else { // fiVars[i] is either resolved or unresolved sym expr; never NULL. INT_ASSERT(isUnresolvedSymExpr(fiVar)); // These should be resolved during scopeResolve. INT_ASSERT(!normalized); } verifyNotOnList(fiVar); INT_ASSERT(fiVar->parentExpr == parentE); Expr* ri = riSpecs[i]; INT_ASSERT(isReduce(i) == !!ri); if (ri) { // ri can be UnresolvedSymExpr, SymExpr, CallExpr, ... (?) verifyNotOnList(ri); INT_ASSERT(ri->parentExpr == parentE); } } INT_ASSERT(!iterRec || iterRec->parentExpr == parentE); INT_ASSERT(!leadIdx || leadIdx->parentExpr == parentE); INT_ASSERT(!leadIdxCopy || leadIdxCopy->parentExpr == parentE); verifyNotOnList(iterRec); verifyNotOnList(leadIdx); verifyNotOnList(leadIdxCopy); // ForallIntents are gone during resolve(). INT_ASSERT(!resolved); }
// Note: This function is currently not recursive static bool inferConst(Symbol* sym) { INT_ASSERT(!sym->isRef()); const bool wasConstVal = sym->qualType().getQual() == QUAL_CONST_VAL; ConstInfo* info = infoMap[sym]; // 'info' may be null if the argument is never used. In that case we can // consider 'sym' to be a const-ref. By letting the rest of the function // proceed, we'll fix up the qualifier for such symbols at the end. if (info == NULL) { return true; } else if (info->finalizedConstness || wasConstVal) { return wasConstVal; } bool isConstVal = true; int numDefs = 0; while (info->hasMore() && isConstVal) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); if (call == NULL) { // Could be a DefExpr, or the condition for a while loop. // BHARSH: I'm not sure of all the possibilities continue; } CallExpr* parent = toCallExpr(call->parentExpr); if (call->isResolved()) { ArgSymbol* form = actual_to_formal(use); // // If 'sym' is constructed through a _retArg, we can consider that to // be a single 'def'. // if (form->hasFlag(FLAG_RETARG)) { numDefs += 1; } else if (form->isRef()) { if (!inferConstRef(form)) { isConstVal = false; } } } else if (parent && isMoveOrAssign(parent)) { if (call->isPrimitive(PRIM_ADDR_OF) || call->isPrimitive(PRIM_SET_REFERENCE)) { Symbol* LHS = toSymExpr(parent->get(1))->symbol(); INT_ASSERT(LHS->isRef()); if (onlyUsedForRetarg(LHS, parent)) { numDefs += 1; } else if (!inferConstRef(LHS)) { isConstVal = false; } } } else if (isMoveOrAssign(call)) { if (use == call->get(1)) { numDefs += 1; } } else { // To be safe, exit the loop with 'false' if we're unsure of how to // handle a primitive. isConstVal = false; } if (numDefs > 1) { isConstVal = false; } } if (isConstVal && !info->finalizedConstness) { if (ArgSymbol* arg = toArgSymbol(sym)) { INT_ASSERT(arg->intent & INTENT_FLAG_IN); arg->intent = INTENT_CONST_IN; } else { INT_ASSERT(isVarSymbol(sym)); sym->qual = QUAL_CONST_VAL; } } info->reset(); info->finalizedConstness = true; return isConstVal; }
// // Returns 'true' if 'sym' is (or should be) a const-ref. // If 'sym' can be a const-ref, but is not, this function will change either // the intent or qual of the Symbol to const-ref. // static bool inferConstRef(Symbol* sym) { INT_ASSERT(sym->isRef()); bool wasConstRef = sym->qualType().getQual() == QUAL_CONST_REF; if (sym->defPoint->parentSymbol->hasFlag(FLAG_EXTERN)) { return wasConstRef; } ConstInfo* info = infoMap[sym]; // 'info' may be null if the argument is never used. In that case we can // consider 'sym' to be a const-ref. By letting the rest of the function // proceed, we'll fix up the qualifier for such symbols at the end. if (info == NULL) { return true; } else if (info->finalizedConstness || wasConstRef) { return wasConstRef; } bool isFirstCall = false; if (info->alreadyCalled == false) { isFirstCall = true; info->alreadyCalled = true; } bool isConstRef = true; while (info->hasMore() && isConstRef) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); INT_ASSERT(call); CallExpr* parent = toCallExpr(call->parentExpr); if (call->isResolved()) { ArgSymbol* form = actual_to_formal(use); if (form->isRef() && !inferConstRef(form)) { isConstRef = false; } } else if (parent && isMoveOrAssign(parent)) { if (!canRHSBeConstRef(parent, use)) { isConstRef = false; } } else if (call->isPrimitive(PRIM_MOVE)) { // // Handles three cases: // 1) MOVE use value - writing to a reference, so 'use' cannot be const // 2) MOVE ref use - if the LHS is not const, use cannot be const either // 3) MOVE value use - a dereference of 'use' // if (use == call->get(1)) { // CASE 1 if (!call->get(2)->isRef()) { isConstRef = false; } } else { // 'use' is the RHS of a MOVE if (call->get(1)->isRef()) { // CASE 2 SymExpr* se = toSymExpr(call->get(1)); INT_ASSERT(se); if (!inferConstRef(se->symbol())) { isConstRef = false; } } // else CASE 3: do nothing because isConstRef is already true } } else if (call->isPrimitive(PRIM_ASSIGN)) { if (use == call->get(1)) { isConstRef = false; } } else if (call->isPrimitive(PRIM_SET_MEMBER) || call->isPrimitive(PRIM_SET_SVEC_MEMBER)) { // BHARSH 2016-11-02 // In the expr (set_member base member rhs), // If use == base, I take the conservative approach and decide that 'use' // is not a const-ref. I'm not sure that we've decided what const means // for fields yet, so this seems safest. // // If use == rhs, then we would need to do analysis for the member field. // That's beyond the scope of what I'm attempting at the moment, so to // be safe we'll return false for that case. if (use == call->get(1) || use == call->get(3)) { isConstRef = false; } else { // use == member // If 'rhs' is not a ref, then we're writing into 'use'. Otherwise it's // a pointer copy and we don't care if 'rhs' is writable. if (!call->get(3)->isRef()) { isConstRef = false; } } } else { // To be safe, exit the loop with 'false' if we're unsure of how to // handle a primitive. isConstRef = false; } } if (isFirstCall) { if (isConstRef) { INT_ASSERT(info->finalizedConstness == false); if (ArgSymbol* arg = toArgSymbol(sym)) { arg->intent = INTENT_CONST_REF; } else { INT_ASSERT(isVarSymbol(sym)); sym->qual = QUAL_CONST_REF; } } info->reset(); info->finalizedConstness = true; } else if (!isConstRef) { info->finalizedConstness = true; } return isConstRef; }