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(); } }
forv_Vec(FnSymbol, fn, gFnSymbols) { if (VarSymbol* ret = toVarSymbol(fn->getReturnSymbol())) { // The return value of an initCopy function should not be autodestroyed. // Normally, the return value of a function is autoCopied, but since // autoCopy is typically defined in terms of initCopy, this would lead to // infinite recursion. That is, the return value of initCopy must be // handled specially. if (fn->hasFlag(FLAG_INIT_COPY_FN)) ret->removeFlag(FLAG_INSERT_AUTO_DESTROY); // This is just a workaround for memory management being handled specially // for internally reference-counted types. (sandboxing) TypeSymbol* ts = ret->type->symbol; if (ts->hasFlag(FLAG_ARRAY) || ts->hasFlag(FLAG_DOMAIN)) ret->removeFlag(FLAG_INSERT_AUTO_DESTROY); // Do we need to add other record-wrapped types here? Testing will tell. // NOTE 1: When the value of a record field is established in a default // constructor, it is initialized using a MOVE. That means that ownership // of that value is shared between the formal_tmp and the record field. // If the autodestroy flag is left on that formal temp, then it will be // destroyed which -- for ref-counted types -- can result in a dangling // reference. So here, we look for that case and remove it. if (fn->hasFlag(FLAG_DEFAULT_CONSTRUCTOR)) { Map<Symbol*,Vec<SymExpr*>*> defMap; Map<Symbol*,Vec<SymExpr*>*> useMap; buildDefUseMaps(fn, defMap, useMap); std::vector<DefExpr*> defs; collectDefExprs(fn, defs); for_vector(DefExpr, def, defs) { if (VarSymbol* var = toVarSymbol(def->sym)) { // Examine only those bearing the explicit autodestroy flag. if (! var->hasFlag(FLAG_INSERT_AUTO_DESTROY)) continue; // Look for a use in a PRIM_SET_MEMBER where the field is a record // type, and remove the flag. // (We don't actually check that var is of record type, because // chpl__autoDestroy() does nothing when applied to all other types. for_uses(se, useMap, var) { CallExpr* call = toCallExpr(se->parentExpr); if (call->isPrimitive(PRIM_SET_MEMBER) && toSymExpr(call->get(3))->var == var) var->removeFlag(FLAG_INSERT_AUTO_DESTROY); } } } freeDefUseMaps(defMap, useMap); }
void ReturnByRef::updateAssignmentsFromRefTypeToValue(FnSymbol* fn) { std::vector<CallExpr*> callExprs; collectCallExprs(fn, callExprs); Map<Symbol*,Vec<SymExpr*>*> defMap; Map<Symbol*,Vec<SymExpr*>*> useMap; buildDefUseMaps(fn, defMap, useMap); for (size_t i = 0; i < callExprs.size(); i++) { CallExpr* move = callExprs[i]; if (move->isPrimitive(PRIM_MOVE) == true) { SymExpr* symLhs = toSymExpr (move->get(1)); CallExpr* callRhs = toCallExpr(move->get(2)); if (symLhs && callRhs && callRhs->isPrimitive(PRIM_DEREF)) { VarSymbol* varLhs = toVarSymbol(symLhs->symbol()); SymExpr* symRhs = toSymExpr(callRhs->get(1)); VarSymbol* varRhs = toVarSymbol(symRhs->symbol()); // MPF 2016-10-02: It seems to me that this code should also handle the // case that symRhs is an ArgSymbol, but adding that caused problems // in the handling of out argument intents. if (varLhs != NULL && varRhs != NULL) { if (isUserDefinedRecord(varLhs->type) == true && varRhs->type == varLhs->type->refType) { // HARSHBARGER 2015-12-11: // `init_untyped_var` in the `normalize` pass may insert an // initCopy, which means that we should not insert an autocopy // for that same variable. bool initCopied = false; for_uses(use, useMap, varLhs) { if (CallExpr* call = toCallExpr(use->parentExpr)) { if (FnSymbol* parentFn = call->isResolved()) { if (parentFn->hasFlag(FLAG_INIT_COPY_FN)) { initCopied = true; break; } } } } if (!initCopied) { SET_LINENO(move); SymExpr* lhsCopy0 = symLhs->copy(); SymExpr* lhsCopy1 = symLhs->copy(); FnSymbol* autoCopy = autoCopyMap.get(varLhs->type); CallExpr* copyExpr = new CallExpr(autoCopy, lhsCopy0); CallExpr* moveExpr = new CallExpr(PRIM_MOVE,lhsCopy1, copyExpr); move->insertAfter(moveExpr); } } } }