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 tool_output_file 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().release(); 214 215 // Check if key 'context' is present. 216 if (!JScop.isMember("context")) { 217 errs() << "JScop file has no key named 'context'.\n"; 218 isl_set_free(OldContext); 219 return false; 220 } 221 222 isl_set *NewContext = 223 isl_set_read_from_str(S.getIslCtx(), JScop["context"].asCString()); 224 225 // Check whether the context was parsed successfully. 226 if (!NewContext) { 227 errs() << "The context was not parsed successfully by ISL.\n"; 228 isl_set_free(NewContext); 229 isl_set_free(OldContext); 230 return false; 231 } 232 233 // Check if the isl_set is a parameter set. 234 if (!isl_set_is_params(NewContext)) { 235 errs() << "The isl_set is not a parameter set.\n"; 236 isl_set_free(NewContext); 237 isl_set_free(OldContext); 238 return false; 239 } 240 241 unsigned OldContextDim = isl_set_dim(OldContext, isl_dim_param); 242 unsigned NewContextDim = isl_set_dim(NewContext, isl_dim_param); 243 244 // Check if the imported context has the right number of parameters. 245 if (OldContextDim != NewContextDim) { 246 errs() << "Imported context has the wrong number of parameters : " 247 << "Found " << NewContextDim << " Expected " << OldContextDim 248 << "\n"; 249 isl_set_free(NewContext); 250 isl_set_free(OldContext); 251 return false; 252 } 253 254 for (unsigned i = 0; i < OldContextDim; i++) { 255 isl_id *Id = isl_set_get_dim_id(OldContext, isl_dim_param, i); 256 NewContext = isl_set_set_dim_id(NewContext, isl_dim_param, i, Id); 257 } 258 259 isl_set_free(OldContext); 260 S.setContext(NewContext); 261 return true; 262 } 263 264 /// Import a new schedule from JScop. 265 /// 266 /// ... and verify that the new schedule does preserve existing data 267 /// dependences. 268 /// 269 /// @param S The scop to update. 270 /// @param JScop The JScop file describing the new schedule. 271 /// @param D The data dependences of the @p S. 272 /// 273 /// @returns True if the import succeeded, otherwise False. 274 static bool importSchedule(Scop &S, Json::Value &JScop, const Dependences &D) { 275 StatementToIslMapTy NewSchedule; 276 277 // Check if key 'statements' is present. 278 if (!JScop.isMember("statements")) { 279 errs() << "JScop file has no key name 'statements'.\n"; 280 return false; 281 } 282 283 Json::Value statements = JScop["statements"]; 284 285 // Check whether the number of indices equals the number of statements 286 if (statements.size() != S.getSize()) { 287 errs() << "The number of indices and the number of statements differ.\n"; 288 return false; 289 } 290 291 int Index = 0; 292 for (ScopStmt &Stmt : S) { 293 // Check if key 'schedule' is present. 294 if (!statements[Index].isMember("schedule")) { 295 errs() << "Statement " << Index << " has no 'schedule' key.\n"; 296 for (auto Element : NewSchedule) { 297 isl_map_free(Element.second); 298 } 299 return false; 300 } 301 Json::Value Schedule = statements[Index]["schedule"]; 302 assert(!Schedule.asString().empty() && 303 "Schedules that contain extension nodes require special handling."); 304 isl_map *Map = isl_map_read_from_str(S.getIslCtx(), Schedule.asCString()); 305 306 // Check whether the schedule was parsed successfully 307 if (!Map) { 308 errs() << "The schedule was not parsed successfully (index = " << Index 309 << ").\n"; 310 for (auto Element : NewSchedule) { 311 isl_map_free(Element.second); 312 } 313 return false; 314 } 315 316 isl_space *Space = Stmt.getDomainSpace().release(); 317 318 // Copy the old tuple id. This is necessary to retain the user pointer, 319 // that stores the reference to the ScopStmt this schedule belongs to. 320 Map = isl_map_set_tuple_id(Map, isl_dim_in, 321 isl_space_get_tuple_id(Space, isl_dim_set)); 322 for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { 323 isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i); 324 Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id); 325 } 326 isl_space_free(Space); 327 NewSchedule[&Stmt] = Map; 328 Index++; 329 } 330 331 // Check whether the new schedule is valid or not. 332 if (!D.isValidSchedule(S, &NewSchedule)) { 333 errs() << "JScop file contains a schedule that changes the " 334 << "dependences. Use -disable-polly-legality to continue anyways\n"; 335 for (auto Element : NewSchedule) 336 isl_map_free(Element.second); 337 return false; 338 } 339 340 auto ScheduleMap = isl_union_map_empty(S.getParamSpace().release()); 341 for (ScopStmt &Stmt : S) { 342 if (NewSchedule.find(&Stmt) != NewSchedule.end()) 343 ScheduleMap = isl_union_map_add_map(ScheduleMap, NewSchedule[&Stmt]); 344 else 345 ScheduleMap = 346 isl_union_map_add_map(ScheduleMap, Stmt.getSchedule().release()); 347 } 348 349 S.setSchedule(ScheduleMap); 350 351 return true; 352 } 353 354 /// Import new memory accesses from JScop. 355 /// 356 /// @param S The scop to update. 357 /// @param JScop The JScop file describing the new schedule. 358 /// @param DL The data layout to assume. 359 /// @param NewAccessStrings optionally record the imported access strings 360 /// 361 /// @returns True if the import succeeded, otherwise False. 362 static bool 363 importAccesses(Scop &S, Json::Value &JScop, const DataLayout &DL, 364 std::vector<std::string> *NewAccessStrings = nullptr) { 365 int StatementIdx = 0; 366 367 // Check if key 'statements' is present. 368 if (!JScop.isMember("statements")) { 369 errs() << "JScop file has no key name 'statements'.\n"; 370 return false; 371 } 372 Json::Value statements = JScop["statements"]; 373 374 // Check whether the number of indices equals the number of statements 375 if (statements.size() != S.getSize()) { 376 errs() << "The number of indices and the number of statements differ.\n"; 377 return false; 378 } 379 380 for (ScopStmt &Stmt : S) { 381 int MemoryAccessIdx = 0; 382 383 // Check if key 'accesses' is present. 384 if (!statements[StatementIdx].isMember("accesses")) { 385 errs() 386 << "Statement from JScop file has no key name 'accesses' for index " 387 << StatementIdx << ".\n"; 388 return false; 389 } 390 391 // Check whether the number of indices equals the number of memory 392 // accesses 393 if (Stmt.size() != statements[StatementIdx]["accesses"].size()) { 394 errs() << "The number of memory accesses in the JSop file and the number " 395 "of memory accesses differ for index " 396 << StatementIdx << ".\n"; 397 return false; 398 } 399 400 for (MemoryAccess *MA : Stmt) { 401 // Check if key 'relation' is present. 402 Json::Value JsonMemoryAccess = 403 statements[StatementIdx]["accesses"][MemoryAccessIdx]; 404 if (!JsonMemoryAccess.isMember("relation")) { 405 errs() << "Memory access number " << MemoryAccessIdx 406 << " has no key name 'relation' for statement number " 407 << StatementIdx << ".\n"; 408 return false; 409 } 410 Json::Value Accesses = JsonMemoryAccess["relation"]; 411 isl_map *NewAccessMap = 412 isl_map_read_from_str(S.getIslCtx(), Accesses.asCString()); 413 414 // Check whether the access was parsed successfully 415 if (!NewAccessMap) { 416 errs() << "The access was not parsed successfully by ISL.\n"; 417 return false; 418 } 419 isl_map *CurrentAccessMap = MA->getAccessRelation().release(); 420 421 // Check if the number of parameter change 422 if (isl_map_dim(NewAccessMap, isl_dim_param) != 423 isl_map_dim(CurrentAccessMap, isl_dim_param)) { 424 errs() << "JScop file changes the number of parameter dimensions.\n"; 425 isl_map_free(CurrentAccessMap); 426 isl_map_free(NewAccessMap); 427 return false; 428 } 429 430 isl_id *NewOutId; 431 432 // If the NewAccessMap has zero dimensions, it is the scalar access; it 433 // must be the same as before. 434 // If it has at least one dimension, it's an array access; search for 435 // its ScopArrayInfo. 436 if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) { 437 NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out); 438 auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId)); 439 isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); 440 auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId)); 441 if (!SAI || SAI->getElementType() != OutSAI->getElementType()) { 442 errs() << "JScop file contains access function with undeclared " 443 "ScopArrayInfo\n"; 444 isl_map_free(CurrentAccessMap); 445 isl_map_free(NewAccessMap); 446 isl_id_free(NewOutId); 447 return false; 448 } 449 isl_id_free(NewOutId); 450 NewOutId = SAI->getBasePtrId().release(); 451 } else { 452 NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out); 453 } 454 455 NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId); 456 457 if (MA->isArrayKind()) { 458 // We keep the old alignment, thus we cannot allow accesses to memory 459 // locations that were not accessed before if the alignment of the 460 // access is not the default alignment. 461 bool SpecialAlignment = true; 462 if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) { 463 SpecialAlignment = 464 LoadI->getAlignment() && 465 DL.getABITypeAlignment(LoadI->getType()) != LoadI->getAlignment(); 466 } else if (StoreInst *StoreI = 467 dyn_cast<StoreInst>(MA->getAccessInstruction())) { 468 SpecialAlignment = 469 StoreI->getAlignment() && 470 DL.getABITypeAlignment(StoreI->getValueOperand()->getType()) != 471 StoreI->getAlignment(); 472 } 473 474 if (SpecialAlignment) { 475 isl_set *NewAccessSet = isl_map_range(isl_map_copy(NewAccessMap)); 476 isl_set *CurrentAccessSet = 477 isl_map_range(isl_map_copy(CurrentAccessMap)); 478 bool IsSubset = isl_set_is_subset(NewAccessSet, CurrentAccessSet); 479 isl_set_free(NewAccessSet); 480 isl_set_free(CurrentAccessSet); 481 482 // Check if the JScop file changes the accessed memory. 483 if (!IsSubset) { 484 errs() << "JScop file changes the accessed memory\n"; 485 isl_map_free(CurrentAccessMap); 486 isl_map_free(NewAccessMap); 487 return false; 488 } 489 } 490 } 491 492 // We need to copy the isl_ids for the parameter dimensions to the new 493 // map. Without doing this the current map would have different 494 // ids then the new one, even though both are named identically. 495 for (unsigned i = 0; i < isl_map_dim(CurrentAccessMap, isl_dim_param); 496 i++) { 497 isl_id *Id = isl_map_get_dim_id(CurrentAccessMap, isl_dim_param, i); 498 NewAccessMap = isl_map_set_dim_id(NewAccessMap, isl_dim_param, i, Id); 499 } 500 501 // Copy the old tuple id. This is necessary to retain the user pointer, 502 // that stores the reference to the ScopStmt this access belongs to. 503 isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in); 504 NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id); 505 506 auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap)); 507 auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap)); 508 509 if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) { 510 errs() << "JScop file contains access function with incompatible " 511 << "dimensions\n"; 512 isl_map_free(CurrentAccessMap); 513 isl_map_free(NewAccessMap); 514 isl_set_free(NewAccessDomain); 515 isl_set_free(CurrentAccessDomain); 516 return false; 517 } 518 519 NewAccessDomain = 520 isl_set_intersect_params(NewAccessDomain, S.getContext().release()); 521 CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain, 522 S.getContext().release()); 523 524 if (MA->isRead() && 525 isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) == 526 isl_bool_false) { 527 errs() << "Mapping not defined for all iteration domain elements\n"; 528 isl_set_free(CurrentAccessDomain); 529 isl_set_free(NewAccessDomain); 530 isl_map_free(CurrentAccessMap); 531 isl_map_free(NewAccessMap); 532 return false; 533 } 534 535 isl_set_free(CurrentAccessDomain); 536 isl_set_free(NewAccessDomain); 537 538 if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) { 539 // Statistics. 540 ++NewAccessMapFound; 541 if (NewAccessStrings) 542 NewAccessStrings->push_back(Accesses.asCString()); 543 MA->setNewAccessRelation(isl::manage(NewAccessMap)); 544 } else { 545 isl_map_free(NewAccessMap); 546 } 547 isl_map_free(CurrentAccessMap); 548 MemoryAccessIdx++; 549 } 550 StatementIdx++; 551 } 552 553 return true; 554 } 555 556 /// Check whether @p SAI and @p Array represent the same array. 557 static bool areArraysEqual(ScopArrayInfo *SAI, Json::Value Array) { 558 std::string Buffer; 559 llvm::raw_string_ostream RawStringOstream(Buffer); 560 561 // Check if key 'type' is present. 562 if (!Array.isMember("type")) { 563 errs() << "Array has no key 'type'.\n"; 564 return false; 565 } 566 567 // Check if key 'sizes' is present. 568 if (!Array.isMember("sizes")) { 569 errs() << "Array has no key 'sizes'.\n"; 570 return false; 571 } 572 573 // Check if key 'name' is present. 574 if (!Array.isMember("name")) { 575 errs() << "Array has no key 'name'.\n"; 576 return false; 577 } 578 579 if (SAI->getName() != Array["name"].asCString()) 580 return false; 581 582 if (SAI->getNumberOfDimensions() != Array["sizes"].size()) 583 return false; 584 585 for (unsigned i = 1; i < Array["sizes"].size(); i++) { 586 SAI->getDimensionSize(i)->print(RawStringOstream); 587 if (RawStringOstream.str() != Array["sizes"][i].asCString()) 588 return false; 589 Buffer.clear(); 590 } 591 592 // Check if key 'type' differs from the current one or is not valid. 593 SAI->getElementType()->print(RawStringOstream); 594 if (RawStringOstream.str() != Array["type"].asCString()) { 595 errs() << "Array has not a valid type.\n"; 596 return false; 597 } 598 599 return true; 600 } 601 602 /// Get the accepted primitive type from its textual representation 603 /// @p TypeTextRepresentation. 604 /// 605 /// @param TypeTextRepresentation The textual representation of the type. 606 /// @return The pointer to the primitive type, if this type is accepted 607 /// or nullptr otherwise. 608 static Type *parseTextType(const std::string &TypeTextRepresentation, 609 LLVMContext &LLVMContext) { 610 std::map<std::string, Type *> MapStrToType = { 611 {"void", Type::getVoidTy(LLVMContext)}, 612 {"half", Type::getHalfTy(LLVMContext)}, 613 {"float", Type::getFloatTy(LLVMContext)}, 614 {"double", Type::getDoubleTy(LLVMContext)}, 615 {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)}, 616 {"fp128", Type::getFP128Ty(LLVMContext)}, 617 {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)}, 618 {"i1", Type::getInt1Ty(LLVMContext)}, 619 {"i8", Type::getInt8Ty(LLVMContext)}, 620 {"i16", Type::getInt16Ty(LLVMContext)}, 621 {"i32", Type::getInt32Ty(LLVMContext)}, 622 {"i64", Type::getInt64Ty(LLVMContext)}, 623 {"i128", Type::getInt128Ty(LLVMContext)}}; 624 625 auto It = MapStrToType.find(TypeTextRepresentation); 626 if (It != MapStrToType.end()) 627 return It->second; 628 629 errs() << "Textual representation can not be parsed: " 630 << TypeTextRepresentation << "\n"; 631 return nullptr; 632 } 633 634 /// Import new arrays from JScop. 635 /// 636 /// @param S The scop to update. 637 /// @param JScop The JScop file describing new arrays. 638 /// 639 /// @returns True if the import succeeded, otherwise False. 640 static bool importArrays(Scop &S, Json::Value &JScop) { 641 Json::Value Arrays = JScop["arrays"]; 642 if (Arrays.size() == 0) 643 return true; 644 645 unsigned ArrayIdx = 0; 646 for (auto &SAI : S.arrays()) { 647 if (!SAI->isArrayKind()) 648 continue; 649 if (ArrayIdx + 1 > Arrays.size()) { 650 errs() << "Not enough array entries in JScop file.\n"; 651 return false; 652 } 653 if (!areArraysEqual(SAI, Arrays[ArrayIdx])) { 654 errs() << "No match for array '" << SAI->getName() << "' in JScop.\n"; 655 return false; 656 } 657 ArrayIdx++; 658 } 659 660 for (; ArrayIdx < Arrays.size(); ArrayIdx++) { 661 auto &Array = Arrays[ArrayIdx]; 662 auto *ElementType = 663 parseTextType(Array["type"].asCString(), S.getSE()->getContext()); 664 if (!ElementType) { 665 errs() << "Error while parsing element type for new array.\n"; 666 return false; 667 } 668 std::vector<unsigned> DimSizes; 669 for (unsigned i = 0; i < Array["sizes"].size(); i++) { 670 auto Size = std::stoi(Array["sizes"][i].asCString()); 671 672 // Check if the size if positive. 673 if (Size <= 0) { 674 errs() << "The size at index " << i << " is =< 0.\n"; 675 return false; 676 } 677 678 DimSizes.push_back(Size); 679 } 680 681 auto NewSAI = 682 S.createScopArrayInfo(ElementType, Array["name"].asCString(), DimSizes); 683 684 if (Array.isMember("allocation")) { 685 NewSAI->setIsOnHeap(Array["allocation"].asString() == "heap"); 686 } 687 } 688 689 return true; 690 } 691 692 /// Import a Scop from a JSCOP file 693 /// @param S The scop to be modified 694 /// @param D Dependence Info 695 /// @param DL The DataLayout of the function 696 /// @param NewAccessStrings Optionally record the imported access strings 697 /// 698 /// @returns true on success, false otherwise. Beware that if this returns 699 /// false, the Scop may still have been modified. In this case the Scop contains 700 /// invalid information. 701 static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL, 702 std::vector<std::string> *NewAccessStrings = nullptr) { 703 std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix); 704 705 std::string FunctionName = S.getFunction().getName(); 706 errs() << "Reading JScop '" << S.getNameStr() << "' in function '" 707 << FunctionName << "' from '" << FileName << "'.\n"; 708 ErrorOr<std::unique_ptr<MemoryBuffer>> result = 709 MemoryBuffer::getFile(FileName); 710 std::error_code ec = result.getError(); 711 712 if (ec) { 713 errs() << "File could not be read: " << ec.message() << "\n"; 714 return false; 715 } 716 717 Json::Reader reader; 718 Json::Value jscop; 719 720 bool parsingSuccessful = reader.parse(result.get()->getBufferStart(), jscop); 721 722 if (!parsingSuccessful) { 723 errs() << "JSCoP file could not be parsed\n"; 724 return false; 725 } 726 727 bool Success = importContext(S, jscop); 728 729 if (!Success) 730 return false; 731 732 Success = importSchedule(S, jscop, D); 733 734 if (!Success) 735 return false; 736 737 Success = importArrays(S, jscop); 738 739 if (!Success) 740 return false; 741 742 Success = importAccesses(S, jscop, DL, NewAccessStrings); 743 744 if (!Success) 745 return false; 746 return true; 747 } 748 749 char JSONExporter::ID = 0; 750 void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; } 751 752 bool JSONExporter::runOnScop(Scop &S) { 753 exportScop(S); 754 return false; 755 } 756 757 void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const { 758 AU.setPreservesAll(); 759 AU.addRequired<ScopInfoRegionPass>(); 760 } 761 762 Pass *polly::createJSONExporterPass() { return new JSONExporter(); } 763 764 PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM, 765 ScopStandardAnalysisResults &SAR, 766 SPMUpdater &) { 767 exportScop(S); 768 return PreservedAnalyses::all(); 769 } 770 771 char JSONImporter::ID = 0; 772 773 void JSONImporter::printScop(raw_ostream &OS, Scop &S) const { 774 OS << S; 775 for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(), 776 E = NewAccessStrings.end(); 777 I != E; I++) 778 OS << "New access function '" << *I << "' detected in JSCOP file\n"; 779 } 780 781 bool JSONImporter::runOnScop(Scop &S) { 782 const Dependences &D = 783 getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement); 784 const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); 785 786 if (!importScop(S, D, DL, &NewAccessStrings)) 787 report_fatal_error("Tried to import a malformed jscop file."); 788 789 return false; 790 } 791 792 void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const { 793 ScopPass::getAnalysisUsage(AU); 794 AU.addRequired<DependenceInfo>(); 795 796 // TODO: JSONImporter should throw away DependenceInfo. 797 AU.addPreserved<DependenceInfo>(); 798 } 799 800 Pass *polly::createJSONImporterPass() { return new JSONImporter(); } 801 802 PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM, 803 ScopStandardAnalysisResults &SAR, 804 SPMUpdater &) { 805 const Dependences &D = 806 SAM.getResult<DependenceAnalysis>(S, SAR).getDependences( 807 Dependences::AL_Statement); 808 const DataLayout &DL = S.getFunction().getParent()->getDataLayout(); 809 810 if (!importScop(S, D, DL)) 811 report_fatal_error("Tried to import a malformed jscop file."); 812 813 // This invalidates all analyses on Scop. 814 PreservedAnalyses PA; 815 PA.preserveSet<AllAnalysesOn<Module>>(); 816 PA.preserveSet<AllAnalysesOn<Function>>(); 817 PA.preserveSet<AllAnalysesOn<Loop>>(); 818 return PA; 819 } 820 821 INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop", 822 "Polly - Export Scops as JSON" 823 " (Writes a .jscop file for each Scop)", 824 false, false); 825 INITIALIZE_PASS_DEPENDENCY(DependenceInfo) 826 INITIALIZE_PASS_END(JSONExporter, "polly-export-jscop", 827 "Polly - Export Scops as JSON" 828 " (Writes a .jscop file for each Scop)", 829 false, false) 830 831 INITIALIZE_PASS_BEGIN(JSONImporter, "polly-import-jscop", 832 "Polly - Import Scops from JSON" 833 " (Reads a .jscop file for each Scop)", 834 false, false); 835 INITIALIZE_PASS_DEPENDENCY(DependenceInfo) 836 INITIALIZE_PASS_END(JSONImporter, "polly-import-jscop", 837 "Polly - Import Scops from JSON" 838 " (Reads a .jscop file for each Scop)", 839 false, false) 840