llvm-project

Форк
0
/
JSONExporter.cpp 
881 строка · 28.9 Кб
1
//===-- JSONExporter.cpp  - Export Scops as JSON  -------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// Export the Scops build by ScopInfo pass as a JSON file.
10
//
11
//===----------------------------------------------------------------------===//
12

13
#include "polly/JSONExporter.h"
14
#include "polly/DependenceInfo.h"
15
#include "polly/LinkAllPasses.h"
16
#include "polly/Options.h"
17
#include "polly/ScopInfo.h"
18
#include "polly/ScopPass.h"
19
#include "polly/Support/ISLTools.h"
20
#include "polly/Support/ScopLocation.h"
21
#include "llvm/ADT/Statistic.h"
22
#include "llvm/IR/Module.h"
23
#include "llvm/Support/FileSystem.h"
24
#include "llvm/Support/JSON.h"
25
#include "llvm/Support/MemoryBuffer.h"
26
#include "llvm/Support/ToolOutputFile.h"
27
#include "llvm/Support/raw_ostream.h"
28
#include "isl/map.h"
29
#include "isl/set.h"
30
#include <memory>
31
#include <string>
32
#include <system_error>
33

34
using namespace llvm;
35
using namespace polly;
36

37
#define DEBUG_TYPE "polly-import-jscop"
38

39
STATISTIC(NewAccessMapFound, "Number of updated access functions");
40

41
namespace {
42
static cl::opt<std::string>
43
    ImportDir("polly-import-jscop-dir",
44
              cl::desc("The directory to import the .jscop files from."),
45
              cl::Hidden, cl::value_desc("Directory path"), cl::ValueRequired,
46
              cl::init("."), cl::cat(PollyCategory));
47

48
static cl::opt<std::string>
49
    ImportPostfix("polly-import-jscop-postfix",
50
                  cl::desc("Postfix to append to the import .jsop files."),
51
                  cl::Hidden, cl::value_desc("File postfix"), cl::ValueRequired,
52
                  cl::init(""), cl::cat(PollyCategory));
53

54
class JSONExporter : public ScopPass {
55
public:
56
  static char ID;
57
  explicit JSONExporter() : ScopPass(ID) {}
58

59
  /// Export the SCoP @p S to a JSON file.
60
  bool runOnScop(Scop &S) override;
61

62
  /// Print the SCoP @p S as it is exported.
63
  void printScop(raw_ostream &OS, Scop &S) const override;
64

65
  /// Register all analyses and transformation required.
66
  void getAnalysisUsage(AnalysisUsage &AU) const override;
67
};
68

69
class JSONImporter : public ScopPass {
70
public:
71
  static char ID;
72
  std::vector<std::string> NewAccessStrings;
73
  explicit JSONImporter() : ScopPass(ID) {}
74
  /// Import new access functions for SCoP @p S from a JSON file.
75
  bool runOnScop(Scop &S) override;
76

77
  /// Print the SCoP @p S and the imported access functions.
78
  void printScop(raw_ostream &OS, Scop &S) const override;
79

80
  /// Register all analyses and transformation required.
81
  void getAnalysisUsage(AnalysisUsage &AU) const override;
82
};
83
} // namespace
84

85
static std::string getFileName(Scop &S, StringRef Suffix = "") {
86
  std::string FunctionName = S.getFunction().getName().str();
87
  std::string FileName = FunctionName + "___" + S.getNameStr() + ".jscop";
88

89
  if (Suffix != "")
90
    FileName += "." + Suffix.str();
91

92
  return FileName;
93
}
94

