| //===--- 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 <utility> |
| |
| 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<unsigned, 31>; |
| |
| const llvm::PointerUnion<ExplosionSchema *, BitSizeTy> 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<ExplosionSchema*>(); |
| } |
| |
| /// Invoke a functor for each element type in the schema. |
| template<typename TypeFn /* void(llvm::Type *schemaType) */> |
| void forEachType(IRGenModule &IGM, TypeFn &&fn) const { |
| // Follow an explosion schema if we have one. |
| if (auto *explosion = Value.dyn_cast<ExplosionSchema *>()) { |
| 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<BitSizeTy>(); |
| 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<llvm::BasicBlock*, 1, IsUnreachable_t>; |
| |
| /// 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<llvm::Value *, llvm::Type *>; |
| |
| mutable SmallVector<LazyValue, 2> 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<std::pair<APInt, llvm::BasicBlock*>> 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 |