static ArgSymbol* addOutErrorArg(FnSymbol* fn) { ArgSymbol* outError = NULL; SET_LINENO(fn); outError = new ArgSymbol(INTENT_REF, "error_out", dtError); outError->addFlag(FLAG_ERROR_VARIABLE); fn->insertFormalAtTail(outError); return outError; }
void ReturnByRef::insertAssignmentToFormal(FnSymbol* fn, ArgSymbol* formal) { Expr* returnPrim = fn->body->body.tail; SET_LINENO(returnPrim); CallExpr* returnCall = toCallExpr(returnPrim); Expr* returnValue = returnCall->get(1)->remove(); CallExpr* moveExpr = new CallExpr(PRIM_MOVE, formal, returnValue); returnPrim->insertBefore(moveExpr); }
void localizeGlobals() { if (fNoGlobalConstOpt) return; forv_Vec(FnSymbol, fn, gFnSymbols) { Map<Symbol*,VarSymbol*> globals; std::vector<BaseAST*> asts; collect_asts(fn->body, asts); for_vector(BaseAST, ast, asts) { if (SymExpr* se = toSymExpr(ast)) { Symbol* var = se->symbol(); ModuleSymbol* parentmod = toModuleSymbol(var->defPoint->parentSymbol); CallExpr* parentExpr = toCallExpr(se->parentExpr); bool inAddrOf = parentExpr && parentExpr->isPrimitive(PRIM_ADDR_OF); bool lhsOfMove = parentExpr && isMoveOrAssign(parentExpr) && (parentExpr->get(1) == se); // Is var a global constant? // Don't replace the var name in its init function since that's // where we're setting the value. Similarly, dont replace them // inside initStringLiterals // If the parentSymbol is the rootModule, the var is 'void,' // 'false,' '0,' ... // Also don't replace it when it's in an addr of primitive. if (parentmod && fn != parentmod->initFn && fn != initStringLiterals && !inAddrOf && !lhsOfMove && var->hasFlag(FLAG_CONST) && var->defPoint->parentSymbol != rootModule) { VarSymbol* local_global = globals.get(var); SET_LINENO(se); // Set the se line number for output if (!local_global) { const char * newname = astr("local_", var->cname); local_global = newTemp(newname, var->type); fn->insertAtHead(new CallExpr(PRIM_MOVE, local_global, var)); fn->insertAtHead(new DefExpr(local_global)); // Copy string immediates to localized strings so that // we can show the string value in comments next to uses. if (!llvmCodegen) if (VarSymbol* localVarSym = toVarSymbol(var)) if (Immediate* immediate = localVarSym->immediate) if (immediate->const_kind == CONST_KIND_STRING) local_global->immediate = new Immediate(immediate->v_string, immediate->string_kind); globals.put(var, local_global); } se->replace(new SymExpr(toSymbol(local_global))); } } } }
ArgSymbol* ReturnByRef::addFormal(FnSymbol* fn) { SET_LINENO(fn); Type* type = fn->retType; AggregateType* refType = type->refType; IntentTag intent = blankIntentForType(refType); ArgSymbol* formal = new ArgSymbol(intent, "_retArg", refType); fn->insertFormalAtTail(formal); return formal; }
// // The argument expr is a use of a wide reference. Insert a check to ensure // that it is on the current locale, then drop its wideness by moving the // addr field into a non-wide of otherwise the same type. Then, replace its // use with the non-wide version. // static void insertLocalTemp(Expr* expr) { SymExpr* se = toSymExpr(expr); Expr* stmt = expr->getStmtExpr(); INT_ASSERT(se && stmt); SET_LINENO(se); VarSymbol* var = newTemp(astr("local_", se->var->name), se->var->type->getField("addr")->type); if (!fNoLocalChecks) { stmt->insertBefore(new CallExpr(PRIM_LOCAL_CHECK, se->copy())); } stmt->insertBefore(new DefExpr(var)); stmt->insertBefore(new CallExpr(PRIM_MOVE, var, se->copy())); se->replace(new SymExpr(var)); }
// // Do a breadth first search starting from functions generated for local blocks // for all function calls in each level of the search, if they directly cause // communication, add a local temp that isn't wide. If it is a resolved call, // meaning that it isn't a primitive or external function, clone it and add it // to the queue of functions to handle at the next iteration of the BFS. // static void handleLocalBlocks() { Map<FnSymbol*,FnSymbol*> cache; // cache of localized functions Vec<BlockStmt*> queue; // queue of blocks to localize forv_Vec(BlockStmt, block, gBlockStmts) { if (block->parentSymbol) { // NOAKES 2014/11/25 Transitional. Avoid calling blockInfoGet() if (block->isLoopStmt() == true) { } else if (block->blockInfoGet()) { if (block->blockInfoGet()->isPrimitive(PRIM_BLOCK_LOCAL)) { queue.add(block); } } } } forv_Vec(BlockStmt, block, queue) { std::vector<CallExpr*> calls; collectCallExprs(block, calls); for_vector(CallExpr, call, calls) { localizeCall(call); if (FnSymbol* fn = call->isResolved()) { SET_LINENO(fn); if (FnSymbol* alreadyLocal = cache.get(fn)) { call->baseExpr->replace(new SymExpr(alreadyLocal)); } else { if (!fn->hasFlag(FLAG_EXTERN)) { FnSymbol* local = fn->copy(); local->addFlag(FLAG_LOCAL_FN); local->name = astr("_local_", fn->name); local->cname = astr("_local_", fn->cname); fn->defPoint->insertBefore(new DefExpr(local)); call->baseExpr->replace(new SymExpr(local)); queue.add(local->body); cache.put(fn, local); cache.put(local, local); // to handle recursion if (local->retType->symbol->hasFlag(FLAG_WIDE_REF)) { CallExpr* ret = toCallExpr(local->body->body.tail); INT_ASSERT(ret && ret->isPrimitive(PRIM_RETURN)); // Capture the return expression in a local temp. insertLocalTemp(ret->get(1)); local->retType = ret->get(1)->typeInfo(); } } } } }
ArgSymbol* ReturnByRef::addFormal(FnSymbol* fn) { SET_LINENO(fn); Type* type = fn->retType; AggregateType* refType = type->refType; IntentTag intent = blankIntentForType(refType); // Note: other code does strcmps against the name _retArg ArgSymbol* formal = new ArgSymbol(intent, "_retArg", refType); formal->addFlag(FLAG_RETARG); fn->insertFormalAtTail(formal); fn->addFlag(FLAG_FN_RETARG); return formal; }
static void lowerErrorHandling(FnSymbol* fn) { ArgSymbol* outError = NULL; LabelSymbol* epilogue = NULL; if (fn->throwsError()) { SET_LINENO(fn); outError = addOutErrorArg(fn); epilogue = fn->getOrCreateEpilogueLabel(); INT_ASSERT(epilogue); // throws requires an epilogue } ErrorHandlingVisitor visitor = ErrorHandlingVisitor(outError, epilogue); fn->accept(&visitor); }
// // inlines the function called by 'call' at that call site // static void inlineCall(FnSymbol* fn, CallExpr* call) { INT_ASSERT(call->isResolved() == fn); SET_LINENO(call); Expr* stmt = call->getStmtExpr(); // // calculate a map from actual symbols to formal symbols // SymbolMap map; for_formals_actuals(formal, actual, call) { SymExpr* se = toSymExpr(actual); INT_ASSERT(se); map.put(formal, se->var); }
forv_Vec(FnSymbol, fn, gFnSymbols) { SET_LINENO(fn); if (!fn->hasFlag(FLAG_TYPE_CONSTRUCTOR) && !fn->hasFlag(FLAG_DEFAULT_CONSTRUCTOR)) fixup_array_formals(fn); if (fn->hasFlag(FLAG_LOCALE_MODEL_ALLOC)) { INT_ASSERT(gChplHereAlloc==NULL); gChplHereAlloc = fn; } if (fn->hasFlag(FLAG_LOCALE_MODEL_FREE)) { INT_ASSERT(gChplHereFree==NULL); gChplHereFree = fn; } clone_parameterized_primitive_methods(fn); fixup_query_formals(fn); change_method_into_constructor(fn); }
forv_Vec(CallExpr, call, gCallExprs) { if (call->isPrimitive(PRIM_CHECK_ERROR)) { SET_LINENO(call); SymExpr* errSe = toSymExpr(call->get(1)); Symbol* errorVar= errSe->symbol(); VarSymbol* errorExistsVar = newTemp("errorExists", dtBool); DefExpr* def = new DefExpr(errorExistsVar); CallExpr* errorExists = new CallExpr(PRIM_NOTEQUAL, errorVar, gNil); CallExpr* move = new CallExpr(PRIM_MOVE, errorExistsVar, errorExists); Expr* stmt = call->getStmtExpr(); stmt->insertBefore(def); def->insertAfter(move); call->replace(new SymExpr(errorExistsVar)); } }
// // 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); } } } } } } }
void localizeGlobals() { if (fNoGlobalConstOpt) return; forv_Vec(FnSymbol, fn, gFnSymbols) { Map<Symbol*,VarSymbol*> globals; std::vector<BaseAST*> asts; collect_asts(fn->body, asts); for_vector(BaseAST, ast, asts) { if (SymExpr* se = toSymExpr(ast)) { Symbol* var = se->var; ModuleSymbol* parentmod = toModuleSymbol(var->defPoint->parentSymbol); CallExpr* parentExpr = toCallExpr(se->parentExpr); bool inAddrOf = parentExpr && parentExpr->isPrimitive(PRIM_ADDR_OF); // Is var a global constant? // Don't replace the var name in its init function since that's // where we're setting the value. Similarly, dont replace them // inside initStringLiterals // If the parentSymbol is the rootModule, the var is 'void,' // 'false,' '0,' ... // Also don't replace it when it's in an addr of primitive. if (parentmod && fn != parentmod->initFn && fn != initStringLiterals && !inAddrOf && var->hasFlag(FLAG_CONST) && var->defPoint->parentSymbol != rootModule) { VarSymbol* local_global = globals.get(var); SET_LINENO(se); // Set the se line number for output if (!local_global) { const char * newname = astr("local_", var->cname); local_global = newTemp(newname, var->type); fn->insertAtHead(new CallExpr(PRIM_MOVE, local_global, var)); fn->insertAtHead(new DefExpr(local_global)); globals.put(var, local_global); } se->replace(new SymExpr(toSymbol(local_global))); } } } }
Expr* postFold(Expr* expr) { SET_LINENO(expr); Expr* retval = expr; INT_ASSERT(expr->inTree()); if (CallExpr* call = toCallExpr(expr)) { if (call->isResolved() == true) { retval = postFoldNormal(call); } else if (call->isPrimitive() == true) { retval = postFoldPrimop(call); } } else if (SymExpr* sym = toSymExpr(expr)) { retval = postFoldSymExpr(sym); } return retval; }
void buildDefaultFunctions() { build_chpl_entry_points(); SET_LINENO(rootModule); // todo - remove reset_ast_loc() calls below? std::vector<BaseAST*> asts; collect_asts(rootModule, asts); for_vector(BaseAST, ast, asts) { if (TypeSymbol* type = toTypeSymbol(ast)) { // Here we build default functions that are always generated (even when // the type symbol has FLAG_NO_DEFAULT_FUNCTIONS attached). if (AggregateType* ct = toAggregateType(type->type)) { buildFieldAccessorFunctions(ct); if (!ct->symbol->hasFlag(FLAG_REF)) buildDefaultDestructor(ct); // Classes should use the nil:<type> _defaultOf method unless they // do not inherit from object. For those types and records, call // we need a more complicated _defaultOf method generated by the // compiler if (!ct->isClass() || ct->symbol->hasFlag(FLAG_NO_OBJECT)) build_record_init_function(ct); } if (type->hasFlag(FLAG_NO_DEFAULT_FUNCTIONS)) continue; // Here we build default functions that respect the "no default // functions" pragma. if (AggregateType* ct = toAggregateType(type->type)) { buildDefaultReadWriteFunctions(ct); if (isRecord(ct)) { if (!isRecordWrappedType(ct)) { build_record_equality_function(ct); build_record_inequality_function(ct); } build_record_assignment_function(ct); build_record_cast_function(ct); build_record_copy_function(ct); build_record_hash_function(ct); } if (isUnion(ct)) build_union_assignment_function(ct); } else if (EnumType* et = toEnumType(type->type)) { //buildDefaultReadFunction(et); buildStringCastFunction(et); build_enum_cast_function(et); build_enum_assignment_function(et); build_enum_first_function(et); build_enum_enumerate_function(et); } else { // The type is a simple type. // Other simple types are handled explicitly in the module code. // But to avoid putting a catch-all case there to implement assignment // for extern types that are simple (as far as we can tell), we build // definitions for those assignments here. if (type->hasFlag(FLAG_EXTERN)) { build_extern_init_function(type->type); build_extern_assignment_function(type->type); } } } } }
// // If call has the potential to cause communication, assert that the wide // reference that might cause communication is local and remove its wide-ness // // The organization of this function follows the order of CallExpr::codegen() // leaving out primitives that don't communicate. // static void localizeCall(CallExpr* call) { if (call->primitive) { switch (call->primitive->tag) { case PRIM_ARRAY_SET: /* Fallthru */ case PRIM_ARRAY_SET_FIRST: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(1)); } break; case PRIM_MOVE: case PRIM_ASSIGN: // Not sure about this one. if (CallExpr* rhs = toCallExpr(call->get(2))) { if (rhs->isPrimitive(PRIM_DEREF)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) || rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(rhs->get(1)); if (!rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_REF)) { INT_ASSERT(rhs->get(1)->typeInfo() == dtString); // special handling for wide strings rhs->replace(rhs->get(1)->remove()); } } break; } else if (rhs->isPrimitive(PRIM_GET_MEMBER) || rhs->isPrimitive(PRIM_GET_SVEC_MEMBER) || rhs->isPrimitive(PRIM_GET_MEMBER_VALUE) || rhs->isPrimitive(PRIM_GET_SVEC_MEMBER_VALUE)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) || rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { SymExpr* sym = toSymExpr(rhs->get(2)); INT_ASSERT(sym); if (!sym->var->hasFlag(FLAG_SUPER_CLASS)) { insertLocalTemp(rhs->get(1)); } } break; } else if (rhs->isPrimitive(PRIM_ARRAY_GET) || rhs->isPrimitive(PRIM_ARRAY_GET_VALUE)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { SymExpr* lhs = toSymExpr(call->get(1)); Expr* stmt = call->getStmtExpr(); INT_ASSERT(lhs && stmt); SET_LINENO(stmt); insertLocalTemp(rhs->get(1)); VarSymbol* localVar = NULL; if (rhs->isPrimitive(PRIM_ARRAY_GET)) localVar = newTemp(astr("local_", lhs->var->name), lhs->var->type->getField("addr")->type); else localVar = newTemp(astr("local_", lhs->var->name), lhs->var->type); stmt->insertBefore(new DefExpr(localVar)); lhs->replace(new SymExpr(localVar)); stmt->insertAfter(new CallExpr(PRIM_MOVE, lhs, new SymExpr(localVar))); } break; } else if (rhs->isPrimitive(PRIM_GET_UNION_ID)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(rhs->get(1)); } break; } else if (rhs->isPrimitive(PRIM_TESTCID) || rhs->isPrimitive(PRIM_GETCID)) { if (rhs->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(rhs->get(1)); } break; } ; } if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { break; } if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF) && !call->get(2)->typeInfo()->symbol->hasFlag(FLAG_REF)) { insertLocalTemp(call->get(1)); } break; case PRIM_DYNAMIC_CAST: if (call->get(2)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(2)); if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) || call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { toSymExpr(call->get(1))->var->type = call->get(1)->typeInfo()->getField("addr")->type; } } break; case PRIM_SETCID: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS)) { insertLocalTemp(call->get(1)); } break; case PRIM_SET_UNION_ID: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(call->get(1)); } break; case PRIM_SET_MEMBER: case PRIM_SET_SVEC_MEMBER: if (call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_CLASS) || call->get(1)->typeInfo()->symbol->hasFlag(FLAG_WIDE_REF)) { insertLocalTemp(call->get(1)); } break; default: break; } } }
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); } } } }
void AutoDestroyScope::variablesDestroy(Expr* refStmt, VarSymbol* excludeVar, std::set<VarSymbol*>* ignored) const { // Handle the primary locals if (mLocalsHandled == false) { Expr* insertBeforeStmt = refStmt; Expr* noop = NULL; size_t count = mLocalsAndDefers.size(); // If this is a simple nested block, insert after the final stmt // But always insert the destruction calls in reverse declaration order. // Do not get tricked by sequences of unreachable code if (refStmt->next == NULL) { if (mParent != NULL && isGotoStmt(refStmt) == false) { SET_LINENO(refStmt); // Add a PRIM_NOOP to insert before noop = new CallExpr(PRIM_NOOP); refStmt->insertAfter(noop); insertBeforeStmt = noop; } } for (size_t i = 1; i <= count; i++) { BaseAST* localOrDefer = mLocalsAndDefers[count - i]; VarSymbol* var = toVarSymbol(localOrDefer); DeferStmt* defer = toDeferStmt(localOrDefer); // This code only handles VarSymbols and DeferStmts. // It handles both in one vector because the order // of interleaving matters. INT_ASSERT(var || defer); if (var != NULL && var != excludeVar && (ignored == NULL || ignored->count(var) == 0)) { if (FnSymbol* autoDestroyFn = autoDestroyMap.get(var->type)) { SET_LINENO(var); INT_ASSERT(autoDestroyFn->hasFlag(FLAG_AUTO_DESTROY_FN)); CallExpr* autoDestroy = new CallExpr(autoDestroyFn, var); insertBeforeStmt->insertBefore(autoDestroy); } } if (defer != NULL) { SET_LINENO(defer); BlockStmt* deferBlockCopy = defer->body()->copy(); insertBeforeStmt->insertBefore(deferBlockCopy); deferBlockCopy->flattenAndRemove(); } } // remove the PRIM_NOOP if we added one. if (noop != NULL) noop->remove(); } // Handle the formal temps if (isReturnStmt(refStmt) == true) { size_t count = mFormalTemps.size(); for (size_t i = 1; i <= count; i++) { VarSymbol* var = mFormalTemps[count - i]; if (FnSymbol* autoDestroyFn = autoDestroyMap.get(var->type)) { SET_LINENO(var); refStmt->insertBefore(new CallExpr(autoDestroyFn, var)); } } } }
// // Attempts to replace references with the variables the references point to, // provided the references have a single definition. // // For example: // var foo : int; // ref A : int; // (move A (addr-of foo)) // // (move B (deref A)) ---> (move B foo) // void eliminateSingleAssignmentReference(Map<Symbol*,Vec<SymExpr*>*>& defMap, Map<Symbol*,Vec<SymExpr*>*>& useMap, Symbol* var) { if (CallExpr* move = findRefDef(defMap, var)) { if (CallExpr* rhs = toCallExpr(move->get(2))) { if (rhs->isPrimitive(PRIM_ADDR_OF) || rhs->isPrimitive(PRIM_SET_REFERENCE)) { bool stillAlive = false; for_uses(se, useMap, var) { CallExpr* parent = toCallExpr(se->parentExpr); SET_LINENO(se); if (parent && (parent->isPrimitive(PRIM_DEREF) || isDerefMove(parent))) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); Expr* toReplace = parent; if (isMoveOrAssign(parent)) { toReplace = parent->get(2); } toReplace->replace(se); ++s_ref_repl_count; addUse(useMap, se); } else if (parent && (parent->isPrimitive(PRIM_GET_MEMBER_VALUE) || parent->isPrimitive(PRIM_GET_MEMBER) || parent->isPrimitive(PRIM_GET_MEMBER_VALUE) || parent->isPrimitive(PRIM_GET_MEMBER))) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); parent->get(1)->replace(se); ++s_ref_repl_count; addUse(useMap, se); } else if (parent && (parent->isPrimitive(PRIM_MOVE) || parent->isPrimitive(PRIM_SET_REFERENCE))) { CallExpr* rhsCopy = rhs->copy(); if (parent->isPrimitive(PRIM_SET_REFERENCE)) { // Essentially a pointer copy like a (move refA refB) parent = toCallExpr(parent->parentExpr); INT_ASSERT(parent && isMoveOrAssign(parent)); } parent->get(2)->replace(rhsCopy); ++s_ref_repl_count; SymExpr* se = toSymExpr(rhsCopy->get(1)); INT_ASSERT(se); addUse(useMap, se); // BHARSH TODO: Is it possible to handle the following case safely // for PRIM_ASSIGN? // // ref i_foo : T; // (move i_foo (set reference bar)) // (= call_tmp i_foo) // // Should that turn into (= call_tmp bar)? } else if (parent && parent->isPrimitive(PRIM_ASSIGN) && parent->get(1) == se) { // for_defs should handle this case } else if (parent && parent->isResolved()) { stillAlive = true; // TODO -- a reference argument can be passed directly } else { stillAlive = true; } } for_defs(se, defMap, var) { CallExpr* parent = toCallExpr(se->parentExpr); SET_LINENO(se); if (parent == move) continue; if (parent && isMoveOrAssign(parent)) { SymExpr* se = toSymExpr(rhs->get(1)->copy()); INT_ASSERT(se); parent->get(1)->replace(se); ++s_ref_repl_count; addDef(defMap, se); } else stillAlive = true; } if (!stillAlive) { var->defPoint->remove(); Vec<SymExpr*>* defs = defMap.get(var); if (defs == NULL) { INT_FATAL(var, "Expected var to be defined"); } // Remove the first definition from the AST. defs->v[0]->getStmtExpr()->remove(); } } else if (rhs->isPrimitive(PRIM_GET_MEMBER) ||
IpeCallExpr* IpeProcedure::resolve(SymExpr* procSymExpr, std::vector<Expr*>& actuals) const { IpeMethod* matchMethod = NULL; int matchIndex = 0; int matchCount = 0; IpeCallExpr* retval = 0; for (size_t i = 0; i < mMethods.size(); i++) { mMethods[i]->resolveFormals(); mMethods[i]->resolveReturnType(); } for (size_t i = 0; i < mMethods.size(); i++) { if (mMethods[i]->isExactMatch(actuals) == true) { matchMethod = mMethods[i]; matchIndex = i; matchCount = matchCount + 1; } } if (matchCount == 1) { SET_LINENO(procSymExpr); retval = new IpeCallExpr(procSymExpr->copy(), matchMethod->typeGet(), mVersion, matchIndex); for (size_t i = 0; i < actuals.size(); i++) { ArgSymbol* formal = matchMethod->formalGet(i); bool formalIsRef = formal->intent & INTENT_REF; Expr* actual = actuals[i]; bool actualIsRef = isActualRef(actual); Expr* actualCopy = actual; Expr* actualNew = NULL; if (formalIsRef == false && actualIsRef == false) actualNew = actualCopy; else if (formalIsRef == false && actualIsRef == true) INT_ASSERT(false); else if (formalIsRef == true && actualIsRef == false) actualNew = new IpeCallExpr(PRIM_ADDR_OF, actualCopy); else if (formalIsRef == true && actualIsRef == true) INT_ASSERT(false); retval->argList.insertAtTail(actualNew); } } else { AstDumpToNode logger(stdout, 6); printf(" IpeProcedure::resolve(SymExpr*, actuals[])\n"); printf(" matchCount = %d\n", matchCount); printf("\n\n"); printf(" "); procSymExpr->accept(&logger); printf("\n"); for (size_t i = 0; i < actuals.size(); i++) { printf(" %d: ", (int) i); actuals[i]->accept(&logger); printf("\n"); } INT_ASSERT(false); } return retval; }