Files
swift-mirror/lib/IRGen/GenOpaque.cpp
John McCall 1f3f33e67d Clean up the internal APIs around dynamic allocas to structurally
discourage accidental use of them.  Relatedly, fix several bugs
where we were accidentally using dynamic allocas.
2017-12-19 00:29:43 -05:00

1224 lines
50 KiB
C++

//===--- GenOpaque.cpp - Swift IR-generation for opaque values ------------===//
//
// 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 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 "swift/AST/IRGenOptions.h"
#include "swift/IRGen/ValueWitness.h"
#include "Callee.h"
#include "FixedTypeInfo.h"
#include "IRGenFunction.h"
#include "IRGenModule.h"
#include "ProtocolInfo.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 (*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);
}
// 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);
}
// 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);
}
/// 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);
}
/// 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);
}
/// 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);
}
/// 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);
}
/// 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);
}
/// int (*getEnumTagSinglePayload)(const T* enum, UINT_TYPE emptyCases,
/// M *self)
case ValueWitness::GetEnumTagSinglePayload: {
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(indexTy, args, false);
}
/// void (*storeEnumTagSinglePayload)(T* enum, INT_TYPE whichCase,
/// UINT_TYPE emptyCases,
/// M *self)
case ValueWitness::StoreEnumTagSinglePayload: {
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, indexTy, metaTy };
return llvm::FunctionType::get(voidTy, args, false);
}
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!");
}
static llvm::AttributeList getValueWitnessAttrs(IRGenModule &IGM,
ValueWitness index) {
assert(isValueWitnessFunction(index));
auto &ctx = IGM.getLLVMContext();
// All value witnesses are nounwind.
auto attrs = llvm::AttributeList::get(ctx, llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoUnwind);
switch (index) {
// These have two arguments, but they can alias.
case ValueWitness::AssignWithCopy:
return attrs;
// These have one argument.
case ValueWitness::Destroy:
case ValueWitness::DestructiveInjectEnumTag:
case ValueWitness::DestructiveProjectEnumData:
case ValueWitness::GetEnumTag:
case ValueWitness::GetExtraInhabitantIndex:
case ValueWitness::StoreExtraInhabitant:
case ValueWitness::StoreEnumTagSinglePayload:
return attrs.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
case ValueWitness::GetEnumTagSinglePayload:
return attrs
.addAttribute(ctx, llvm::AttributeList::FunctionIndex,
llvm::Attribute::ReadOnly)
.addAttribute(ctx, 1, llvm::Attribute::NoAlias);
// These have two arguments and they don't alias each other.
case ValueWitness::AssignWithTake:
case ValueWitness::InitializeBufferWithCopyOfBuffer:
case ValueWitness::InitializeBufferWithTakeOfBuffer:
case ValueWitness::InitializeWithCopy:
case ValueWitness::InitializeWithTake:
return attrs.addAttribute(ctx, 1, llvm::Attribute::NoAlias)
.addAttribute(ctx, 2, llvm::Attribute::NoAlias);
case ValueWitness::Size:
case ValueWitness::Flags:
case ValueWitness::Stride:
case ValueWitness::ExtraInhabitantFlags:
llvm_unreachable("not a function value witness");
}
llvm_unreachable("bad 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;
}
Signature IRGenModule::getValueWitnessSignature(ValueWitness index) {
assert(isValueWitnessFunction(index));
auto fnTy = cast<llvm::FunctionType>(getValueWitnessTy(index));
auto attrs = getValueWitnessAttrs(*this, index);
return Signature(fnTy, attrs, DefaultCC);
}
static StringRef getValueWitnessLabel(ValueWitness index) {
switch (index) {
case ValueWitness::Destroy:
return "destroy";
case ValueWitness::InitializeBufferWithCopyOfBuffer:
return "initializeBufferWithCopyOfBuffer";
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::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";
case ValueWitness::GetEnumTagSinglePayload:
return "getEnumTagSinglePayload";
case ValueWitness::StoreEnumTagSinglePayload:
return "storeEnumTagSinglePayload";
}
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 *emitLoadOfValueWitnessValue(IRGenFunction &IGF,
llvm::Value *table,
ValueWitness index) {
assert(!isValueWitnessFunction(index));
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
auto label = getValueWitnessLabel(index);
auto type = IGF.IGM.getValueWitnessTy(index);
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 *
emitLoadOfValueWitnessValueFromMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
ValueWitness index) {
llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata);
return emitLoadOfValueWitnessValue(IGF, vwtable, index);
}
/// Given a value witness table, load one of the value witnesses.
/// The result has the appropriate type for the witness.
static FunctionPointer emitLoadOfValueWitnessFunction(IRGenFunction &IGF,
llvm::Value *table,
ValueWitness index) {
assert(isValueWitnessFunction(index));
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, table, index);
auto label = getValueWitnessLabel(index);
auto signature = IGF.IGM.getValueWitnessSignature(index);
auto type = signature.getType()->getPointerTo();
witness = IGF.Builder.CreateBitCast(witness, type, label);
return FunctionPointer(witness, signature);
}
/// Given a type metadata pointer, load one of the function
/// value witnesses from its value witness table.
static FunctionPointer
emitLoadOfValueWitnessFunctionFromMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
ValueWitness index) {
llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata);
return emitLoadOfValueWitnessFunction(IGF, vwtable, index);
}
llvm::Value * IRGenFunction::emitValueWitnessValue(SILType type,
ValueWitness index) {
assert(!isValueWitnessFunction(index));
if (auto witness = tryGetLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitness(index))) {
return witness;
}
auto vwtable = emitValueWitnessTableRef(type);
auto witness = emitLoadOfValueWitnessValue(*this, vwtable, index);
setScopedLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitness(index),
witness);
return witness;
}
FunctionPointer
IRGenFunction::emitValueWitnessFunctionRef(SILType type,
llvm::Value *&metadataSlot,
ValueWitness index) {
assert(isValueWitnessFunction(index));
if (auto witness = tryGetLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitness(index))) {
metadataSlot = emitTypeMetadataRefForLayout(type);
auto signature = IGM.getValueWitnessSignature(index);
return FunctionPointer(witness, signature);
}
auto vwtable = emitValueWitnessTableRef(type, &metadataSlot);
auto witness = emitLoadOfValueWitnessFunction(*this, vwtable, index);
setScopedLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitness(index),
witness.getPointer());
return witness;
}
llvm::Value *irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF,
SILType T,
Address destBuffer,
Address srcBuffer) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
return emitInitializeBufferWithCopyOfBufferCall(IGF, metadata,
destBuffer, srcBuffer);
}
/// Emit a call to do an 'initializeBufferWithCopyOfBuffer' operation.
llvm::Value *
irgen::emitInitializeBufferWithCopyOfBufferCall(IRGenFunction &IGF,
llvm::Value *metadata,
Address destBuffer,
Address srcBuffer) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::InitializeBufferWithCopyOfBuffer);
llvm::CallInst *call =
IGF.Builder.CreateCall(copyFn,
{destBuffer.getAddress(), srcBuffer.getAddress(), metadata});
return call;
}
llvm::Value *
irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF,
SILType T,
Address destBuffer,
Address srcBuffer) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
return emitInitializeBufferWithTakeOfBufferCall(IGF, metadata,
destBuffer, srcBuffer);
}
/// Emit a call to do an 'initializeBufferWithTakeOfBuffer' operation.
llvm::Value *
irgen::emitInitializeBufferWithTakeOfBufferCall(IRGenFunction &IGF,
llvm::Value *metadata,
Address destBuffer,
Address srcBuffer) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::InitializeBufferWithTakeOfBuffer);
llvm::CallInst *call =
IGF.Builder.CreateCall(copyFn,
{destBuffer.getAddress(), srcBuffer.getAddress(), metadata});
return call;
}
/// Emit a dynamic alloca call to allocate enough memory to hold an object of
/// type 'T' and an optional llvm.stackrestore point if 'isInEntryBlock' is
/// false.
StackAddress IRGenFunction::emitDynamicAlloca(SILType T,
const llvm::Twine &name) {
llvm::Value *size = emitLoadOfSize(*this, T);
return emitDynamicAlloca(IGM.Int8Ty, size, Alignment(16), name);
}
StackAddress IRGenFunction::emitDynamicAlloca(llvm::Type *eltTy,
llvm::Value *arraySize,
Alignment align,
const llvm::Twine &name) {
llvm::Value *stackRestorePoint = nullptr;
// Save the stack pointer if we are not in the entry block (we could be
// executed more than once).
bool isInEntryBlock = (Builder.GetInsertBlock() == &*CurFn->begin());
if (!isInEntryBlock) {
auto *stackSaveFn = llvm::Intrinsic::getDeclaration(
&IGM.Module, llvm::Intrinsic::ID::stacksave);
stackRestorePoint = Builder.CreateCall(stackSaveFn, {}, "spsave");
}
// Emit the dynamic alloca.
auto *alloca = Builder.IRBuilderBase::CreateAlloca(eltTy, arraySize, name);
alloca->setAlignment(align.getValue());
assert(!isInEntryBlock ||
getActiveDominancePoint().isUniversal() &&
"Must be in entry block if we insert dynamic alloca's without "
"stackrestores");
return {Address(alloca, align), stackRestorePoint};
}
/// Deallocate dynamic alloca's memory if requested by restoring the stack
/// location before the dynamic alloca's call.
void IRGenFunction::emitDeallocateDynamicAlloca(StackAddress address) {
if (!address.needsSPRestore())
return;
auto *stackRestoreFn = llvm::Intrinsic::getDeclaration(
&IGM.Module, llvm::Intrinsic::ID::stackrestore);
Builder.CreateCall(stackRestoreFn, address.getSavedSP());
}
/// 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);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithCopyFn(),
{dest, src, count, metadata});
}
/// Emit a call to do an 'initializeArrayWithTakeNoAlias' operation.
void irgen::emitInitializeArrayWithTakeNoAliasCall(IRGenFunction &IGF,
SILType T,
Address destObject,
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeNoAliasFn(),
{dest, src, count, metadata});
}
/// 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);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeFrontToBackFn(),
{dest, src, count, metadata});
}
/// 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);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayInitWithTakeBackToFrontFn(),
{dest, src, count, metadata});
}
/// Emit a call to do an 'assignWithCopy' operation.
void irgen::emitAssignWithCopyCall(IRGenFunction &IGF,
SILType T,
Address destObject,
Address srcObject) {
llvm::Value *metadata;
auto copyFn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::AssignWithCopy);
IGF.Builder.CreateCall(copyFn,
{destObject.getAddress(), srcObject.getAddress(), metadata});
}
/// Emit a call to do an 'assignWithCopy' operation.
void irgen::emitAssignWithCopyCall(IRGenFunction &IGF,
llvm::Value *metadata,
Address destObject,
Address srcObject) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::AssignWithCopy);
IGF.Builder.CreateCall(copyFn,
{destObject.getAddress(), srcObject.getAddress(), metadata});
}
/// Emit a call to do an 'arrayAssignWithCopyNoAlias' operation.
void irgen::emitAssignArrayWithCopyNoAliasCall(IRGenFunction &IGF, SILType T,
Address destObject, Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyNoAliasFn(),
{dest, src, count, metadata});
}
/// Emit a call to do an 'arrayAssignWithCopyFrontToBack' operation.
void irgen::emitAssignArrayWithCopyFrontToBackCall(IRGenFunction &IGF,
SILType T,
Address destObject,
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyFrontToBackFn(),
{dest, src, count, metadata});
}
/// Emit a call to do an 'arrayAssignWithCopyBackToFront' operation.
void irgen::emitAssignArrayWithCopyBackToFrontCall(IRGenFunction &IGF,
SILType T,
Address destObject,
Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithCopyBackToFrontFn(),
{dest, src, count, metadata});
}
/// Emit a call to do an 'assignWithTake' operation.
void irgen::emitAssignWithTakeCall(IRGenFunction &IGF,
SILType T,
Address destObject,
Address srcObject) {
llvm::Value *metadata;
auto copyFn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::AssignWithTake);
IGF.Builder.CreateCall(copyFn,
{destObject.getAddress(), srcObject.getAddress(), metadata});
}
/// Emit a call to do an 'arrayAssignWithTake' operation.
void irgen::emitAssignArrayWithTakeCall(IRGenFunction &IGF, SILType T,
Address destObject, Address srcObject,
llvm::Value *count) {
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto dest =
IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy);
auto src =
IGF.Builder.CreateBitCast(srcObject.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayAssignWithTakeFn(),
{dest, src, count, metadata});
}
/// Emit a call to do a 'destroyArray' operation.
void irgen::emitDestroyArrayCall(IRGenFunction &IGF,
SILType T,
Address object,
llvm::Value *count) {
// If T is a trivial/POD type, nothing needs to be done.
if (T.getObjectType().isTrivial(IGF.getSILModule()))
return;
auto metadata = IGF.emitTypeMetadataRefForLayout(T);
auto obj =
IGF.Builder.CreateBitCast(object.getAddress(), IGF.IGM.OpaquePtrTy);
IGF.Builder.CreateCall(IGF.IGM.getArrayDestroyFn(), {obj, count, metadata});
}
/// 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) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::GetExtraInhabitantIndex);
llvm::CallInst *call =
IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
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) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::StoreExtraInhabitant);
llvm::CallInst *call =
IGF.Builder.CreateCall(fn, {destObject.getAddress(), index, metadata});
return call;
}
/// Emit a trampoline to call the getEnumTagSinglePayload witness. API:
/// INT_TYPE (const T* enum, UINT_TYPE emptyCases, M *self)
static llvm::Constant *
getGetEnumTagSinglePayloadTrampolineFn(IRGenModule &IGM) {
llvm::Type *argTys[] = {IGM.OpaquePtrTy, IGM.Int32Ty, IGM.TypeMetadataPtrTy};
llvm::SmallString<40> fnName("__swift_getEnumTagSinglePayload");
auto func = IGM.getOrCreateHelperFunction(
fnName, IGM.Int32Ty, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
auto *enumAddr = &*(it++);
auto *numEmptyCases = &*(it++);
auto *metadata = &*(it++);
auto &Builder = IGF.Builder;
auto witnessFunc = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::GetEnumTagSinglePayload);
auto *result = Builder.CreateCall(witnessFunc,
{enumAddr, numEmptyCases, metadata});
Builder.CreateRet(result);
},
true /*noinline*/);
// This function is readonly.
cast<llvm::Function>(func)->addFnAttr(llvm::Attribute::ReadOnly);
return func;
}
/// Emit a trampoline to call the storeEnumTagSinglePayload witness. API:
/// VOID_TYPE (const T* enum, INT_TYPE whichCase, UINT_TYPE emptyCases,
/// M *self)
static llvm::Constant *
getStoreEnumTagSinglePayloadTrampolineFn(IRGenModule &IGM) {
llvm::Type *argTys[] = {IGM.OpaquePtrTy, IGM.Int32Ty, IGM.Int32Ty,
IGM.TypeMetadataPtrTy};
llvm::SmallString<40> fnName("__swift_storeEnumTagSinglePayload");
return IGM.getOrCreateHelperFunction(
fnName, IGM.VoidTy, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
auto *enumAddr = &*(it++);
auto *whichCase = &*(it++);
auto *numEmptyCases = &*(it++);
auto *metadata = &*(it++);
auto &Builder = IGF.Builder;
auto witnessFunc = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::StoreEnumTagSinglePayload);
Builder.CreateCall(witnessFunc,
{enumAddr, whichCase, numEmptyCases, metadata});
Builder.CreateRetVoid();
},
true /*noinline*/);
}
llvm::Value *irgen::emitGetEnumTagSinglePayloadCall(IRGenFunction &IGF,
SILType T,
llvm::Value *numEmptyCases,
Address destObject) {
if (!IGF.optimizeForSize()) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(
T, metadata, ValueWitness::GetEnumTagSinglePayload);
llvm::CallInst *call = IGF.Builder.CreateCall(
fn, {destObject.getAddress(), numEmptyCases, metadata});
return call;
}
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
auto *func = getGetEnumTagSinglePayloadTrampolineFn(IGF.IGM);
auto *result = IGF.Builder.CreateCall(
func,
{IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
numEmptyCases, metadata});
return result;
}
llvm::Value *irgen::emitStoreEnumTagSinglePayloadCall(
IRGenFunction &IGF, SILType T, llvm::Value *whichCase,
llvm::Value *numEmptyCases, Address destObject) {
if (!IGF.optimizeForSize()) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(
T, metadata, ValueWitness::StoreEnumTagSinglePayload);
llvm::CallInst *call = IGF.Builder.CreateCall(
fn, {destObject.getAddress(), whichCase, numEmptyCases, metadata});
return call;
}
auto *metadata = IGF.emitTypeMetadataRefForLayout(T);
auto *func = getStoreEnumTagSinglePayloadTrampolineFn(IGF.IGM);
auto *result = IGF.Builder.CreateCall(
func,
{IGF.Builder.CreateBitCast(destObject.getAddress(), IGF.IGM.OpaquePtrTy),
whichCase, numEmptyCases, metadata});
return result;
}
/// Emit a call to the 'getEnumTag' operation.
llvm::Value *irgen::emitGetEnumTagCall(IRGenFunction &IGF,
SILType T,
Address srcObject) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::GetEnumTag);
llvm::CallInst *call =
IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
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) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::DestructiveProjectEnumData);
IGF.Builder.CreateCall(fn, {srcObject.getAddress(), metadata});
}
/// 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) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::DestructiveInjectEnumTag);
llvm::Value *tagValue =
llvm::ConstantInt::get(IGF.IGM.Int32Ty, tag);
IGF.Builder.CreateCall(fn, {srcObject.getAddress(), tagValue, metadata});
}
/// Load the 'size' value witness from the given table as a size_t.
llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, SILType T) {
return IGF.emitValueWitnessValue(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.emitValueWitnessValue(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.emitValueWitnessValue(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.emitValueWitnessValue(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.emitValueWitnessValue(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.emitValueWitnessValue(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.emitValueWitnessValue(T, ValueWitness::Stride);
}
llvm::Value *irgen::emitLoadOfExtraInhabitantCount(IRGenFunction &IGF,
SILType T) {
auto xiFlags =
IGF.emitValueWitnessValue(T, ValueWitness::ExtraInhabitantFlags);
auto mask = IGF.IGM.getSize(
Size(ExtraInhabitantFlags::NumExtraInhabitantsMask));
return IGF.Builder.CreateAnd(xiFlags, mask,
xiFlags->getName() + ".extraInhabitantCount");
}
std::pair<llvm::Value *, llvm::Value *>
irgen::emitLoadOfIsInline(IRGenFunction &IGF, llvm::Value *metadata) {
auto *flags = emitLoadOfValueWitnessValueFromMetadata(IGF, metadata,
ValueWitness::Flags);
auto mask = IGF.IGM.getSize(Size(ValueWitnessFlags::IsNonInline));
auto masked = IGF.Builder.CreateAnd(flags, mask);
return std::make_pair(
IGF.Builder.CreateICmpEQ(masked, IGF.IGM.getSize(Size(0)),
flags->getName() + ".isInline"),
flags);
}
llvm::Value *irgen::emitLoadOfSize(IRGenFunction &IGF, llvm::Value *metadata) {
auto *size = emitLoadOfValueWitnessValueFromMetadata(IGF, metadata,
ValueWitness::Size);
return size;
}
llvm::Value *irgen::emitAlignMaskFromFlags(IRGenFunction &IGF,
llvm::Value *flags) {
auto *alignMask = IGF.IGM.getSize(Size(ValueWitnessFlags::AlignmentMask));
return IGF.Builder.CreateAnd(flags, alignMask,
flags->getName() + ".alignmentMask");
}
/// Emit a call to do an 'initializeWithCopy' operation.
void irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithCopy);
IGF.Builder.CreateCall(fn, {dest.getAddress(), src.getAddress(), metadata});
}
llvm::Value *irgen::emitInitializeWithCopyCall(IRGenFunction &IGF,
llvm::Value *metadata,
Address dest, Address src) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::InitializeWithCopy);
llvm::CallInst *call = IGF.Builder.CreateCall(
copyFn, {dest.getAddress(), src.getAddress(), metadata});
return call;
}
/// Emit a call to do an 'initializeWithTake' operation.
void irgen::emitInitializeWithTakeCall(IRGenFunction &IGF,
SILType T,
Address dest,
Address src) {
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::InitializeWithTake);
IGF.Builder.CreateCall(fn, {dest.getAddress(), src.getAddress(), metadata});
}
llvm::Value *irgen::emitInitializeWithTakeCall(IRGenFunction &IGF,
llvm::Value *metadata,
Address dest, Address src) {
auto copyFn = emitLoadOfValueWitnessFunctionFromMetadata(
IGF, metadata, ValueWitness::InitializeWithTake);
llvm::CallInst *call = IGF.Builder.CreateCall(
copyFn, {dest.getAddress(), src.getAddress(), metadata});
return call;
}
/// Emit a call to do a 'destroy' operation.
void irgen::emitDestroyCall(IRGenFunction &IGF,
SILType T,
Address object) {
// If T is a trivial/POD type, nothing needs to be done.
if (T.getObjectType().isTrivial(IGF.getSILModule()))
return;
llvm::Value *metadata;
auto fn = IGF.emitValueWitnessFunctionRef(T, metadata,
ValueWitness::Destroy);
IGF.Builder.CreateCall(fn, {object.getAddress(), metadata});
}
void irgen::emitDestroyCall(IRGenFunction &IGF, llvm::Value *metadata,
Address object) {
auto fn = emitLoadOfValueWitnessFunctionFromMetadata(IGF, metadata,
ValueWitness::Destroy);
IGF.Builder.CreateCall(fn, {object.getAddress(), metadata});
}
static llvm::Constant *getAllocateValueBufferFunction(IRGenModule &IGM) {
llvm::Type *argTys[] = {IGM.TypeMetadataPtrTy, IGM.OpaquePtrTy};
llvm::SmallString<40> fnName("__swift_allocate_value_buffer");
return IGM.getOrCreateHelperFunction(
fnName, IGM.OpaquePtrTy, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
auto *metadata = &*(it++);
auto buffer = Address(&*(it++), Alignment(1));
// Dynamically check whether this type is inline or needs an allocation.
llvm::Value *isInline, *flags;
std::tie(isInline, flags) = emitLoadOfIsInline(IGF, metadata);
auto *outlineBB = IGF.createBasicBlock("outline.allocateValueInBuffer");
auto *doneBB = IGF.createBasicBlock("done");
llvm::Value *addressInline, *addressOutline;
addressInline = buffer.getAddress();
auto *origBB = IGF.Builder.GetInsertBlock();
IGF.Builder.CreateCondBr(isInline, doneBB, outlineBB);
IGF.Builder.emitBlock(outlineBB);
{
auto *size = emitLoadOfSize(IGF, metadata);
auto *alignMask = emitAlignMaskFromFlags(IGF, flags);
auto valueAddr =
IGF.emitAllocRawCall(size, alignMask, "outline.ValueBuffer");
IGF.Builder.CreateStore(
valueAddr, Address(IGF.Builder.CreateBitCast(
buffer.getAddress(),
valueAddr->getType()->getPointerTo()),
Alignment(1)));
addressOutline =
IGF.Builder.CreateBitCast(valueAddr, IGM.OpaquePtrTy);
IGF.Builder.CreateBr(doneBB);
}
IGF.Builder.emitBlock(doneBB);
auto *addressOfValue = IGF.Builder.CreatePHI(IGM.OpaquePtrTy, 2);
addressOfValue->addIncoming(addressInline, origBB);
addressOfValue->addIncoming(addressOutline, outlineBB);
IGF.Builder.CreateRet(addressOfValue);
},
true /*noinline*/);
}
Address irgen::emitAllocateValueInBuffer(IRGenFunction &IGF, SILType type,
Address buffer) {
// Handle FixedSize types.
auto &IGM = IGF.IGM;
auto storagePtrTy = IGM.getStoragePointerType(type);
auto &Builder = IGF.Builder;
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&IGF.getTypeInfo(type))) {
auto packing = fixedTI->getFixedPacking(IGM);
// Inline representation.
if (packing == FixedPacking::OffsetZero) {
return Address(Builder.CreateBitCast(buffer.getAddress(), storagePtrTy),
buffer.getAlignment());
}
// Outline representation.
assert(packing == FixedPacking::Allocate && "Expect non dynamic packing");
auto size = fixedTI->getStaticSize(IGM);
auto alignMask = fixedTI->getStaticAlignmentMask(IGM);
auto valueAddr =
IGF.emitAllocRawCall(size, alignMask, "outline.ValueBuffer");
Builder.CreateStore(
valueAddr,
Address(Builder.CreateBitCast(buffer.getAddress(),
valueAddr->getType()->getPointerTo()),
buffer.getAlignment()));
return Address(Builder.CreateBitCast(valueAddr, storagePtrTy),
buffer.getAlignment());
}
// Dynamic packing.
/// Call a function to handle the non-fixed case.
auto *allocateFun = getAllocateValueBufferFunction(IGF.IGM);
auto *metadata = IGF.emitTypeMetadataRefForLayout(type);
auto *call = Builder.CreateCall(
allocateFun,
{metadata, Builder.CreateBitCast(buffer.getAddress(), IGM.OpaquePtrTy)});
call->setCallingConv(IGF.IGM.DefaultCC);
call->setDoesNotThrow();
auto addressOfValue = Builder.CreateBitCast(call, storagePtrTy);
return Address(addressOfValue, Alignment(1));
}
static llvm::Constant *getProjectValueInBufferFunction(IRGenModule &IGM) {
llvm::Type *argTys[] = {IGM.TypeMetadataPtrTy, IGM.OpaquePtrTy};
llvm::SmallString<40> fnName("__swift_project_value_buffer");
return IGM.getOrCreateHelperFunction(
fnName, IGM.OpaquePtrTy, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
auto *metadata = &*(it++);
auto buffer = Address(&*(it++), Alignment(1));
auto &Builder = IGF.Builder;
// Dynamically check whether this type is inline or needs an allocation.
llvm::Value *isInline, *flags;
std::tie(isInline, flags) = emitLoadOfIsInline(IGF, metadata);
auto *outlineBB = IGF.createBasicBlock("outline.projectValueInBuffer");
auto *doneBB = IGF.createBasicBlock("done");
llvm::Value *addressInline, *addressOutline;
auto *origBB = Builder.GetInsertBlock();
addressInline = buffer.getAddress();
Builder.CreateCondBr(isInline, doneBB, outlineBB);
Builder.emitBlock(outlineBB);
{
addressOutline = Builder.CreateLoad(
Address(Builder.CreateBitCast(buffer.getAddress(),
IGM.OpaquePtrTy->getPointerTo()),
Alignment(1)));
Builder.CreateBr(doneBB);
}
Builder.emitBlock(doneBB);
auto *addressOfValue = Builder.CreatePHI(IGM.OpaquePtrTy, 2);
addressOfValue->addIncoming(addressInline, origBB);
addressOfValue->addIncoming(addressOutline, outlineBB);
Builder.CreateRet(addressOfValue);
},
true /*noinline*/);
}
Address irgen::emitProjectValueInBuffer(IRGenFunction &IGF, SILType type,
Address buffer) {
// Handle FixedSize types.
auto &IGM = IGF.IGM;
auto storagePtrTy = IGM.getStoragePointerType(type);
auto &Builder = IGF.Builder;
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&IGF.getTypeInfo(type))) {
auto packing = fixedTI->getFixedPacking(IGM);
// Inline representation.
if (packing == FixedPacking::OffsetZero) {
return Address(Builder.CreateBitCast(buffer.getAddress(), storagePtrTy),
buffer.getAlignment());
}
// Outline representation.
assert(packing == FixedPacking::Allocate && "Expect non dynamic packing");
auto valueAddr = Builder.CreateLoad(
Address(Builder.CreateBitCast(buffer.getAddress(),
storagePtrTy->getPointerTo()),
buffer.getAlignment()));
return Address(Builder.CreateBitCast(valueAddr, storagePtrTy),
buffer.getAlignment());
}
// Dynamic packing.
auto *projectFun = getProjectValueInBufferFunction(IGF.IGM);
auto *metadata = IGF.emitTypeMetadataRefForLayout(type);
auto *call = Builder.CreateCall(
projectFun,
{metadata, Builder.CreateBitCast(buffer.getAddress(), IGM.OpaquePtrTy)});
call->setCallingConv(IGF.IGM.DefaultCC);
call->setDoesNotThrow();
auto addressOfValue = Builder.CreateBitCast(call, storagePtrTy);
return Address(addressOfValue, Alignment(1));
}
static llvm::Constant *getDeallocateValueInBufferFunction(IRGenModule &IGM) {
llvm::Type *argTys[] = {IGM.TypeMetadataPtrTy, IGM.OpaquePtrTy};
llvm::SmallString<40> fnName("__swift_deallocate_value_buffer");
return IGM.getOrCreateHelperFunction(
fnName, IGM.VoidTy, argTys,
[&](IRGenFunction &IGF) {
auto it = IGF.CurFn->arg_begin();
auto *metadata = &*(it++);
auto buffer = Address(&*(it++), Alignment(1));
auto &Builder = IGF.Builder;
// Dynamically check whether this type is inline or needs an allocation.
llvm::Value *isInline, *flags;
std::tie(isInline, flags) = emitLoadOfIsInline(IGF, metadata);
auto *outlineBB = IGF.createBasicBlock("outline.deallocateValueInBuffer");
auto *doneBB = IGF.createBasicBlock("done");
Builder.CreateCondBr(isInline, doneBB, outlineBB);
Builder.emitBlock(outlineBB);
{
auto *size = emitLoadOfSize(IGF, metadata);
auto *alignMask = emitAlignMaskFromFlags(IGF, flags);
auto *ptr = Builder.CreateLoad(Address(
Builder.CreateBitCast(buffer.getAddress(), IGM.Int8PtrPtrTy),
buffer.getAlignment()));
IGF.emitDeallocRawCall(ptr, size, alignMask);
Builder.CreateBr(doneBB);
}
Builder.emitBlock(doneBB);
Builder.CreateRetVoid();
},
true /*noinline*/);
}
void irgen::emitDeallocateValueInBuffer(IRGenFunction &IGF,
SILType type,
Address buffer) {
// Handle FixedSize types.
auto &IGM = IGF.IGM;
auto &Builder = IGF.Builder;
if (auto *fixedTI = dyn_cast<FixedTypeInfo>(&IGF.getTypeInfo(type))) {
auto packing = fixedTI->getFixedPacking(IGM);
// Inline representation.
if (packing == FixedPacking::OffsetZero)
return;
// Outline representation.
assert(packing == FixedPacking::Allocate && "Expect non dynamic packing");
auto size = fixedTI->getStaticSize(IGM);
auto alignMask = fixedTI->getStaticAlignmentMask(IGM);
auto *ptr = Builder.CreateLoad(Address(
Builder.CreateBitCast(buffer.getAddress(), IGM.Int8PtrPtrTy),
buffer.getAlignment()));
IGF.emitDeallocRawCall(ptr, size, alignMask);
return;
}
// Dynamic packing.
auto *projectFun = getDeallocateValueInBufferFunction(IGF.IGM);
auto *metadata = IGF.emitTypeMetadataRefForLayout(type);
auto *call = Builder.CreateCall(
projectFun,
{metadata, Builder.CreateBitCast(buffer.getAddress(), IGM.OpaquePtrTy)});
call->setCallingConv(IGF.IGM.DefaultCC);
call->setDoesNotThrow();
}