//===--- LSBase.h -----------------------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// /// /// This file defines LSBase, a class containing a SILValue base /// and a ProjectionPath. It is used as the base class for LSLocation and /// LSValue. /// /// In the case of LSLocation, the base represents the base of the allocated /// objects and the ProjectionPath tells which field in the object the /// LSLocation represents. /// /// In the case of LSValue, the base represents the root of loaded or stored /// value it represents. And the ProjectionPath represents the field in the /// loaded/store value the LSValue represents. /// //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_LSBASE_H #define SWIFT_SIL_LSBASE_H #include "swift/SIL/InstructionUtils.h" #include "swift/SIL/Projection.h" #include "swift/SILOptimizer/Analysis/AliasAnalysis.h" #include "swift/SILOptimizer/Analysis/EscapeAnalysis.h" #include "swift/SILOptimizer/Analysis/TypeExpansionAnalysis.h" #include "swift/SILOptimizer/Analysis/ValueTracking.h" #include "swift/SILOptimizer/Utils/Local.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Debug.h" #include namespace swift { class LSBase; class LSLocation; class LSValue; //===----------------------------------------------------------------------===// // Load Store Base //===----------------------------------------------------------------------===// class LSBase { public: enum KeyKind : uint8_t { Empty = 0, Tombstone, Normal }; protected: /// The base of the object. SILValue Base; /// Empty key, tombstone key or normal key. KeyKind Kind; /// The path to reach the accessed field of the object. Optional Path; public: /// Constructors. LSBase() : Base(), Kind(Normal) {} LSBase(KeyKind Kind) : Base(), Kind(Kind) {} LSBase(SILValue B) : Base(B), Kind(Normal) {} LSBase(SILValue B, const Optional &P, KeyKind Kind = Normal) : Base(B), Kind(Kind), Path(P) {} /// Virtual destructor. virtual ~LSBase() {} /// Copy constructor. LSBase(const LSBase &RHS) { Base = RHS.Base; Kind = RHS.Kind; Path = RHS.Path; } /// Assignment operator. LSBase &operator=(const LSBase &RHS) { Base = RHS.Base; Kind = RHS.Kind; Path = RHS.Path; return *this; } /// Getters for LSBase. KeyKind getKind() const { return Kind; } SILValue getBase() const { return Base; } const Optional &getPath() const { return Path; } /// Reset the LSBase, i.e. clear base and path. void reset() { Base = SILValue(); Kind = Normal; Path.reset(); } /// Returns whether the LSBase has been initialized properly. virtual bool isValid() const { return Base && Path.hasValue(); } /// Returns true if the LSBase has a non-empty projection path. bool hasEmptyProjectionPath() const { return !Path.getValue().size(); } /// return true if that the two objects have the same base but access different /// fields of the base object. bool hasNonEmptySymmetricPathDifference(const LSBase &RHS) const { const ProjectionPath &P = RHS.Path.getValue(); return Path.getValue().hasNonEmptySymmetricDifference(P); } /// Subtract the given path from the ProjectionPath. void removePathPrefix(Optional &P) { if (!P.hasValue()) return; // Remove prefix does not modify the Path in-place. Path = ProjectionPath::removePrefix(Path.getValue(), P.getValue()); } /// Return true if the RHS have identical projection paths. /// /// If both LSBase have empty paths, they are treated as having /// identical projection path. bool hasIdenticalProjectionPath(const LSBase &RHS) const { // If both Paths have no value, then the 2 LSBases are // different. if (!Path.hasValue() && !RHS.Path.hasValue()) return false; // If 1 Path has value while the other does not, then the 2 // LSBases are different. if (Path.hasValue() != RHS.Path.hasValue()) return false; // If both Paths are empty, then the 2 LSBases are the same. if (Path.getValue().empty() && RHS.Path.getValue().empty()) return true; // If both Paths have different values, then the 2 LSBases are // different. if (Path.getValue() != RHS.Path.getValue()) return false; // Otherwise, the 2 LSBases are the same. return true; } /// Comparisons. bool operator!=(const LSBase &RHS) const { return !(*this == RHS); } bool operator==(const LSBase &RHS) const { // If type is not the same, then LSBases different. if (Kind != RHS.Kind) return false; // Return true if this is a Tombstone or Empty. if (Kind == Empty || Kind == Tombstone) return true; // If Base is different, then LSBases different. if (Base != RHS.Base) return false; // If the projection paths are different, then LSBases are // different. if (!hasIdenticalProjectionPath(RHS)) return false; // These LSBases represent the same memory location. return true; } /// Print the LSBase. virtual void print(SILModule *Mod) { llvm::outs() << Base; Path.getValue().print(llvm::outs(), *Mod); } }; static inline llvm::hash_code hash_value(const LSBase &S) { const SILValue Base = S.getBase(); const Optional &Path = S.getPath(); llvm::hash_code HC = llvm::hash_combine(Base.getOpaqueValue()); if (!Path.hasValue()) return HC; return llvm::hash_combine(HC, hash_value(Path.getValue())); } //===----------------------------------------------------------------------===// // Load Store Value //===----------------------------------------------------------------------===// using LSLocationValueMap = llvm::DenseMap; using LSValueList = llvm::SmallVector; using LSValueIndexMap = llvm::SmallDenseMap; using ValueTableMap = llvm::SmallMapVector; /// A LSValue is an abstraction of an object field value in program. It /// consists of a base that is the tracked SILValue, and a projection path to /// the represented field. class LSValue : public LSBase { /// If this is a covering value, we need to go to each predecessor to /// materialize the value. bool CoveringValue; public: /// Constructors. LSValue() : LSBase(), CoveringValue(false) {} LSValue(KeyKind Kind) : LSBase(Kind), CoveringValue(false) {} LSValue(bool CSVal) : LSBase(Normal), CoveringValue(CSVal) {} LSValue(SILValue B, const ProjectionPath &P) : LSBase(B, P), CoveringValue(false) {} /// Copy constructor. LSValue(const LSValue &RHS) : LSBase(RHS) { CoveringValue = RHS.CoveringValue; } /// Assignment operator. LSValue &operator=(const LSValue &RHS) { LSBase::operator=(RHS); CoveringValue = RHS.CoveringValue; return *this; } /// Comparisons. bool operator!=(const LSValue &RHS) const { return !(*this == RHS); } bool operator==(const LSValue &RHS) const { if (CoveringValue && RHS.isCoveringValue()) return true; if (CoveringValue != RHS.isCoveringValue()) return false; return LSBase::operator==(RHS); } /// Returns whether the LSValue has been initialized properly. bool isValid() const { if (CoveringValue) return true; return LSBase::isValid(); } /// Take the last level projection off. Return the modified LSValue. LSValue &stripLastLevelProjection() { Path.getValue().pop_back(); return *this; } /// Returns true if this LSValue is a covering value. bool isCoveringValue() const { return CoveringValue; } /// Materialize the SILValue that this LSValue represents. /// /// In the case where we have a single value this can be materialized by /// applying Path to the Base. SILValue materialize(SILInstruction *Inst) { if (CoveringValue) return SILValue(); return Path.getValue().createExtract(Base, Inst, true); } void print(SILModule *Mod) { if (CoveringValue) { llvm::outs() << "Covering Value"; return; } LSBase::print(Mod); } /// Expand this SILValue to all individual fields it contains. static void expand(SILValue Base, SILModule *Mod, LSValueList &Vals, TypeExpansionAnalysis *TE); /// Given a memory location and a map between the expansions of the location /// and their corresponding values, try to come up with a single SILValue this /// location holds. This may involve extracting and aggregating available /// values. static void reduceInner(LSLocation &B, SILModule *M, LSLocationValueMap &Vals, SILInstruction *InsertPt); static SILValue reduce(LSLocation &B, SILModule *M, LSLocationValueMap &Vals, SILInstruction *InsertPt); }; static inline llvm::hash_code hash_value(const LSValue &V) { llvm::hash_code HC = llvm::hash_combine(V.isCoveringValue()); if (V.isCoveringValue()) return HC; return llvm::hash_combine(HC, hash_value((LSBase)V)); } //===----------------------------------------------------------------------===// // Load Store Location //===----------------------------------------------------------------------===// using LSLocationSet = llvm::DenseSet; using LSLocationList = llvm::SmallVector; using LSLocationIndexMap = llvm::SmallDenseMap; using LSLocationBaseMap = llvm::DenseMap; /// This class represents a field in an allocated object. It consists of a /// base that is the tracked SILValue, and a projection path to the /// represented field. class LSLocation : public LSBase { public: /// Constructors. LSLocation() {} LSLocation(SILValue B, const Optional &P, KeyKind K = Normal) : LSBase(B, P, K) {} LSLocation(KeyKind Kind) : LSBase(Kind) {} /// Use the concatenation of the 2 ProjectionPaths as the Path. LSLocation(SILValue B, const ProjectionPath &BP, const ProjectionPath &AP) : LSBase(B) { ProjectionPath P((*Base).getType()); P.append(BP); P.append(AP); Path = P; } /// Initialize a location with a new set of base, projectionpath and kind. void init(SILValue B, const Optional &P, KeyKind K= Normal) { Base = B; Path = P; Kind = K; } /// Copy constructor. LSLocation(const LSLocation &RHS) : LSBase(RHS) {} /// Assignment operator. LSLocation &operator=(const LSLocation &RHS) { LSBase::operator=(RHS); return *this; } /// Returns the type of the object the LSLocation represents. SILType getType(SILModule *M) { return Path.getValue().getMostDerivedType(*M); } /// Get the first level locations based on this location's first level /// projection. void getNextLevelLSLocations(LSLocationList &Locs, SILModule *Mod); /// Check whether the 2 LSLocations may alias each other or not. bool isMayAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA); /// Check whether the 2 LSLocations must alias each other or not. bool isMustAliasLSLocation(const LSLocation &RHS, AliasAnalysis *AA); /// Check whether the LSLocation can escape the current function. bool isNonEscapingLocalLSLocation(SILFunction *Fn, EscapeAnalysis *EA); /// Expand this location to all individual fields it contains. /// /// In SIL, we can have a store to an aggregate and loads from its individual /// fields. Therefore, we expand all the operations on aggregates onto /// individual fields and process them separately. static void expand(LSLocation Base, SILModule *Mod, LSLocationList &Locs, TypeExpansionAnalysis *TE); /// Given a set of locations derived from the same base, try to merge/reduce /// them into smallest number of LSLocations possible. static bool reduce(LSLocation Base, SILModule *Mod, LSLocationSet &Locs); /// Enumerate the given Mem LSLocation. static void enumerateLSLocation(SILModule *M, SILValue Mem, std::vector &LSLocationVault, LSLocationIndexMap &LocToBit, LSLocationBaseMap &BaseToLoc, TypeExpansionAnalysis *TE); /// Enumerate all the locations in the function. static void enumerateLSLocations(SILFunction &F, std::vector &LSLocationVault, LSLocationIndexMap &LocToBit, LSLocationBaseMap &BaseToLoc, TypeExpansionAnalysis *TE, std::pair &LSCount); }; static inline llvm::hash_code hash_value(const LSLocation &L) { return llvm::hash_combine(hash_value((LSBase)L)); } } // end swift namespace /// LSLocation and LSValue are used in DenseMap. namespace llvm { using swift::LSBase; using swift::LSLocation; using swift::LSValue; template <> struct DenseMapInfo { static inline LSValue getEmptyKey() { return LSValue(LSBase::Empty); } static inline LSValue getTombstoneKey() { return LSValue(LSBase::Tombstone); } static inline unsigned getHashValue(const LSValue &Val) { return hash_value(Val); } static bool isEqual(const LSValue &LHS, const LSValue &RHS) { return LHS == RHS; } }; template <> struct DenseMapInfo { static inline LSLocation getEmptyKey() { return LSLocation(LSBase::Empty); } static inline LSLocation getTombstoneKey() { return LSLocation(LSBase::Tombstone); } static inline unsigned getHashValue(const LSLocation &Loc) { return hash_value(Loc); } static bool isEqual(const LSLocation &LHS, const LSLocation &RHS) { return LHS == RHS; } }; } // namespace llvm #endif // SWIFT_SIL_LSBASE_H