95
/// Export all arrays from the Scop.
96
///
97
/// @param S The Scop containing the arrays.
98
///
99
/// @returns Json::Value containing the arrays.
100
static json::Array exportArrays(const Scop &S) {
101
  json::Array Arrays;
102
  std::string Buffer;
103
  llvm::raw_string_ostream RawStringOstream(Buffer);
104

105
  for (auto &SAI : S.arrays()) {
106
    if (!SAI->isArrayKind())
107
      continue;
108

109
    json::Object Array;
110
    json::Array Sizes;
111
    Array["name"] = SAI->getName();
112
    unsigned i = 0;
113
    if (!SAI->getDimensionSize(i)) {
114
      Sizes.push_back("*");
115
      i++;
116
    }
117
    for (; i < SAI->getNumberOfDimensions(); i++) {
118
      SAI->getDimensionSize(i)->print(RawStringOstream);
119
      Sizes.push_back(RawStringOstream.str());
120
      Buffer.clear();
121
    }
122
    Array["sizes"] = std::move(Sizes);
123
    SAI->getElementType()->print(RawStringOstream);
124
    Array["type"] = RawStringOstream.str();
125
    Buffer.clear();
126
    Arrays.push_back(std::move(Array));
127
  }
128
  return Arrays;
129
}
130

131
static json::Value getJSON(Scop &S) {
132
  json::Object root;
133
  unsigned LineBegin, LineEnd;
134
  std::string FileName;
135

136
  getDebugLocation(&S.getRegion(), LineBegin, LineEnd, FileName);
137
  std::string Location;
138
  if (LineBegin != (unsigned)-1)
139
    Location = FileName + ":" + std::to_string(LineBegin) + "-" +
140
               std::to_string(LineEnd);
141

142
  root["name"] = S.getNameStr();
143
  root["context"] = S.getContextStr();
144
  if (LineBegin != (unsigned)-1)
145
    root["location"] = Location;
146

147
  root["arrays"] = exportArrays(S);
148

149
  root["statements"];
150

151
  json::Array Statements;
152
  for (ScopStmt &Stmt : S) {
153
    json::Object statement;
154

155
    statement["name"] = Stmt.getBaseName();
156
    statement["domain"] = Stmt.getDomainStr();
157
    statement["schedule"] = Stmt.getScheduleStr();
158

159
    json::Array Accesses;
160
    for (MemoryAccess *MA : Stmt) {
161
      json::Object access;
162

163
      access["kind"] = MA->isRead() ? "read" : "write";
164
      access["relation"] = MA->getAccessRelationStr();
165

166
      Accesses.push_back(std::move(access));
167
    }
168
    statement["accesses"] = std::move(Accesses);
169

170
    Statements.push_back(std::move(statement));
171
  }
172

173
  root["statements"] = std::move(Statements);
174
  return json::Value(std::move(root));
175
}
176

