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(")"); }
/* * Attempts to replace iteration over simple anonymous ranges with calls to * direct iterators that take low, high and stride as arguments. This is to * avoid the cost of constructing ranges, and if the stride is known at compile * time, provide a more optimized iterator that uses "<, <=, >, or >=" as the * relational operator. * * This is only meant to replace anonymous range iteration for "simple" bounded * ranges. Simple means it's a range of the form "low..high" or "low..high by * stride". Anything more complex is ignored with the thinking that this should * optimize the most common range iterators, but it could be expanded to handle * more cases. * * An alternative is to update scalar replacement of aggregates to work on * ranges, which should be able to achieve similar results as this optimization * while handling all ranges, including non-anonymous ranges. * * Will optimize things like: * - "for i in 1..10" * - "for i in 1..10+1" * - "var lo=1, hi=10;for i in lo..hi" * - "for i in 1..10 by 2" * - "for (i, j) in zip(1..10 by 2, 1..10 by -2)" * - "for (i, j) in zip(A, 1..10 by 2)" // will optimize range iter still * - "coforall i in 1..10 by 2" // works for coforalls as well * * Will not optimize ranges like: * - "for in in (1..)" // doesn't handle unbounded ranges * - "for i in 1..10 by 2 by 2" // doesn't handle more than one by operator * - "for i in 1..10 align 2" // doesn't handle align operator * - "for i in 1..#10" // doesn't handle # operator * - "var r = 1..10"; for i in r" // not an anonymous range * - "forall i in 1..10" // does not get applied to foralls * * Note that this function is pretty fragile because it relies on names of * functions/iterators as well as the arguments and order of those * functions/iterators but there's not really a way around it this early in * compilation. If the iterator can't be replaced, it is left unchanged. */ static void tryToReplaceWithDirectRangeIterator(Expr* iteratorExpr) { CallExpr* range = NULL; Expr* stride = NULL; if (CallExpr* call = toCallExpr(iteratorExpr)) { // grab the stride if we have a strided range if (call->isNamed("chpl_by")) { range = toCallExpr(call->get(1)->copy()); stride = toExpr(call->get(2)->copy()); } // assume the call is the range (checked below) and set default stride else { range = call; stride = new SymExpr(new_IntSymbol(1)); } // see if we're looking at a builder for a bounded range. the builder is // iteratable since range has these() iterators if (range && range->isNamed("chpl_build_bounded_range")) { // replace the range construction with a direct range iterator Expr* low = range->get(1)->copy(); Expr* high = range->get(2)->copy(); iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride)); } } }
UseStmt::UseStmt(BaseAST* source, std::vector<const char*>* args, bool exclude, std::map<const char*, const char*>* renames) : Stmt(E_UseStmt), src(NULL), named(), renamed(), except(exclude), relatedNames() { if (Symbol* b = toSymbol(source)) { src = new SymExpr(b); } else if (Expr* b = toExpr(source)) { src = b; } else { INT_FATAL(this, "Bad mod in UseStmt constructor"); } if (args->size() > 0) { // Symbols to search when going through this module's scope from an outside // scope for_vector(const char, str, *args) { named.push_back(str); } }
void collect_stmts(BaseAST* ast, Vec<Expr*>& stmts) { if (Expr* expr = toExpr(ast)) { stmts.add(expr); if (isBlockStmt(expr) || isCondStmt(expr)) { AST_CHILDREN_CALL(ast, collect_stmts, stmts); } } }
void collect_stmts_STL(BaseAST* ast, std::vector<Expr*>& stmts) { if (Expr* expr = toExpr(ast)) { stmts.push_back(expr); if (isBlockStmt(expr) || isCondStmt(expr)) { AST_CHILDREN_CALL(ast, collect_stmts_STL, stmts); } } }
static bool list_line(Expr* expr, BaseAST* parentAst) { if (expr->isStmt()) return !*block_explanation(expr, parentAst); if (CondStmt* cond = toCondStmt(parentAst)) { if (cond->condExpr == expr) return false; } if (Expr* pExpr = toExpr(parentAst)) if (pExpr->isStmt()) return true; if (isSymbol(parentAst)) return true; return false; }
UseStmt::UseStmt(BaseAST* source) : Stmt(E_UseStmt) { src = NULL; except = false; if (Symbol* b = toSymbol(source)) { src = new SymExpr(b); } else if (Expr* b = toExpr(source)) { src = b; } else { INT_FATAL(this, "Bad mod in UseStmt constructor"); } gUseStmts.add(this); }
UseStmt::UseStmt(BaseAST* source): Stmt(E_UseStmt), src(NULL), named(), renamed(), except(false), relatedNames() { if (Symbol* b = toSymbol(source)) { src = new SymExpr(b); } else if (Expr* b = toExpr(source)) { src = b; } else { INT_FATAL(this, "Bad mod in UseStmt constructor"); } gUseStmts.add(this); }
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 collectExprs(BaseAST* ast, std::vector<Expr*>& exprs) { AST_CHILDREN_CALL(ast, collectExprs, exprs); if (Expr* expr = toExpr(ast)) exprs.push_back(expr); }
/* * Attempts to replace iteration over simple anonymous ranges with calls to * direct iterators that take low, high and stride as arguments. This is to * avoid the cost of constructing ranges, and if the stride is known at compile * time, provide a more optimized iterator that uses "<, <=, >, or >=" as the * relational operator. * * This is only meant to replace anonymous range iteration for "simple" ranges. * Simple means it's a range of the form "low..high", "low..high by stride", or * "low..#count". Anything more complex is ignored with the thinking that this * should optimize the most common range iterators, but it could be expanded to * handle more cases. * * An alternative is to update scalar replacement of aggregates to work on * ranges, which should be able to achieve similar results as this optimization * while handling all ranges, including non-anonymous ranges. * * This function will optimize things like: * - "for i in 1..10" * - "for i in 1..10+1" * - "var lo=1, hi=10;for i in lo..hi" * - "for i in 1..10 by 2" * - "for i in 1..#10" * - "for (i, j) in zip(1..10 by 2, 1..10 by -2)" * - "for (i, j) in zip(A, 1..10 by 2)" // will optimize range iter still * - "coforall i in 1..10 by 2" // works for coforalls as well * * Will not optimize ranges like: * - "for in in (1..)" // doesn't handle unbounded ranges * - "for i in 1..10 by 2 by 2" // doesn't handle more than one by operator * - "for i in 1..10 align 2" // doesn't handle align operator * - "for i in (1..10)#2" // doesn't handle bounded counted ranges * - "for i in 1..#10 by 2" // doesn't handle strided and counted ranges * - "var r = 1..10"; for i in r" // not an anonymous range * - "forall i in 1..10" // doesn't get applied to foralls * * Note that this function is pretty fragile because it relies on names of * functions/iterators as well as the arguments and order of those * functions/iterators but there's not really a way around it this early in * compilation. If the iterator can't be replaced, it is left unchanged. */ static void tryToReplaceWithDirectRangeIterator(Expr* iteratorExpr) { if (CallExpr* call = toCallExpr(iteratorExpr)) { CallExpr* range = NULL; Expr* stride = NULL; Expr* count = NULL; // grab the stride if we have a strided range if (call->isNamed("chpl_by")) { range = toCallExpr(call->get(1)->copy()); stride = toExpr(call->get(2)->copy()); } // or grab the count if we have a counted range and set unit stride else if (call->isNamed("#")) { range = toCallExpr(call->get(1)->copy()); count = toExpr(call->get(2)->copy()); stride = new SymExpr(new_IntSymbol(1)); } // or assume the call is the range (checked below) and set unit stride else { range = call; stride = new SymExpr(new_IntSymbol(1)); } // // see if we're looking at a range builder. The builder is iteratable since // range has these() iterators // // replace fully bounded (and possibly strided range) with a direct range // iter. e.g. replace: // // `low..high by stride` // // with: // // `chpl_direct_range_iter(low, high, stride)` if (range && range->isNamed("chpl_build_bounded_range")) { // replace the range construction with a direct range iterator Expr* low = range->get(1)->copy(); Expr* high = range->get(2)->copy(); iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride)); } // replace a counted, low bounded range with unit stride with an equivalent // direct range iter. e.g. replace: // // `low..#count` (which is equivalent to `low..low+count-1`) // // with: // // `chpl_direct_range_iter(low, low+count-1, 1)` else if (count && range && range->isNamed("chpl_build_low_bounded_range")) { Expr* low = range->get(1)->copy(); Expr* high = new CallExpr("-", new CallExpr("+", low->copy(), count), new_IntSymbol(1)); iteratorExpr->replace(new CallExpr("chpl_direct_range_iter", low, high, stride)); } } }
value caml_toExpr(value t) { CAMLparam1(t); CAMLreturn(alloc_Expr(toExpr(Type_val(t)))); }
static bool printErrorHeader(BaseAST* ast) { if (!err_print) { if (Expr* expr = toExpr(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->hasFlag(FLAG_INLINE) && err_fn->linenum()) { fprintf(stderr, "%s:%d: In ", cleanFilename(err_fn), err_fn->linenum()); if (!strncmp(err_fn->name, "_construct_", 11)) { fprintf(stderr, "initializer '%s':\n", err_fn->name+11); } 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; }