// 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 FnSymbol::verify() { Symbol::verify(); if (astTag != E_FnSymbol) { INT_FATAL(this, "Bad FnSymbol::astTag"); } if (_this && _this->defPoint->parentSymbol != this) INT_FATAL(this, "Each method must contain a 'this' declaration."); if (normalized) { CallExpr* last = toCallExpr(body->body.last()); if (last == NULL || last->isPrimitive(PRIM_RETURN) == false) { INT_FATAL(this, "Last statement in normalized function is not a return"); } } if (formals.parent != this) { INT_FATAL(this, "Bad AList::parent in FnSymbol"); } if (where && where->parentSymbol != this) { INT_FATAL(this, "Bad FnSymbol::where::parentSymbol"); } if (retExprType && retExprType->parentSymbol != this) { INT_FATAL(this, "Bad FnSymbol::retExprType::parentSymbol"); } if (body && body->parentSymbol != this) { INT_FATAL(this, "Bad FnSymbol::body::parentSymbol"); } for_alist(fExpr, formals) { DefExpr* argDef = toDefExpr(fExpr); INT_ASSERT(argDef); INT_ASSERT(isArgSymbol(argDef->sym)); }
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); }
// // Functions have an informal epilogue defined by code that // // 1) appears after a common "return label" (if present) // 2) copies values to out/in-out formals // // We must destroy the primaries before (1). // We choose to destroy the primaries before (2). // // This code detects the start of (2) // bool AutoDestroyScope::handlingFormalTemps(const Expr* stmt) const { bool retval = false; if (mLocalsHandled == false) { if (const CallExpr* call = toConstCallExpr(stmt)) { if (FnSymbol* fn = call->resolvedFunction()) { if (fn->hasFlag(FLAG_ASSIGNOP) == true && call->numActuals() == 2) { SymExpr* lhs = toSymExpr(call->get(1)); SymExpr* rhs = toSymExpr(call->get(2)); if (lhs != NULL && rhs != NULL && isArgSymbol(lhs->symbol()) == true && rhs->symbol()->hasFlag(FLAG_FORMAL_TEMP) == true) { retval = true; } } } } } return retval; }
static void collect_top_asts_internal(BaseAST* ast, Vec<BaseAST*>& asts) { if (!isSymbol(ast) || isArgSymbol(ast)) { AST_CHILDREN_CALL(ast, collect_top_asts_internal, asts); asts.add(ast); } }
static bool printErrorHeader(const BaseAST* ast) { if (!err_print) { if (const Expr* expr = toConstExpr(ast)) { Symbol* parent = expr->parentSymbol; if (isArgSymbol(parent)) parent = parent->defPoint->parentSymbol; FnSymbol* fn = toFnSymbol(parent); fn = findNonTaskCaller(fn); if (fn && fn != err_fn) { err_fn = fn; while ((fn = toFnSymbol(err_fn->defPoint->parentSymbol))) { if (fn == fn->getModule()->initFn) { break; } err_fn = fn; } // If the function is compiler-generated, or inlined, or doesn't match // the error function and line number, nothing is printed. if (err_fn->getModule()->initFn != err_fn && !err_fn->hasFlag(FLAG_COMPILER_GENERATED) && err_fn->linenum()) { bool suppress = false; // Initializer might be inlined if (err_fn->hasFlag(FLAG_INLINE) == true) { suppress = (strcmp(err_fn->name, "init") != 0) ? true : false; } if (suppress == false) { fprintf(stderr, "%s:%d: In ", cleanFilename(err_fn), err_fn->linenum()); if (strncmp(err_fn->name, "_construct_", 11) == 0) { fprintf(stderr, "initializer '%s':\n", err_fn->name+11); } else if (strcmp(err_fn->name, "init") == 0) { fprintf(stderr, "initializer:\n"); } else { fprintf(stderr, "%s '%s':\n", (err_fn->isIterator() ? "iterator" : "function"), err_fn->name); } } } } } } bool have_ast_line = false; const char* filename; int linenum; if ( ast && ast->linenum() ) { have_ast_line = true; filename = cleanFilename(ast); linenum = ast->linenum(); } else { have_ast_line = false; if ( !err_print && currentAstLoc.filename && currentAstLoc.lineno > 0 ) { // Use our best guess for the line number for user errors, // but don't do that for err_print (USR_PRINT) notes that don't // come with line numbers. filename = cleanFilename(currentAstLoc.filename); linenum = currentAstLoc.lineno; } else { filename = NULL; linenum = -1; } } bool guess = filename && !have_ast_line; if (filename) { fprintf(stderr, "%s:%d: ", filename, linenum); } if (err_print) { fprintf(stderr, "note: "); } else if (err_fatal) { if (err_user) { fprintf(stderr, "error: "); } else { fprintf(stderr, "internal error: "); } } else { fprintf(stderr, "warning: "); } if (!err_user) { if (!developer) { print_user_internal_error(); } } return guess; }
static bool inferRefToConst(Symbol* sym) { INT_ASSERT(sym->isRef()); bool isConstRef = sym->qualType().getQual() == QUAL_CONST_REF; const bool wasRefToConst = sym->hasFlag(FLAG_REF_TO_CONST); ConstInfo* info = infoMap[sym]; // If this ref isn't const, then it can't point to a const thing if (info == NULL) { return false; } else if (info->finalizedRefToConst || wasRefToConst || !isConstRef) { return wasRefToConst; } bool isFirstCall = false; if (info->alreadyCalled == false) { isFirstCall = true; info->alreadyCalled = true; } bool isRefToConst = true; if (isArgSymbol(sym)) { // Check each call and set isRefToConst to false if any actual is not a ref // to a const. FnSymbol* fn = toFnSymbol(sym->defPoint->parentSymbol); if (fn->hasFlag(FLAG_VIRTUAL) || fn->hasFlag(FLAG_EXPORT) || fn->hasFlag(FLAG_EXTERN)) { // Not sure how to best handle virtual calls, so simply set false for now // // For export or extern functions, return false because we don't have // all the information about how the function is called. isRefToConst = false; } else { // Need this part to be re-entrant in case of recursive functions while (info->fnUses != NULL && isRefToConst) { SymExpr* se = info->fnUses; info->fnUses = se->symbolSymExprsNext; CallExpr* call = toCallExpr(se->parentExpr); INT_ASSERT(call && call->isResolved()); Symbol* actual = toSymExpr(formal_to_actual(call, sym))->symbol(); if (actual->isRef()) { // I don't think we technically need to skip if the actual is the // same symbol as the formal, but it makes things simpler. if (actual != sym && !inferRefToConst(actual)) { isRefToConst = false; } } else { // Passing a non-ref actual to a reference formal is currently // considered to be the same as an addr-of if (actual->qualType().getQual() != QUAL_CONST_VAL) { isRefToConst = false; } } } } } while (info->hasMore() && isRefToConst) { SymExpr* use = info->next(); CallExpr* call = toCallExpr(use->parentExpr); if (call == NULL) continue; if (isMoveOrAssign(call)) { if (use == call->get(1)) { if (SymExpr* se = toSymExpr(call->get(2))) { if (se->isRef() && !inferRefToConst(se->symbol())) { isRefToConst = false; } } else { CallExpr* RHS = toCallExpr(call->get(2)); INT_ASSERT(RHS); if (RHS->isPrimitive(PRIM_ADDR_OF) || RHS->isPrimitive(PRIM_SET_REFERENCE)) { SymExpr* src = toSymExpr(RHS->get(1)); if (src->isRef()) { if (!inferRefToConst(src->symbol())) { isRefToConst = false; } } else { if (src->symbol()->qualType().getQual() != QUAL_CONST_VAL) { isRefToConst = false; } } } else { isRefToConst = false; } } } } else if (call->isResolved()) { isRefToConst = true; } else { isRefToConst = isSafeRefPrimitive(use); } } if (isFirstCall) { if (isRefToConst) { INT_ASSERT(info->finalizedRefToConst == false); sym->addFlag(FLAG_REF_TO_CONST); } info->reset(); info->finalizedRefToConst = true; } else if (!isRefToConst) { info->finalizedRefToConst = true; } return isRefToConst; }
static void collect_top_asts_internal_STL(BaseAST* ast, std::vector<BaseAST*>& asts) { if (!isSymbol(ast) || isArgSymbol(ast)) { AST_CHILDREN_CALL(ast, collect_top_asts_internal_STL, asts); asts.push_back(ast); } }