bool ReturnByRef::isTransformableFunction(FnSymbol* fn) { bool retval = false; if (AggregateType* type = toAggregateType(fn->retType)) { if (fn->hasFlag(FLAG_INIT_COPY_FN) == true) retval = false; else if (fn->hasFlag(FLAG_AUTO_COPY_FN) == true) retval = false; // Function is an iterator "helper" else if (fn->hasFlag(FLAG_AUTO_II) == true) retval = false; // Can't transform extern functions else if (fn->hasFlag(FLAG_EXTERN) == true) retval = false; // Noakes: 2016/02/24. Only "user defined records" for now else if (isUserDefinedRecord(type) == true) retval = true; else retval = false; } return retval; }
// // Consider a function that takes a formal of type Record by const ref // and that returns that value from the function. The compiler inserts // a PRIM_MOVE operation. // // This work-around inserts an autoCopy to compensate // void ReturnByRef::updateAssignmentsFromRefArgToValue(FnSymbol* fn) { std::vector<CallExpr*> callExprs; collectCallExprs(fn, callExprs); for (size_t i = 0; i < callExprs.size(); i++) { CallExpr* move = callExprs[i]; if (move->isPrimitive(PRIM_MOVE) == true) { SymExpr* lhs = toSymExpr(move->get(1)); SymExpr* rhs = toSymExpr(move->get(2)); if (lhs != NULL && rhs != NULL) { VarSymbol* symLhs = toVarSymbol(lhs->symbol()); ArgSymbol* symRhs = toArgSymbol(rhs->symbol()); if (symLhs != NULL && symRhs != NULL) { if (isUserDefinedRecord(symLhs->type) == true && symRhs->type == symLhs->type) { if (symLhs->hasFlag(FLAG_ARG_THIS) == false && (symRhs->intent == INTENT_REF || symRhs->intent == INTENT_CONST_REF)) { SET_LINENO(move); CallExpr* autoCopy = NULL; rhs->remove(); autoCopy = new CallExpr(autoCopyMap.get(symRhs->type), rhs); move->insertAtTail(autoCopy); } } } } } } }
// Walk backwards from the current statement to determine if a sequence of // moves have copied a variable that is marked for auto destruction in to // the dedicated return-temp within the current scope. // // Note that the value we are concerned about may be copied in to one or // more temporary variables between being copied to the return temp. static VarSymbol* variableToExclude(FnSymbol* fn, Expr* refStmt) { VarSymbol* retVar = toVarSymbol(fn->getReturnSymbol()); VarSymbol* retval = NULL; if (retVar != NULL) { if (isUserDefinedRecord(retVar) == true || fn->hasFlag(FLAG_INIT_COPY_FN) == true) { VarSymbol* needle = retVar; Expr* expr = refStmt; // Walk backwards looking for the variable that is being returned while (retval == NULL && expr != NULL && needle != NULL) { if (CallExpr* move = toCallExpr(expr)) { if (move->isPrimitive(PRIM_MOVE) == true) { SymExpr* lhs = toSymExpr(move->get(1)); VarSymbol* lhsVar = toVarSymbol(lhs->symbol()); if (needle == lhsVar) { if (SymExpr* rhs = toSymExpr(move->get(2))) { VarSymbol* rhsVar = toVarSymbol(rhs->symbol()); if (isAutoDestroyedVariable(rhsVar) == true) { retval = rhsVar; } else { needle = rhsVar; } } else { needle = NULL; } } } } expr = expr->prev; } } } return retval; }
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); } } } }