Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,95 @@
//===------ DumpModulePass.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Write a module to a file.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/DumpModulePass.h"
#include "polly/Options.h"
#include "llvm/IR/LegacyPassManagers.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ToolOutputFile.h"
#include <string.h>
#define DEBUG_TYPE "polly-dump-module"
using namespace llvm;
using namespace polly;
namespace {
class DumpModule : public ModulePass {
private:
DumpModule(const DumpModule &) = delete;
const DumpModule &operator=(const DumpModule &) = delete;
std::string Filename;
bool IsSuffix;
public:
static char ID;
/// This constructor is used e.g. if using opt -polly-dump-module.
///
/// Provide a default suffix to not overwrite the original file.
explicit DumpModule() : ModulePass(ID), Filename("-dump"), IsSuffix(true) {}
explicit DumpModule(llvm::StringRef Filename, bool IsSuffix)
: ModulePass(ID), Filename(Filename), IsSuffix(IsSuffix) {}
/// @name ModulePass interface
//@{
virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
virtual bool runOnModule(llvm::Module &M) override {
std::string Dumpfile;
if (IsSuffix) {
auto ModuleName = M.getName();
auto Stem = sys::path::stem(ModuleName);
Dumpfile = (Twine(Stem) + Filename + ".ll").str();
} else {
Dumpfile = Filename;
}
DEBUG(dbgs() << "Dumping module to " << Dumpfile << '\n');
std::unique_ptr<ToolOutputFile> Out;
std::error_code EC;
Out.reset(new ToolOutputFile(Dumpfile, EC, sys::fs::F_None));
if (EC) {
errs() << EC.message() << '\n';
return false;
}
M.print(Out->os(), nullptr);
Out->keep();
return false;
}
//@}
};
char DumpModule::ID;
} // namespace
ModulePass *polly::createDumpModulePass(llvm::StringRef Filename,
bool IsSuffix) {
return new DumpModule(Filename, IsSuffix);
}
INITIALIZE_PASS_BEGIN(DumpModule, "polly-dump-module", "Polly - Dump Module",
false, false)
INITIALIZE_PASS_END(DumpModule, "polly-dump-module", "Polly - Dump Module",
false, false)

View File

