mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
There are several interesting new features here. The first is that, when emitting a SILFunction, we're now able to cache type data according to the full dominance structure of the original function. For example, if we ask for type metadata, and we've already computed it in a dominating position, we're now able to re-use that value; previously, we were limited to only doing this if the value was from the entry block or the LLVM basic block matched exactly. Since this tracks the SIL dominance relationship, things in IRGen which add their own control flow must be careful to suppress caching within blocks that may not dominate the fallthrough; this mechanism is currently very crude, but could be made to allow a limited amount of caching within the conditionally-executed blocks. This query is done using a proper dominator tree analysis, even at -O0. I do not expect that we will frequently need to actually build the tree, and I expect that the code-size benefits of doing a real analysis will be significant, especially as we move towards making more metadata lazily computed. The second feature is that this adds support for "abstract" cache entries, which indicate that we know how to derive the metadata but haven't actually done so. This code isn't yet tested, but it's going to be the basis of making a lot of things much lazier.
235 lines
8.4 KiB
C++
235 lines
8.4 KiB
C++
//===--- IRGenFunction.cpp - Swift Per-Function IR Generation -------------===//
|
|
//
|
|
// 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 basic setup and teardown for the class which
|
|
// performs IR generation for function bodies.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/SourceLoc.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "Explosion.h"
|
|
#include "IRGenDebugInfo.h"
|
|
#include "IRGenFunction.h"
|
|
#include "IRGenModule.h"
|
|
#include "Linking.h"
|
|
#include "LoadableTypeInfo.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
IRGenFunction::IRGenFunction(IRGenModule &IGM,
|
|
llvm::Function *Fn,
|
|
const SILDebugScope *DbgScope,
|
|
Optional<SILLocation> DbgLoc)
|
|
: IGM(IGM), Builder(IGM.getLLVMContext()),
|
|
CurFn(Fn), DbgScope(DbgScope)
|
|
{
|
|
|
|
// Make sure the instructions in this function are attached its debug scope.
|
|
if (IGM.DebugInfo) {
|
|
// Functions, especially artificial thunks and closures, are often
|
|
// generated on-the-fly while we are in the middle of another
|
|
// function. Be nice and preserve the current debug location until
|
|
// after we're done with this function.
|
|
IGM.DebugInfo->pushLoc();
|
|
}
|
|
|
|
emitPrologue();
|
|
}
|
|
|
|
IRGenFunction::~IRGenFunction() {
|
|
emitEpilogue();
|
|
|
|
// Restore the debug location.
|
|
if (IGM.DebugInfo) IGM.DebugInfo->popLoc();
|
|
|
|
// Tear down any side-table data structures.
|
|
if (LocalTypeData) destroyLocalTypeData();
|
|
}
|
|
|
|
/// Call the llvm.memcpy intrinsic. The arguments need not already
|
|
/// be of i8* type.
|
|
void IRGenFunction::emitMemCpy(llvm::Value *dest, llvm::Value *src,
|
|
Size size, Alignment align) {
|
|
emitMemCpy(dest, src, IGM.getSize(size), align);
|
|
}
|
|
|
|
void IRGenFunction::emitMemCpy(llvm::Value *dest, llvm::Value *src,
|
|
llvm::Value *size, Alignment align) {
|
|
Builder.CreateMemCpy(dest, src, size, align.getValue(), false);
|
|
}
|
|
|
|
void IRGenFunction::emitMemCpy(Address dest, Address src, Size size) {
|
|
emitMemCpy(dest, src, IGM.getSize(size));
|
|
}
|
|
|
|
void IRGenFunction::emitMemCpy(Address dest, Address src, llvm::Value *size) {
|
|
// Map over to the inferior design of the LLVM intrinsic.
|
|
emitMemCpy(dest.getAddress(), src.getAddress(), size,
|
|
std::min(dest.getAlignment(), src.getAlignment()));
|
|
}
|
|
|
|
static llvm::Value *emitAllocatingCall(IRGenFunction &IGF,
|
|
llvm::Value *fn,
|
|
std::initializer_list<llvm::Value*> args,
|
|
const llvm::Twine &name) {
|
|
auto allocAttrs = IGF.IGM.getAllocAttrs();
|
|
llvm::CallInst *call =
|
|
IGF.Builder.CreateCall(fn, makeArrayRef(args.begin(), args.size()));
|
|
call->setCallingConv(IGF.IGM.RuntimeCC);
|
|
call->setAttributes(allocAttrs);
|
|
return call;
|
|
}
|
|
|
|
/// Emit a 'raw' allocation, which has no heap pointer and is
|
|
/// not guaranteed to be zero-initialized.
|
|
llvm::Value *IRGenFunction::emitAllocRawCall(llvm::Value *size,
|
|
llvm::Value *alignMask,
|
|
const llvm::Twine &name) {
|
|
// For now, all we have is swift_slowAlloc.
|
|
return emitAllocatingCall(*this, IGM.getSlowAllocFn(),
|
|
{size, alignMask},
|
|
name);
|
|
}
|
|
|
|
/// Emit a heap allocation.
|
|
llvm::Value *IRGenFunction::emitAllocObjectCall(llvm::Value *metadata,
|
|
llvm::Value *size,
|
|
llvm::Value *alignMask,
|
|
const llvm::Twine &name) {
|
|
// For now, all we have is swift_allocObject.
|
|
return emitAllocatingCall(*this, IGM.getAllocObjectFn(),
|
|
{ metadata, size, alignMask }, name);
|
|
}
|
|
|
|
llvm::Value *IRGenFunction::emitInitStackObjectCall(llvm::Value *metadata,
|
|
llvm::Value *object,
|
|
const llvm::Twine &name) {
|
|
llvm::CallInst *call =
|
|
Builder.CreateCall(IGM.getInitStackObjectFn(), { metadata, object }, name);
|
|
call->setDoesNotThrow();
|
|
call->setCallingConv(IGM.RuntimeCC);
|
|
return call;
|
|
}
|
|
|
|
llvm::Value *IRGenFunction::emitVerifyEndOfLifetimeCall(llvm::Value *object,
|
|
const llvm::Twine &name) {
|
|
llvm::CallInst *call =
|
|
Builder.CreateCall(IGM.getVerifyEndOfLifetimeFn(), { object }, name);
|
|
call->setDoesNotThrow();
|
|
call->setCallingConv(IGM.RuntimeCC);
|
|
return call;
|
|
}
|
|
|
|
void IRGenFunction::emitAllocBoxCall(llvm::Value *typeMetadata,
|
|
llvm::Value *&box,
|
|
llvm::Value *&valueAddress) {
|
|
auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
|
|
llvm::AttributeSet::FunctionIndex,
|
|
llvm::Attribute::NoUnwind);
|
|
|
|
llvm::CallInst *call =
|
|
Builder.CreateCall(IGM.getAllocBoxFn(), typeMetadata);
|
|
call->setCallingConv(IGM.RuntimeCC);
|
|
call->setAttributes(attrs);
|
|
|
|
box = Builder.CreateExtractValue(call, 0);
|
|
valueAddress = Builder.CreateExtractValue(call, 1);
|
|
}
|
|
|
|
void IRGenFunction::emitDeallocBoxCall(llvm::Value *box,
|
|
llvm::Value *typeMetadata) {
|
|
auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
|
|
llvm::AttributeSet::FunctionIndex,
|
|
llvm::Attribute::NoUnwind);
|
|
|
|
llvm::CallInst *call =
|
|
Builder.CreateCall(IGM.getDeallocBoxFn(), box);
|
|
call->setCallingConv(IGM.RuntimeCC);
|
|
call->setAttributes(attrs);
|
|
}
|
|
|
|
llvm::Value *IRGenFunction::emitProjectBoxCall(llvm::Value *box,
|
|
llvm::Value *typeMetadata) {
|
|
llvm::Attribute::AttrKind attrKinds[] = {
|
|
llvm::Attribute::NoUnwind,
|
|
llvm::Attribute::ReadNone,
|
|
};
|
|
auto attrs = llvm::AttributeSet::get(IGM.LLVMContext,
|
|
llvm::AttributeSet::FunctionIndex,
|
|
attrKinds);
|
|
llvm::CallInst *call =
|
|
Builder.CreateCall(IGM.getProjectBoxFn(), box);
|
|
call->setCallingConv(IGM.RuntimeCC);
|
|
call->setAttributes(attrs);
|
|
return call;
|
|
}
|
|
|
|
static void emitDeallocatingCall(IRGenFunction &IGF, llvm::Constant *fn,
|
|
std::initializer_list<llvm::Value *> args) {
|
|
llvm::CallInst *call =
|
|
IGF.Builder.CreateCall(fn, makeArrayRef(args.begin(), args.size()));
|
|
call->setCallingConv(IGF.IGM.RuntimeCC);
|
|
call->setDoesNotThrow();
|
|
}
|
|
|
|
/// Emit a 'raw' deallocation, which has no heap pointer and is not
|
|
/// guaranteed to be zero-initialized.
|
|
void IRGenFunction::emitDeallocRawCall(llvm::Value *pointer,
|
|
llvm::Value *size,
|
|
llvm::Value *alignMask) {
|
|
// For now, all we have is swift_slowDealloc.
|
|
return emitDeallocatingCall(*this, IGM.getSlowDeallocFn(),
|
|
{pointer, size, alignMask});
|
|
}
|
|
|
|
void IRGenFunction::emitFakeExplosion(const TypeInfo &type,
|
|
Explosion &explosion) {
|
|
if (!isa<LoadableTypeInfo>(type)) {
|
|
explosion.add(llvm::UndefValue::get(type.getStorageType()->getPointerTo()));
|
|
return;
|
|
}
|
|
|
|
ExplosionSchema schema = cast<LoadableTypeInfo>(type).getSchema();
|
|
for (auto &element : schema) {
|
|
llvm::Type *elementType;
|
|
if (element.isAggregate()) {
|
|
elementType = element.getAggregateType()->getPointerTo();
|
|
} else {
|
|
elementType = element.getScalarType();
|
|
}
|
|
|
|
explosion.add(llvm::UndefValue::get(elementType));
|
|
}
|
|
}
|
|
|
|
void IRGenFunction::unimplemented(SourceLoc Loc, StringRef Message) {
|
|
return IGM.unimplemented(Loc, Message);
|
|
}
|
|
|
|
// Debug output for Explosions.
|
|
|
|
void Explosion::print(llvm::raw_ostream &OS) {
|
|
for (auto value : makeArrayRef(Values).slice(NextValue)) {
|
|
value->print(OS);
|
|
OS << '\n';
|
|
}
|
|
}
|
|
|
|
void Explosion::dump() {
|
|
print(llvm::errs());
|
|
}
|