//===--- SILNode.h - Node base class for SIL --------------------*- 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 defines the SILNode class. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SILNODE_H #define SWIFT_SIL_SILNODE_H #include "llvm/Support/Compiler.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/SwiftObjectHeader.h" #include namespace swift { class SILBasicBlock; class SILFunction; class SILInstruction; class SingleValueInstruction; class NonSingleValueInstruction; class SILModule; class ValueBase; class SILNode; class SILValue; /// An enumeration which contains values for all the nodes in SILNodes.def. /// Other enumerators, like ValueKind and SILInstructionKind, ultimately /// take their values from this enumerator. enum class SILNodeKind { #define NODE(ID, PARENT) \ ID, #define NODE_RANGE(ID, FIRST, LAST) \ First_##ID = FIRST, \ Last_##ID = LAST, #include "swift/SIL/SILNodes.def" }; enum class SILInstructionKind : std::underlying_type::type; /// A SILNode pointer which makes it possible to implicitly cast from all kind /// of nodes, values and instructions (note: there is no implicit cast from /// SILInstruction* to SILNode*). /// It's mainly used to simplify classof-functions, but it can be used for other /// SILNode-taking APIs, too. /// Currently there is only a const-version of it. class SILNodePointer { const SILNode *node; public: SILNodePointer(const SILNode *node) : node(node) { } SILNodePointer(const SILInstruction *inst); SILNodePointer(const SingleValueInstruction *svi); SILNodePointer(const NonSingleValueInstruction *nsvi); SILNodePointer(SILValue value); const SILNode *get() const { return node; } const SILNode *operator->() const { return node; } operator const SILNode *() const { return node; } }; /// A SILNode is a node in the use-def graph of a SILFunction. It is /// either an instruction or a defined value which can be used by an /// instruction. A defined value may be an instruction result, a basic /// block argument, or the special 'undef' value. /// /// The 'node' intuition is slightly imprecise because a single instruction /// may be composed of multiple SILNodes: one for the instruction itself /// and one for each value it produces. When an instruction kind always /// produces exactly one value, the cast machinery (isa, cast, and dyn_cast) /// works to make both nodes appear to be the same object: there is a value /// kind exactly equal to the instruction kind and the value node can be /// directly cast to the instruction's class. When an instruction kind /// never produces values, it has no corresponding value kind, and it is /// a compile-time error to attempt to cast a value node to the instruction /// class. When an instruction kind can have multiple values (not yet /// implemented), its value nodes have a different kind from the /// instruction kind and it is a static error to attempt to cast a value /// node to the instruction kind. /// /// Another way of interpreting SILNode is that there is a SILNode for /// everything that can be numbered in SIL assembly (plus 'undef', which /// is not conventionally numbered). Instructions without results are /// still numbered in SIL in order to describe the users lists of an /// instruction or argument. Instructions with multiple results are /// numbered using their first result. /// /// SILNode is a base class of both SILInstruction and ValueBase. /// Because there can be multiple SILNodes within a single instruction /// object, some care must be taken when working with SILNode pointers. /// These precautions only apply to SILNode* and not its subclasses. /// /// - There may have multiple SILNode* values that refer to the same /// instruction. Data structures and algorithms that rely on uniqueness of a /// SILNode* should generally make sure that they're working with the /// representative SILNode*; see getRepresentativeSILNodeInObject(). /// /// - Do not use builtin C++ casts to downcast a SILNode*. A static_cast /// from SILNode* to SILInstruction* only works if the referenced /// SILNode is the base subobject of the object's SILInstruction /// subobject. If the SILNode is actually the base subobject of a /// ValueBase subobject, the cast will yield a corrupted value. /// Always use the LLVM casts (cast<>, dyn_cast<>, etc.) instead. class alignas(8) SILNode : // SILNode contains a swift object header for bridging with Swift. // For details see SwiftCompilerSources/README.md. public SwiftObjectHeader { public: enum { NumVOKindBits = 3 }; enum { NumStoreOwnershipQualifierBits = 2 }; enum { NumLoadOwnershipQualifierBits = 2 }; enum { NumAssignOwnershipQualifierBits = 2 }; enum { NumAssignByWrapperModeBits = 2 }; enum { NumSILAccessKindBits = 2 }; enum { NumSILAccessEnforcementBits = 3 }; enum { NumAllocRefTailTypesBits = 4 }; enum { NumMarkDependenceKindBits = 2 }; enum { numCustomBits = 20 }; constexpr static const uint64_t maxBitfieldID = std::numeric_limits::max() >> numCustomBits; protected: friend class SILInstruction; template friend class SILBitfield; static_assert((unsigned)SILNodeKind::Last_SILNode <= (unsigned)std::numeric_limits::max(), "too many SILNode kinds"); uint8_t kind; bool deleted = false; // Part of SILInstruction's debug location. Together with // `SILInstruction::locationStorage` this forms the SILLocation. uint8_t locationKindAndFlags; //===--------------------------------------------------------------------===// // MARK: Shared 8-bit and 32-bit fields // // Several instructions share the space for integer fields to reduce SIL // instruction memory. // // How to define a shared field in a SIL instruction class: // // * Decide whether to use an 8-bit (e.g. a boolean) or 32-bit integer. // * Add the `USE_SHARED_UINT8/32` or `TEMPLATE_USE_SHARED_UINT8/32` macros // to the instruction class. This is mainly used to check for accidental // overlaps of shared fields in base and derived classes. // * Use `SHARED_FIELD` or `SHARED_TEMPLATE_FIELD` below to add the field. // * In the instruction implementation use `sharedUInt8/32()` to access the // field. //===--------------------------------------------------------------------===// /// Adds a shared field for instruction class `I`. #define SHARED_FIELD(I, ...) \ class { friend class I; __VA_ARGS__; } I /// Adds a shared field for a template instruction class `I` which has a single /// template argument of type `T`. #define SHARED_TEMPLATE_FIELD(T, I, ...) \ class { template friend class I; __VA_ARGS__; } I #define SHARED_TEMPLATE2_FIELD(T1, T2, I, ...) \ class { \ template \ friend class I; \ __VA_ARGS__; \ } I /// Special case for `InstructionBaseWithTrailingOperands`. #define SHARED_TEMPLATE4_FIELD(T1, T2, T3, T4, I, ...) \ class { template friend class I; __VA_ARGS__; } I // clang-format off union SharedUInt8Fields { uint8_t opaque; SHARED_TEMPLATE_FIELD(typename, SwitchEnumInstBase, bool hasDefault); SHARED_TEMPLATE2_FIELD(typename, typename, SelectEnumInstBase, bool hasDefault); SHARED_TEMPLATE_FIELD(SILInstructionKind, LoadReferenceInstBase, bool isTake); SHARED_TEMPLATE_FIELD(SILInstructionKind, StoreReferenceInstBase, bool isInitializationOfDest); SHARED_FIELD(MultipleValueInstructionResult, uint8_t valueOwnershipKind); SHARED_FIELD(UncheckedOwnershipConversionInst, uint8_t valueOwnershipKind); SHARED_FIELD(StoreInst, uint8_t ownershipQualifier); SHARED_FIELD(LoadInst, uint8_t ownershipQualifier); SHARED_FIELD(AssignInst, uint8_t ownershipQualifier); SHARED_FIELD(AssignByWrapperInst, uint8_t mode); SHARED_FIELD(AssignOrInitInst, uint8_t mode); SHARED_FIELD(StringLiteralInst, uint8_t encoding); SHARED_FIELD(SwitchValueInst, bool hasDefault); SHARED_FIELD(RefCountingInst, bool atomicity); SHARED_FIELD(EndAccessInst, bool aborting); SHARED_FIELD(RefElementAddrInst, bool immutable); SHARED_FIELD(RefTailAddrInst, bool immutable); SHARED_FIELD(AddressToPointerInst, bool needsStackProtection); SHARED_FIELD(IndexAddrInst, bool needsStackProtection); SHARED_FIELD(HopToExecutorInst, bool mandatory); SHARED_FIELD(DestroyValueInst, uint8_t poisonRefs : 1, deadEnd : 1); SHARED_FIELD(EndCOWMutationInst, bool keepUnique); SHARED_FIELD(ConvertFunctionInst, bool withoutActuallyEscaping); SHARED_FIELD(BeginCOWMutationInst, bool native); SHARED_FIELD(GlobalValueInst, bool isBare); SHARED_FIELD(SILArgument, uint8_t valueOwnershipKind : NumVOKindBits, reborrow : 1, pointerEscape : 1); SHARED_FIELD(DebugValueInst, uint8_t poisonRefs : 1, usesMoveableValueDebugInfo : 1, trace : 1); SHARED_FIELD(AllocStackInst, uint8_t dynamicLifetime : 1, lexical : 1, fromVarDecl : 1, usesMoveableValueDebugInfo : 1, hasInvalidatedVarInfo : 1); SHARED_FIELD(AllocBoxInst, uint8_t dynamicLifetime : 1, reflection : 1, usesMoveableValueDebugInfo : 1, pointerEscape : 1); SHARED_FIELD(AllocRefInstBase, uint8_t objC : 1, onStack : 1, isBare : 1, // Only used in AllocRefInst numTailTypes: NumAllocRefTailTypesBits); SHARED_FIELD(BeginBorrowInst, uint8_t lexical : 1, pointerEscape : 1, fromVarDecl : 1, fixed : 1); SHARED_FIELD(DeallocBoxInst, uint8_t deadEnd : 1); SHARED_FIELD(CopyAddrInst, uint8_t isTakeOfSrc : 1, isInitializationOfDest : 1); SHARED_FIELD(ExplicitCopyAddrInst, uint8_t isTakeOfSrc : 1, isInitializationOfDest : 1); SHARED_FIELD(TupleAddrConstructorInst, uint8_t isInitializationOfDest : 1); SHARED_FIELD(PointerToAddressInst, uint8_t isStrict : 1, isInvariant : 1); SHARED_TEMPLATE_FIELD(typename, BeginAccessBase, uint8_t accessKind : NumSILAccessKindBits, enforcement : NumSILAccessEnforcementBits, noNestedConflict : 1, fromBuiltin : 1); SHARED_FIELD(EndUnpairedAccessInst, uint8_t enforcement : NumSILAccessEnforcementBits, aborting : 1, fromBuiltin : 1); SHARED_FIELD(MoveValueInst, uint8_t allowDiagnostics : 1, lexical : 1, pointerEscape : 1, fromVarDecl : 1); SHARED_TEMPLATE2_FIELD(SILInstructionKind, typename, MarkDependenceInstBase, uint8_t dependenceKind : NumMarkDependenceKindBits); // Do not use `_sharedUInt8_private` outside of SILNode. } _sharedUInt8_private; // clang-format on static_assert(sizeof(SharedUInt8Fields) == sizeof(uint8_t), "A SILNode's shared uint8 field is too large"); // clang-format off union SharedUInt32Fields { uint32_t opaque; SHARED_TEMPLATE4_FIELD(SILInstructionKind, typename, typename, typename..., InstructionBaseWithTrailingOperands, uint32_t numOperands); SHARED_TEMPLATE_FIELD(typename, FieldIndexCacheBase, uint32_t fieldIndex); SHARED_TEMPLATE_FIELD(typename, SwitchEnumInstBase, uint32_t numCases); SHARED_FIELD(AllocStackInst, uint32_t numOperands); SHARED_FIELD(EnumInst, uint32_t caseIndex); SHARED_FIELD(UncheckedEnumDataInst, uint32_t caseIndex); SHARED_FIELD(InjectEnumAddrInst, uint32_t caseIndex); SHARED_FIELD(InitEnumDataAddrInst, uint32_t caseIndex); SHARED_FIELD(UncheckedTakeEnumDataAddrInst, uint32_t caseIndex); SHARED_FIELD(TupleExtractInst, uint32_t fieldNo); SHARED_FIELD(TupleElementAddrInst, uint32_t fieldNo); SHARED_FIELD(MultipleValueInstructionResult, uint32_t index); SHARED_FIELD(IntegerLiteralInst, uint32_t numBits); SHARED_FIELD(FloatLiteralInst, uint32_t numBits); SHARED_FIELD(StringLiteralInst, uint32_t length); SHARED_FIELD(PointerToAddressInst, uint32_t alignment); SHARED_FIELD(SILFunctionArgument, uint32_t noImplicitCopy : 1, lifetimeAnnotation : 2, closureCapture : 1, parameterPack : 1); SHARED_FIELD(MergeRegionIsolationInst, uint32_t numOperands); // Do not use `_sharedUInt32_private` outside of SILNode. } _sharedUInt32_private; // clang-format on static_assert(sizeof(SharedUInt32Fields) == sizeof(uint32_t), "A SILNode's shared uint32 field is too large"); #undef SHARED_FIELD #undef SHARED_TEMPLATE_FIELD #undef SHARED_TEMPLATE4_FIELD // Used for checking field overlaps between super and derived classes. enum { SharedUInt8Used = 0 }; enum { SharedUInt32Used = 0 }; #define _USE_SHARED_UINT_BASE(T, SUPER) \ static_assert(SUPER == 0, \ "SILNode's shared " #T " already used in super class"); \ enum { Shared##T##Used = 1 }; \ SILNode::Shared##T##Fields &shared##T() { \ return SILNode::_shared##T##_private; \ } \ SILNode::Shared##T##Fields shared##T() const { \ return SILNode::_shared##T##_private; \ } /// To be used inside a SIL instruction/value class. It declares that the /// instruction/value uses the SILNode's shared uint8 field. #define USE_SHARED_UINT8 \ _USE_SHARED_UINT_BASE(UInt8, SharedUInt8Used) /// To be used inside a SIL instruction/value class. It declares that the /// instruction/value uses the SILNode's shared uint32 field. #define USE_SHARED_UINT32 \ _USE_SHARED_UINT_BASE(UInt32, SharedUInt32Used) /// To be used inside a template SILInstruction class. It declares that the /// instruction uses the SILNode's shared uint8 field. The `BASE` is the /// template argument which defines the super class of the instruction. #define TEMPLATE_USE_SHARED_UINT8(BASE) \ _USE_SHARED_UINT_BASE(UInt8, BASE::SharedUInt8Used) /// To be used inside a template SILInstruction class. It declares that the /// instruction uses the SILNode's shared uint32 field. The `BASE` is the /// template argument which defines the super class of the instruction. #define TEMPLATE_USE_SHARED_UINT32(BASE) \ _USE_SHARED_UINT_BASE(UInt32, BASE::SharedUInt32Used) //===---------------------- end of shared fields ------------------------===// // Used by `NodeBitfield`. uint64_t customBits : numCustomBits; /// The NodeBitfield ID of the last initialized bitfield in `customBits`. /// Example: /// /// Last initialized field: /// lastInitializedBitfieldID == C.bitfieldID /// | /// V /// customBits: EE DDD C BB AAA /// 31 ... 0 /// /// -> AAA, BB and C are initialized, /// DD and EEE are uninitialized /// /// The size of lastInitializedBitfieldID should be more than 32 bits to /// absolutely avoid an overflow. /// /// See also: SILBitfield::bitfieldID, SILFunction::currentBitfieldID. uint64_t lastInitializedBitfieldID : (64 - numCustomBits); private: SwiftMetatype getSILNodeMetatype(SILNodeKind kind); protected: SILNode(SILNodeKind kind) : SwiftObjectHeader(getSILNodeMetatype(kind)), kind((uint8_t)kind), customBits(0), lastInitializedBitfieldID(0) { _sharedUInt8_private.opaque = 0; _sharedUInt32_private.opaque = 0; } // Used by `NodeBitfield`. unsigned getCustomBits() const { return customBits; } // Used by `NodeBitfield`. void setCustomBits(unsigned value) { customBits = value; } public: LLVM_ATTRIBUTE_ALWAYS_INLINE SILNodeKind getKind() const { return SILNodeKind(kind); } /// If this is a SILArgument or a SILInstruction get its parent basic block, /// otherwise return null. SILBasicBlock *getParentBlock() const; /// Returns the parent function of this value. /// /// Only returns nullptr if the given value's parent is a sil global variable /// initializer. SILFunction *getFunction() const; /// Return the parent module of this value. SILModule *getModule() const; /// Pretty-print the node. If the node is an instruction, the output /// will be valid SIL assembly; otherwise, it will be an arbitrary /// format suitable for debugging. void print(raw_ostream &OS) const; void dump() const; /// Pretty-print the node in context, preceded by its operands (if the /// value represents the result of an instruction) and followed by its /// users. void printInContext(raw_ostream &OS) const; void dumpInContext() const; // Cast to SingleValueInstruction. This is an implementation detail // of the cast machinery. At a high level, all you need to know is to // never use static_cast to downcast a SILNode. SILInstruction *castToInstruction(); const SILInstruction *castToInstruction() const; // Called when transferring basic blocks from one function to another. void resetBitfields() { lastInitializedBitfieldID = 0; } void markAsDeleted() { deleted = true; } bool isMarkedAsDeleted() const { return deleted; } static SILNode *instAsNode(SILInstruction *inst); static const SILNode *instAsNode(const SILInstruction *inst); static bool classof(SILNodePointer node) { return true; } }; static_assert(sizeof(SILNode) <= 4 * sizeof(uint64_t), "SILNode must stay small"); inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SILNode &node) { node.print(OS); return OS; } // Simply do a pointer cast from a SILNode to a SILNode. This is always // possible, except the To-type is SILInstruction itself. template struct cast_from_SILNode { static To *doit(SILNode *node) { return &static_cast(*node); } }; // Handle the special case of casting a SILNode to SILInstruction itself. // This does not apply to sub-classes of SILInstruction, because all sub-classes // from SILInstructions are derived from SILNode. template <> struct cast_from_SILNode { static SILInstruction *doit(SILNode *node) { return &static_cast(*node->castToInstruction()); } }; template <> struct cast_from_SILNode { static const SILInstruction *doit(SILNode *node) { return &static_cast(*node->castToInstruction()); } }; template ::value> struct cast_from_SILInstruction; // Simply do a pointer cast from a SILInstruction to a SILInstruction. template struct cast_from_SILInstruction { static To *doit(SILInstruction *inst) { return &static_cast(*inst); } }; // Cast from a SILInstruction to a SILNode, which is not a SILInstruction. template struct cast_from_SILInstruction { static To *doit(SILInstruction *inst) { return &static_cast(*SILNode::instAsNode(inst)); } }; } // end namespace swift namespace llvm { /// Completely take over cast<>'ing from SILNode* and SILInstruction*. /// A static_cast to ValueBase* or SILInstruction* can be quite wrong. template struct cast_convert_val { using ret_type = typename cast_retty::ret_type; static ret_type doit(swift::SILNode *node) { return swift::cast_from_SILNode::doit(node); } }; template struct cast_convert_val { using ret_type = typename cast_retty::ret_type; static ret_type doit(const swift::SILNode *node) { return swift::cast_from_SILNode::doit(const_cast(node)); } }; template struct cast_convert_val { using ret_type = typename cast_retty::ret_type; static ret_type doit(swift::SILInstruction *inst) { return swift::cast_from_SILInstruction::doit(inst); } }; template struct cast_convert_val { using ret_type = typename cast_retty::ret_type; static ret_type doit(const swift::SILInstruction *inst) { return swift::cast_from_SILInstruction:: doit(const_cast(inst)); } }; // We don't support casting from SILNode references yet. template struct cast_convert_val; template struct cast_convert_val; /// ValueBase * is always at least eight-byte aligned; make the three tag bits /// available through PointerLikeTypeTraits. template<> struct PointerLikeTypeTraits { public: static inline void *getAsVoidPointer(swift::SILNode *I) { return (void*)I; } static inline swift::SILNode *getFromVoidPointer(void *P) { return (swift::SILNode *)P; } enum { NumLowBitsAvailable = 3 }; }; } // end namespace llvm #endif