@@ -0,0 +1,282 @@
//===- GmpConv.cpp - Recreate LLVM IR from the Scop. ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Functions for converting between gmp objects and llvm::APInt.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/GICHelper.h"
#include "llvm/IR/Value.h"
#include "isl/aff.h"
#include "isl/map.h"
#include "isl/schedule.h"
#include "isl/set.h"
#include "isl/space.h"
#include "isl/union_map.h"
#include "isl/union_set.h"
#include "isl/val.h"
#include <climits>
using namespace llvm;
__isl_give isl_val *polly::isl_valFromAPInt(isl_ctx *Ctx, const APInt Int,
bool IsSigned) {
APInt Abs;
isl_val *v;
// As isl is interpreting the input always as unsigned value, we need some
// additional pre and post processing to import signed values. The approach
// we take is to first obtain the absolute value of Int and then negate the
// value after it has been imported to isl.
//
// It should be noted that the smallest integer value represented in two's
// complement with a certain amount of bits does not have a corresponding
// positive representation in two's complement representation with the same
// number of bits. E.g. 110 (-2) does not have a corresponding value for (2).
// To ensure that there is always a corresponding value available we first
// sign-extend the input by one bit and only then take the absolute value.
if (IsSigned)
Abs = Int.sext(Int.getBitWidth() + 1).abs();
else
Abs = Int;
const uint64_t *Data = Abs.getRawData();
unsigned Words = Abs.getNumWords();
v = isl_val_int_from_chunks(Ctx, Words, sizeof(uint64_t), Data);
if (IsSigned && Int.isNegative())
v = isl_val_neg(v);
return v;
}
APInt polly::APIntFromVal(__isl_take isl_val *Val) {
uint64_t *Data;
int NumChunks;
const static int ChunkSize = sizeof(uint64_t);
assert(isl_val_is_int(Val) && "Only integers can be converted to APInt");
NumChunks = isl_val_n_abs_num_chunks(Val, ChunkSize);
Data = (uint64_t *)malloc(NumChunks * ChunkSize);
isl_val_get_abs_num_chunks(Val, ChunkSize, Data);
int NumBits = CHAR_BIT * ChunkSize * NumChunks;
APInt A(NumBits, NumChunks, Data);
// As isl provides only an interface to obtain data that describes the
// absolute value of an isl_val, A at this point always contains a positive
// number. In case Val was originally negative, we expand the size of A by
// one and negate the value (in two's complement representation). As a result,
// the new value in A corresponds now with Val.
if (isl_val_is_neg(Val)) {
A = A.zext(A.getBitWidth() + 1);
A = -A;
}
// isl may represent small numbers with more than the minimal number of bits.
// We truncate the APInt to the minimal number of bits needed to represent the
// signed value it contains, to ensure that the bitwidth is always minimal.
if (A.getMinSignedBits() < A.getBitWidth())
A = A.trunc(A.getMinSignedBits());
free(Data);
isl_val_free(Val);
return A;
}
template <typename ISLTy, typename ISL_CTX_GETTER, typename ISL_PRINTER>
static inline std::string stringFromIslObjInternal(__isl_keep ISLTy *isl_obj,
ISL_CTX_GETTER ctx_getter_fn,
ISL_PRINTER printer_fn) {
if (!isl_obj)
return "null";
isl_ctx *ctx = ctx_getter_fn(isl_obj);
isl_printer *p = isl_printer_to_str(ctx);
p = printer_fn(p, isl_obj);
char *char_str = isl_printer_get_str(p);
std::string string;
if (char_str)
string = char_str;
else
string = "null";
free(char_str);
isl_printer_free(p);
return string;
}
std::string polly::stringFromIslObj(__isl_keep isl_map *map) {
return stringFromIslObjInternal(map, isl_map_get_ctx, isl_printer_print_map);
}
std::string polly::stringFromIslObj(__isl_keep isl_set *set) {
return stringFromIslObjInternal(set, isl_set_get_ctx, isl_printer_print_set);
}
std::string polly::stringFromIslObj(__isl_keep isl_union_map *umap) {
return stringFromIslObjInternal(umap, isl_union_map_get_ctx,
isl_printer_print_union_map);
}
std::string polly::stringFromIslObj(__isl_keep isl_union_set *uset) {
return stringFromIslObjInternal(uset, isl_union_set_get_ctx,
isl_printer_print_union_set);
}
std::string polly::stringFromIslObj(__isl_keep isl_schedule *schedule) {
return stringFromIslObjInternal(schedule, isl_schedule_get_ctx,
isl_printer_print_schedule);
}
std::string polly::stringFromIslObj(__isl_keep isl_multi_aff *maff) {
return stringFromIslObjInternal(maff, isl_multi_aff_get_ctx,
isl_printer_print_multi_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_pw_multi_aff *pma) {
return stringFromIslObjInternal(pma, isl_pw_multi_aff_get_ctx,
isl_printer_print_pw_multi_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_multi_pw_aff *mpa) {
return stringFromIslObjInternal(mpa, isl_multi_pw_aff_get_ctx,
isl_printer_print_multi_pw_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_union_pw_multi_aff *upma) {
return stringFromIslObjInternal(upma, isl_union_pw_multi_aff_get_ctx,
isl_printer_print_union_pw_multi_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_aff *aff) {
return stringFromIslObjInternal(aff, isl_aff_get_ctx, isl_printer_print_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_pw_aff *pwaff) {
return stringFromIslObjInternal(pwaff, isl_pw_aff_get_ctx,
isl_printer_print_pw_aff);
}
std::string polly::stringFromIslObj(__isl_keep isl_space *space) {
return stringFromIslObjInternal(space, isl_space_get_ctx,
isl_printer_print_space);
}
static void replace(std::string &str, const std::string &find,
const std::string &replace) {
size_t pos = 0;
while ((pos = str.find(find, pos)) != std::string::npos) {
str.replace(pos, find.length(), replace);
pos += replace.length();
}
}
static void makeIslCompatible(std::string &str) {
replace(str, ".", "_");
replace(str, "\"", "_");
replace(str, " ", "__");
replace(str, "=>", "TO");
replace(str, "+", "_");
}
std::string polly::getIslCompatibleName(const std::string &Prefix,
const std::string &Middle,
const std::string &Suffix) {
std::string S = Prefix + Middle + Suffix;
makeIslCompatible(S);
return S;
}
std::string polly::getIslCompatibleName(const std::string &Prefix,
const std::string &Name, long Number,
const std::string &Suffix,
bool UseInstructionNames) {
std::string S = Prefix;
if (UseInstructionNames)
S += std::string("_") + Name;
else
S += std::to_string(Number);
S += Suffix;
makeIslCompatible(S);
return S;
}
std::string polly::getIslCompatibleName(const std::string &Prefix,
const Value *Val, long Number,
const std::string &Suffix,
bool UseInstructionNames) {
std::string ValStr;
if (UseInstructionNames && Val->hasName())
ValStr = std::string("_") + std::string(Val->getName());
else
ValStr = std::to_string(Number);
return getIslCompatibleName(Prefix, ValStr, Suffix);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
/// To call a inline dump() method in a debugger, at it must have been
/// instantiated in at least one translation unit. Because isl's dump() method
/// are meant to be called from a debugger only, but not from code, no such
/// instantiation would exist. We use this method to force an instantiation in
/// this translation unit. Because it has non-static linking, the compiler does
/// not know that it is never called, and therefore must ensure the existence of
/// the dump functions.
void neverCalled() {
isl::aff().dump();
isl::aff_list().dump();
isl::ast_expr().dump();
isl::ast_expr_list().dump();
isl::ast_node().dump();
isl::ast_node_list().dump();
isl::band_list().dump();
isl::basic_map().dump();
isl::basic_map_list().dump();
isl::basic_set().dump();
isl::basic_set_list().dump();
isl::constraint().dump();
isl::constraint_list().dump();
isl::id().dump();
isl::id_list().dump();
isl::id_to_ast_expr().dump();
isl::local_space().dump();
isl::map().dump();
isl::map_list().dump();
isl::multi_aff().dump();
isl::multi_pw_aff().dump();
isl::multi_union_pw_aff().dump();
isl::multi_val().dump();
isl::point().dump();
isl::pw_aff().dump();
isl::pw_aff_list().dump();
isl::pw_multi_aff().dump();
isl::pw_qpolynomial().dump();
isl::qpolynomial().dump();
isl::schedule().dump();
isl::schedule_constraints().dump();
isl::schedule_node().dump();
isl::set().dump();
isl::set_list().dump();
isl::space().dump();
isl::union_map().dump();
isl::union_map_list().dump();
isl::union_pw_aff().dump();
isl::union_pw_aff_list().dump();
isl::union_pw_multi_aff().dump();
isl::union_pw_multi_aff_list().dump();
isl::union_set().dump();
isl::union_set_list().dump();
isl::val().dump();
isl::val_list().dump();
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
/*! \mainpage Polly main page
*
* This is the documentation of http://polly.llvm.org
*/

View File

@@ -0,0 +1,31 @@
#ifndef FUNCTION_ANALYSIS
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
#endif
FUNCTION_ANALYSIS("polly-detect", ScopAnalysis())
FUNCTION_ANALYSIS("polly-function-scops", ScopInfoAnalysis())
#undef FUNCTION_ANALYSIS
#ifndef FUNCTION_PASS
#define FUNCTION_PASS(NAME, CREATE_PASS)
#endif
FUNCTION_PASS("polly-prepare", CodePreparationPass())
FUNCTION_PASS("print<polly-detect>", ScopAnalysisPrinterPass(errs()))
FUNCTION_PASS("print<polly-function-scops>", ScopInfoPrinterPass(errs()))
#undef FUNCTION_PASS
#ifndef SCOP_ANALYSIS
#define SCOP_ANALYSIS(NAME, CREATE_PASS)
#endif
SCOP_ANALYSIS("polly-ast", IslAstAnalysis())
SCOP_ANALYSIS("polly-dependences", DependenceAnalysis())
#undef SCOP_ANALYSIS
#ifndef SCOP_PASS
#define SCOP_PASS(NAME, CREATE_PASS)
#endif
SCOP_PASS("polly-export-jscop", JSONExportPass())
SCOP_PASS("polly-import-jscop", JSONImportPass())
SCOP_PASS("print<polly-ast>", IslAstPrinterPass(outs()))
SCOP_PASS("print<polly-dependences>", DependenceInfoPrinterPass(outs()))
SCOP_PASS("polly-codegen", CodeGenerationPass())
#undef SCOP_PASS

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
//=== ScopLocation.cpp - Debug location for ScopDetection ----- -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Helper function for extracting region debug information.
//
//===----------------------------------------------------------------------===//
//
#include "polly/Support/ScopLocation.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugLoc.h"
using namespace llvm;
namespace polly {
void getDebugLocation(const Region *R, unsigned &LineBegin, unsigned &LineEnd,
std::string &FileName) {
LineBegin = -1;
LineEnd = 0;
for (const BasicBlock *BB : R->blocks())
for (const Instruction &Inst : *BB) {
DebugLoc DL = Inst.getDebugLoc();
if (!DL)
continue;
auto *Scope = cast<DIScope>(DL.getScope());
if (FileName.empty())
FileName = Scope->getFilename();
unsigned NewLine = DL.getLine();
LineBegin = std::min(LineBegin, NewLine);
LineEnd = std::max(LineEnd, NewLine);
}
}
} // namespace polly

View File

@@ -0,0 +1,401 @@
//===------ VirtualInstruction.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Tools for determining which instructions are within a statement and the
// nature of their operands.
//
//===----------------------------------------------------------------------===//
#include "polly/Support/VirtualInstruction.h"
#include "polly/Support/SCEVValidator.h"
using namespace polly;
using namespace llvm;
VirtualUse VirtualUse ::create(Scop *S, const Use &U, LoopInfo *LI,
bool Virtual) {
auto *UserBB = getUseBlock(U);
Instruction *UI = dyn_cast<Instruction>(U.getUser());
ScopStmt *UserStmt = nullptr;
if (PHINode *PHI = dyn_cast<PHINode>(UI))
UserStmt = S->getLastStmtFor(PHI->getIncomingBlock(U));
else
UserStmt = S->getStmtFor(UI);
auto *UserScope = LI->getLoopFor(UserBB);
return create(S, UserStmt, UserScope, U.get(), Virtual);
}
VirtualUse VirtualUse::create(Scop *S, ScopStmt *UserStmt, Loop *UserScope,
Value *Val, bool Virtual) {
assert(!isa<StoreInst>(Val) && "a StoreInst cannot be used");
if (isa<BasicBlock>(Val))
return VirtualUse(UserStmt, Val, Block, nullptr, nullptr);
if (isa<llvm::Constant>(Val) || isa<MetadataAsValue>(Val))
return VirtualUse(UserStmt, Val, Constant, nullptr, nullptr);
// Is the value synthesizable? If the user has been pruned
// (UserStmt == nullptr), it is either not used anywhere or is synthesizable.
// We assume synthesizable which practically should have the same effect.
auto *SE = S->getSE();
if (SE->isSCEVable(Val->getType())) {
auto *ScevExpr = SE->getSCEVAtScope(Val, UserScope);
if (!UserStmt || canSynthesize(Val, *UserStmt->getParent(), SE, UserScope))
return VirtualUse(UserStmt, Val, Synthesizable, ScevExpr, nullptr);
}
// FIXME: Inconsistency between lookupInvariantEquivClass and
// getRequiredInvariantLoads. Querying one of them should be enough.
auto &RIL = S->getRequiredInvariantLoads();
if (S->lookupInvariantEquivClass(Val) || RIL.count(dyn_cast<LoadInst>(Val)))
return VirtualUse(UserStmt, Val, Hoisted, nullptr, nullptr);
// ReadOnly uses may have MemoryAccesses that we want to associate with the
// use. This is why we look for a MemoryAccess here already.
MemoryAccess *InputMA = nullptr;
if (UserStmt && Virtual)
InputMA = UserStmt->lookupValueReadOf(Val);
// Uses are read-only if they have been defined before the SCoP, i.e., they
// cannot be written to inside the SCoP. Arguments are defined before any
// instructions, hence also before the SCoP. If the user has been pruned
// (UserStmt == nullptr) and is not SCEVable, assume it is read-only as it is
// neither an intra- nor an inter-use.
if (!UserStmt || isa<Argument>(Val))
return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
auto Inst = cast<Instruction>(Val);
if (!S->contains(Inst))
return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
// A use is inter-statement if either it is defined in another statement, or
// there is a MemoryAccess that reads its value that has been written by
// another statement.
if (InputMA || (!Virtual && UserStmt != S->getStmtFor(Inst)))
return VirtualUse(UserStmt, Val, Inter, nullptr, InputMA);
return VirtualUse(UserStmt, Val, Intra, nullptr, nullptr);
}
void VirtualUse::print(raw_ostream &OS, bool Reproducible) const {
OS << "User: [" << User->getBaseName() << "] ";
switch (Kind) {
case VirtualUse::Constant:
OS << "Constant Op:";
break;
case VirtualUse::Block:
OS << "BasicBlock Op:";
break;
case VirtualUse::Synthesizable:
OS << "Synthesizable Op:";
break;
case VirtualUse::Hoisted:
OS << "Hoisted load Op:";
break;
case VirtualUse::ReadOnly:
OS << "Read-Only Op:";
break;
case VirtualUse::Intra:
OS << "Intra Op:";
break;
case VirtualUse::Inter:
OS << "Inter Op:";
break;
}
if (Val) {
OS << ' ';
if (Reproducible)
OS << '"' << Val->getName() << '"';
else
Val->print(OS, true);
}
if (ScevExpr) {
OS << ' ';
ScevExpr->print(OS);
}
if (InputMA && !Reproducible)
OS << ' ' << InputMA;
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void VirtualUse::dump() const {
print(errs(), false);
errs() << '\n';
}
#endif
void VirtualInstruction::print(raw_ostream &OS, bool Reproducible) const {
if (!Stmt || !Inst) {
OS << "[null VirtualInstruction]";
return;
}
OS << "[" << Stmt->getBaseName() << "]";
Inst->print(OS, !Reproducible);
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void VirtualInstruction::dump() const {
print(errs(), false);
errs() << '\n';
}
#endif
/// Return true if @p Inst cannot be removed, even if it is nowhere referenced.
static bool isRoot(const Instruction *Inst) {
// The store is handled by its MemoryAccess. The load must be reached from the
// roots in order to be marked as used.
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
return false;
// Terminator instructions (in region statements) are required for control
// flow.
if (isa<TerminatorInst>(Inst))
return true;
// Writes to memory must be honored.
if (Inst->mayWriteToMemory())
return true;
return false;
}
/// Return true for MemoryAccesses that cannot be removed because it represents
/// an llvm::Value that is used after the SCoP.
static bool isEscaping(MemoryAccess *MA) {
assert(MA->isOriginalValueKind());
Scop *S = MA->getStatement()->getParent();
return S->isEscaping(cast<Instruction>(MA->getAccessValue()));
}
/// Add non-removable virtual instructions in @p Stmt to @p RootInsts.
static void
addInstructionRoots(ScopStmt *Stmt,
SmallVectorImpl<VirtualInstruction> &RootInsts) {
if (!Stmt->isBlockStmt()) {
// In region statements the terminator statement and all statements that
// are not in the entry block cannot be eliminated and consequently must
// be roots.
RootInsts.emplace_back(Stmt,
Stmt->getRegion()->getEntry()->getTerminator());
for (BasicBlock *BB : Stmt->getRegion()->blocks())
if (Stmt->getRegion()->getEntry() != BB)
for (Instruction &Inst : *BB)
RootInsts.emplace_back(Stmt, &Inst);
return;
}
for (Instruction *Inst : Stmt->getInstructions())
if (isRoot(Inst))
RootInsts.emplace_back(Stmt, Inst);
}
/// Add non-removable memory accesses in @p Stmt to @p RootInsts.
///
/// @param Local If true, all writes are assumed to escape. markAndSweep
/// algorithms can use this to be applicable to a single ScopStmt only without
/// the risk of removing definitions required by other statements.
/// If false, only writes for SCoP-escaping values are roots. This
/// is global mode, where such writes must be marked by theirs uses
/// in order to be reachable.
static void addAccessRoots(ScopStmt *Stmt,
SmallVectorImpl<MemoryAccess *> &RootAccs,
bool Local) {
for (auto *MA : *Stmt) {
if (!MA->isWrite())
continue;
// Writes to arrays are always used.
if (MA->isLatestArrayKind())
RootAccs.push_back(MA);
// Values are roots if they are escaping.
else if (MA->isLatestValueKind()) {
if (Local || isEscaping(MA))
RootAccs.push_back(MA);
}
// Exit phis are, by definition, escaping.
else if (MA->isLatestExitPHIKind())
RootAccs.push_back(MA);
// phi writes are only roots if we are not visiting the statement
// containing the PHINode.
else if (Local && MA->isLatestPHIKind())
RootAccs.push_back(MA);
}
}
/// Determine all instruction and access roots.
static void addRoots(ScopStmt *Stmt,
SmallVectorImpl<VirtualInstruction> &RootInsts,
SmallVectorImpl<MemoryAccess *> &RootAccs, bool Local) {
addInstructionRoots(Stmt, RootInsts);
addAccessRoots(Stmt, RootAccs, Local);
}
/// Mark accesses and instructions as used if they are reachable from a root,
/// walking the operand trees.
///
/// @param S The SCoP to walk.
/// @param LI The LoopInfo Analysis.
/// @param RootInsts List of root instructions.
/// @param RootAccs List of root accesses.
/// @param UsesInsts[out] Receives all reachable instructions, including the
/// roots.
/// @param UsedAccs[out] Receives all reachable accesses, including the roots.
/// @param OnlyLocal If non-nullptr, restricts walking to a single
/// statement.
static void walkReachable(Scop *S, LoopInfo *LI,
ArrayRef<VirtualInstruction> RootInsts,
ArrayRef<MemoryAccess *> RootAccs,
DenseSet<VirtualInstruction> &UsedInsts,
DenseSet<MemoryAccess *> &UsedAccs,
ScopStmt *OnlyLocal = nullptr) {
UsedInsts.clear();
UsedAccs.clear();
SmallVector<VirtualInstruction, 32> WorklistInsts;
SmallVector<MemoryAccess *, 32> WorklistAccs;
WorklistInsts.append(RootInsts.begin(), RootInsts.end());
WorklistAccs.append(RootAccs.begin(), RootAccs.end());
auto AddToWorklist = [&](VirtualUse VUse) {
switch (VUse.getKind()) {
case VirtualUse::Block:
case VirtualUse::Constant:
case VirtualUse::Synthesizable:
case VirtualUse::Hoisted:
break;
case VirtualUse::ReadOnly:
// Read-only scalars only have MemoryAccesses if ModelReadOnlyScalars is
// enabled.
if (!VUse.getMemoryAccess())
break;
LLVM_FALLTHROUGH;
case VirtualUse::Inter:
assert(VUse.getMemoryAccess());
WorklistAccs.push_back(VUse.getMemoryAccess());
break;
case VirtualUse::Intra:
WorklistInsts.emplace_back(VUse.getUser(),
cast<Instruction>(VUse.getValue()));
break;
}
};
while (true) {
// We have two worklists to process: Only when the MemoryAccess worklist is
// empty, we process the instruction worklist.
while (!WorklistAccs.empty()) {
auto *Acc = WorklistAccs.pop_back_val();
ScopStmt *Stmt = Acc->getStatement();
if (OnlyLocal && Stmt != OnlyLocal)
continue;
auto Inserted = UsedAccs.insert(Acc);
if (!Inserted.second)
continue;
if (Acc->isRead()) {
const ScopArrayInfo *SAI = Acc->getScopArrayInfo();
if (Acc->isLatestValueKind()) {
MemoryAccess *DefAcc = S->getValueDef(SAI);
// Accesses to read-only values do not have a definition.
if (DefAcc)
WorklistAccs.push_back(S->getValueDef(SAI));
}
if (Acc->isLatestAnyPHIKind()) {
auto IncomingMAs = S->getPHIIncomings(SAI);
WorklistAccs.append(IncomingMAs.begin(), IncomingMAs.end());
}
}
if (Acc->isWrite()) {
if (Acc->isOriginalValueKind() ||
(Acc->isOriginalArrayKind() && Acc->getAccessValue())) {
Loop *Scope = Stmt->getSurroundingLoop();
VirtualUse VUse =
VirtualUse::create(S, Stmt, Scope, Acc->getAccessValue(), true);
AddToWorklist(VUse);
}
if (Acc->isOriginalAnyPHIKind()) {
for (auto Incoming : Acc->getIncoming()) {
VirtualUse VUse = VirtualUse::create(
S, Stmt, LI->getLoopFor(Incoming.first), Incoming.second, true);
AddToWorklist(VUse);
}
}
if (Acc->isOriginalArrayKind())
WorklistInsts.emplace_back(Stmt, Acc->getAccessInstruction());
}
}
// If both worklists are empty, stop walking.
if (WorklistInsts.empty())
break;
VirtualInstruction VInst = WorklistInsts.pop_back_val();
ScopStmt *Stmt = VInst.getStmt();
Instruction *Inst = VInst.getInstruction();
// Do not process statements other than the local.
if (OnlyLocal && Stmt != OnlyLocal)
continue;
auto InsertResult = UsedInsts.insert(VInst);
if (!InsertResult.second)
continue;
// Add all operands to the worklists.
PHINode *PHI = dyn_cast<PHINode>(Inst);
if (PHI && PHI->getParent() == Stmt->getEntryBlock()) {
if (MemoryAccess *PHIRead = Stmt->lookupPHIReadOf(PHI))
WorklistAccs.push_back(PHIRead);
} else {
for (VirtualUse VUse : VInst.operands())
AddToWorklist(VUse);
}
// If there is an array access, also add its MemoryAccesses to the worklist.
const MemoryAccessList *Accs = Stmt->lookupArrayAccessesFor(Inst);
if (!Accs)
continue;
for (MemoryAccess *Acc : *Accs)
WorklistAccs.push_back(Acc);
}
}
void polly::markReachable(Scop *S, LoopInfo *LI,
DenseSet<VirtualInstruction> &UsedInsts,
DenseSet<MemoryAccess *> &UsedAccs,
ScopStmt *OnlyLocal) {
SmallVector<VirtualInstruction, 32> RootInsts;
SmallVector<MemoryAccess *, 32> RootAccs;
if (OnlyLocal) {
addRoots(OnlyLocal, RootInsts, RootAccs, true);
} else {
for (auto &Stmt : *S)
addRoots(&Stmt, RootInsts, RootAccs, false);
}
walkReachable(S, LI, RootInsts, RootAccs, UsedInsts, UsedAccs, OnlyLocal);
}