void FakeDirectiveHandler::InsertAccess(Expr * Current, DeclRefExpr * Original, bool Write, vector<LocalStmtPair> WritePairs, bool ActualVar, string Struct) { if (!ActualVar) return; const Type * T = Current->getType().getTypePtr(); if (FullDirectives->IsPrivate(Original, Struct, T, Original->getLocStart())) { return; } vector<LocalStmtPair>::iterator it; CompilerInstance &CI = FullDirectives->GetCI(Current->getLocStart()); for (it = WritePairs.begin(); it != WritePairs.end(); it++) { bool insertAfter = it->insertAfter; Stmt * curStmt = it->stmt; bool isBracket = false; SourceLocation start = curStmt->getLocStart(); SourceLocation end = FindSemiAfterLocation(curStmt->getLocEnd(), CI.getASTContext()); if (end.isInvalid()) { end = curStmt->getLocEnd(); isBracket = true; } SourceLocation loc; if (insertAfter) { if (isBracket) { loc = end; } else { loc = end.getLocWithOffset(1); } } else { loc = start; } loc = tools::UnpackMacroLoc(loc, CI); if (GetOrSetAccessed(loc, Current, Write)) { continue; } FullDirectives->InsertDeclAccess(Original->getFoundDecl(), Write); } }
/// VerifyJumps - Verify each element of the Jumps array to see if they are /// valid, emitting diagnostics if not. void JumpScopeChecker::VerifyJumps() { while (!Jumps.empty()) { Stmt *Jump = Jumps.pop_back_val(); // With a goto, if (GotoStmt *GS = dyn_cast<GotoStmt>(Jump)) { CheckJump(GS, GS->getLabel(), GS->getGotoLoc(), diag::err_goto_into_protected_scope); continue; } if (SwitchStmt *SS = dyn_cast<SwitchStmt>(Jump)) { for (SwitchCase *SC = SS->getSwitchCaseList(); SC; SC = SC->getNextSwitchCase()) { assert(LabelAndGotoScopes.count(SC) && "Case not visited?"); CheckJump(SS, SC, SC->getLocStart(), diag::err_switch_into_protected_scope); } continue; } unsigned DiagnosticScope; // We don't know where an indirect goto goes, require that it be at the // top level of scoping. if (IndirectGotoStmt *IG = dyn_cast<IndirectGotoStmt>(Jump)) { assert(LabelAndGotoScopes.count(Jump) && "Jump didn't get added to scopes?"); unsigned GotoScope = LabelAndGotoScopes[IG]; if (GotoScope == 0) continue; // indirect jump is ok. S.Diag(IG->getGotoLoc(), diag::err_indirect_goto_in_protected_scope); DiagnosticScope = GotoScope; } else { // We model &&Label as a jump for purposes of scope tracking. We actually // don't care *where* the address of label is, but we require the *label // itself* to be in scope 0. If it is nested inside of a VLA scope, then // it is possible for an indirect goto to illegally enter the VLA scope by // indirectly jumping to the label. assert(isa<AddrLabelExpr>(Jump) && "Unknown jump type"); LabelStmt *TheLabel = cast<AddrLabelExpr>(Jump)->getLabel(); assert(LabelAndGotoScopes.count(TheLabel) && "Referenced label didn't get added to scopes?"); unsigned LabelScope = LabelAndGotoScopes[TheLabel]; if (LabelScope == 0) continue; // Addr of label is ok. S.Diag(Jump->getLocStart(), diag::err_addr_of_label_in_protected_scope); DiagnosticScope = LabelScope; } // Report all the things that would be skipped over by this &&label or // indirect goto. while (DiagnosticScope != 0) { S.Diag(Scopes[DiagnosticScope].Loc, Scopes[DiagnosticScope].Diag); DiagnosticScope = Scopes[DiagnosticScope].ParentScope; } } }
Stmt IRMutator2::visit(const LetStmt *op) { Expr value = mutate(op->value); Stmt body = mutate(op->body); if (value.same_as(op->value) && body.same_as(op->body)) { return op; } return LetStmt::make(op->name, std::move(value), std::move(body)); }
bool uses_branches(Func f) { Target t = get_jit_target_from_environment(); t.set_feature(Target::NoBoundsQuery); t.set_feature(Target::NoAsserts); Stmt s = Internal::lower(f.function(), t); ContainsBranches b; s.accept(&b); return b.result; }
int count_host_alignment_asserts(Func f, std::map<string, int> m) { Target t = get_jit_target_from_environment(); t.set_feature(Target::NoBoundsQuery); f.compute_root(); Stmt s = Internal::lower({f.function()}, f.name(), t); CountHostAlignmentAsserts c(m); s.accept(&c); return c.count; }
Stmt IRMutator2::visit(const Block *op) { Stmt first = mutate(op->first); Stmt rest = mutate(op->rest); if (first.same_as(op->first) && rest.same_as(op->rest)) { return op; } return Block::make(std::move(first), std::move(rest)); }
Stmt IRMutator::mutate(Stmt s) { if (s.defined()) { s.accept(this); } else { stmt = Stmt(); } expr = Expr(); return stmt; }
int count_interleaves(Func f) { Target t = get_jit_target_from_environment(); t.set_feature(Target::NoBoundsQuery); t.set_feature(Target::NoAsserts); Stmt s = Internal::lower(f.function(), t); CountInterleaves i; s.accept(&i); return i.result; }
void NetworkDriverRewriteVisitor::InstrumentEntryPoints(FunctionDecl* funcDecl, string fdFile) { if (funcDecl->getStorageClass() == SC_Static) RW.RemoveText(funcDecl->getInnerLocStart(), 7); if (DI->getInstance().GetInitFunction() == funcDecl->getNameInfo().getName().getAsString()) return; if (funcDecl->getParamDecl(0)->getOriginalType().getAsString() != "struct device *" && funcDecl->getParamDecl(0)->getOriginalType().getAsString() != "struct pci_dev *") return; SourceRange sr = funcDecl->getParamDecl(0)->getSourceRange(); RW.InsertTextBefore(sr.getBegin(), "struct net_device *dev, "); Stmt *body = funcDecl->getBody(); list<DeclStmt*> stmtsToRewrite; for (auto i = body->child_begin(), e = body->child_end(); i != e; ++i) { if (!isa<DeclStmt>(*i)) continue; DeclStmt *declStmt = cast<DeclStmt>(*i); if (!declStmt->isSingleDecl() && !isa<VarDecl>(declStmt->getSingleDecl())) continue; VarDecl *var = cast<VarDecl>(declStmt->getSingleDecl()); if (!var->hasInit()) continue; Expr *expr = var->getInit(); if (!isa<ImplicitCastExpr>(expr)) continue; ImplicitCastExpr *implicit = cast<ImplicitCastExpr>(expr); if (!isa<CallExpr>(implicit->getSubExpr())) continue; CallExpr *call = cast<CallExpr>(implicit->getSubExpr()); DeclRefExpr *callee = cast<DeclRefExpr>(cast<ImplicitCastExpr>(call->getCallee())->getSubExpr()); if (callee->getNameInfo().getName().getAsString() == "to_pci_dev" || callee->getNameInfo().getName().getAsString() == "pci_get_drvdata") { stmtsToRewrite.push_back(declStmt); } } while (!stmtsToRewrite.empty()) { DeclStmt *stmt = stmtsToRewrite.back(); RW.RemoveText(stmt->getSourceRange()); stmtsToRewrite.pop_back(); } }
bool ReserveCandidates::isInComplexLoop(clang::Stmt *s, SourceLocation declLocation, bool isMemberVariable) const { if (!s || declLocation.isInvalid()) return false; int forCount = 0; int foreachCount = 0; static vector<unsigned int> nonComplexOnesCache; static vector<unsigned int> complexOnesCache; auto rawLoc = s->getLocStart().getRawEncoding(); // For some reason we generate two warnings on some foreaches, so cache the ones we processed // and return true so we don't trigger a warning if (clazy_std::contains(nonComplexOnesCache, rawLoc) || clazy_std::contains(complexOnesCache, rawLoc)) return true; Stmt *parent = s; PresumedLoc lastForeachForStm; while ((parent = HierarchyUtils::parent(m_parentMap, parent))) { const SourceLocation parentStart = parent->getLocStart(); if (!isMemberVariable && sm().isBeforeInSLocAddrSpace(parentStart, declLocation)) { nonComplexOnesCache.push_back(rawLoc); return false; } bool isLoop = false; if (loopIsComplex(parent, isLoop)) { complexOnesCache.push_back(rawLoc); return true; } if (QtUtils::isInForeach(m_ci, parentStart)) { auto ploc = sm().getPresumedLoc(parentStart); if (Utils::presumedLocationsEqual(ploc, lastForeachForStm)) { // Q_FOREACH comes in pairs, because each has two for statements inside, so ignore one when counting } else { foreachCount++; lastForeachForStm = ploc; } } else { if (isLoop) forCount++; } if (foreachCount > 1 || forCount > 1) { // two foreaches are almost always a false-positve complexOnesCache.push_back(rawLoc); return true; } } nonComplexOnesCache.push_back(rawLoc); return false; }
Stmt IRMutator::mutate(const Stmt &s) { if (s.defined()) { s.accept(this); } else { stmt = Stmt(); } expr = Expr(); return std::move(stmt); }
void IRMutator::visit(const LetStmt *op) { Expr value = mutate(op->value); Stmt body = mutate(op->body); if (value.same_as(op->value) && body.same_as(op->body)) { stmt = op; } else { stmt = LetStmt::make(op->name, std::move(value), std::move(body)); } }
void IRMutator::visit(const Block *op) { Stmt first = mutate(op->first); Stmt rest = mutate(op->rest); if (first.same_as(op->first) && rest.same_as(op->rest)) { stmt = op; } else { stmt = Block::make(std::move(first), std::move(rest)); } }
void print_vine_ir(asm_program_t *prog, vector<vine_block_t *> vblocks ) { unsigned int i, j; for ( i = 0; i < vblocks.size(); i++ ) { vine_block_t *block = vblocks.at(i); assert(block); vector<Stmt *> *inner = block->vine_ir; // cout << "Vine Block " << i << endl; cout << " {" << endl; // declvis vis; // vis.compute(inner); // print_decls(vis.decls); // cout << " "; ostringstream os; ostream_insn(prog, block->inst, os); cout << " // " << os.str() << endl; vector<VarDecl *> globals = get_reg_decls(); map<string,reg_t> context; for(vector<VarDecl *>::const_iterator gi = globals.begin(); gi != globals.end(); gi++){ VarDecl *vd = *gi; context.insert(pair<string, reg_t>(vd->name, vd->typ)); } for ( j = 0; j < inner->size(); j++ ) { #ifdef TYPECHECKING try { if (typecheck_stmt(&context, inner->at(j)) < 0) { cout <<"Type error found at:" <<endl; } } catch (TypeError &e) { cout <<"Type Error: " << e.what() <<endl; cout <<"Found at:" <<endl; } #endif Stmt *s = inner->at(j); cout << " " << s->tostring(); // if(s->stmt_type == LABEL) // cout << endl; // else // cout << ";" << endl; cout << endl; } cout << " }" << endl; } }
void visit(const For *for_loop) { Stmt body = mutate(for_loop->body); const IntImm *extent = for_loop->extent.as<IntImm>(); if (extent && extent->value == 1) { stmt = new LetStmt(for_loop->name, for_loop->min, body); } else if (body.same_as(for_loop->body)) { stmt = for_loop; } else { stmt = new For(for_loop->name, for_loop->min, for_loop->extent, for_loop->for_type, body); } }
void IRMutator::visit(const For *op) { Expr min = mutate(op->min); Expr extent = mutate(op->extent); Stmt body = mutate(op->body); if (min.same_as(op->min) && extent.same_as(op->extent) && body.same_as(op->body)) { stmt = op; } else { stmt = For::make(op->name, min, extent, op->for_type, body); } }
void print_merged_ir( vector<Stmt *> ir ) { unsigned int i; for ( i = 0; i < ir.size(); i++ ) { Stmt *stmt = ir.at(i); assert(stmt); cout << stmt->ir_address << "\t\t" << stmt->tostring() << endl; } }
Stmt Pipeline::make(std::string name, Stmt produce, Stmt update, Stmt consume) { internal_assert(produce.defined()) << "Pipeline of undefined\n"; // update is allowed to be null internal_assert(consume.defined()) << "Pipeline of undefined\n"; Pipeline *node = new Pipeline; node->name = name; node->produce = produce; node->update = update; node->consume = consume; return node; }
void BlockStmt::genCode(const Label& next) { const unsigned n = stmts->size(); for (unsigned i = 0; i < n; i++) { Stmt *stmt = (*stmts)[i]; if (i < n-1) { Label nxt; stmt->genCode(nxt); cout << nxt << ":" << endl; } else stmt->genCode(next); } }
void visit(const LetStmt *op) { Expr value = mutate(op->value); if (value.type() == Int(32)) alignment_info.push(op->name, modulus_remainder(value, alignment_info)); Stmt body = mutate(op->body); if (value.type() == Int(32)) alignment_info.pop(op->name); if (value.same_as(op->value) && body.same_as(op->body)) { stmt = op; } else { stmt = LetStmt::make(op->name, value, body); } }
bool Interpret::EvaluateExpression(const string& expr_str) { string trim = expr_str; trim.erase(trim.find_last_not_of(" \n\r\t")+1); if (trim == "") { return true; } ScopeTracer tracer(session(), "Interpret::EvaluateExpression()"); assert(_repl_module != NULL); assert(_repl_block != NULL); session()->diagnostic()->resetReport(); // Parses the expression. Parser parser(trim, session()); Stmt* stmt = parser.parseStatement(); if (session()->diagnostic()->mostSignificantLevel() <= REPORT_ERROR) { return false; } // resolving Resolver resolver(session()); resolver.resolveAst(stmt); _repl_block->addStatement(stmt); stmt->parent(_repl_block); // Resolves names. resolver.resolveSymbol(stmt); if (session()->diagnostic()->mostSignificantLevel() <= REPORT_ERROR) { return false; } if (session()->config()->print_ast()) { AstPrinter astPrinter(session(), stdout, session()->str_table()); astPrinter.print(stmt); } // Evaluates it. Evaluator eval(this); _eval = &eval; Value* v = eval.evaluate(stmt); if (v) { printf("%s\n", v->toString().c_str()); } env_curr()->clear(); return true; }
void SimpleInliner::copyFunctionBody(void) { Stmt *Body = CurrentFD->getBody(); TransAssert(Body && "NULL Body!"); std::string FuncBodyStr(""); RewriteHelper->getStmtString(Body, FuncBodyStr); TransAssert(FuncBodyStr[0] == '{'); SourceLocation StartLoc = Body->getLocStart(); const char *StartBuf = SrcManager->getCharacterData(StartLoc); std::vector< std::pair<ReturnStmt *, int> > SortedReturnStmts; sortReturnStmtsByOffs(StartBuf, SortedReturnStmts); // Now we start rewriting int Delta = 1; // skip the first { symbol FuncBodyStr.insert(Delta, "\n"); ++Delta; for(SmallVector<std::string, 10>::iterator I = ParmStrings.begin(), E = ParmStrings.end(); I != E; ++I) { std::string PStr = (*I); FuncBodyStr.insert(Delta, PStr); Delta += PStr.size(); } // restore the effect of { Delta--; int ReturnSZ = 6; std::string TmpVarStr = TmpVarName + " = "; int TmpVarNameSize = static_cast<int>(TmpVarStr.size()); for(std::vector< std::pair<ReturnStmt *, int> >::iterator I = SortedReturnStmts.begin(), E = SortedReturnStmts.end(); I != E; ++I) { ReturnStmt *RS = (*I).first; int Off = (*I).second + Delta; Expr *Exp = RS->getRetValue(); if (Exp) { const Type *T = Exp->getType().getTypePtr(); if (!T->isVoidType()) { FuncBodyStr.replace(Off, ReturnSZ, TmpVarStr); Delta += (TmpVarNameSize - ReturnSZ); continue; } } FuncBodyStr.replace(Off, ReturnSZ, ""); Delta -= ReturnSZ; } RewriteHelper->addStringBeforeStmt(TheStmt, FuncBodyStr, NeedParen); }
void Func::realize(Buffer dst) { if (!compiled_module.wrapped_function) { assert(func.defined() && "Can't realize NULL function handle"); assert(value().defined() && "Can't realize undefined function"); Stmt stmt = lower(); // Infer arguments InferArguments infer_args; stmt.accept(&infer_args); Argument me(name(), true, Int(1)); infer_args.arg_types.push_back(me); arg_values = infer_args.arg_values; arg_values.push_back(dst.raw_buffer()); image_param_args = infer_args.image_param_args; Internal::log(2) << "Inferred argument list:\n"; for (size_t i = 0; i < infer_args.arg_types.size(); i++) { Internal::log(2) << infer_args.arg_types[i].name << ", " << infer_args.arg_types[i].type << ", " << infer_args.arg_types[i].is_buffer << "\n"; } StmtCompiler cg; cg.compile(stmt, name(), infer_args.arg_types); if (log::debug_level >= 3) { cg.compile_to_native(name() + ".s", true); cg.compile_to_bitcode(name() + ".bc"); std::ofstream stmt_debug((name() + ".stmt").c_str()); stmt_debug << stmt; } compiled_module = cg.compile_to_function_pointers(); if (error_handler) compiled_module.set_error_handler(error_handler); else compiled_module.set_error_handler(NULL); } else { // Update the address of the buffer we're realizing into arg_values[arg_values.size()-1] = dst.raw_buffer(); // update the addresses of the image param args for (size_t i = 0; i < image_param_args.size(); i++) { Buffer b = image_param_args[i].second.get_buffer(); assert(b.defined() && "An ImageParam is not bound to a buffer"); arg_values[image_param_args[i].first] = b.raw_buffer(); } } compiled_module.wrapped_function(&(arg_values[0])); }
bool VisitStmt(Stmt *s) { // Only care about If statements. if (isa<IfStmt>(s)) { IfStmt *IfStatement = cast<IfStmt>(s); Stmt *Then = IfStatement->getThen(); TheRewriter.InsertText(Then->getLocStart(), "// the 'if' part\n", true, true); Stmt *Else = IfStatement->getElse(); if (Else) TheRewriter.InsertText(Else->getLocStart(), "// the 'else' part\n", true, true); } return true; }
Stmt IRMutator2::visit(const For *op) { Expr min = mutate(op->min); Expr extent = mutate(op->extent); Stmt body = mutate(op->body); if (min.same_as(op->min) && extent.same_as(op->extent) && body.same_as(op->body)) { return op; } return For::make(op->name, std::move(min), std::move(extent), op->for_type, op->device_api, std::move(body)); }
void visit(const Realize *op) { Stmt body = mutate(op->body); IsBufferSpecial special(op->name); op->accept(&special); // Get the function associated with this realization, which // contains the explicit fold directives from the schedule. auto func_it = env.find(op->name); Function func = func_it != env.end() ? func_it->second : Function(); if (special.special) { for (const StorageDim &i : func.schedule().storage_dims()) { user_assert(!i.fold_factor.defined()) << "Dimension " << i.var << " of " << op->name << " cannot be folded because it is accessed by extern or device stages.\n"; } debug(3) << "Not attempting to fold " << op->name << " because its buffer is used\n"; if (body.same_as(op->body)) { stmt = op; } else { stmt = Realize::make(op->name, op->types, op->bounds, op->condition, body); } } else { // Don't attempt automatic storage folding if there is // more than one produce node for this func. bool explicit_only = count_producers(body, op->name) != 1; AttemptStorageFoldingOfFunction folder(func, explicit_only); debug(3) << "Attempting to fold " << op->name << "\n"; body = folder.mutate(body); if (body.same_as(op->body)) { stmt = op; } else if (folder.dims_folded.empty()) { stmt = Realize::make(op->name, op->types, op->bounds, op->condition, body); } else { Region bounds = op->bounds; for (size_t i = 0; i < folder.dims_folded.size(); i++) { int d = folder.dims_folded[i].dim; Expr f = folder.dims_folded[i].factor; internal_assert(d >= 0 && d < (int)bounds.size()); bounds[d] = Range(0, f); } stmt = Realize::make(op->name, op->types, bounds, op->condition, body); } } }
void IRRewriter::visit(const Func *f) { Stmt body = rewrite(f->getBody()); if (body == f->getBody()) { func = *f; } else { if (!body.defined()) { body = Pass::make(); } func = Func(*f, body); } }
void visit(const Allocate *op) { allocs.push(op->name, 1); Stmt body = mutate(op->body); if (allocs.contains(op->name)) { stmt = body; allocs.pop(op->name); } else if (body.same_as(op->body)) { stmt = op; } else { stmt = Allocate::make(op->name, op->type, op->extents, op->condition, body, op->new_expr, op->free_function); } }
string print_loop_nest(const vector<Function> &output_funcs) { // Do the first part of lowering: // Compute an environment map<string, Function> env; for (Function f : output_funcs) { populate_environment(f, env); } // Create a deep-copy of the entire graph of Funcs. vector<Function> outputs; std::tie(outputs, env) = deep_copy(output_funcs, env); // Output functions should all be computed and stored at root. for (Function f: outputs) { Func(f).compute_root().store_root(); } // Ensure that all ScheduleParams become well-defined constant Exprs. for (auto &f : env) { f.second.substitute_schedule_param_exprs(); } // Substitute in wrapper Funcs env = wrap_func_calls(env); // Compute a realization order vector<string> order = realization_order(outputs, env); // Try to simplify the RHS/LHS of a function definition by propagating its // specializations' conditions simplify_specializations(env); // For the purposes of printing the loop nest, we don't want to // worry about which features are and aren't enabled. Target target = get_host_target(); for (DeviceAPI api : all_device_apis) { target.set_feature(target_feature_for_device_api(DeviceAPI(api))); } bool any_memoized = false; // Schedule the functions. Stmt s = schedule_functions(outputs, order, env, target, any_memoized); // Now convert that to pseudocode std::ostringstream sstr; PrintLoopNest pln(sstr, env); s.accept(&pln); return sstr.str(); }
void visit(const Allocate *op) { int idx = get_func_id(op->name); vector<Expr> new_extents; bool all_extents_unmodified = true; for (size_t i = 0; i < op->extents.size(); i++) { new_extents.push_back(mutate(op->extents[i])); all_extents_unmodified &= new_extents[i].same_as(op->extents[i]); } Expr condition = mutate(op->condition); bool on_stack; Expr size = compute_allocation_size(new_extents, condition, op->type, op->name, on_stack); func_alloc_sizes.push(op->name, {on_stack, size}); // compute_allocation_size() might return a zero size, if the allocation is // always conditionally false. remove_dead_allocations() is called after // inject_profiling() so this is a possible scenario. if (!is_zero(size) && on_stack) { const int64_t *int_size = as_const_int(size); internal_assert(int_size != NULL); // Stack size is always a const int func_stack_current[idx] += *int_size; func_stack_peak[idx] = std::max(func_stack_peak[idx], func_stack_current[idx]); debug(3) << " Allocation on stack: " << op->name << "(" << size << ") in pipeline " << pipeline_name << "; current: " << func_stack_current[idx] << "; peak: " << func_stack_peak[idx] << "\n"; } Stmt body = mutate(op->body); Expr new_expr; if (op->new_expr.defined()) { new_expr = mutate(op->new_expr); } if (all_extents_unmodified && body.same_as(op->body) && condition.same_as(op->condition) && new_expr.same_as(op->new_expr)) { stmt = op; } else { stmt = Allocate::make(op->name, op->type, new_extents, condition, body, new_expr, op->free_function); } if (!is_zero(size) && !on_stack) { Expr profiler_pipeline_state = Variable::make(Handle(), "profiler_pipeline_state"); debug(3) << " Allocation on heap: " << op->name << "(" << size << ") in pipeline " << pipeline_name << "\n"; Expr set_task = Call::make(Int(32), "halide_profiler_memory_allocate", {profiler_pipeline_state, idx, size}, Call::Extern); stmt = Block::make(Evaluate::make(set_task), stmt); } }