177
static void exportScop(Scop &S) {
178
  std::string FileName = ImportDir + "/" + getFileName(S);
179

180
  json::Value jscop = getJSON(S);
181

182
  // Write to file.
183
  std::error_code EC;
184
  ToolOutputFile F(FileName, EC, llvm::sys::fs::OF_TextWithCRLF);
185

186
  std::string FunctionName = S.getFunction().getName().str();
187
  errs() << "Writing JScop '" << S.getNameStr() << "' in function '"
188
         << FunctionName << "' to '" << FileName << "'.\n";
189

190
  if (!EC) {
191
    F.os() << formatv("{0:3}", jscop);
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, const json::Object &JScop) {
213
  isl::set OldContext = S.getContext();
214

215
  // Check if key 'context' is present.
216
  if (!JScop.get("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.getString("context").value().str()};
223

224
  // Check whether the context was parsed successfully.
225
  if (NewContext.is_null()) {
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 = unsignedFromIslSize(OldContext.dim(isl::dim::param));
237
  unsigned NewContextDim = unsignedFromIslSize(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, const json::Object &JScop,
267
                           const Dependences &D) {
268
  StatementToIslMapTy NewSchedule;
269

270
  // Check if key 'statements' is present.
271
  if (!JScop.get("statements")) {
272
    errs() << "JScop file has no key name 'statements'.\n";
273
    return false;
274
  }
275

276
  const json::Array &statements = *JScop.getArray("statements");
277

278
  // Check whether the number of indices equals the number of statements
279
  if (statements.size() != S.getSize()) {
280
    errs() << "The number of indices and the number of statements differ.\n";
281
    return false;
282
  }
283

284
  int Index = 0;
285
  for (ScopStmt &Stmt : S) {
286
    // Check if key 'schedule' is present.
287
    if (!statements[Index].getAsObject()->get("schedule")) {
288
      errs() << "Statement " << Index << " has no 'schedule' key.\n";
289
      return false;
290
    }
291
    std::optional<StringRef> Schedule =
292
        statements[Index].getAsObject()->getString("schedule");
293
    assert(Schedule.has_value() &&
294
           "Schedules that contain extension nodes require special handling.");
295
    isl_map *Map = isl_map_read_from_str(S.getIslCtx().get(),
296
                                         Schedule.value().str().c_str());
297

298
    // Check whether the schedule was parsed successfully
299
    if (!Map) {
300
      errs() << "The schedule was not parsed successfully (index = " << Index
301
             << ").\n";
302
      return false;
303
    }
304

305
    isl_space *Space = Stmt.getDomainSpace().release();
306

307
    // Copy the old tuple id. This is necessary to retain the user pointer,
308
    // that stores the reference to the ScopStmt this schedule belongs to.
309
    Map = isl_map_set_tuple_id(Map, isl_dim_in,
310
                               isl_space_get_tuple_id(Space, isl_dim_set));
311
    for (isl_size i = 0; i < isl_space_dim(Space, isl_dim_param); i++) {
312
      isl_id *Id = isl_space_get_dim_id(Space, isl_dim_param, i);
313
      Map = isl_map_set_dim_id(Map, isl_dim_param, i, Id);
314
    }
315
    isl_space_free(Space);
316
    NewSchedule[&Stmt] = isl::manage(Map);
317
    Index++;
318
  }
319

320
  // Check whether the new schedule is valid or not.
321
  if (!D.isValidSchedule(S, NewSchedule)) {
322
    errs() << "JScop file contains a schedule that changes the "
323
           << "dependences. Use -disable-polly-legality to continue anyways\n";
324
    return false;
325
  }
326

327
  auto ScheduleMap = isl::union_map::empty(S.getIslCtx());
328
  for (ScopStmt &Stmt : S) {
329
    if (NewSchedule.contains(&Stmt))
330
      ScheduleMap = ScheduleMap.unite(NewSchedule[&Stmt]);
331
    else
332
      ScheduleMap = ScheduleMap.unite(Stmt.getSchedule());
333
  }
334

335
  S.setSchedule(ScheduleMap);
336

337
  return true;
338
}
339

340
/// Import new memory accesses from JScop.
341
///
342
/// @param S The scop to update.
343
/// @param JScop The JScop file describing the new schedule.
344
/// @param DL The data layout to assume.
345
/// @param NewAccessStrings optionally record the imported access strings
346
///
347
/// @returns True if the import succeeded, otherwise False.
348
static bool
349
importAccesses(Scop &S, const json::Object &JScop, const DataLayout &DL,
350
               std::vector<std::string> *NewAccessStrings = nullptr) {
351
  int StatementIdx = 0;
352

353
  // Check if key 'statements' is present.
354
  if (!JScop.get("statements")) {
355
    errs() << "JScop file has no key name 'statements'.\n";
356
    return false;
357
  }
358
  const json::Array &statements = *JScop.getArray("statements");
359

360
  // Check whether the number of indices equals the number of statements
361
  if (statements.size() != S.getSize()) {
362
    errs() << "The number of indices and the number of statements differ.\n";
363
    return false;
364
  }
365

366
  for (ScopStmt &Stmt : S) {
367
    int MemoryAccessIdx = 0;
368
    const json::Object *Statement = statements[StatementIdx].getAsObject();
369
    assert(Statement);
370

371
    // Check if key 'accesses' is present.
372
    if (!Statement->get("accesses")) {
373
      errs()
374
          << "Statement from JScop file has no key name 'accesses' for index "
375
          << StatementIdx << ".\n";
376
      return false;
377
    }
378
    const json::Array &JsonAccesses = *Statement->getArray("accesses");
379

380
    // Check whether the number of indices equals the number of memory
381
    // accesses
382
    if (Stmt.size() != JsonAccesses.size()) {
383
      errs() << "The number of memory accesses in the JSop file and the number "
384
                "of memory accesses differ for index "
385
             << StatementIdx << ".\n";
386
      return false;
387
    }
388

389
    for (MemoryAccess *MA : Stmt) {
390
      // Check if key 'relation' is present.
391
      const json::Object *JsonMemoryAccess =
392
          JsonAccesses[MemoryAccessIdx].getAsObject();
393
      assert(JsonMemoryAccess);
394
      if (!JsonMemoryAccess->get("relation")) {
395
        errs() << "Memory access number " << MemoryAccessIdx
396
               << " has no key name 'relation' for statement number "
397
               << StatementIdx << ".\n";
398
        return false;
399
      }
400
      StringRef Accesses = *JsonMemoryAccess->getString("relation");
401
      isl_map *NewAccessMap =
402
          isl_map_read_from_str(S.getIslCtx().get(), Accesses.str().c_str());
403

404
      // Check whether the access was parsed successfully
405
      if (!NewAccessMap) {
406
        errs() << "The access was not parsed successfully by ISL.\n";
407
        return false;
408
      }
409
      isl_map *CurrentAccessMap = MA->getAccessRelation().release();
410

411
      // Check if the number of parameter change
412
      if (isl_map_dim(NewAccessMap, isl_dim_param) !=
413
          isl_map_dim(CurrentAccessMap, isl_dim_param)) {
414
        errs() << "JScop file changes the number of parameter dimensions.\n";
415
        isl_map_free(CurrentAccessMap);
416
        isl_map_free(NewAccessMap);
417
        return false;
418
      }
419

420
      isl_id *NewOutId;
421

422
      // If the NewAccessMap has zero dimensions, it is the scalar access; it
423
      // must be the same as before.
424
      // If it has at least one dimension, it's an array access; search for
425
      // its ScopArrayInfo.
426
      if (isl_map_dim(NewAccessMap, isl_dim_out) >= 1) {
427
        NewOutId = isl_map_get_tuple_id(NewAccessMap, isl_dim_out);
428
        auto *SAI = S.getArrayInfoByName(isl_id_get_name(NewOutId));
429
        isl_id *OutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
430
        auto *OutSAI = ScopArrayInfo::getFromId(isl::manage(OutId));
431
        if (!SAI || SAI->getElementType() != OutSAI->getElementType()) {
432
          errs() << "JScop file contains access function with undeclared "
433
                    "ScopArrayInfo\n";
434
          isl_map_free(CurrentAccessMap);
435
          isl_map_free(NewAccessMap);
436
          isl_id_free(NewOutId);
437
          return false;
438
        }
439
        isl_id_free(NewOutId);
440
        NewOutId = SAI->getBasePtrId().release();
441
      } else {
442
        NewOutId = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_out);
443
      }
444

445
      NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_out, NewOutId);
446

447
      if (MA->isArrayKind()) {
448
        // We keep the old alignment, thus we cannot allow accesses to memory
449
        // locations that were not accessed before if the alignment of the
450
        // access is not the default alignment.
451
        bool SpecialAlignment = true;
452
        if (LoadInst *LoadI = dyn_cast<LoadInst>(MA->getAccessInstruction())) {
453
          SpecialAlignment =
454
              DL.getABITypeAlign(LoadI->getType()) != LoadI->getAlign();
455
        } else if (StoreInst *StoreI =
456
                       dyn_cast<StoreInst>(MA->getAccessInstruction())) {
457
          SpecialAlignment =
458
              DL.getABITypeAlign(StoreI->getValueOperand()->getType()) !=
459
              StoreI->getAlign();
460
        }
461

462
        if (SpecialAlignment) {
463
          isl_set *NewAccessSet = isl_map_range(isl_map_copy(NewAccessMap));
464
          isl_set *CurrentAccessSet =
465
              isl_map_range(isl_map_copy(CurrentAccessMap));
466
          bool IsSubset = isl_set_is_subset(NewAccessSet, CurrentAccessSet);
467
          isl_set_free(NewAccessSet);
468
          isl_set_free(CurrentAccessSet);
469

470
          // Check if the JScop file changes the accessed memory.
471
          if (!IsSubset) {
472
            errs() << "JScop file changes the accessed memory\n";
473
            isl_map_free(CurrentAccessMap);
474
            isl_map_free(NewAccessMap);
475
            return false;
476
          }
477
        }
478
      }
479

480
      // We need to copy the isl_ids for the parameter dimensions to the new
481
      // map. Without doing this the current map would have different
482
      // ids then the new one, even though both are named identically.
483
      for (isl_size i = 0; i < isl_map_dim(CurrentAccessMap, isl_dim_param);
484
           i++) {
485
        isl_id *Id = isl_map_get_dim_id(CurrentAccessMap, isl_dim_param, i);
486
        NewAccessMap = isl_map_set_dim_id(NewAccessMap, isl_dim_param, i, Id);
487
      }
488

489
      // Copy the old tuple id. This is necessary to retain the user pointer,
490
      // that stores the reference to the ScopStmt this access belongs to.
491
      isl_id *Id = isl_map_get_tuple_id(CurrentAccessMap, isl_dim_in);
492
      NewAccessMap = isl_map_set_tuple_id(NewAccessMap, isl_dim_in, Id);
493

494
      auto NewAccessDomain = isl_map_domain(isl_map_copy(NewAccessMap));
495
      auto CurrentAccessDomain = isl_map_domain(isl_map_copy(CurrentAccessMap));
496

497
      if (!isl_set_has_equal_space(NewAccessDomain, CurrentAccessDomain)) {
498
        errs() << "JScop file contains access function with incompatible "
499
               << "dimensions\n";
500
        isl_map_free(CurrentAccessMap);
501
        isl_map_free(NewAccessMap);
502
        isl_set_free(NewAccessDomain);
503
        isl_set_free(CurrentAccessDomain);
504
        return false;
505
      }
506

507
      NewAccessDomain =
508
          isl_set_intersect_params(NewAccessDomain, S.getContext().release());
509
      CurrentAccessDomain = isl_set_intersect_params(CurrentAccessDomain,
510
                                                     S.getContext().release());
511
      CurrentAccessDomain =
512
          isl_set_intersect(CurrentAccessDomain, Stmt.getDomain().release());
513

514
      if (MA->isRead() &&
515
          isl_set_is_subset(CurrentAccessDomain, NewAccessDomain) ==
516
              isl_bool_false) {
517
        errs() << "Mapping not defined for all iteration domain elements\n";
518
        isl_set_free(CurrentAccessDomain);
519
        isl_set_free(NewAccessDomain);
520
        isl_map_free(CurrentAccessMap);
521
        isl_map_free(NewAccessMap);
522
        return false;
523
      }
524

525
      isl_set_free(CurrentAccessDomain);
526
      isl_set_free(NewAccessDomain);
527

528
      if (!isl_map_is_equal(NewAccessMap, CurrentAccessMap)) {
529
        // Statistics.
530
        ++NewAccessMapFound;
531
        if (NewAccessStrings)
532
          NewAccessStrings->push_back(Accesses.str());
533
        MA->setNewAccessRelation(isl::manage(NewAccessMap));
534
      } else {
535
        isl_map_free(NewAccessMap);
536
      }
537
      isl_map_free(CurrentAccessMap);
538
      MemoryAccessIdx++;
539
    }
540
    StatementIdx++;
541
  }
542

543
  return true;
544
}
545

546
/// Check whether @p SAI and @p Array represent the same array.
547
static bool areArraysEqual(ScopArrayInfo *SAI, const json::Object &Array) {
548
  std::string Buffer;
549
  llvm::raw_string_ostream RawStringOstream(Buffer);
550

551
  // Check if key 'type' is present.
552
  if (!Array.get("type")) {
553
    errs() << "Array has no key 'type'.\n";
554
    return false;
555
  }
556

557
  // Check if key 'sizes' is present.
558
  if (!Array.get("sizes")) {
559
    errs() << "Array has no key 'sizes'.\n";
560
    return false;
561
  }
562

563
  // Check if key 'name' is present.
564
  if (!Array.get("name")) {
565
    errs() << "Array has no key 'name'.\n";
566
    return false;
567
  }
568

569
  if (SAI->getName() != *Array.getString("name"))
570
    return false;
571

572
  if (SAI->getNumberOfDimensions() != Array.getArray("sizes")->size())
573
    return false;
574

575
  for (unsigned i = 1; i < Array.getArray("sizes")->size(); i++) {
576
    SAI->getDimensionSize(i)->print(RawStringOstream);
577
    const json::Array &SizesArray = *Array.getArray("sizes");
578
    if (RawStringOstream.str() != SizesArray[i].getAsString().value())
579
      return false;
580
    Buffer.clear();
581
  }
582

583
  // Check if key 'type' differs from the current one or is not valid.
584
  SAI->getElementType()->print(RawStringOstream);
585
  if (RawStringOstream.str() != Array.getString("type").value()) {
586
    errs() << "Array has not a valid type.\n";
587
    return false;
588
  }
589

590
  return true;
591
}
592

593
/// Get the accepted primitive type from its textual representation
594
///        @p TypeTextRepresentation.
595
///
596
/// @param TypeTextRepresentation The textual representation of the type.
597
/// @return The pointer to the primitive type, if this type is accepted
598
///         or nullptr otherwise.
599
static Type *parseTextType(const std::string &TypeTextRepresentation,
600
                           LLVMContext &LLVMContext) {
601
  std::map<std::string, Type *> MapStrToType = {
602
      {"void", Type::getVoidTy(LLVMContext)},
603
      {"half", Type::getHalfTy(LLVMContext)},
604
      {"float", Type::getFloatTy(LLVMContext)},
605
      {"double", Type::getDoubleTy(LLVMContext)},
606
      {"x86_fp80", Type::getX86_FP80Ty(LLVMContext)},
607
      {"fp128", Type::getFP128Ty(LLVMContext)},
608
      {"ppc_fp128", Type::getPPC_FP128Ty(LLVMContext)},
609
      {"i1", Type::getInt1Ty(LLVMContext)},
610
      {"i8", Type::getInt8Ty(LLVMContext)},
611
      {"i16", Type::getInt16Ty(LLVMContext)},
612
      {"i32", Type::getInt32Ty(LLVMContext)},
613
      {"i64", Type::getInt64Ty(LLVMContext)},
614
      {"i128", Type::getInt128Ty(LLVMContext)}};
615

616
  auto It = MapStrToType.find(TypeTextRepresentation);
617
  if (It != MapStrToType.end())
618
    return It->second;
619

620
  errs() << "Textual representation can not be parsed: "
621
         << TypeTextRepresentation << "\n";
622
  return nullptr;
623
}
624

625
/// Import new arrays from JScop.
626
///
627
/// @param S The scop to update.
628
/// @param JScop The JScop file describing new arrays.
629
///
630
/// @returns True if the import succeeded, otherwise False.
631
static bool importArrays(Scop &S, const json::Object &JScop) {
632
  if (!JScop.get("arrays"))
633
    return true;
634
  const json::Array &Arrays = *JScop.getArray("arrays");
635
  if (Arrays.size() == 0)
636
    return true;
637

638
  unsigned ArrayIdx = 0;
639
  for (auto &SAI : S.arrays()) {
640
    if (!SAI->isArrayKind())
641
      continue;
642
    if (ArrayIdx + 1 > Arrays.size()) {
643
      errs() << "Not enough array entries in JScop file.\n";
644
      return false;
645
    }
646
    if (!areArraysEqual(SAI, *Arrays[ArrayIdx].getAsObject())) {
647
      errs() << "No match for array '" << SAI->getName() << "' in JScop.\n";
648
      return false;
649
    }
650
    ArrayIdx++;
651
  }
652

653
  for (; ArrayIdx < Arrays.size(); ArrayIdx++) {
654
    const json::Object &Array = *Arrays[ArrayIdx].getAsObject();
655
    auto *ElementType =
656
        parseTextType(Array.get("type")->getAsString().value().str(),
657
                      S.getSE()->getContext());
658
    if (!ElementType) {
659
      errs() << "Error while parsing element type for new array.\n";
660
      return false;
661
    }
662
    const json::Array &SizesArray = *Array.getArray("sizes");
663
    std::vector<unsigned> DimSizes;
664
    for (unsigned i = 0; i < SizesArray.size(); i++) {
665
      auto Size = std::stoi(SizesArray[i].getAsString()->str());
666

667
      // Check if the size if positive.
668
      if (Size <= 0) {
669
        errs() << "The size at index " << i << " is =< 0.\n";
670
        return false;
671
      }
672

673
      DimSizes.push_back(Size);
674
    }
675

676
    auto NewSAI = S.createScopArrayInfo(
677
        ElementType, Array.getString("name").value().str(), DimSizes);
678

679
    if (Array.get("allocation")) {
680
      NewSAI->setIsOnHeap(Array.getString("allocation").value() == "heap");
681
    }
682
  }
683

684
  return true;
685
}
686

687
/// Import a Scop from a JSCOP file
688
/// @param S The scop to be modified
689
/// @param D Dependence Info
690
/// @param DL The DataLayout of the function
691
/// @param NewAccessStrings Optionally record the imported access strings
692
///
693
/// @returns true on success, false otherwise. Beware that if this returns
694
/// false, the Scop may still have been modified. In this case the Scop contains
695
/// invalid information.
696
static bool importScop(Scop &S, const Dependences &D, const DataLayout &DL,
697
                       std::vector<std::string> *NewAccessStrings = nullptr) {
698
  std::string FileName = ImportDir + "/" + getFileName(S, ImportPostfix);
699

700
  std::string FunctionName = S.getFunction().getName().str();
701
  errs() << "Reading JScop '" << S.getNameStr() << "' in function '"
702
         << FunctionName << "' from '" << FileName << "'.\n";
703
  ErrorOr<std::unique_ptr<MemoryBuffer>> result =
704
      MemoryBuffer::getFile(FileName);
705
  std::error_code ec = result.getError();
706

707
  if (ec) {
708
    errs() << "File could not be read: " << ec.message() << "\n";
709
    return false;
710
  }
711

712
  Expected<json::Value> ParseResult =
713
      json::parse(result.get().get()->getBuffer());
714

715
  if (Error E = ParseResult.takeError()) {
716
    errs() << "JSCoP file could not be parsed\n";
717
    errs() << E << "\n";
718
    consumeError(std::move(E));
719
    return false;
720
  }
721
  json::Object &jscop = *ParseResult.get().getAsObject();
722

723
  bool Success = importContext(S, jscop);
724

725
  if (!Success)
726
    return false;
727

728
  Success = importSchedule(S, jscop, D);
729

730
  if (!Success)
731
    return false;
732

733
  Success = importArrays(S, jscop);
734

735
  if (!Success)
736
    return false;
737

738
  Success = importAccesses(S, jscop, DL, NewAccessStrings);
739

740
  if (!Success)
741
    return false;
742
  return true;
743
}
744

745
char JSONExporter::ID = 0;
746
void JSONExporter::printScop(raw_ostream &OS, Scop &S) const { OS << S; }
747

748
bool JSONExporter::runOnScop(Scop &S) {
749
  exportScop(S);
750
  return false;
751
}
752

753
void JSONExporter::getAnalysisUsage(AnalysisUsage &AU) const {
754
  AU.setPreservesAll();
755
  AU.addRequired<ScopInfoRegionPass>();
756
}
757

758
Pass *polly::createJSONExporterPass() { return new JSONExporter(); }
759

760
PreservedAnalyses JSONExportPass::run(Scop &S, ScopAnalysisManager &SAM,
761
                                      ScopStandardAnalysisResults &SAR,
762
                                      SPMUpdater &) {
763
  exportScop(S);
764
  return PreservedAnalyses::all();
765
}
766

767
char JSONImporter::ID = 0;
768

769
void JSONImporter::printScop(raw_ostream &OS, Scop &S) const {
770
  OS << S;
771
  for (std::vector<std::string>::const_iterator I = NewAccessStrings.begin(),
772
                                                E = NewAccessStrings.end();
773
       I != E; I++)
774
    OS << "New access function '" << *I << "' detected in JSCOP file\n";
775
}
776

777
bool JSONImporter::runOnScop(Scop &S) {
778
  const Dependences &D =
779
      getAnalysis<DependenceInfo>().getDependences(Dependences::AL_Statement);
780
  const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
781

782
  if (!importScop(S, D, DL, &NewAccessStrings))
783
    report_fatal_error("Tried to import a malformed jscop file.");
784

785
  return false;
786
}
787

788
void JSONImporter::getAnalysisUsage(AnalysisUsage &AU) const {
789
  ScopPass::getAnalysisUsage(AU);
790
  AU.addRequired<DependenceInfo>();
791

792
  // TODO: JSONImporter should throw away DependenceInfo.
793
  AU.addPreserved<DependenceInfo>();
794
}
795

796
Pass *polly::createJSONImporterPass() { return new JSONImporter(); }
797

798
PreservedAnalyses JSONImportPass::run(Scop &S, ScopAnalysisManager &SAM,
799
                                      ScopStandardAnalysisResults &SAR,
800
                                      SPMUpdater &) {
801
  const Dependences &D =
802
      SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(
803
          Dependences::AL_Statement);
804
  const DataLayout &DL = S.getFunction().getParent()->getDataLayout();
805

806
  if (!importScop(S, D, DL))
807
    report_fatal_error("Tried to import a malformed jscop file.");
808

809
  // This invalidates all analyses on Scop.
810
  PreservedAnalyses PA;
811
  PA.preserveSet<AllAnalysesOn<Module>>();
812
  PA.preserveSet<AllAnalysesOn<Function>>();
813
  PA.preserveSet<AllAnalysesOn<Loop>>();
814
  return PA;
815
}
816

817
INITIALIZE_PASS_BEGIN(JSONExporter, "polly-export-jscop",
818
                      "Polly - Export Scops as JSON"
819
                      " (Writes a .jscop file for each Scop)",
820
                      false, false);
821
INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
822
INITIALIZE_PASS_END(JSONExporter, "polly-export-jscop",
823
                    "Polly - Export Scops as JSON"
824
                    " (Writes a .jscop file for each Scop)",
825
                    false, false)
826

827
INITIALIZE_PASS_BEGIN(JSONImporter, "polly-import-jscop",
828
                      "Polly - Import Scops from JSON"
829
                      " (Reads a .jscop file for each Scop)",
830
                      false, false);
831
INITIALIZE_PASS_DEPENDENCY(DependenceInfo)
832
INITIALIZE_PASS_END(JSONImporter, "polly-import-jscop",
833
                    "Polly - Import Scops from JSON"
834
                    " (Reads a .jscop file for each Scop)",
835
                    false, false)
836

837
//===----------------------------------------------------------------------===//
838

839
namespace {
840
/// Print result from JSONImporter.
841
class JSONImporterPrinterLegacyPass final : public ScopPass {
842
public:
843
  static char ID;
844

845
  JSONImporterPrinterLegacyPass() : JSONImporterPrinterLegacyPass(outs()) {}
846
  explicit JSONImporterPrinterLegacyPass(llvm::raw_ostream &OS)
847
      : ScopPass(ID), OS(OS) {}
848

849
  bool runOnScop(Scop &S) override {
850
    JSONImporter &P = getAnalysis<JSONImporter>();
851

852
    OS << "Printing analysis '" << P.getPassName() << "' for region: '"
853
       << S.getRegion().getNameStr() << "' in function '"
854
       << S.getFunction().getName() << "':\n";
855
    P.printScop(OS, S);
856

857
    return false;
858
  }
859

860
  void getAnalysisUsage(AnalysisUsage &AU) const override {
861
    ScopPass::getAnalysisUsage(AU);
862
    AU.addRequired<JSONImporter>();
863
    AU.setPreservesAll();
864
  }
865

866
private:
867
  llvm::raw_ostream &OS;
868
};
869

870
char JSONImporterPrinterLegacyPass::ID = 0;
871
} // namespace
872

873
Pass *polly::createJSONImporterPrinterLegacyPass(llvm::raw_ostream &OS) {
874
  return new JSONImporterPrinterLegacyPass(OS);
875
}
876

877
INITIALIZE_PASS_BEGIN(JSONImporterPrinterLegacyPass, "polly-print-import-jscop",
878
                      "Polly - Print Scop import result", false, false)
879
INITIALIZE_PASS_DEPENDENCY(JSONImporter)
880
INITIALIZE_PASS_END(JSONImporterPrinterLegacyPass, "polly-print-import-jscop",
881
                    "Polly - Print Scop import result", false, false)
882

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.