blob: 5fe1903ee856888b465ea82d2228f39338cc55f0 [file] [log] [blame]
//===--- IRGenFunction.h - IR Generation for Swift Functions ----*- C++ -*-===//
//
// 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 defines the structure used to generate the IR body of a
// function.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_IRGENFUNCTION_H
#define SWIFT_IRGEN_IRGENFUNCTION_H
#include "swift/Basic/LLVM.h"
#include "swift/AST/Type.h"
#include "swift/SIL/SILLocation.h"
#include "swift/SIL/SILType.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/CallingConv.h"
#include "IRBuilder.h"
namespace llvm {
class AllocaInst;
class CallSite;
class Constant;
class Function;
}
namespace swift {
class ArchetypeType;
class ClassDecl;
class ConstructorDecl;
class Decl;
class ExtensionDecl;
class FuncDecl;
class EnumElementDecl;
class EnumType;
class Pattern;
class PatternBindingDecl;
class SILDebugScope;
class SILType;
class SourceLoc;
class StructType;
class Substitution;
class ValueDecl;
class VarDecl;
namespace irgen {
class Explosion;
class FunctionRef;
class HeapLayout;
class HeapNonFixedOffsets;
class IRGenModule;
class LinkEntity;
class Scope;
class TypeInfo;
enum class ValueWitness : unsigned;
enum class ReferenceCounting : unsigned char;
/// A nonce value for storing some sort of locally-known information about a type.
class LocalTypeData {
unsigned Value;
explicit LocalTypeData(unsigned Value) : Value(Value) {}
/// Magic values for special kinds of index.
enum : unsigned {
Metatype = ~0U,
ValueWitnessTable = ~1U,
ValueWitnessBase = 0xFFFFFF00U,
};
public:
LocalTypeData() = default;
// The magic values are all in the "negative" range and so do
// not collide with reasonable index values.
/// A reference to the type metadata.
static LocalTypeData forMetatype() { return LocalTypeData(Metatype); }
/// A reference to the value witness table.
static LocalTypeData forValueWitnessTable() {
return LocalTypeData(ValueWitnessTable);
}
/// A reference to a specific value witness.
static LocalTypeData forValueWitness(ValueWitness witness) {
return LocalTypeData((unsigned)witness + ValueWitnessBase);
}
/// A reference to a protocol witness table for an archetype.
static LocalTypeData forArchetypeProtocolWitness(unsigned index) {
return LocalTypeData(index);
}
unsigned getValue() const {
return Value;
}
};
/// IRGenFunction - Primary class for emitting LLVM instructions for a
/// specific function.
class IRGenFunction {
public:
IRGenModule &IGM;
IRBuilder Builder;
llvm::Function *CurFn;
IRGenFunction(IRGenModule &IGM, llvm::Function *fn,
const SILDebugScope *DbgScope = nullptr,
Optional<SILLocation> DbgLoc = None);
~IRGenFunction();
void unimplemented(SourceLoc Loc, StringRef Message);
friend class Scope;
//--- Function prologue and epilogue -------------------------------------------
public:
Explosion collectParameters();
void emitScalarReturn(SILType resultTy, Explosion &scalars);
void emitScalarReturn(llvm::Type *resultTy, Explosion &scalars);
void emitBBForReturn();
bool emitBranchToReturnBB();
/// Return the error result slot, given an error type. There's
/// always only one error type.
Address getErrorResultSlot(SILType errorType);
/// Return the error result slot provided by the caller.
Address getCallerErrorResultSlot();
/// Set the error result slot.
void setErrorResultSlot(llvm::Value *address);
private:
void emitPrologue();
void emitEpilogue();
Address ReturnSlot;
llvm::BasicBlock *ReturnBB;
llvm::Value *ErrorResultSlot = nullptr;
//--- Helper methods -----------------------------------------------------------
public:
Address createAlloca(llvm::Type *ty, Alignment align,
const llvm::Twine &name);
Address createFixedSizeBufferAlloca(const llvm::Twine &name);
llvm::BasicBlock *createBasicBlock(const llvm::Twine &Name);
const TypeInfo &getTypeInfoForUnlowered(Type subst);
const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig, Type subst);
const TypeInfo &getTypeInfoForUnlowered(AbstractionPattern orig,
CanType subst);
const TypeInfo &getTypeInfoForLowered(CanType T);
const TypeInfo &getTypeInfo(SILType T);
void emitMemCpy(llvm::Value *dest, llvm::Value *src,
Size size, Alignment align);
void emitMemCpy(llvm::Value *dest, llvm::Value *src,
llvm::Value *size, Alignment align);
void emitMemCpy(Address dest, Address src, Size size);
void emitMemCpy(Address dest, Address src, llvm::Value *size);
llvm::Value *emitByteOffsetGEP(llvm::Value *base, llvm::Value *offset,
llvm::Type *objectType,
const llvm::Twine &name = "");
Address emitByteOffsetGEP(llvm::Value *base, llvm::Value *offset,
const TypeInfo &type,
const llvm::Twine &name = "");
llvm::Value *emitAllocObjectCall(llvm::Value *metadata, llvm::Value *size,
llvm::Value *alignMask,
const llvm::Twine &name = "");
llvm::Value *emitInitStackObjectCall(llvm::Value *metadata,
llvm::Value *object,
const llvm::Twine &name = "");
llvm::Value *emitVerifyEndOfLifetimeCall(llvm::Value *object,
const llvm::Twine &name = "");
llvm::Value *emitAllocRawCall(llvm::Value *size, llvm::Value *alignMask,
const llvm::Twine &name ="");
void emitDeallocRawCall(llvm::Value *pointer, llvm::Value *size,
llvm::Value *alignMask);
void emitAllocBoxCall(llvm::Value *typeMetadata,
llvm::Value *&box,
llvm::Value *&valueAddress);
void emitDeallocBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
llvm::Value *emitProjectBoxCall(llvm::Value *box, llvm::Value *typeMetadata);
// Emit a reference to the canonical type metadata record for the given AST
// type. This can be used to identify the type at runtime. For types with
// abstraction difference, the metadata contains the layout information for
// values in the maximally-abstracted representation of the type; this is
// correct for all uses of reabstractable values in opaque contexts.
llvm::Value *emitTypeMetadataRef(CanType type);
// Emit a reference to a type layout record for the given type. The referenced
// data is enough to lay out an aggregate containing a value of the type, but
// can't uniquely represent the type or perform value witness operations on
// it.
llvm::Value *emitTypeLayoutRef(SILType type);
// Emit a reference to a metadata object that can be used for layout, but
// cannot be used to identify a type. This will produce a layout appropriate
// to the abstraction level of the given type. It may be able to avoid runtime
// calls if there is a standard metadata object with the correct layout for
// the type.
//
// TODO: It might be better to return just a value witness table reference
// here, since for some types it's easier to get a shared reference to one
// than a metadata reference, and it would be more type-safe.
llvm::Value *emitTypeMetadataRefForLayout(SILType type);
llvm::Value *emitValueWitnessTableRef(CanType type);
llvm::Value *emitValueWitnessTableRefForLayout(SILType type);
llvm::Value *emitValueWitnessTableRefForMetadata(llvm::Value *metadata);
llvm::Value *emitValueWitness(CanType type, ValueWitness index);
llvm::Value *emitValueWitnessForLayout(SILType type, ValueWitness index);
/// Emit a load of a reference to the given Objective-C selector.
llvm::Value *emitObjCSelectorRefLoad(StringRef selector);
/// Return the SILDebugScope for this function.
const SILDebugScope *getDebugScope() const { return DbgScope; }
llvm::Value *coerceValue(llvm::Value *value, llvm::Type *toTy,
const llvm::DataLayout &);
/// Mark a load as invariant.
void setInvariantLoad(llvm::LoadInst *load);
/// Mark a load as dereferenceable to `size` bytes.
void setDereferenceableLoad(llvm::LoadInst *load, unsigned size);
private:
llvm::Instruction *AllocaIP;
const SILDebugScope *DbgScope;
//--- Reference-counting methods -----------------------------------------------
public:
llvm::Value *emitUnmanagedAlloc(const HeapLayout &layout,
const llvm::Twine &name,
const HeapNonFixedOffsets *offsets = 0);
// Functions that don't care about the reference-counting style.
void emitFixLifetime(llvm::Value *value);
// Routines that are generic over the reference-counting style:
// - strong references
void emitStrongRetain(llvm::Value *value, ReferenceCounting refcounting);
void emitStrongRelease(llvm::Value *value, ReferenceCounting refcounting);
llvm::Value *emitLoadRefcountedPtr(Address addr, ReferenceCounting style);
// - unowned references
void emitUnownedRetain(llvm::Value *value, ReferenceCounting style);
void emitUnownedRelease(llvm::Value *value, ReferenceCounting style);
void emitStrongRetainUnowned(llvm::Value *value, ReferenceCounting style);
void emitStrongRetainAndUnownedRelease(llvm::Value *value,
ReferenceCounting style);
void emitUnownedInit(llvm::Value *val, Address dest, ReferenceCounting style);
void emitUnownedAssign(llvm::Value *value, Address dest,
ReferenceCounting style);
void emitUnownedCopyInit(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitUnownedTakeInit(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitUnownedCopyAssign(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitUnownedTakeAssign(Address destAddr, Address srcAddr,
ReferenceCounting style);
llvm::Value *emitUnownedLoadStrong(Address src, llvm::Type *resultType,
ReferenceCounting style);
llvm::Value *emitUnownedTakeStrong(Address src, llvm::Type *resultType,
ReferenceCounting style);
void emitUnownedDestroy(Address addr, ReferenceCounting style);
llvm::Value *getUnownedExtraInhabitantIndex(Address src,
ReferenceCounting style);
void storeUnownedExtraInhabitant(llvm::Value *index, Address dest,
ReferenceCounting style);
// - weak references
void emitWeakInit(llvm::Value *ref, Address dest, ReferenceCounting style);
void emitWeakAssign(llvm::Value *ref, Address dest, ReferenceCounting style);
void emitWeakCopyInit(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitWeakTakeInit(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitWeakCopyAssign(Address destAddr, Address srcAddr,
ReferenceCounting style);
void emitWeakTakeAssign(Address destAddr, Address srcAddr,
ReferenceCounting style);
llvm::Value *emitWeakLoadStrong(Address src, llvm::Type *resultType,
ReferenceCounting style);
llvm::Value *emitWeakTakeStrong(Address src, llvm::Type *resultType,
ReferenceCounting style);
void emitWeakDestroy(Address addr, ReferenceCounting style);
// Routines for the Swift native reference-counting style.
// - strong references
void emitNativeStrongAssign(llvm::Value *value, Address addr);
void emitNativeStrongInit(llvm::Value *value, Address addr);
void emitNativeStrongRetain(llvm::Value *value);
void emitNativeStrongRelease(llvm::Value *value);
// - unowned references
void emitNativeUnownedRetain(llvm::Value *value);
void emitNativeUnownedRelease(llvm::Value *value);
void emitNativeStrongRetainUnowned(llvm::Value *value);
void emitNativeStrongRetainAndUnownedRelease(llvm::Value *value);
void emitNativeUnownedInit(llvm::Value *val, Address dest);
void emitNativeUnownedAssign(llvm::Value *value, Address dest);
void emitNativeUnownedCopyInit(Address destAddr, Address srcAddr);
void emitNativeUnownedTakeInit(Address destAddr, Address srcAddr);
void emitNativeUnownedCopyAssign(Address destAddr, Address srcAddr);
void emitNativeUnownedTakeAssign(Address destAddr, Address srcAddr);
llvm::Value *emitNativeUnownedLoadStrong(Address src, llvm::Type *resultType);
llvm::Value *emitNativeUnownedTakeStrong(Address src, llvm::Type *resultType);
void emitNativeUnownedDestroy(Address addr);
// - weak references
void emitNativeWeakInit(llvm::Value *value, Address dest);
void emitNativeWeakAssign(llvm::Value *value, Address dest);
llvm::Value *emitNativeWeakLoadStrong(Address src, llvm::Type *type);
llvm::Value *emitNativeWeakTakeStrong(Address src, llvm::Type *type);
void emitNativeWeakDestroy(Address addr);
void emitNativeWeakCopyInit(Address destAddr, Address srcAddr);
void emitNativeWeakTakeInit(Address destAddr, Address srcAddr);
void emitNativeWeakCopyAssign(Address destAddr, Address srcAddr);
void emitNativeWeakTakeAssign(Address destAddr, Address srcAddr);
// - other operations
llvm::Value *emitNativeTryPin(llvm::Value *object);
void emitNativeUnpin(llvm::Value *handle);
// Routines for the ObjC reference-counting style.
void emitObjCStrongRetain(llvm::Value *value);
llvm::Value *emitObjCRetainCall(llvm::Value *value);
llvm::Value *emitObjCAutoreleaseCall(llvm::Value *value);
void emitObjCStrongRelease(llvm::Value *value);
llvm::Value *emitBlockCopyCall(llvm::Value *value);
void emitBlockRelease(llvm::Value *value);
// Routines for an unknown reference-counting style (meaning,
// dynamically something compatible with either the ObjC or Swift styles).
// - strong references
void emitUnknownStrongRetain(llvm::Value *value);
void emitUnknownStrongRelease(llvm::Value *value);
// - unowned references
void emitUnknownUnownedInit(llvm::Value *val, Address dest);
void emitUnknownUnownedAssign(llvm::Value *value, Address dest);
void emitUnknownUnownedCopyInit(Address destAddr, Address srcAddr);
void emitUnknownUnownedTakeInit(Address destAddr, Address srcAddr);
void emitUnknownUnownedCopyAssign(Address destAddr, Address srcAddr);
void emitUnknownUnownedTakeAssign(Address destAddr, Address srcAddr);
llvm::Value *emitUnknownUnownedLoadStrong(Address src, llvm::Type *resultTy);
llvm::Value *emitUnknownUnownedTakeStrong(Address src, llvm::Type *resultTy);
void emitUnknownUnownedDestroy(Address addr);
// - weak references
void emitUnknownWeakDestroy(Address addr);
void emitUnknownWeakCopyInit(Address destAddr, Address srcAddr);
void emitUnknownWeakTakeInit(Address destAddr, Address srcAddr);
void emitUnknownWeakCopyAssign(Address destAddr, Address srcAddr);
void emitUnknownWeakTakeAssign(Address destAddr, Address srcAddr);
void emitUnknownWeakInit(llvm::Value *value, Address dest);
void emitUnknownWeakAssign(llvm::Value *value, Address dest);
llvm::Value *emitUnknownWeakLoadStrong(Address src, llvm::Type *type);
llvm::Value *emitUnknownWeakTakeStrong(Address src, llvm::Type *type);
// Routines for the Builtin.NativeObject reference-counting style.
void emitBridgeStrongRetain(llvm::Value *value);
void emitBridgeStrongRelease(llvm::Value *value);
// Routines for the ErrorType reference-counting style.
void emitErrorStrongRetain(llvm::Value *value);
void emitErrorStrongRelease(llvm::Value *value);
llvm::Value *emitIsUniqueCall(llvm::Value *value, SourceLoc loc,
bool isNonNull, bool checkPinned);
//--- Expression emission ------------------------------------------------------
public:
void emitFakeExplosion(const TypeInfo &type, Explosion &explosion);
//--- Declaration emission -----------------------------------------------------
public:
void bindArchetype(ArchetypeType *type,
llvm::Value *metadata,
ArrayRef<llvm::Value*> wtables);
//--- Type emission ------------------------------------------------------------
public:
/// Look for a mapping for a local type-metadata reference.
/// The lookup is done for the current block which is the Builder's
/// insert-block.
llvm::Value *tryGetLocalTypeData(CanType type, LocalTypeData index) {
return lookupTypeDataMap(type, index, ScopedTypeDataMap);
}
/// The same as tryGetLocalTypeData, just for the Layout metadata.
llvm::Value *tryGetLocalTypeDataForLayout(SILType type, LocalTypeData index) {
return lookupTypeDataMap(type.getSwiftRValueType(), index,
ScopedTypeDataMapForLayout);
}
/// Retrieve a local type-metadata reference which is known to exist.
llvm::Value *getLocalTypeData(CanType type, LocalTypeData index) {
auto key = getLocalTypeDataKey(type, index);
assert(LocalTypeDataMap.count(key) && "no mapping for local type data");
return LocalTypeDataMap.find(key)->second;
}
/// Add a local type-metadata reference at a point which dominates
/// the entire function.
void setUnscopedLocalTypeData(CanType type, LocalTypeData index,
llvm::Value *data) {
assert(data && "setting a null value for type data!");
auto key = getLocalTypeDataKey(type, index);
assert(!LocalTypeDataMap.count(key) &&
"existing mapping for local type data");
LocalTypeDataMap.insert({key, data});
}
/// Add a local type-metadata reference, which is valid for the containing
/// block.
void setScopedLocalTypeData(CanType type, LocalTypeData index,
llvm::Value *data) {
assert(_isValidScopedLocalTypeData(data) &&
"metadata instruction not inserted into the Builder's insert-block");
ScopedTypeDataMap[getLocalTypeDataKey(type, index)] = data;
}
/// Add a local type-metadata reference, which is valid for the containing
/// block.
void setScopedLocalTypeDataForLayout(SILType type, LocalTypeData index,
llvm::Value *data) {
assert(_isValidScopedLocalTypeData(data) &&
"metadata instruction not inserted into the Builder's insert-block");
ScopedTypeDataMapForLayout[
getLocalTypeDataKey(type.getSwiftRValueType(), index)] = data;
}
/// The kind of value LocalSelf is.
enum LocalSelfKind {
/// An object reference.
ObjectReference,
/// A Swift metatype.
SwiftMetatype,
/// An ObjC metatype.
ObjCMetatype,
};
llvm::Value *getLocalSelfMetadata();
void setLocalSelfMetadata(llvm::Value *value, LocalSelfKind kind);
private:
#ifndef NDEBUG
bool _isValidScopedLocalTypeData(llvm::Value *v) {
// Constants are valid anywhere.
if (isa<llvm::Constant>(v))
return true;
// Instructions are valid only in the current insert block.
if (auto inst = dyn_cast<llvm::Instruction>(v))
return inst->getParent() == Builder.GetInsertBlock();
// TODO: Other kinds of value?
return false;
}
#endif
typedef unsigned LocalTypeDataDepth;
typedef std::pair<TypeBase*,unsigned> LocalTypeDataPair;
LocalTypeDataPair getLocalTypeDataKey(CanType type, LocalTypeData index) {
return LocalTypeDataPair(type.getPointer(), index.getValue());
}
typedef llvm::DenseMap<LocalTypeDataPair, llvm::Value*> TypeDataMap;
llvm::Value *lookupTypeDataMap(CanType type, LocalTypeData index,
const TypeDataMap &scopedMap);
TypeDataMap LocalTypeDataMap;
TypeDataMap ScopedTypeDataMap;
TypeDataMap ScopedTypeDataMapForLayout;
/// The value that satisfies metadata lookups for dynamic Self.
llvm::Value *LocalSelf = nullptr;
LocalSelfKind SelfKind;
};
} // end namespace irgen
} // end namespace swift
#endif