mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
421 lines
14 KiB
C++
421 lines
14 KiB
C++
//===--- 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 <utility>
|
|
|
|
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<ProjectionPath> 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<ProjectionPath> &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<ProjectionPath> &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<ProjectionPath> &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<ProjectionPath> &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<LSLocation, LSValue>;
|
|
using LSValueList = llvm::SmallVector<LSValue, 8>;
|
|
using LSValueIndexMap = llvm::SmallDenseMap<LSValue, unsigned, 32>;
|
|
using ValueTableMap = llvm::SmallMapVector<unsigned, unsigned, 8>;
|
|
|
|
/// 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<LSLocation>;
|
|
using LSLocationList = llvm::SmallVector<LSLocation, 8>;
|
|
using LSLocationIndexMap = llvm::SmallDenseMap<LSLocation, unsigned, 32>;
|
|
using LSLocationBaseMap = llvm::DenseMap<SILValue, LSLocation>;
|
|
|
|
/// 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<ProjectionPath> &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<ProjectionPath> &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<LSLocation> &LSLocationVault,
|
|
LSLocationIndexMap &LocToBit,
|
|
LSLocationBaseMap &BaseToLoc,
|
|
TypeExpansionAnalysis *TE);
|
|
|
|
/// Enumerate all the locations in the function.
|
|
static void enumerateLSLocations(SILFunction &F,
|
|
std::vector<LSLocation> &LSLocationVault,
|
|
LSLocationIndexMap &LocToBit,
|
|
LSLocationBaseMap &BaseToLoc,
|
|
TypeExpansionAnalysis *TE,
|
|
std::pair<int, int> &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<LSValue> {
|
|
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<LSLocation> {
|
|
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
|