//===--- EnumPayload.h - Payload management for 'enum' Types ----*- 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_IRGEN_ENUMPAYLOAD_H #define SWIFT_IRGEN_ENUMPAYLOAD_H #include "IRGenModule.h" #include "Explosion.h" #include "TypeInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/PointerUnion.h" #include namespace swift { namespace irgen { /// A description of how to represent an enum payload as a value. /// A payload can either use a generic word-chunked representation, or attempt /// to follow the explosion schema of one of its payload types. class EnumPayloadSchema { using BitSizeTy = llvm::PointerEmbeddedInt; const llvm::PointerUnion Value; public: EnumPayloadSchema() : Value((ExplosionSchema *)nullptr) {} explicit operator bool() { return Value.getOpaqueValue() != nullptr; } explicit EnumPayloadSchema(unsigned bits) : Value(BitSizeTy(bits)) {} EnumPayloadSchema(ExplosionSchema &s) : Value(&s) {} static EnumPayloadSchema withBitSize(unsigned bits) { return EnumPayloadSchema(bits); } ExplosionSchema *getSchema() const { return Value.dyn_cast(); } /// Invoke a functor for each element type in the schema. template void forEachType(IRGenModule &IGM, TypeFn &&fn) const { // Follow an explosion schema if we have one. if (auto *explosion = Value.dyn_cast()) { for (auto &element : *explosion) { auto type = element.getScalarType(); assert(IGM.DataLayout.getTypeSizeInBits(type) == IGM.DataLayout.getTypeAllocSizeInBits(type) && "enum payload schema elements should use full alloc size"); (void) type; fn(element.getScalarType()); } return; } // Otherwise, chunk into pointer-sized integer values by default. unsigned bitSize = Value.get(); unsigned pointerSize = IGM.getPointerSize().getValueInBits(); while (bitSize >= pointerSize) { fn(IGM.SizeTy); bitSize -= pointerSize; } if (bitSize > 0) fn(llvm::IntegerType::get(IGM.getLLVMContext(), bitSize)); } }; /// Is a switch default destination unreachable? enum IsUnreachable_t: bool { IsNotUnreachable = false, IsUnreachable = true, }; using SwitchDefaultDest = llvm::PointerIntPair; /// An enum payload value. The payload is represented as an explosion of /// integers and pointers that together represent the bit pattern of /// the payload. class EnumPayload { public: /// A value, or the type of a zero value in the payload. using LazyValue = llvm::PointerUnion; mutable SmallVector PayloadValues; mutable llvm::Type *StorageType = nullptr; EnumPayload() = default; /// Generate a "zero" enum payload. static EnumPayload zero(IRGenModule &IGM, EnumPayloadSchema schema); /// Generate an enum payload containing the given bit pattern. static EnumPayload fromBitPattern(IRGenModule &IGM, APInt bitPattern, EnumPayloadSchema schema); /// Insert a value into the enum payload. /// /// The current payload value at the given offset is assumed to be zero. /// If \p numBitsUsedInValue is non-negative denotes the actual number of bits /// that need storing in \p value otherwise the full bit-width of \p value /// will be stored. void insertValue(IRGenFunction &IGF, llvm::Value *value, unsigned bitOffset, int numBitsUsedInValue = -1); /// Extract a value from the enum payload. llvm::Value *extractValue(IRGenFunction &IGF, llvm::Type *type, unsigned bitOffset) const; /// Take an enum payload out of an explosion. static EnumPayload fromExplosion(IRGenModule &IGM, Explosion &in, EnumPayloadSchema schema); /// Add the payload to an explosion. void explode(IRGenModule &IGM, Explosion &out) const; /// Pack into another enum payload. void packIntoEnumPayload(IRGenFunction &IGF, EnumPayload &dest, unsigned bitOffset) const; /// Unpack from another enum payload. static EnumPayload unpackFromEnumPayload(IRGenFunction &IGF, const EnumPayload &src, unsigned bitOffset, EnumPayloadSchema schema); /// Load an enum payload from memory. static EnumPayload load(IRGenFunction &IGF, Address address, EnumPayloadSchema schema); /// Store an enum payload to memory. void store(IRGenFunction &IGF, Address address) const; /// Emit a switch over specific bit patterns for the payload. /// The value will be tested as if AND-ed against the given mask. void emitSwitch(IRGenFunction &IGF, APInt mask, ArrayRef> cases, SwitchDefaultDest dflt) const; /// Emit an equality comparison operation that payload & mask == value. llvm::Value *emitCompare(IRGenFunction &IGF, APInt mask, APInt value) const; /// Apply an AND mask to the payload. void emitApplyAndMask(IRGenFunction &IGF, APInt mask); /// Apply an OR mask to the payload. void emitApplyOrMask(IRGenFunction &IGF, APInt mask); /// Apply an OR mask to the payload. void emitApplyOrMask(IRGenFunction &IGF, EnumPayload mask); /// Gather bits from an enum payload based on a spare bit mask. llvm::Value *emitGatherSpareBits(IRGenFunction &IGF, const SpareBitVector &spareBits, unsigned firstBitOffset, unsigned bitWidth) const; }; } } #endif