//===--- GenOpaque.cpp - Swift IR-generation for opaque values ------------===// // // 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 implements IR generation for opaque values and value // witness operations. // // In the comments throughout this file, three type names are used: // 'B' is the type of a fixed-size buffer // 'T' is the type which implements a protocol // 'W' is the type of a witness to the protocol // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/DerivedTypes.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "ProtocolInfo.h" #include "ValueWitness.h" #include "GenOpaque.h" using namespace swift; using namespace irgen; /// A fixed-size buffer is always 16 bytes and pointer-aligned. /// If we align them more, we'll need to introduce padding to /// make protocol types work. Size irgen::getFixedBufferSize(IRGenModule &IGM) { return 3 * IGM.getPointerSize(); } Alignment irgen::getFixedBufferAlignment(IRGenModule &IGM) { return IGM.getPointerAlignment(); } /// Lazily create the standard fixed-buffer type. llvm::Type *IRGenModule::getFixedBufferTy() { if (FixedBufferTy) return FixedBufferTy; auto size = getFixedBufferSize(*this).getValue(); FixedBufferTy = llvm::ArrayType::get(Int8Ty, size); return FixedBufferTy; } static llvm::Type *createWitnessType(IRGenModule &IGM, ValueWitness index) { switch (index) { // void (*deallocateBuffer)(B *buffer, M *self); // void (*destroyBuffer)(B *buffer, M *self); case ValueWitness::DeallocateBuffer: case ValueWitness::DestroyBuffer: { llvm::Type *bufPtrTy = IGM.getFixedBufferTy()->getPointerTo(0); llvm::Type *args[] = { bufPtrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.VoidTy, args, /*isVarArg*/ false) ->getPointerTo(); } // void (*destroy)(T *object, witness_t *self); case ValueWitness::Destroy: { llvm::Type *args[] = { IGM.OpaquePtrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.VoidTy, args, /*isVarArg*/ false) ->getPointerTo(); } // void (*destroyArray)(T *object, size_t n, witness_t *self); case ValueWitness::DestroyArray: { llvm::Type *args[] = { IGM.OpaquePtrTy, IGM.SizeTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.VoidTy, args, /*isVarArg*/ false) ->getPointerTo(); } // T *(*initializeBufferWithCopyOfBuffer)(B *dest, B *src, M *self); // T *(*initializeBufferWithTakeOfBuffer)(B *dest, B *src, M *self); case ValueWitness::InitializeBufferWithCopyOfBuffer: case ValueWitness::InitializeBufferWithTakeOfBuffer: { llvm::Type *bufPtrTy = IGM.getFixedBufferTy()->getPointerTo(0); llvm::Type *args[] = { bufPtrTy, bufPtrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.OpaquePtrTy, args, /*isVarArg*/ false) ->getPointerTo(); } // T *(*allocateBuffer)(B *buffer, M *self); // T *(*projectBuffer)(B *buffer, M *self); case ValueWitness::AllocateBuffer: case ValueWitness::ProjectBuffer: { llvm::Type *bufPtrTy = IGM.getFixedBufferTy()->getPointerTo(0); llvm::Type *args[] = { bufPtrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.OpaquePtrTy, args, /*isVarArg*/ false) ->getPointerTo(); } // T *(*initializeBufferWithCopy)(B *dest, T *src, M *self); // T *(*initializeBufferWithTake)(B *dest, T *src, M *self); case ValueWitness::InitializeBufferWithCopy: case ValueWitness::InitializeBufferWithTake: { llvm::Type *bufPtrTy = IGM.getFixedBufferTy()->getPointerTo(0); llvm::Type *args[] = { bufPtrTy, IGM.OpaquePtrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(IGM.OpaquePtrTy, args, /*isVarArg*/ false) ->getPointerTo(); } // T *(*assignWithCopy)(T *dest, T *src, M *self); // T *(*assignWithTake)(T *dest, T *src, M *self); // T *(*initializeWithCopy)(T *dest, T *src, M *self); // T *(*initializeWithTake)(T *dest, T *src, M *self); case ValueWitness::AssignWithCopy: case ValueWitness::AssignWithTake: case ValueWitness::InitializeWithCopy: case ValueWitness::InitializeWithTake: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *args[] = { ptrTy, ptrTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(ptrTy, args, /*isVarArg*/ false) ->getPointerTo(); } // T *(*initializeArrayWithCopy)(T *dest, T *src, size_t n, M *self); // T *(*initializeArrayWithTakeFrontToBack)(T *dest, T *src, size_t n, M *self); // T *(*initializeArrayWithTakeBackToFront)(T *dest, T *src, size_t n, M *self); case ValueWitness::InitializeArrayWithCopy: case ValueWitness::InitializeArrayWithTakeFrontToBack: case ValueWitness::InitializeArrayWithTakeBackToFront: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *args[] = { ptrTy, ptrTy, IGM.SizeTy, IGM.TypeMetadataPtrTy }; return llvm::FunctionType::get(ptrTy, args, /*isVarArg*/ false) ->getPointerTo(); } /// void (*storeExtraInhabitant)(T *obj, unsigned index, M *self); case ValueWitness::StoreExtraInhabitant: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *indexTy = IGM.Int32Ty; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; llvm::Type *voidTy = IGM.VoidTy; llvm::Type *args[] = {ptrTy, indexTy, metaTy}; return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false) ->getPointerTo(); } /// int (*getExtraInhabitantIndex)(T *obj, M *self); case ValueWitness::GetExtraInhabitantIndex: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; llvm::Type *indexTy = IGM.Int32Ty; llvm::Type *args[] = {ptrTy, metaTy}; return llvm::FunctionType::get(indexTy, args, /*isVarArg*/ false) ->getPointerTo(); } /// int (*getEnumTag)(T *obj, M *self); case ValueWitness::GetEnumTag: { llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; llvm::Type *indexTy = IGM.Int32Ty; llvm::Type *args[] = {ptrTy, metaTy}; return llvm::FunctionType::get(indexTy, args, /*isVarArg*/ false) ->getPointerTo(); } /// void (*destructiveProjectEnumData)(T *obj, M *self); case ValueWitness::DestructiveProjectEnumData: { llvm::Type *voidTy = IGM.VoidTy; llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; llvm::Type *args[] = {ptrTy, metaTy}; return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false) ->getPointerTo(); } /// void (*destructiveInjectEnumTag)(T *obj, int tag, M *self); case ValueWitness::DestructiveInjectEnumTag: { llvm::Type *voidTy = IGM.VoidTy; llvm::Type *ptrTy = IGM.OpaquePtrTy; llvm::Type *indexTy = IGM.Int32Ty; llvm::Type *metaTy = IGM.TypeMetadataPtrTy; llvm::Type *args[] = {ptrTy, indexTy, metaTy}; return llvm::FunctionType::get(voidTy, args, /*isVarArg*/ false) ->getPointerTo(); } case ValueWitness::Size: case ValueWitness::Flags: case ValueWitness::Stride: case ValueWitness::ExtraInhabitantFlags: // Non-function witnesses all have type size_t. return IGM.SizeTy; } llvm_unreachable("bad value witness!"); } /// Return the cached pointer-to-function type for the given value /// witness index. llvm::Type *IRGenModule::getValueWitnessTy(ValueWitness index) { assert(unsigned(index) < MaxNumValueWitnesses); auto &ty = ValueWitnessTys[unsigned(index)]; if (ty) return ty; ty = createWitnessType(*this, index); return ty; } static StringRef getValueWitnessLabel(ValueWitness index) { switch (index) { case ValueWitness::DeallocateBuffer: return "deallocateBuffer"; case ValueWitness::DestroyBuffer: return "destroyBuffer"; case ValueWitness::Destroy: return "destroy"; case ValueWitness::InitializeBufferWithCopyOfBuffer: return "initializeBufferWithCopyOfBuffer"; case ValueWitness::AllocateBuffer: return "allocateBuffer"; case ValueWitness::ProjectBuffer: return "projectBuffer"; case ValueWitness::InitializeBufferWithCopy: return "initializeBufferWithCopy"; case ValueWitness::InitializeBufferWithTake: return "initializeBufferWithTake"; case ValueWitness::AssignWithCopy: return "assignWithCopy"; case ValueWitness::AssignWithTake: return "assignWithTake"; case ValueWitness::InitializeWithCopy: return "initializeWithCopy"; case ValueWitness::InitializeWithTake: return "initializeWithTake"; case ValueWitness::InitializeBufferWithTakeOfBuffer: return "initializeBufferWithTakeOfBuffer"; case ValueWitness::Size: return "size"; case ValueWitness::Flags: return "flags"; case ValueWitness::Stride: return "stride"; case ValueWitness::DestroyArray: return "destroyArray"; case ValueWitness::InitializeArrayWithCopy: return "initializeArrayWithCopy"; case ValueWitness::InitializeArrayWithTakeFrontToBack: return "initializeArrayWithTakeFrontToBack"; case ValueWitness::InitializeArrayWithTakeBackToFront: return "initializeArrayWithTakeBackToFront"; case ValueWitness::StoreExtraInhabitant: return "storeExtraInhabitant"; case ValueWitness::GetExtraInhabitantIndex: return "getExtraInhabitantIndex"; case ValueWitness::ExtraInhabitantFlags: return "extraInhabitantFlags"; case ValueWitness::GetEnumTag: return "getEnumTag"; case ValueWitness::DestructiveProjectEnumData: return "destructiveProjectEnumData"; case ValueWitness::DestructiveInjectEnumTag: return "destructiveInjectEnumTag"; } llvm_unreachable("bad value witness index"); } /// Load a specific witness from a known table. The result is /// always an i8*. llvm::Value *irgen::emitInvariantLoadOfOpaqueWitness(IRGenFunction &IGF, llvm::Value *table, WitnessIndex index) { assert(table->getType() == IGF.IGM.WitnessTablePtrTy); // GEP to the appropriate index, avoiding spurious IR in the trivial case. llvm::Value *slot = table; if (index.getValue() != 0) slot = IGF.Builder.CreateConstInBoundsGEP1_32( /*Ty=*/nullptr, table, index.getValue()); auto witness = IGF.Builder.CreateLoad(Address(slot, IGF.IGM.getPointerAlignment())); IGF.setInvariantLoad(witness); return witness; } /// Given a value witness table, load one of the value witnesses. /// The result has the appropriate type for the witness. static llvm::Value *emitLoadOfValueWitness(IRGenFunction &IGF, llvm::Value *table, ValueWitness index) { llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index); auto label = getValueWitnessLabel(index); auto type = IGF.IGM.getValueWitnessTy(index); if (isValueWitnessFunction(index)) { return IGF.Builder.CreateBitCast(witness, type, label); } else { return IGF.Builder.CreatePtrToInt(witness, type, label); } } /// Given a type metadata pointer, load one of the value witnesses from its /// value witness table. static llvm::Value *emitLoadOfValueWitnessFromMetadata(IRGenFunction &IGF, llvm::Value *metadata, ValueWitness index) { llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata); return emitLoadOfValueWitness(IGF, vwtable, index); } llvm::Value *IRGenFunction::emitValueWitness(CanType type, ValueWitness index) { if (auto witness = tryGetLocalTypeData(type, LocalTypeDataKind::forValueWitness(index))) return witness; auto vwtable = emitValueWitnessTableRef(type); auto witness = emitLoadOfValueWitness(*this, vwtable, index); setScopedLocalTypeData(type, LocalTypeDataKind::forValueWitness(index), witness); return witness; } llvm::Value *IRGenFunction::emitValueWitnessForLayout(SILType type, ValueWitness index) { if (auto witness = tryGetLocalTypeDataForLayout(type, LocalTypeDataKind::forValueWitness(index))) return witness; auto vwtable = emitValueWitnessTableRefForLayout(type); auto witness = emitLoadOfValueWitness(*this, vwtable, index); setScopedLocalTypeDataForLayout(type, LocalTypeDataKind::forValueWitness(index), witness); return witness; } /// Given a call to a helper function that produces a result /// into its first argument, set attributes appropriately. static void setHelperAttributesForAggResult(llvm::CallInst *call, bool isFormalResult = true) { // Set as nounwind. auto attrs = llvm::AttributeSet::get(call->getContext(), llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind); attrs = attrs.addAttribute(call->getContext(), 1, llvm::Attribute::NoAlias); // Only set 'sret' if this is also the formal result. if (isFormalResult) { attrs = attrs.addAttribute(call->getContext(), 1, llvm::Attribute::StructRet); } call->setAttributes(attrs); } /// Given a call to a helper function, set attributes appropriately. static void setHelperAttributes(llvm::CallInst *call) { // Set as nounwind. auto attrs = llvm::AttributeSet::get(call->getContext(), llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind); call->setAttributes(attrs); } /// Emit a call to do an 'initializeBufferWithCopyOfBuffer' operation. llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address destBuffer, Address srcBuffer) { llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::InitializeBufferWithCopyOfBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributesForAggResult(call, false); return call; } llvm::Value *irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, SILType T, Address destBuffer, Address srcBuffer) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithTakeOfBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); return call; } /// Emit a call to do an 'initializeBufferWithTakeOfBuffer' operation. llvm::Value *irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address destBuffer, Address srcBuffer) { llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::InitializeBufferWithTakeOfBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributesForAggResult(call, false); return call; } llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF, SILType T, Address destBuffer, Address srcBuffer) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithCopyOfBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destBuffer.getAddress(), srcBuffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); return call; } /// Emit a call to do an 'allocateBuffer' operation. llvm::Value *irgen::emitAllocateBufferCall(IRGenFunction &IGF, SILType T, Address buffer) { llvm::Value *metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *allocateFn = IGF.emitValueWitnessForLayout(T, ValueWitness::AllocateBuffer); llvm::CallInst *result = IGF.Builder.CreateCall(allocateFn, {buffer.getAddress(), metadata}); result->setCallingConv(IGF.IGM.DefaultCC); result->setDoesNotThrow(); return result; } /// Emit a call to do a 'projectBuffer' operation. llvm::Value *irgen::emitProjectBufferCall(IRGenFunction &IGF, SILType T, Address buffer) { llvm::Value *metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::ProjectBuffer); llvm::CallInst *result = IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); result->setCallingConv(IGF.IGM.DefaultCC); result->setDoesNotThrow(); return result; } /// Emit a call to do a 'projectBuffer' operation. llvm::Value *irgen::emitProjectBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address buffer) { llvm::Value *projectFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::ProjectBuffer); llvm::CallInst *result = IGF.Builder.CreateCall(projectFn, {buffer.getAddress(), metadata}); result->setCallingConv(IGF.IGM.DefaultCC); result->setDoesNotThrow(); return result; } /// Emit a call to do an 'initializeWithCopy' operation. void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeWithCopy); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } llvm::Value *irgen::emitInitializeBufferWithTakeCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithTake); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); return call; } llvm::Value *irgen::emitInitializeBufferWithCopyCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeBufferWithCopy); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); return call; } /// Emit a call to do an 'initializeArrayWithCopy' operation. void irgen::emitInitializeArrayWithCopyCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithCopy); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do an 'initializeWithTake' operation. void irgen::emitInitializeWithTakeCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeWithTake); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do an 'initializeArrayWithTakeFrontToBack' operation. void irgen::emitInitializeArrayWithTakeFrontToBackCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithTakeFrontToBack); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do an 'initializeArrayWithTakeBackToFront' operation. void irgen::emitInitializeArrayWithTakeBackToFrontCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::InitializeArrayWithTakeBackToFront); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do an 'assignWithCopy' operation. void irgen::emitAssignWithCopyCall(IRGenFunction &IGF, llvm::Value *metadata, Address destObject, Address srcObject) { llvm::Value *copyFn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::AssignWithCopy); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } void irgen::emitAssignWithCopyCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::AssignWithCopy); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do an 'assignWithTake' operation. void irgen::emitAssignWithTakeCall(IRGenFunction &IGF, SILType T, Address destObject, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *copyFn = IGF.emitValueWitnessForLayout(T, ValueWitness::AssignWithTake); llvm::CallInst *call = IGF.Builder.CreateCall(copyFn, {destObject.getAddress(), srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); call->setDoesNotThrow(); } /// Emit a call to do a 'destroy' operation. void irgen::emitDestroyCall(IRGenFunction &IGF, SILType T, Address object) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::Destroy); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {object.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Emit a call to do a 'destroyArray' operation. void irgen::emitDestroyArrayCall(IRGenFunction &IGF, SILType T, Address object, llvm::Value *count) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestroyArray); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {object.getAddress(), count, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Emit a call to do a 'destroyBuffer' operation. void irgen::emitDestroyBufferCall(IRGenFunction &IGF, SILType T, Address buffer) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestroyBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } void irgen::emitDestroyBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address buffer) { auto fn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::DestroyBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Emit a call to do a 'deallocateBuffer' operation. void irgen::emitDeallocateBufferCall(IRGenFunction &IGF, llvm::Value *metadata, Address buffer) { auto fn = emitLoadOfValueWitnessFromMetadata(IGF, metadata, ValueWitness::DeallocateBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } void irgen::emitDeallocateBufferCall(IRGenFunction &IGF, SILType T, Address buffer) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DeallocateBuffer); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {buffer.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Emit a call to the 'getExtraInhabitantIndex' operation. /// The type must be dynamically known to have extra inhabitant witnesses. llvm::Value *irgen::emitGetExtraInhabitantIndexCall(IRGenFunction &IGF, SILType T, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::GetExtraInhabitantIndex); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); return call; } /// Emit a call to the 'storeExtraInhabitant' operation. /// The type must be dynamically known to have extra inhabitant witnesses. llvm::Value *irgen::emitStoreExtraInhabitantCall(IRGenFunction &IGF, SILType T, llvm::Value *index, Address destObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::StoreExtraInhabitant); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {destObject.getAddress(), index, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); return call; } /// Emit a call to the 'getEnumTag' operation. llvm::Value *irgen::emitGetEnumTagCall(IRGenFunction &IGF, SILType T, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::GetEnumTag); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); return call; } /// Emit a call to the 'destructiveProjectEnumData' operation. /// The type must be dynamically known to have enum witnesses. void irgen::emitDestructiveProjectEnumDataCall(IRGenFunction &IGF, SILType T, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestructiveProjectEnumData); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Emit a call to the 'destructiveInjectEnumTag' operation. /// The type must be dynamically known to have enum witnesses. void irgen::emitDestructiveInjectEnumTagCall(IRGenFunction &IGF, SILType T, unsigned tag, Address srcObject) { auto metadata = IGF.emitTypeMetadataRefForLayout(T); llvm::Value *fn = IGF.emitValueWitnessForLayout(T, ValueWitness::DestructiveInjectEnumTag); llvm::Value *tagValue = llvm::ConstantInt::get(IGF.IGM.Int32Ty, tag); llvm::CallInst *call = IGF.Builder.CreateCall(fn, {srcObject.getAddress(), tagValue, metadata}); call->setCallingConv(IGF.IGM.DefaultCC); setHelperAttributes(call); } /// Load the 'size' value witness from the given table as a size_t. llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, SILType T) { return IGF.emitValueWitnessForLayout(T, ValueWitness::Size); } /// Load the 'alignmentMask' value witness from the given table as a size_t. llvm::Value *irgen::emitLoadOfAlignmentMask(IRGenFunction &IGF, SILType T) { auto flags = IGF.emitValueWitnessForLayout(T, ValueWitness::Flags); auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask)); return IGF.Builder.CreateAnd(flags, mask, flags->getName() + ".alignmentMask"); } /// Load the 'isPOD' valueWitness from the given table as an i1. llvm::Value *irgen::emitLoadOfIsPOD(IRGenFunction &IGF, SILType T) { auto flags = IGF.emitValueWitnessForLayout(T, ValueWitness::Flags); auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonPOD)); auto masked = IGF.Builder.CreateAnd(flags, mask); return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)), flags->getName() + ".isPOD"); } /// Load the 'isBitwiseTakable' valueWitness from the given table as an i1. llvm::Value *irgen::emitLoadOfIsBitwiseTakable(IRGenFunction &IGF, SILType T) { auto flags = IGF.emitValueWitnessForLayout(T, ValueWitness::Flags); auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonBitwiseTakable)); auto masked = IGF.Builder.CreateAnd(flags, mask); return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)), flags->getName() + ".isBitwiseTakable"); } /// Load the 'isInline' valueWitness from the given table as an i1. llvm::Value *irgen::emitLoadOfIsInline(IRGenFunction &IGF, SILType T) { auto flags = IGF.emitValueWitnessForLayout(T, ValueWitness::Flags); auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline)); auto masked = IGF.Builder.CreateAnd(flags, mask); return IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)), flags->getName() + ".isInline"); } /// Load the 'hasExtraInhabitants' valueWitness from the given table as an i1. llvm::Value *irgen::emitLoadOfHasExtraInhabitants(IRGenFunction &IGF, SILType T) { auto flags = IGF.emitValueWitnessForLayout(T, ValueWitness::Flags); auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::Enum_HasExtraInhabitants)); auto masked = IGF.Builder.CreateAnd(flags, mask); return IGF.Builder.CreateICmpNE(masked, IGF.IGM.getSize(Size(0)), flags->getName() + ".hasExtraInhabitants"); } /// Load the 'stride' value witness from the given table as a size_t. llvm::Value *irgen::emitLoadOfStride(IRGenFunction &IGF, SILType T) { return IGF.emitValueWitnessForLayout(T, ValueWitness::Stride); } llvm::Value *irgen::emitLoadOfExtraInhabitantCount(IRGenFunction &IGF, SILType T) { auto xiFlags = IGF.emitValueWitnessForLayout(T, ValueWitness::ExtraInhabitantFlags); auto mask = IGF.IGM.getSize( Size(ExtraInhabitantFlags::NumExtraInhabitantsMask)); return IGF.Builder.CreateAnd(xiFlags, mask, xiFlags->getName() + ".extraInhabitantCount"); }