static void view_ast(BaseAST* ast, bool number = false, int mark = -1, int indent = 0) { if (!ast) return; if (Expr* expr = toExpr(ast)) { printf("\n"); for (int i = 0; i < indent; i++) printf(" "); printf("("); if (ast->id == mark) printf("***"); if (number) printf("%d ", ast->id); printf("%s", expr->astTagAsString()); if (isBlockStmt(expr)) if (FnSymbol* fn = toFnSymbol(expr->parentSymbol)) if (expr == fn->where) printf(" where"); if (GotoStmt *gs= toGotoStmt(ast)) { printf( " "); view_ast(gs->label, number, mark, indent+1); } if (CallExpr* call = toCallExpr(expr)) if (call->primitive) printf(" %s", call->primitive->name); if (NamedExpr* named = toNamedExpr(expr)) printf(" \"%s\"", named->name); if (toDefExpr(expr)) printf(" "); int64_t i; const char *str; if (get_int(expr, &i)) { printf(" %" PRId64, i); } else if (get_string(expr, &str)) { printf(" \"%s\"", str); } if (SymExpr* sym = toSymExpr(expr)) { printf(" "); view_sym(sym->var, number, mark); } else if (UnresolvedSymExpr* sym = toUnresolvedSymExpr(expr)) { printf(" '%s'", sym->unresolved); } } if (Symbol* sym = toSymbol(ast)) { view_sym(sym, number, mark); } AST_CHILDREN_CALL(ast, view_ast, number, mark, indent+2); if (toExpr(ast)) printf(")"); }
void Expr::prettyPrint(std::ostream *o) { if (BlockStmt *stmt = toBlockStmt(this)) printf("blockstmt %s", stmt->userLabel); else if (CondStmt *stmt = toCondStmt(this)) printf("condstmt %s", stmt->condExpr->parentSymbol->name); else if (GotoStmt *stmt = toGotoStmt(this)) printf("gotostmt %s", stmt->label->parentSymbol->name); printf("Oh no! This method hasn't been defined for this class!\n"); }
// If the refStmt is a goto then we need to recurse // to the block that contains the target of the goto void AutoDestroyScope::insertAutoDestroys(FnSymbol* fn, Expr* refStmt, std::set<VarSymbol*>* ignored) { GotoStmt* gotoStmt = toGotoStmt(refStmt); bool recurse = (gotoStmt != NULL) ? true : false; BlockStmt* forTarget = findBlockForTarget(gotoStmt); VarSymbol* excludeVar = variableToExclude(fn, refStmt); const AutoDestroyScope* scope = this; bool includeParent = false; if (gotoStmt != NULL && gotoStmt->gotoTag == GOTO_ERROR_HANDLING) includeParent = true; // Error handling gotos need to include auto-destroys // for any in-scope variables for the block containing // the error-handling label. // Compare with while/break, say, in which the // variables in the parent block are assumed to be destroyed by the // parent block. // Problem: this loop terminates because // scope->mBlock == forTarget by the time we should be running it. while (scope != NULL) { // stop when block == forTarget for non-error-handling gotos if (scope->mBlock == forTarget && includeParent == false) break; scope->variablesDestroy(refStmt, excludeVar, ignored); // stop if recurse == false or if block == forTarget if (recurse == false) break; if (scope->mBlock == forTarget) break; scope = scope->mParent; } mLocalsHandled = true; }
bool WhileStmt::loopBodyHasExits() { std::vector<Expr*> exprs; collectExprs(this, exprs); for_vector(Expr, node, exprs) { if (CallExpr* call = toCallExpr(node)) { if (call->isPrimitive(PRIM_YIELD) || call->isPrimitive(PRIM_RETURN)) return true; } else if (GotoStmt* gs = toGotoStmt(node)) { if (gs->gotoTag == GOTO_RETURN || gs->gotoTag == GOTO_BREAK) return true; } } return false; }
// // Removes gotos where the label immediately follows the goto and // unused labels // void removeUnnecessaryGotos(FnSymbol* fn) { std::vector<BaseAST*> asts; std::set<BaseAST*> labels; collect_asts_STL(fn, asts); for_vector(BaseAST, ast, asts) { if (GotoStmt* gotoStmt = toGotoStmt(ast)) { DefExpr* def = toDefExpr(gotoStmt->next); SymExpr* label = toSymExpr(gotoStmt->label); INT_ASSERT(label); if (def && def->sym == label->var) gotoStmt->remove(); else labels.insert(label->var); } } for_vector(BaseAST, ast2, asts) { if (DefExpr* def = toDefExpr(ast2)) if (LabelSymbol* label = toLabelSymbol(def->sym)) if (labels.find(label) == labels.end()) def->remove(); } }
void collectGotoStmts(BaseAST* ast, Vec<GotoStmt*>& gotoStmts) { AST_CHILDREN_CALL(ast, collectGotoStmts, gotoStmts); if (GotoStmt* gotoStmt = toGotoStmt(ast)) gotoStmts.add(gotoStmt); }
static void list_ast(BaseAST* ast, BaseAST* parentAst = NULL, int indent = 0) { bool do_list_line = false; bool is_C_loop = false; const char* block_explain = NULL; if (Expr* expr = toExpr(ast)) { do_list_line = !parentAst || list_line(expr, parentAst); if (do_list_line) { printf("%-7d ", expr->id); for (int i = 0; i < indent; i++) printf(" "); } if (GotoStmt* e = toGotoStmt(ast)) { printf("goto "); if (SymExpr* label = toSymExpr(e->label)) { if (label->var != gNil) { list_ast(e->label, ast, indent+1); } } else { list_ast(e->label, ast, indent+1); } } else if (toBlockStmt(ast)) { block_explain = block_explanation(ast, parentAst); printf("%s{\n", block_explain); } else if (toCondStmt(ast)) { printf("if "); } else if (CallExpr* e = toCallExpr(expr)) { if (e->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) is_C_loop = true; if (e->primitive) printf("%s( ", e->primitive->name); else printf("call( "); } else if (NamedExpr* e = toNamedExpr(expr)) { printf("%s = ", e->name); } else if (toDefExpr(expr)) { printf("def "); } else if (SymExpr* e = toSymExpr(expr)) { list_sym(e->var, false); } else if (UnresolvedSymExpr* e = toUnresolvedSymExpr(expr)) { printf("%s ", e->unresolved); } } if (Symbol* sym = toSymbol(ast)) list_sym(sym); bool early_newline = toFnSymbol(ast) || toModuleSymbol(ast); if (early_newline || is_C_loop) printf("\n"); int new_indent = indent; if (isExpr(ast)) if (do_list_line) new_indent = indent+2; AST_CHILDREN_CALL(ast, list_ast, ast, new_indent); if (Expr* expr = toExpr(ast)) { CallExpr* parent_C_loop = NULL; if (CallExpr* call = toCallExpr(parentAst)) if (call->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) parent_C_loop = call; if (toCallExpr(expr)) { printf(") "); } if (toBlockStmt(ast)) { printf("%-7d ", expr->id); if (*block_explain) indent -= 2; for (int i = 0; i < indent; i++) printf(" "); if ((parent_C_loop && parent_C_loop->get(3) == expr) || *block_explain) printf("} "); else printf("}\n"); } else if (CondStmt* cond = toCondStmt(parentAst)) { if (cond->condExpr == expr) printf("\n"); } else if (!toCondStmt(expr) && do_list_line) { DefExpr* def = toDefExpr(expr); if (!(def && early_newline)) if (!parent_C_loop) printf("\n"); } } }
static void list_ast(BaseAST* ast, BaseAST* parentAst = NULL, int indent = 0) { bool do_list_line = false; bool is_C_loop = false; const char* block_explain = NULL; if (Expr* expr = toExpr(ast)) { if (ForallStmt* pfs = toForallStmt(parentAst)) { if (expr == pfs->fRecIterIRdef) { printf("fRecIterIRdef"); } else if (expr == pfs->loopBody()) { if (pfs->numShadowVars() == 0) print_on_its_own_line(indent, "with() do\n"); else print_on_its_own_line(indent, "do\n", false); indent -= 2; } } do_list_line = !parentAst || list_line(expr, parentAst); if (do_list_line) { printf("%-7d ", expr->id); print_indent(indent); } if (const char* expl = forall_explanation_start(ast, parentAst)) printf("%s", expl); if (GotoStmt* e = toGotoStmt(ast)) { printf("goto "); if (SymExpr* label = toSymExpr(e->label)) { if (label->symbol() != gNil) { list_ast(e->label, ast, indent+1); } } else { list_ast(e->label, ast, indent+1); } } else if (toBlockStmt(ast)) { block_explain = block_explanation(ast, parentAst); const char* block_kind = ast->astTagAsString(); if (!strcmp(block_kind, "BlockStmt")) block_kind = ""; printf("%s{%s\n", block_explain, block_kind); } else if (toCondStmt(ast)) { printf("if "); } else if (toIfExpr(ast)) { printf("IfExpr "); } else if (toForallStmt(ast)) { printf("forall\n"); } else if (CallExpr* e = toCallExpr(expr)) { if (e->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) is_C_loop = true; if (e->primitive) printf("%s( ", e->primitive->name); else printf("call( "); } else if (ForallExpr* e = toForallExpr(expr)) { if (e->zippered) printf("zip "); printf("forall( "); } else if (NamedExpr* e = toNamedExpr(expr)) { printf("%s = ", e->name); } else if (toDefExpr(expr)) { Symbol* sym = toDefExpr(expr)->sym; if (sym->type != NULL) { printf("def %s ", sym->qualType().qualStr()); } else { printf("def "); } } else if (SymExpr* e = toSymExpr(expr)) { list_sym(e->symbol(), false); } else if (UnresolvedSymExpr* e = toUnresolvedSymExpr(expr)) { printf("%s ", e->unresolved); } else if (isUseStmt(expr)) { printf("use "); } } if (Symbol* sym = toSymbol(ast)) list_sym(sym); bool early_newline = toFnSymbol(ast) || toModuleSymbol(ast); if (early_newline || is_C_loop) printf("\n"); int new_indent = indent; if (isExpr(ast)) if (do_list_line) new_indent = indent+2; AST_CHILDREN_CALL(ast, list_ast, ast, new_indent); if (Expr* expr = toExpr(ast)) { CallExpr* parent_C_loop = NULL; if (CallExpr* call = toCallExpr(parentAst)) if (call->isPrimitive(PRIM_BLOCK_C_FOR_LOOP)) parent_C_loop = call; if (toCallExpr(expr)) { printf(") "); } if (toBlockStmt(ast)) { printf("%-7d ", expr->id); if (*block_explain) indent -= 2; print_indent(indent); if ((parent_C_loop && parent_C_loop->get(3) == expr) || *block_explain) printf("} "); else if (isDeferStmt(parentAst)) printf("}"); // newline is coming else printf("}\n"); if (isForallLoopBody(expr) && parentAst != NULL) { print_indent(indent); printf(" end forall %d", parentAst->id); } } else if (ForallExpr* e = toForallExpr(expr)) { if (e->cond) printf(") "); else printf("} "); } else if (UseStmt* use = toUseStmt(expr)) { if (!use->isPlainUse()) { if (use->hasExceptList()) { printf("except "); } else { printf("only "); } bool first = true; for_vector(const char, str, use->named) { if (first) { first = false; } else { printf(", "); } printf("%s", str); } for (std::map<const char*, const char*>::iterator it = use->renamed.begin(); it != use->renamed.end(); ++it) { if (first) { first = false; } else { printf(", "); } printf("%s as %s", it->second, it->first); } printf("\n"); } } else if (CondStmt* cond = toCondStmt(parentAst)) {
void collectGotoStmtsSTL(BaseAST* ast, std::vector<GotoStmt*>& gotoStmts) { AST_CHILDREN_CALL(ast, collectGotoStmtsSTL, gotoStmts); if (GotoStmt* gotoStmt = toGotoStmt(ast)) gotoStmts.push_back(gotoStmt); }
// Returns true if the symbol is read in the containing expression, // false otherwise. If the operand is used as an address, // that does not count as a 'read', so false is returned in that case. static bool isUse(SymExpr* se) { if (toGotoStmt(se->parentExpr)) return false; if (toCondStmt(se->parentExpr)) return true; if (toBlockStmt(se->parentExpr)) return true; if (isDefExpr(se->parentExpr)) return false; CallExpr* call = toCallExpr(se->parentExpr); if (FnSymbol* fn = call->resolvedFunction()) { // Skip the "base" symbol. if (se->symbol() == fn) return false; // A "normal" call. ArgSymbol* arg = actual_to_formal(se); if (arg->intent == INTENT_OUT || (arg->intent & INTENT_FLAG_REF)) return false; } else { INT_ASSERT(call->primitive); const bool isFirstActual = call->get(1) == se; switch(call->primitive->tag) { default: return true; case PRIM_MOVE: case PRIM_ASSIGN: case PRIM_ADD_ASSIGN: case PRIM_SUBTRACT_ASSIGN: case PRIM_MULT_ASSIGN: case PRIM_DIV_ASSIGN: case PRIM_MOD_ASSIGN: case PRIM_LSH_ASSIGN: case PRIM_RSH_ASSIGN: case PRIM_AND_ASSIGN: case PRIM_OR_ASSIGN: case PRIM_XOR_ASSIGN: if (isFirstActual) { return false; } return true; case PRIM_ADDR_OF: case PRIM_SET_REFERENCE: return false; // See Note #2. case PRIM_PRIVATE_BROADCAST: // The operand is used by name (it must be a manifest constant). // Thus it acts more like an address than a value. return false; case PRIM_CHPL_COMM_GET: case PRIM_CHPL_COMM_PUT: case PRIM_CHPL_COMM_ARRAY_GET: case PRIM_CHPL_COMM_ARRAY_PUT: case PRIM_CHPL_COMM_GET_STRD: case PRIM_CHPL_COMM_PUT_STRD: // ('comm_get/put' locAddr locale widePtr len) // The first and third operands are treated as addresses. // The second and fourth are values if (se == call->get(2) || se == call->get(4)) { return true; } return false; case PRIM_CHPL_COMM_REMOTE_PREFETCH: // comm prefetch locale widePtr len // second argument is an address // first and third are values. if (isFirstActual || se == call->get(3)) { return true; } return false; case PRIM_SET_MEMBER: // The first operand works like a reference, and the second is a field // name. Only the third is a replaceable use. if (se == call->get(3)) { return true; } return false; case PRIM_GET_MEMBER: case PRIM_GET_MEMBER_VALUE: if (isFirstActual) { return false; } return true; case PRIM_ARRAY_SET: case PRIM_ARRAY_SET_FIRST: case PRIM_ARRAY_GET: case PRIM_ARRAY_GET_VALUE: // The first operand is treated like a reference. if (isFirstActual) { return false; } return true; case PRIM_SET_UNION_ID: // The first operand is treated like a reference. if (isFirstActual) { return false; } return true; } } return true; }
// This routine returns true if the value of the given symbol may have changed // due to execution of the containing expression. // If the symbol is a reference, this means that the address to which the // symbol points will be changed, not the value contained in that address. See // isRefUse() for that case. // To be conservative, the routine should return true by default and then // select the cases where we are sure nothing has changed. static bool needsKilling(SymExpr* se, std::set<Symbol*>& liveRefs) { INT_ASSERT(se->isRef() == false); if (toGotoStmt(se->parentExpr)) { return false; } if (toCondStmt(se->parentExpr)) { return false; } if (toBlockStmt(se->parentExpr)) { return false; } if (isDefExpr(se->parentExpr)) { return false; } CallExpr* call = toCallExpr(se->parentExpr); if (FnSymbol* fn = call->resolvedFunction()) { // Skip the "base" symbol. if (se->symbol() == fn) { return false; } ArgSymbol* arg = actual_to_formal(se); if (arg->intent == INTENT_OUT || arg->intent == INTENT_INOUT || arg->intent == INTENT_REF || arg->hasFlag(FLAG_ARG_THIS)) // Todo: replace with arg intent check? { liveRefs.insert(se->symbol()); return true; } if (isRecordWrappedType(arg->type)) { return true; } return false; } else { const bool isFirstActual = call->get(1) == se; if ((call->isPrimitive(PRIM_MOVE) || call->isPrimitive(PRIM_ASSIGN)) && isFirstActual) { return true; } if (isOpEqualPrim(call) && isFirstActual) { return true; } if (call->isPrimitive(PRIM_SET_MEMBER) && isFirstActual) { return true; } if (call->isPrimitive(PRIM_ARRAY_SET) || call->isPrimitive(PRIM_ARRAY_SET_FIRST)) { if (isFirstActual) { return true; } return false; } if (call->isPrimitive(PRIM_GET_MEMBER)) { // This creates an alias to a portion of the first arg. // We could track this as a reference and invalidate a pair containing // this symbol when the ref is dereferenced. But for now, we want to // preserve the mapping ref = &value in the RefMap, so having a (ref, // value) pair also possibly mean ref = &(value.subfield) does not quite // fit. // We could keep the ability to do (deref ref) <- value substitution by // keeping a separate map for "true" references, or by performing those // substitutions in a separate pass. // For now, we treat subfield extraction as evidence of a future change // to the symbol itself, and use that fact to remove it from // consideration in copy propagation. if (isFirstActual) { // We select just the case where the referent is passed by value, // because in the other case, the address of the object is not // returned, so that means that the address (i.e. the value of the // reference variable) does not change. return true; } return false; } if (call->isPrimitive(PRIM_ADDR_OF) || call->isPrimitive(PRIM_SET_REFERENCE)) { liveRefs.insert(se->symbol()); return true; } return false; } INT_ASSERT(0); // Should never get here. return true; }