void IslAstInfo::printScop(raw_ostream &OS, Scop &S) const { isl_ast_print_options *Options; isl_ast_node *RootNode = getAst(); Function *F = S.getRegion().getEntry()->getParent(); OS << ":: isl ast :: " << F->getName() << " :: " << S.getRegion().getNameStr() << "\n"; if (!RootNode) { OS << ":: isl ast generation and code generation was skipped!\n\n"; OS << ":: This is either because no useful optimizations could be applied " "(use -polly-process-unprofitable to enforce code generation) or " "because earlier passes such as dependence analysis timed out (use " "-polly-dependences-computeout=0 to set dependence analysis timeout " "to infinity)\n\n"; return; } isl_ast_expr *RunCondition = getRunCondition(); char *RtCStr, *AstStr; Options = isl_ast_print_options_alloc(S.getIslCtx()); Options = isl_ast_print_options_set_print_for(Options, cbPrintFor, nullptr); isl_printer *P = isl_printer_to_str(S.getIslCtx()); P = isl_printer_print_ast_expr(P, RunCondition); RtCStr = isl_printer_get_str(P); P = isl_printer_flush(P); P = isl_printer_indent(P, 4); P = isl_printer_set_output_format(P, ISL_FORMAT_C); P = isl_ast_node_print(RootNode, P, Options); AstStr = isl_printer_get_str(P); isl_union_map *Schedule = isl_union_map_intersect_domain(S.getSchedule(), S.getDomains()); DEBUG({ dbgs() << S.getContextStr() << "\n"; dbgs() << stringFromIslObj(Schedule); });
bool IslScheduleOptimizer::runOnScop(Scop &S) { Dependences *D = &getAnalysis<Dependences>(); if (!D->hasValidDependences()) return false; isl_schedule_free(LastSchedule); LastSchedule = nullptr; // Build input data. int ValidityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; int ProximityKinds; if (OptimizeDeps == "all") ProximityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; else if (OptimizeDeps == "raw") ProximityKinds = Dependences::TYPE_RAW; else { errs() << "Do not know how to optimize for '" << OptimizeDeps << "'" << " Falling back to optimizing all dependences.\n"; ProximityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; } isl_union_set *Domain = S.getDomains(); if (!Domain) return false; isl_union_map *Validity = D->getDependences(ValidityKinds); isl_union_map *Proximity = D->getDependences(ProximityKinds); // Simplify the dependences by removing the constraints introduced by the // domains. This can speed up the scheduling time significantly, as large // constant coefficients will be removed from the dependences. The // introduction of some additional dependences reduces the possible // transformations, but in most cases, such transformation do not seem to be // interesting anyway. In some cases this option may stop the scheduler to // find any schedule. if (SimplifyDeps == "yes") { Validity = isl_union_map_gist_domain(Validity, isl_union_set_copy(Domain)); Validity = isl_union_map_gist_range(Validity, isl_union_set_copy(Domain)); Proximity = isl_union_map_gist_domain(Proximity, isl_union_set_copy(Domain)); Proximity = isl_union_map_gist_range(Proximity, isl_union_set_copy(Domain)); } else if (SimplifyDeps != "no") { errs() << "warning: Option -polly-opt-simplify-deps should either be 'yes' " "or 'no'. Falling back to default: 'yes'\n"; } DEBUG(dbgs() << "\n\nCompute schedule from: "); DEBUG(dbgs() << "Domain := "; isl_union_set_dump(Domain); dbgs() << ";\n"); DEBUG(dbgs() << "Proximity := "; isl_union_map_dump(Proximity); dbgs() << ";\n"); DEBUG(dbgs() << "Validity := "; isl_union_map_dump(Validity); dbgs() << ";\n"); int IslFusionStrategy; if (FusionStrategy == "max") { IslFusionStrategy = ISL_SCHEDULE_FUSE_MAX; } else if (FusionStrategy == "min") { IslFusionStrategy = ISL_SCHEDULE_FUSE_MIN; } else { errs() << "warning: Unknown fusion strategy. Falling back to maximal " "fusion.\n"; IslFusionStrategy = ISL_SCHEDULE_FUSE_MAX; } int IslMaximizeBands; if (MaximizeBandDepth == "yes") { IslMaximizeBands = 1; } else if (MaximizeBandDepth == "no") { IslMaximizeBands = 0; } else { errs() << "warning: Option -polly-opt-maximize-bands should either be 'yes'" " or 'no'. Falling back to default: 'yes'\n"; IslMaximizeBands = 1; } isl_options_set_schedule_fuse(S.getIslCtx(), IslFusionStrategy); isl_options_set_schedule_maximize_band_depth(S.getIslCtx(), IslMaximizeBands); isl_options_set_schedule_max_constant_term(S.getIslCtx(), MaxConstantTerm); isl_options_set_schedule_max_coefficient(S.getIslCtx(), MaxCoefficient); isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE); isl_schedule_constraints *ScheduleConstraints; ScheduleConstraints = isl_schedule_constraints_on_domain(Domain); ScheduleConstraints = isl_schedule_constraints_set_proximity(ScheduleConstraints, Proximity); ScheduleConstraints = isl_schedule_constraints_set_validity( ScheduleConstraints, isl_union_map_copy(Validity)); ScheduleConstraints = isl_schedule_constraints_set_coincidence(ScheduleConstraints, Validity); isl_schedule *Schedule; Schedule = isl_schedule_constraints_compute_schedule(ScheduleConstraints); isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT); // In cases the scheduler is not able to optimize the code, we just do not // touch the schedule. if (!Schedule) return false; DEBUG(dbgs() << "Schedule := "; isl_schedule_dump(Schedule); dbgs() << ";\n"); isl_union_map *ScheduleMap = getScheduleMap(Schedule); for (ScopStmt *Stmt : S) { isl_map *StmtSchedule; isl_set *Domain = Stmt->getDomain(); isl_union_map *StmtBand; StmtBand = isl_union_map_intersect_domain(isl_union_map_copy(ScheduleMap), isl_union_set_from_set(Domain)); if (isl_union_map_is_empty(StmtBand)) { StmtSchedule = isl_map_from_domain(isl_set_empty(Stmt->getDomainSpace())); isl_union_map_free(StmtBand); } else { assert(isl_union_map_n_map(StmtBand) == 1); StmtSchedule = isl_map_from_union_map(StmtBand); } Stmt->setScattering(StmtSchedule); } isl_union_map_free(ScheduleMap); LastSchedule = Schedule; unsigned MaxScatDims = 0; for (ScopStmt *Stmt : S) MaxScatDims = std::max(Stmt->getNumScattering(), MaxScatDims); extendScattering(S, MaxScatDims); return false; }
bool IslScheduleOptimizer::runOnScop(Scop &S) { // Skip empty SCoPs but still allow code generation as it will delete the // loops present but not needed. if (S.getSize() == 0) { S.markAsOptimized(); return false; } const Dependences &D = getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement); if (!D.hasValidDependences()) return false; isl_schedule_free(LastSchedule); LastSchedule = nullptr; // Build input data. int ValidityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; int ProximityKinds; if (OptimizeDeps == "all") ProximityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; else if (OptimizeDeps == "raw") ProximityKinds = Dependences::TYPE_RAW; else { errs() << "Do not know how to optimize for '" << OptimizeDeps << "'" << " Falling back to optimizing all dependences.\n"; ProximityKinds = Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW; } isl_union_set *Domain = S.getDomains(); if (!Domain) return false; isl_union_map *Validity = D.getDependences(ValidityKinds); isl_union_map *Proximity = D.getDependences(ProximityKinds); // Simplify the dependences by removing the constraints introduced by the // domains. This can speed up the scheduling time significantly, as large // constant coefficients will be removed from the dependences. The // introduction of some additional dependences reduces the possible // transformations, but in most cases, such transformation do not seem to be // interesting anyway. In some cases this option may stop the scheduler to // find any schedule. if (SimplifyDeps == "yes") { Validity = isl_union_map_gist_domain(Validity, isl_union_set_copy(Domain)); Validity = isl_union_map_gist_range(Validity, isl_union_set_copy(Domain)); Proximity = isl_union_map_gist_domain(Proximity, isl_union_set_copy(Domain)); Proximity = isl_union_map_gist_range(Proximity, isl_union_set_copy(Domain)); } else if (SimplifyDeps != "no") { errs() << "warning: Option -polly-opt-simplify-deps should either be 'yes' " "or 'no'. Falling back to default: 'yes'\n"; } DEBUG(dbgs() << "\n\nCompute schedule from: "); DEBUG(dbgs() << "Domain := " << stringFromIslObj(Domain) << ";\n"); DEBUG(dbgs() << "Proximity := " << stringFromIslObj(Proximity) << ";\n"); DEBUG(dbgs() << "Validity := " << stringFromIslObj(Validity) << ";\n"); unsigned IslSerializeSCCs; if (FusionStrategy == "max") { IslSerializeSCCs = 0; } else if (FusionStrategy == "min") { IslSerializeSCCs = 1; } else { errs() << "warning: Unknown fusion strategy. Falling back to maximal " "fusion.\n"; IslSerializeSCCs = 0; } int IslMaximizeBands; if (MaximizeBandDepth == "yes") { IslMaximizeBands = 1; } else if (MaximizeBandDepth == "no") { IslMaximizeBands = 0; } else { errs() << "warning: Option -polly-opt-maximize-bands should either be 'yes'" " or 'no'. Falling back to default: 'yes'\n"; IslMaximizeBands = 1; } isl_options_set_schedule_serialize_sccs(S.getIslCtx(), IslSerializeSCCs); isl_options_set_schedule_maximize_band_depth(S.getIslCtx(), IslMaximizeBands); isl_options_set_schedule_max_constant_term(S.getIslCtx(), MaxConstantTerm); isl_options_set_schedule_max_coefficient(S.getIslCtx(), MaxCoefficient); isl_options_set_tile_scale_tile_loops(S.getIslCtx(), 0); isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE); isl_schedule_constraints *ScheduleConstraints; ScheduleConstraints = isl_schedule_constraints_on_domain(Domain); ScheduleConstraints = isl_schedule_constraints_set_proximity(ScheduleConstraints, Proximity); ScheduleConstraints = isl_schedule_constraints_set_validity( ScheduleConstraints, isl_union_map_copy(Validity)); ScheduleConstraints = isl_schedule_constraints_set_coincidence(ScheduleConstraints, Validity); isl_schedule *Schedule; Schedule = isl_schedule_constraints_compute_schedule(ScheduleConstraints); isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT); // In cases the scheduler is not able to optimize the code, we just do not // touch the schedule. if (!Schedule) return false; DEBUG({ auto *P = isl_printer_to_str(S.getIslCtx()); P = isl_printer_set_yaml_style(P, ISL_YAML_STYLE_BLOCK); P = isl_printer_print_schedule(P, Schedule); dbgs() << "NewScheduleTree: \n" << isl_printer_get_str(P) << "\n"; isl_printer_free(P); });
bool JSONImporter::runOnScop(Scop &S) { const Dependences &D = getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement); const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); std::string FileName = ImportDir + "/" + getFileName(S); std::string FunctionName = S.getFunction().getName(); errs() << "Reading JScop '" << S.getNameStr() << "' in function '" << FunctionName << "' from '" << FileName << "'.\n"; ErrorOr<std::unique_ptr<MemoryBuffer>> result = MemoryBuffer::getFile(FileName); std::error_code ec = result.getError(); if (ec) { errs() << "File could not be read: " << ec.message() << "\n"; return false; } Json::Reader reader; Json::Value jscop; bool parsingSuccessful = reader.parse(result.get()->getBufferStart(), jscop); if (!parsingSuccessful) { errs() << "JSCoP file could not be parsed\n"; return false; } isl_set *OldContext = S.getContext(); isl_set *NewContext = isl_set_read_from_str(S.getIslCtx(), jscop["context"].asCString()); for (unsigned i = 0; i < isl_set_dim(OldContext, isl_dim_param); i++) { isl_id *id = isl_set_get_dim_id(OldContext, isl_dim_param, i); NewContext = isl_set_set_dim_id(NewContext, isl_dim_param, i, id); } isl_set_free(OldContext); S.setContext(NewContext); StatementToIslMapTy NewSchedule; int index = 0; for (ScopStmt &Stmt : S) { Json::Value schedule = jscop["statements"][index]["schedule"]; isl_map *m = isl_map_read_from_str(S.getIslCtx(), schedule.asCString()); isl_space *Space = Stmt.getDomainSpace(); // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this schedule belongs to. m = isl_map_set_tuple_id(m, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { isl_id *id = isl_space_get_dim_id(Space, isl_dim_param, i); m = isl_map_set_dim_id(m, isl_dim_param, i, id); } isl_space_free(Space); NewSchedule[&Stmt] = m; index++; } if (!D.isValidSchedule(S, &NewSchedule)) { errs() << "JScop file contains a schedule that changes the " << "dependences. Use -disable-polly-legality to continue anyways\n"; for (StatementToIslMapTy::iterator SI = NewSchedule.begin(), SE = NewSchedule.end(); SI != SE; ++SI) isl_map_free(SI->second); return false; } auto ScheduleMap = isl_union_map_empty(S.getParamSpace()); for (ScopStmt &Stmt : S) { if (NewSchedule.find(&Stmt) != NewSchedule.end()) ScheduleMap = isl_union_map_add_map(ScheduleMap, NewSchedule[&Stmt]); else ScheduleMap = isl_union_map_add_map(ScheduleMap, Stmt.getSchedule()); } S.setSchedule(ScheduleMap); int statementIdx = 0; for (ScopStmt &Stmt : S) { int memoryAccessIdx = 0; for (MemoryAccess *MA : Stmt) { Json::Value accesses = jscop["statements"][statementIdx]["accesses"] [memoryAccessIdx]["relation"]; isl_map *newAccessMap = isl_map_read_from_str(S.getIslCtx(), accesses.asCString()); isl_map *currentAccessMap = MA->getAccessRelation(); if (isl_map_dim(newAccessMap, isl_dim_param) != isl_map_dim(currentAccessMap, isl_dim_param)) { errs() << "JScop file changes the number of parameter dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } isl_id *OutId = isl_map_get_tuple_id(currentAccessMap, isl_dim_out); newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_out, OutId); if (MA->isArrayKind()) { // We keep the old alignment, thus we cannot allow accesses to memory // locations that were not accessed before if the alignment of the // access is not the default alignment. bool SpecialAlignment = true; if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) { SpecialAlignment = DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment(); } else if (StoreInst *StoreI = dyn_cast<StoreInst>(MA->getAccessInstruction())) { SpecialAlignment = DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) != StoreI->getAlignment(); } if (SpecialAlignment) { isl_set *newAccessSet = isl_map_range(isl_map_copy(newAccessMap)); isl_set *currentAccessSet = isl_map_range(isl_map_copy(currentAccessMap)); bool isSubset = isl_set_is_subset(newAccessSet, currentAccessSet); isl_set_free(newAccessSet); isl_set_free(currentAccessSet); if (!isSubset) { errs() << "JScop file changes the accessed memory\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } } } // We need to copy the isl_ids for the parameter dimensions to the new // map. Without doing this the current map would have different // ids then the new one, even though both are named identically. for (unsigned i = 0; i < isl_map_dim(currentAccessMap, isl_dim_param); i++) { isl_id *id = isl_map_get_dim_id(currentAccessMap, isl_dim_param, i); newAccessMap = isl_map_set_dim_id(newAccessMap, isl_dim_param, i, id); } // Copy the old tuple id. This is necessary to retain the user pointer, // that stores the reference to the ScopStmt this access belongs to. isl_id *Id = isl_map_get_tuple_id(currentAccessMap, isl_dim_in); newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_in, Id); if (!isl_map_has_equal_space(currentAccessMap, newAccessMap)) { errs() << "JScop file contains access function with incompatible " << "dimensions\n"; isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } auto NewAccessDomain = isl_map_domain(isl_map_copy(newAccessMap)); auto CurrentAccessDomain = isl_map_domain(isl_map_copy(currentAccessMap)); NewAccessDomain = isl_set_intersect_params(NewAccessDomain, S.getContext()); CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain, S.getContext()); if (isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) == isl_bool_false) { errs() << "Mapping not defined for all iteration domain elements\n"; isl_set_free(CurrentAccessDomain); isl_set_free(NewAccessDomain); isl_map_free(currentAccessMap); isl_map_free(newAccessMap); return false; } isl_set_free(CurrentAccessDomain); isl_set_free(NewAccessDomain); if (!isl_map_is_equal(newAccessMap, currentAccessMap)) { // Statistics. ++NewAccessMapFound; newAccessStrings.push_back(accesses.asCString()); MA->setNewAccessRelation(newAccessMap); } else { isl_map_free(newAccessMap); } isl_map_free(currentAccessMap); memoryAccessIdx++; } statementIdx++; } return false; }
bool Pocc::runTransform(Scop &S) { Dependences *D = &getAnalysis<Dependences>(); // Create the scop file. SmallString<128> TempDir; SmallString<128> ScopFile; llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/true, TempDir); ScopFile = TempDir; llvm::sys::path::append(ScopFile, "polly.scop"); FILE *F = fopen(ScopFile.c_str(), "w"); arguments.clear(); if (!F) { errs() << "Cannot open file: " << TempDir.c_str() << "\n"; errs() << "Skipping export.\n"; return false; } ScopLib scoplib(&S); scoplib.print(F); fclose(F); // Execute pocc std::string pocc = sys::FindProgramByName("pocc"); arguments.push_back("pocc"); arguments.push_back("--read-scop"); arguments.push_back(ScopFile.c_str()); arguments.push_back("--pluto-tile-scat"); arguments.push_back("--candl-dep-isl-simp"); arguments.push_back("--cloogify-scheds"); arguments.push_back("--output-scop"); arguments.push_back("--pluto"); arguments.push_back("--pluto-bounds"); arguments.push_back("10"); arguments.push_back("--pluto-fuse"); arguments.push_back(PlutoFuse.c_str()); if (!DisablePollyTiling) arguments.push_back("--pluto-tile"); if (PollyVectorizerChoice != VECTORIZER_NONE) arguments.push_back("--pluto-prevector"); arguments.push_back(0); PlutoStdout = TempDir; llvm::sys::path::append(PlutoStdout, "pluto.stdout"); PlutoStderr = TempDir; llvm::sys::path::append(PlutoStderr, "pluto.stderr"); std::vector<llvm::StringRef> Redirect; Redirect.push_back(0); Redirect.push_back(PlutoStdout.c_str()); Redirect.push_back(PlutoStderr.c_str()); sys::ExecuteAndWait(pocc, &arguments[0], 0, (const llvm::StringRef **)&Redirect[0]); // Read the created scop file SmallString<128> NewScopFile; NewScopFile = TempDir; llvm::sys::path::append(NewScopFile, "polly.pocc.c.scop"); FILE *poccFile = fopen(NewScopFile.c_str(), "r"); ScopLib newScoplib(&S, poccFile, D); if (!newScoplib.updateScattering()) { errs() << "Failure when calculating the optimization with " "the following command: "; for (std::vector<const char *>::const_iterator AI = arguments.begin(), AE = arguments.end(); AI != AE; ++AI) if (*AI) errs() << " " << *AI; errs() << "\n"; return false; } else fclose(poccFile); if (PollyVectorizerChoice == VECTORIZER_NONE) return false; // Find the innermost dimension that is not a constant dimension. This // dimension will be vectorized. unsigned scatterDims = S.getScatterDim(); int lastLoop = scatterDims - 1; while (lastLoop) { bool isSingleValued = true; for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) { isl_map *scat = (*SI)->getScattering(); isl_map *projected = isl_map_project_out(scat, isl_dim_out, lastLoop, scatterDims - lastLoop); if (!isl_map_is_bijective(projected)) { isSingleValued = false; break; } } if (!isSingleValued) break; lastLoop--; } // Strip mine the innermost loop. for (Scop::iterator SI = S.begin(), SE = S.end(); SI != SE; ++SI) { isl_map *scat = (*SI)->getScattering(); int scatDims = (*SI)->getNumScattering(); isl_space *Space = isl_space_alloc(S.getIslCtx(), S.getNumParams(), scatDims, scatDims + 1); isl_basic_map *map = isl_basic_map_universe(isl_space_copy(Space)); isl_local_space *LSpace = isl_local_space_from_space(Space); for (int i = 0; i <= lastLoop - 1; i++) { isl_constraint *c = isl_equality_alloc(isl_local_space_copy(LSpace)); isl_constraint_set_coefficient_si(c, isl_dim_in, i, 1); isl_constraint_set_coefficient_si(c, isl_dim_out, i, -1); map = isl_basic_map_add_constraint(map, c); } for (int i = lastLoop; i < scatDims; i++) { isl_constraint *c = isl_equality_alloc(isl_local_space_copy(LSpace)); isl_constraint_set_coefficient_si(c, isl_dim_in, i, 1); isl_constraint_set_coefficient_si(c, isl_dim_out, i + 1, -1); map = isl_basic_map_add_constraint(map, c); } isl_constraint *c; int vectorWidth = 4; c = isl_inequality_alloc(isl_local_space_copy(LSpace)); isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop, -vectorWidth); isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop + 1, 1); map = isl_basic_map_add_constraint(map, c); c = isl_inequality_alloc(LSpace); isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop, vectorWidth); isl_constraint_set_coefficient_si(c, isl_dim_out, lastLoop + 1, -1); isl_constraint_set_constant_si(c, vectorWidth - 1); map = isl_basic_map_add_constraint(map, c); isl_map *transform = isl_map_from_basic_map(map); transform = isl_map_set_tuple_name(transform, isl_dim_out, "scattering"); transform = isl_map_set_tuple_name(transform, isl_dim_in, "scattering"); scat = isl_map_apply_range(scat, isl_map_copy(transform)); (*SI)->setScattering(scat); } return false; }