blob: 1a3021a0f093b985ce3496829c4cc1b692fe0bc7 [file] [log] [blame]
//===--- DIMemoryUseCollector.h - Memory use information for DI -*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file declares logic used by definitive analysis related passes that look
// at all the instructions that access a memory object. This is quite specific
// to definitive analysis in that it is tuple element sensitive instead of
// relying on SROA.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILOPTIMIZER_MANDATORY_DIMEMORYUSECOLLECTOR_H
#define SWIFT_SILOPTIMIZER_MANDATORY_DIMEMORYUSECOLLECTOR_H
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/APInt.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILType.h"
namespace swift {
class SILBuilder;
/// DIMemoryObjectInfo - This struct holds information about the memory object
/// being analyzed that is required to correctly break it down into elements.
///
/// This includes a collection of utilities for reasoning about (potentially
/// recursively) exploded aggregate elements, and computing access paths and
/// indexes into the flattened namespace.
///
/// The flattened namespace is assigned lexicographically. For example, in:
/// (Int, ((Float, (), Double)))
/// the Int member is numbered 0, the Float is numbered 1, and the Double is
/// numbered 2. Empty tuples don't get numbered since they contain no state.
///
/// Structs and classes have their elements exploded when we are analyzing the
/// 'self' member in an initializer for the aggregate.
///
/// Derived classes have an additional field at the end that models whether or
/// not super.init() has been called or not.
class DIMemoryObjectInfo {
public:
/// This is the instruction that represents the memory. It is either an
/// allocation (alloc_box, alloc_stack) or a mark_uninitialized.
SingleValueInstruction *MemoryInst;
/// This is the base type of the memory allocation.
SILType MemorySILType;
/// True if the memory object being analyzed represents a 'let', which is
/// initialize-only (reassignments are not allowed).
bool IsLet = false;
/// This is the count of elements being analyzed. For memory objects that are
/// tuples, this is the flattened element count. For 'self' members in init
/// methods, this is the local field count (+1 for derive classes).
unsigned NumElements;
public:
DIMemoryObjectInfo(SingleValueInstruction *MemoryInst);
SILLocation getLoc() const { return MemoryInst->getLoc(); }
SILFunction &getFunction() const { return *MemoryInst->getFunction(); }
/// Return the first instruction of the function containing the memory object.
SILInstruction *getFunctionEntryPoint() const;
CanType getType() const {
return MemorySILType.getSwiftRValueType();
}
SingleValueInstruction *getAddress() const {
if (isa<AllocStackInst>(MemoryInst))
return MemoryInst;
assert(false);
return nullptr;
}
AllocBoxInst *getContainer() const {
return dyn_cast<AllocBoxInst>(MemoryInst);
}
/// getNumMemoryElements - Return the number of elements, without the extra
/// "super.init" tracker in initializers of derived classes.
unsigned getNumMemoryElements() const {
return NumElements - unsigned(false);
}
/// getElementType - Return the swift type of the specified element.
SILType getElementType(unsigned EltNo) const;
/// Push the symbolic path name to the specified element number onto the
/// specified std::string. If the actual decl (or a subelement thereof) can
/// be determined, return it. Otherwise, return null.
ValueDecl *getPathStringToElement(unsigned Element,
std::string &Result) const;
/// If the specified value is a 'let' property in an initializer, return true.
bool isElementLetProperty(unsigned Element) const;
};
enum DIUseKind {
/// The instruction is a Load.
Load,
/// The instruction is either an initialization or an assignment, we don't
/// know which. This classification only happens with values of trivial type
/// where the different isn't significant.
InitOrAssign,
/// The instruction is an initialization of the tuple element.
Initialization,
/// The instruction is an assignment, overwriting an already initialized
/// value.
Assign,
/// The instruction is a store to a member of a larger struct value.
PartialStore,
/// An indirect 'inout' parameter of an Apply instruction.
InOutUse,
/// An indirect 'in' parameter of an Apply instruction.
IndirectIn,
/// This instruction is a general escape of the value, e.g. a call to a
/// closure that captures it.
Escape,
/// This instruction is a call to 'super.init' in a 'self' initializer of a
/// derived class.
SuperInit,
/// This instruction is a call to 'self.init' in a delegating initializer.
SelfInit
};
/// This struct represents a single classified access to the memory object
/// being analyzed, along with classification information about the access.
struct DIMemoryUse {
/// This is the instruction accessing the memory.
SILInstruction *Inst;
/// This is what kind of access it is, load, store, escape, etc.
DIUseKind Kind;
/// For memory objects of (potentially recursive) tuple type, this keeps
/// track of which tuple elements are affected.
unsigned short FirstElement, NumElements;
DIMemoryUse(SILInstruction *Inst, DIUseKind Kind, unsigned FE, unsigned NE)
: Inst(Inst), Kind(Kind), FirstElement(FE), NumElements(NE) {
assert(FE == FirstElement && NumElements == NE &&
"more than 64K elements not supported yet");
}
DIMemoryUse() : Inst(nullptr) {}
bool isInvalid() const { return Inst == nullptr; }
bool isValid() const { return Inst != nullptr; }
bool usesElement(unsigned i) const {
return i >= FirstElement && i < static_cast<unsigned>(FirstElement+NumElements);
}
/// onlyTouchesTrivialElements - Return true if all of the accessed elements
/// have trivial type.
bool onlyTouchesTrivialElements(const DIMemoryObjectInfo &MemoryInfo) const;
/// getElementBitmask - Return a bitmask with the touched tuple elements
/// set.
APInt getElementBitmask(unsigned NumMemoryTupleElements) const {
return APInt::getBitsSet(NumMemoryTupleElements, FirstElement,
FirstElement+NumElements);
}
};
/// collectDIElementUsesFrom - Analyze all uses of the specified allocation
/// instruction (alloc_box, alloc_stack or mark_uninitialized), classifying them
/// and storing the information found into the Uses and Releases lists.
void collectDIElementUsesFrom(const DIMemoryObjectInfo &MemoryInfo,
SmallVectorImpl<DIMemoryUse> &Uses,
SmallVectorImpl<SILInstruction *> &Releases);
} // end namespace swift
#endif