1 //===-- JSONExporter.cpp - Export Scops as JSON -------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Export the Scops build by ScopInfo pass as a JSON file. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "polly/JSONExporter.h" 15 #include "polly/DependenceInfo.h" 16 #include "polly/LinkAllPasses.h" 17 #include "polly/Options.h" 18 #include "polly/ScopInfo.h" 19 #include "polly/ScopPass.h" 20 #include "polly/Support/ScopLocation.h" 21 #include "llvm/ADT/Statistic.h" 22 #include "llvm/Analysis/RegionInfo.h" 23 #include "llvm/IR/Module.h" 24 #include "llvm/Support/FileSystem.h" 25 #include "llvm/Support/MemoryBuffer.h" 26 #include "llvm/Support/ToolOutputFile.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include "isl/constraint.h" 29 #include "isl/map.h" 30 #include "isl/printer.h" 31 #include "isl/set.h" 32 #include "isl/union_map.h" 33 #include "json/reader.h" 34 #include "json/writer.h" 35 #include <memory> 36 #include <string> 37 #include <system_error> 38 39 using namespace llvm; 40 using namespace polly; 41 42 #define DEBUG_TYPE "polly-import-jscop" 43 44 STATISTIC(NewAccessMapFound, "Number of updated access functions"); 45 46 namespace { 47 static cl::opt<std::string> 48 ImportDir("polly-import-jscop-dir", 49 cl::desc("The directory to import the .jscop files from."), 50 cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired, 51 cl::init("."), cl::cat(PollyCategory)); 52 53 static cl::opt<std::string> 54 ImportPostfix("polly-import-jscop-postfix", 55 cl::desc("Postfix to append to the import .jsop files."), 56 cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired, 57 cl::init(""), cl::cat(PollyCategory)); 58 59 struct JSONExporter : public ScopPass { 60 static char ID; 61 explicit JSONExporter() : ScopPass(ID) {} 62 63 /// Export the SCoP @p S to a JSON file. 64 bool runOnScop(Scop &S) override; 65 66 /// Print the SCoP @p S as it is exported. 67 void printScop(raw_ostream &OS, Scop &S) const override; 68 69 /// Register all analyses and transformation required. 70 void getAnalysisUsage(AnalysisUsage &AU) const override; 71 }; 72 73 struct JSONImporter : public ScopPass { 74 static char ID; 75 std::vector<std::string> NewAccessStrings; 76 explicit JSONImporter() : ScopPass(ID) {} 77 /// Import new access functions for SCoP @p S from a JSON file. 78 bool runOnScop(Scop &S) override; 79 80 /// Print the SCoP @p S and the imported access functions. 81 void printScop(raw_ostream &OS, Scop &S) const override; 82 83 /// Register all analyses and transformation required. 84 void getAnalysisUsage(AnalysisUsage &AU) const override; 85 }; 86 } // namespace 87 88 static std::string getFileName(Scop &S, StringRef Suffix = "") { 89 std::string FunctionName = S.getFunction().getName(); 90 std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop"; 91 92 if (Suffix != "") 93 FileName += "." + Suffix.str(); 94 95 return FileName; 96 } 97 98 /// Export all arrays from the Scop. 99 /// 100 /// @param S The Scop containing the arrays. 101 /// 102 /// @returns Json::Value containing the arrays. 103 static Json::Value exportArrays(const Scop &S) { 104 Json::Value Arrays; 105 std::string Buffer; 106 llvm::raw_string_ostream RawStringOstream(Buffer); 107 108 for (auto &SAI : S.arrays()) { 109 if (!SAI->isArrayKind()) 110 continue; 111 112 Json::Value Array; 113 Array["name"] = SAI->getName(); 114 unsigned i = 0; 115 if (!SAI->getDimensionSize(i)) { 116 Array["sizes"].append("*"); 117 i++; 118 } 119 for (; i < SAI->getNumberOfDimensions(); i++) { 120 SAI->getDimensionSize(i)->print(RawStringOstream); 121 Array["sizes"].append(RawStringOstream.str()); 122 Buffer.clear(); 123 } 124 SAI->getElementType()->print(RawStringOstream); 125 Array["type"] = RawStringOstream.str(); 126 Buffer.clear(); 127 Arrays.append(Array); 128 } 129 return Arrays; 130 } 131 132 static Json::Value getJSON(Scop &S) { 133 Json::Value root; 134 unsigned LineBegin, LineEnd; 135 std::string FileName; 136 137 getDebugLocation(&S.getRegion(), LineBegin, LineEnd, FileName); 138 std::string Location; 139 if (LineBegin != (unsigned)-1) 140 Location = FileName + ":" + std::to_string(LineBegin) + "-" + 141 std::to_string(LineEnd); 142 143 root["name"] = S.getNameStr(); 144 root["context"] = S.getContextStr(); 145 if (LineBegin != (unsigned)-1) 146 root["location"] = Location; 147 148 root["arrays"] = exportArrays(S); 149 150 root["statements"]; 151 152 for (ScopStmt &Stmt : S) { 153 Json::Value statement; 154 155 statement["name"] = Stmt.getBaseName(); 156 statement["domain"] = Stmt.getDomainStr(); 157 statement["schedule"] = Stmt.getScheduleStr(); 158 statement["accesses"]; 159 160 for (MemoryAccess *MA : Stmt) { 161 Json::Value access; 162 163 access["kind"] = MA->isRead() ? "read" : "write"; 164 access["relation"] = MA->getAccessRelationStr(); 165 166 statement["accesses"].append(access); 167 } 168 169 root["statements"].append(statement); 170 } 171 172 return root; 173 } 174 175 static void exportScop(Scop &S) { 176 std::string FileName = ImportDir + "/" + getFileName(S); 177 178 Json::Value jscop = getJSON(S); 179 Json::StyledWriter writer; 180 std::string fileContent = writer.write(jscop); 181 182 // Write to file. 183 std::error_code EC; 184 ToolOutputFile F(FileName, EC, llvm::sys::fs::F_Text); 185 186 std::string FunctionName = S.getFunction().getName(); 187 errs() << "Writing JScop '" << S.getNameStr() << "' in function '" 188 << FunctionName << "' to '" << FileName << "'.\n"; 189 190 if (!EC) { 191 F.os() << fileContent; 192 F.os().close(); 193 if (!F.os().has_error()) { 194 errs() << "\n"; 195 F.keep(); 196 return; 197 } 198 } 199 200 errs() << " error opening file for writing!\n"; 201 F.os().clear_error(); 202 } 203 204 typedef Dependences::StatementToIslMapTy StatementToIslMapTy; 205 206 /// Import a new context from JScop. 207 /// 208 /// @param S The scop to update. 209 /// @param JScop The JScop file describing the new schedule. 210 /// 211 /// @returns True if the import succeeded, otherwise False. 212 static bool importContext(Scop &S, Json::Value &JScop) { 213 isl::set OldContext = S.getContext(); 214 215 // Check if key 'context' is present. 216 if (!JScop.isMember("context")) { 217 errs() << "JScop file has no key named 'context'.\n"; 218 return false; 219 } 220 221 isl::set NewContext = 222 isl::set{S.getIslCtx().get(), JScop["context"].asString()}; 223 224 // Check whether the context was parsed successfully. 225 if (!NewContext) { 226 errs() << "The context was not parsed successfully by ISL.\n"; 227 return false; 228 } 229 230 // Check if the isl_set is a parameter set. 231 if (!NewContext.is_params()) { 232 errs() << "The isl_set is not a parameter set.\n"; 233 return false; 234 } 235 236 unsigned OldContextDim = OldContext.dim(isl::dim::param); 237 unsigned NewContextDim = NewContext.dim(isl::dim::param); 238 239 // Check if the imported context has the right number of parameters. 240 if (OldContextDim != NewContextDim) { 241 errs() << "Imported context has the wrong number of parameters : " 242 << "Found " << NewContextDim << " Expected " << OldContextDim 243 << "\n"; 244 return false; 245 } 246 247 for (unsigned i = 0; i < OldContextDim; i++) { 248 isl::id Id = OldContext.get_dim_id(isl::dim::param, i); 249 NewContext = NewContext.set_dim_id(isl::dim::param, i, Id); 250 } 251 252 S.setContext(NewContext); 253 return true; 254 } 255 256 /// Import a new schedule from JScop. 257 /// 258 /// ... and verify that the new schedule does preserve existing data 259 /// dependences. 260 /// 261 /// @param S The scop to update. 262 /// @param JScop The JScop file describing the new schedule. 263 /// @param D The data dependences of the @p S. 264 /// 265 /// @returns True if the import succeeded, otherwise False. 266 static bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D) { 267 StatementToIslMapTy NewSchedule; 268 269 // Check if key 'statements' is present. 270 if (!JScop.isMember("statements")) { 271 errs() << "JScop file has no key name 'statements'.\n"; 272 return false; 273 } 274 275 Json::Value statements = JScop["statements"]; 276 277 // Check whether the number of indices equals the number of statements 278 if (statements.size() != S.getSize()) { 279 errs() << "The number of indices and the number of statements differ.\n"; 280 return false; 281 } 282 283 int Index = 0; 284 for (ScopStmt &Stmt : S) { 285 // Check if key 'schedule' is present. 286 if (!statements[Index].isMember("schedule")) { 287 errs() << "Statement " << Index << " has no 'schedule' key.\n"; 288 for (auto Element : NewSchedule) { 289 isl_map_free(Element.second); 290 } 291 return false; 292 } 293 Json::Value Schedule = statements[Index]["schedule"]; 294 assert(!Schedule.asString().empty() && 295 "Schedules that contain extension nodes require special handling."); 296 isl_map *Map = 297 isl_map_read_from_str(S.getIslCtx().get(), Schedule.asCString()); 298 299 // Check whether the schedule was parsed successfully 300 if (!Map) { 301 errs() << "The schedule was not parsed successfully (index = " << Index 302 << ").\n"; 303 for (auto Element : NewSchedule) { 304 isl_map_free(Element.second); 305 } 306 return false; 307 } 308 309 isl_space *Space = Stmt.getDomainSpace().release(); 310 311 // Copy the old tuple id. This is necessary to retain the user pointer, 312 // that stores the reference to the ScopStmt this schedule belongs to. 313 Map = isl_map_set_tuple_id(Map, isl_dim_in, 314 isl_space_get_tuple_id(Space, isl_dim_set)); 315 for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { 316 isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i); 317 Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id); 318 } 319 isl_space_free(Space); 320 NewSchedule[&Stmt] = Map; 321 Index++; 322 } 323 324 // Check whether the new schedule is valid or not. 325 if (!D.isValidSchedule(S, &NewSchedule)) { 326 errs() << "JScop file contains a schedule that changes the " 327 << "dependences. Use -disable-polly-legality to continue anyways\n"; 328 for (auto Element : NewSchedule) 329 isl_map_free(Element.second); 330 return false; 331 } 332 333 auto ScheduleMap = isl::union_map::empty(S.getParamSpace()); 334 for (ScopStmt &Stmt : S) { 335 if (NewSchedule.find(&Stmt) != NewSchedule.end()) 336 ScheduleMap = ScheduleMap.add_map(isl::manage(NewSchedule[&Stmt])); 337 else 338 ScheduleMap = ScheduleMap.add_map(Stmt.getSchedule()); 339 } 340 341 S.setSchedule(ScheduleMap); 342 343 return true; 344 } 345 346 /// Import new memory accesses from JScop. 347 /// 348 /// @param S The scop to update. 349 /// @param JScop The JScop file describing the new schedule. 350 /// @param DL The data layout to assume. 351 /// @param NewAccessStrings optionally record the imported access strings 352 /// 353 /// @returns True if the import succeeded, otherwise False. 354 static bool 355 importAccesses(Scop &S, Json::Value &JScop, const DataLayout &DL, 356 std::vector<std::string> *NewAccessStrings = nullptr) { 357 int StatementIdx = 0; 358 359 // Check if key 'statements' is present. 360 if (!JScop.isMember("statements")) { 361 errs() << "JScop file has no key name 'statements'.\n"; 362 return false; 363 } 364 Json::Value statements = JScop["statements"]; 365 366 // Check whether the number of indices equals the number of statements 367 if (statements.size() != S.getSize()) { 368 errs() << "The number of indices and the number of statements differ.\n"; 369 return false; 370 } 371 372 for (ScopStmt &Stmt : S) { 373 int MemoryAccessIdx = 0; 374 375 // Check if key 'accesses' is present. 376 if (!statements[StatementIdx].isMember("accesses")) { 377 errs() 378 << "Statement from JScop file has no key name 'accesses' for index " 379 << StatementIdx << ".\n"; 380 return false; 381 } 382 383 // Check whether the number of indices equals the number of memory 384 // accesses 385 if (Stmt.size() != statements[StatementIdx]["accesses"].size()) { 386 errs() << "The number of memory accesses in the JSop file and the number " 387 "of memory accesses differ for index " 388 << StatementIdx << ".\n"; 389 return false; 390 } 391 392 for (MemoryAccess *MA : Stmt) { 393 // Check if key 'relation' is present. 394 Json::Value JsonMemoryAccess = 395 statements[StatementIdx]["accesses"][MemoryAccessIdx]; 396 if (!JsonMemoryAccess.isMember("relation")) { 397 errs() << "Memory access number " << MemoryAccessIdx 398 << " has no key name 'relation' for statement number " 399 << StatementIdx << ".\n"; 400 return false; 401 } 402 Json::Value Accesses = JsonMemoryAccess["relation"]; 403 isl_map *NewAccessMap = 404 isl_map_read_from_str(S.getIslCtx().get(), Accesses.asCString()); 405 406 // Check whether the access was parsed successfully 407 if (!NewAccessMap) { 408 errs() << "The access was not parsed successfully by ISL.\n"; 409 return false; 410 } 411 isl_map *CurrentAccessMap = MA->getAccessRelation().release(); 412 413 // Check if the number of parameter change 414 if (isl_map_dim(NewAccessMap, isl_dim_param) != 415 isl_map_dim(CurrentAccessMap, isl_dim_param)) { 416 errs() << "JScop file changes the number of parameter dimensions.\n"; 417 isl_map_free(CurrentAccessMap); 418 isl_map_free(NewAccessMap); 419 return false; 420 } 421 422 isl_id *NewOutId; 423 424 // If the NewAccessMap has zero dimensions, it is the scalar access; it 425 // must be the same as before. 426 // If it has at least one dimension, it's an array access; search for 427 // its ScopArrayInfo. 428 if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) { 429 NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out); 430 auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId)); 431 isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); 432 auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId)); 433 if (!SAI || SAI->getElementType() != OutSAI->getElementType()) { 434 errs() << "JScop file contains access function with undeclared " 435 "ScopArrayInfo\n"; 436 isl_map_free(CurrentAccessMap); 437 isl_map_free(NewAccessMap); 438 isl_id_free(NewOutId); 439 return false; 440 } 441 isl_id_free(NewOutId); 442 NewOutId = SAI->getBasePtrId().release(); 443 } else { 444 NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); 445 } 446 447 NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId); 448 449 if (MA->isArrayKind()) { 450 // We keep the old alignment, thus we cannot allow accesses to memory 451 // locations that were not accessed before if the alignment of the 452 // access is not the default alignment. 453 bool SpecialAlignment = true; 454 if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) { 455 SpecialAlignment = 456 LoadI->getAlignment() && 457 DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment(); 458 } else if (StoreInst *StoreI = 459 dyn_cast<StoreInst>(MA->getAccessInstruction())) { 460 SpecialAlignment = 461 StoreI->getAlignment() && 462 DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) != 463 StoreI->getAlignment(); 464 } 465 466 if (SpecialAlignment) { 467 isl_set *NewAccessSet = isl_map_range(isl_map_copy(NewAccessMap)); 468 isl_set *CurrentAccessSet = 469 isl_map_range(isl_map_copy(CurrentAccessMap)); 470 bool IsSubset = isl_set_is_subset(NewAccessSet, CurrentAccessSet); 471 isl_set_free(NewAccessSet); 472 isl_set_free(CurrentAccessSet); 473 474 // Check if the JScop file changes the accessed memory. 475 if (!IsSubset) { 476 errs() << "JScop file changes the accessed memory\n"; 477 isl_map_free(CurrentAccessMap); 478 isl_map_free(NewAccessMap); 479 return false; 480 } 481 } 482 } 483 484 // We need to copy the isl_ids for the parameter dimensions to the new 485 // map. Without doing this the current map would have different 486 // ids then the new one, even though both are named identically. 487 for (unsigned i = 0; i < isl_map_dim(CurrentAccessMap, isl_dim_param); 488 i++) { 489 isl_id *Id = isl_map_get_dim_id(CurrentAccessMap, isl_dim_param, i); 490 NewAccessMap = isl_map_set_dim_id(NewAccessMap, isl_dim_param, i, Id); 491 } 492 493 // Copy the old tuple id. This is necessary to retain the user pointer, 494 // that stores the reference to the ScopStmt this access belongs to. 495 isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in); 496 NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id); 497 498 auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap)); 499 auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap)); 500 501 if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) { 502 errs() << "JScop file contains access function with incompatible " 503 << "dimensions\n"; 504 isl_map_free(CurrentAccessMap); 505 isl_map_free(NewAccessMap); 506 isl_set_free(NewAccessDomain); 507 isl_set_free(CurrentAccessDomain); 508 return false; 509 } 510 511 NewAccessDomain = 512 isl_set_intersect_params(NewAccessDomain, S.getContext().release()); 513 CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain, 514 S.getContext().release()); 515 516 if (MA->isRead() && 517 isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) == 518 isl_bool_false) { 519 errs() << "Mapping not defined for all iteration domain elements\n"; 520 isl_set_free(CurrentAccessDomain); 521 isl_set_free(NewAccessDomain); 522 isl_map_free(CurrentAccessMap); 523 isl_map_free(NewAccessMap); 524 return false; 525 } 526 527 isl_set_free(CurrentAccessDomain); 528 isl_set_free(NewAccessDomain); 529 530 if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) { 531 // Statistics. 532 ++NewAccessMapFound; 533 if (NewAccessStrings) 534 NewAccessStrings->push_back(Accesses.asCString()); 535 MA->setNewAccessRelation(isl::manage(NewAccessMap)); 536 } else { 537 isl_map_free(NewAccessMap); 538 } 539 isl_map_free(CurrentAccessMap); 540 MemoryAccessIdx++; 541 } 542 StatementIdx++; 543 } 544 545 return true; 546 } 547 548 /// Check whether @p SAI and @p Array represent the same array. 549 static bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) { 550 std::string Buffer; 551 llvm::raw_string_ostream RawStringOstream(Buffer); 552 553 // Check if key 'type' is present. 554 if (!Array.isMember("type")) { 555 errs() << "Array has no key 'type'.\n"; 556 return false; 557 } 558 559 // Check if key 'sizes' is present. 560 if (!Array.isMember("sizes")) { 561 errs() << "Array has no key 'sizes'.\n"; 562 return false; 563 } 564 565 // Check if key 'name' is present. 566 if (!Array.isMember("name")) { 567 errs() << "Array has no key 'name'.\n"; 568 return false; 569 } 570 571 if (SAI->getName() != Array["name"].asCString()) 572 return false; 573 574 if (SAI->getNumberOfDimensions() != Array["sizes"].size()) 575 return false; 576 577 for (unsigned i = 1; i < Array["sizes"].size(); i++) { 578 SAI->getDimensionSize(i)->print(RawStringOstream); 579 if (RawStringOstream.str() != Array["sizes"][i].asCString()) 580 return false; 581 Buffer.clear(); 582 } 583 584 // Check if key 'type' differs from the current one or is not valid. 585 SAI->getElementType()->print(RawStringOstream); 586 if (RawStringOstream.str() != Array["type"].asCString()) { 587 errs() << "Array has not a valid type.\n"; 588 return false; 589 } 590 591 return true; 592 } 593 594 /// Get the accepted primitive type from its textual representation 595 /// @p TypeTextRepresentation. 596 /// 597 /// @param TypeTextRepresentation The textual representation of the type. 598 /// @return The pointer to the primitive type, if this type is accepted 599 /// or nullptr otherwise. 600 static Type *parseTextType(const std::string &TypeTextRepresentation, 601 LLVMContext &LLVMContext) { 602 std::map<std::string, Type *> MapStrToType = { 603 {"void", Type::getVoidTy(LLVMContext)}, 604 {"half", Type::getHalfTy(LLVMContext)}, 605 {"float", Type::getFloatTy(LLVMContext)}, 606 {"double", Type::getDoubleTy(LLVMContext)}, 607 {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)}, 608 {"fp128", Type::getFP128Ty(LLVMContext)}, 609 {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)}, 610 {"i1", Type::getInt1Ty(LLVMContext)}, 611 {"i8", Type::getInt8Ty(LLVMContext)}, 612 {"i16", Type::getInt16Ty(LLVMContext)}, 613 {"i32", Type::getInt32Ty(LLVMContext)}, 614 {"i64", Type::getInt64Ty(LLVMContext)}, 615 {"i128", Type::getInt128Ty(LLVMContext)}}; 616 617 auto It = MapStrToType.find(TypeTextRepresentation); 618 if (It != MapStrToType.end()) 619 return It->second; 620 621 errs() << "Textual representation can not be parsed: " 622 << TypeTextRepresentation << "\n"; 623 return nullptr; 624 } 625 626 /// Import new arrays from JScop. 627 /// 628 /// @param S The scop to update. 629 /// @param JScop The JScop file describing new arrays. 630 /// 631 /// @returns True if the import succeeded, otherwise False. 632 static bool importArrays(Scop &S, Json::Value &JScop) { 633 Json::Value Arrays = JScop["arrays"]; 634 if (Arrays.size() == 0) 635 return true; 636 637 unsigned ArrayIdx = 0; 638 for (auto &SAI : S.arrays()) { 639 if (!SAI->isArrayKind()) 640 continue; 641 if (ArrayIdx + 1 > Arrays.size()) { 642 errs() << "Not enough array entries in JScop file.\n"; 643 return false; 644 } 645 if (!areArraysEqual(SAI, Arrays[ArrayIdx])) { 646 errs() << "No match for array '" << SAI->getName() << "' in JScop.\n"; 647 return false; 648 } 649 ArrayIdx++; 650 } 651 652 for (; ArrayIdx < Arrays.size(); ArrayIdx++) { 653 auto &Array = Arrays[ArrayIdx]; 654 auto *ElementType = 655 parseTextType(Array["type"].asCString(), S.getSE()->getContext()); 656 if (!ElementType) { 657 errs() << "Error while parsing element type for new array.\n"; 658 return false; 659 } 660 std::vector<unsigned> DimSizes; 661 for (unsigned i = 0; i < Array["sizes"].size(); i++) { 662 auto Size = std::stoi(Array["sizes"][i].asCString()); 663 664 // Check if the size if positive. 665 if (Size <= 0) { 666 errs() << "The size at index " << i << " is =< 0.\n"; 667 return false; 668 } 669 670 DimSizes.push_back(Size); 671 } 672 673 auto NewSAI = 674 S.createScopArrayInfo(ElementType, Array["name"].asCString(), DimSizes); 675 676 if (Array.isMember("allocation")) { 677 NewSAI->setIsOnHeap(Array["allocation"].asString() == "heap"); 678 } 679 } 680 681 return true; 682 } 683 684 /// Import a Scop from a JSCOP file 685 /// @param S The scop to be modified 686 /// @param D Dependence Info 687 /// @param DL The DataLayout of the function 688 /// @param NewAccessStrings Optionally record the imported access strings 689 /// 690 /// @returns true on success, false otherwise. Beware that if this returns 691 /// false, the Scop may still have been modified. In this case the Scop contains 692 /// invalid information. 693 static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL, 694 std::vector<std::string> *NewAccessStrings = nullptr) { 695 std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix); 696 697 std::string FunctionName = S.getFunction().getName(); 698 errs() << "Reading JScop '" << S.getNameStr() << "' in function '" 699 << FunctionName << "' from '" << FileName << "'.\n"; 700 ErrorOr<std::unique_ptr<MemoryBuffer>> result = 701 MemoryBuffer::getFile(FileName); 702 std::error_code ec = result.getError(); 703 704 if (ec) { 705 errs() << "File could not be read: " << ec.message() << "\n"; 706 return false; 707 } 708 709 Json::Reader reader; 710 Json::Value jscop; 711 712 bool parsingSuccessful = reader.parse(result.get()->getBufferStart(), jscop); 713 714 if (!parsingSuccessful) { 715 errs() << "JSCoP file could not be parsed\n"; 716 return false; 717 } 718 719 bool Success = importContext(S, jscop); 720 721 if (!Success) 722 return false; 723 724 Success = importSchedule(S, jscop, D); 725 726 if (!Success) 727 return false; 728 729 Success = importArrays(S, jscop); 730 731 if (!Success) 732 return false; 733 734 Success = importAccesses(S, jscop, DL, NewAccessStrings); 735 736 if (!Success) 737 return false; 738 return true; 739 } 740 741 char JSONExporter::ID = 0; 742 void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; } 743 744 bool JSONExporter::runOnScop(Scop &S) { 745 exportScop(S); 746 return false; 747 } 748 749 void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const { 750 AU.setPreservesAll(); 751 AU.addRequired<ScopInfoRegionPass>(); 752 } 753 754 Pass *polly::createJSONExporterPass() { return new JSONExporter(); } 755 756 PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM, 757 ScopStandardAnalysisResults &SAR, 758 SPMUpdater &) { 759 exportScop(S); 760 return PreservedAnalyses::all(); 761 } 762 763 char JSONImporter::ID = 0; 764 765 void JSONImporter::printScop(raw_ostream &OS, Scop &S) const { 766 OS << S; 767 for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(), 768 E = NewAccessStrings.end(); 769 I != E; I++) 770 OS << "New access function '" << *I << "' detected in JSCOP file\n"; 771 } 772 773 bool JSONImporter::runOnScop(Scop &S) { 774 const Dependences &D = 775 getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement); 776 const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); 777 778 if (!importScop(S, D, DL, &NewAccessStrings)) 779 report_fatal_error("Tried to import a malformed jscop file."); 780 781 return false; 782 } 783 784 void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const { 785 ScopPass::getAnalysisUsage(AU); 786 AU.addRequired<DependenceInfo>(); 787 788 // TODO: JSONImporter should throw away DependenceInfo. 789 AU.addPreserved<DependenceInfo>(); 790 } 791 792 Pass *polly::createJSONImporterPass() { return new JSONImporter(); } 793 794 PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM, 795 ScopStandardAnalysisResults &SAR, 796 SPMUpdater &) { 797 const Dependences &D = 798 SAM.getResult<DependenceAnalysis>(S, SAR).getDependences( 799 Dependences::AL_Statement); 800 const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); 801 802 if (!importScop(S, D, DL)) 803 report_fatal_error("Tried to import a malformed jscop file."); 804 805 // This invalidates all analyses on Scop. 806 PreservedAnalyses PA; 807 PA.preserveSet<AllAnalysesOn<Module>>(); 808 PA.preserveSet<AllAnalysesOn<Function>>(); 809 PA.preserveSet<AllAnalysesOn<Loop>>(); 810 return PA; 811 } 812 813 INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop", 814 "Polly - Export Scops as JSON" 815 " (Writes a .jscop file for each Scop)", 816 false, false); 817 INITIALIZE_PASS_DEPENDENCY(DependenceInfo) 818 INITIALIZE_PASS_END(JSONExporter, "polly-export-jscop", 819 "Polly - Export Scops as JSON" 820 " (Writes a .jscop file for each Scop)", 821 false, false) 822 823 INITIALIZE_PASS_BEGIN(JSONImporter, "polly-import-jscop", 824 "Polly - Import Scops from JSON" 825 " (Reads a .jscop file for each Scop)", 826 false, false); 827 INITIALIZE_PASS_DEPENDENCY(DependenceInfo) 828 INITIALIZE_PASS_END(JSONImporter, "polly-import-jscop", 829 "Polly - Import Scops from JSON" 830 " (Reads a .jscop file for each Scop)", 831 false, false) 832