blob: f96eba672b13fe1f84c76ed4882b413d9f8e5d4a [file] [log] [blame]
//===--- IRGenModule.cpp - Swift Global LLVM IR Generation ----------------===//
//
// 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 global declarations in Swift.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/DiagnosticsIRGen.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/Basic/Dwarf.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Runtime/RuntimeFnWrappersGen.h"
#include "swift/Runtime/Config.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/CodeGenABITypes.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/CodeGen/SwiftCallingConv.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MD5.h"
#include "GenEnum.h"
#include "GenType.h"
#include "IRGenModule.h"
#include "IRGenDebugInfo.h"
#include "Linking.h"
#include <initializer_list>
using namespace swift;
using namespace irgen;
using llvm::Attribute;
const unsigned DefaultAS = 0;
/// A helper for creating LLVM struct types.
static llvm::StructType *createStructType(IRGenModule &IGM,
StringRef name,
std::initializer_list<llvm::Type*> types,
bool packed = false) {
return llvm::StructType::create(IGM.getLLVMContext(),
ArrayRef<llvm::Type*>(types.begin(),
types.size()),
name, packed);
};
/// A helper for creating pointer-to-struct types.
static llvm::PointerType *createStructPointerType(IRGenModule &IGM,
StringRef name,
std::initializer_list<llvm::Type*> types) {
return createStructType(IGM, name, types)->getPointerTo(DefaultAS);
};
static clang::CodeGenerator *createClangCodeGenerator(ASTContext &Context,
llvm::LLVMContext &LLVMContext,
IRGenOptions &Opts,
StringRef ModuleName) {
auto Loader = Context.getClangModuleLoader();
auto *Importer = static_cast<ClangImporter*>(&*Loader);
assert(Importer && "No clang module loader!");
auto &ClangContext = Importer->getClangASTContext();
auto &CGO = Importer->getClangCodeGenOpts();
CGO.OptimizationLevel = Opts.Optimize ? 3 : 0;
CGO.DisableFPElim = Opts.DisableFPElim;
CGO.DiscardValueNames = !Opts.shouldProvideValueNames();
switch (Opts.DebugInfoKind) {
case IRGenDebugInfoKind::None:
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::NoDebugInfo);
break;
case IRGenDebugInfoKind::LineTables:
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::DebugLineTablesOnly);
break;
case IRGenDebugInfoKind::ASTTypes:
// TODO: Enable -gmodules for the clang code generator.
case IRGenDebugInfoKind::DwarfTypes:
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::FullDebugInfo);
break;
}
if (Opts.DebugInfoKind > IRGenDebugInfoKind::None) {
CGO.DebugCompilationDir = Opts.DebugCompilationDir;
CGO.DwarfVersion = Opts.DWARFVersion;
CGO.DwarfDebugFlags = Opts.DWARFDebugFlags;
}
auto &HSI = Importer->getClangPreprocessor()
.getHeaderSearchInfo()
.getHeaderSearchOpts();
auto &PPO = Importer->getClangPreprocessor().getPreprocessorOpts();
auto *ClangCodeGen = clang::CreateLLVMCodeGen(ClangContext.getDiagnostics(),
ModuleName, HSI, PPO, CGO,
LLVMContext);
ClangCodeGen->Initialize(ClangContext);
return ClangCodeGen;
}
/// A helper for determining if the triple uses the DLL storage
static bool useDllStorage(const llvm::Triple &Triple) {
return Triple.isOSBinFormatCOFF() && !Triple.isOSCygMing();
}
IRGenModule::IRGenModule(IRGenerator &irgen,
std::unique_ptr<llvm::TargetMachine> &&target,
SourceFile *SF, llvm::LLVMContext &LLVMContext,
StringRef ModuleName, StringRef OutputFilename)
: IRGen(irgen), Context(irgen.SIL.getASTContext()),
ClangCodeGen(createClangCodeGenerator(Context, LLVMContext, irgen.Opts,
ModuleName)),
Module(*ClangCodeGen->GetModule()), LLVMContext(Module.getContext()),
DataLayout(target->createDataLayout()), Triple(Context.LangOpts.Target),
TargetMachine(std::move(target)), silConv(irgen.SIL),
OutputFilename(OutputFilename),
TargetInfo(SwiftTargetInfo::get(*this)), DebugInfo(nullptr),
ModuleHash(nullptr), ObjCInterop(Context.LangOpts.EnableObjCInterop),
Types(*new TypeConverter(*this)) {
irgen.addGenModule(SF, this);
auto &opts = irgen.Opts;
EnableValueNames = opts.shouldProvideValueNames();
VoidTy = llvm::Type::getVoidTy(getLLVMContext());
Int1Ty = llvm::Type::getInt1Ty(getLLVMContext());
Int8Ty = llvm::Type::getInt8Ty(getLLVMContext());
Int16Ty = llvm::Type::getInt16Ty(getLLVMContext());
Int32Ty = llvm::Type::getInt32Ty(getLLVMContext());
Int64Ty = llvm::Type::getInt64Ty(getLLVMContext());
Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
SizeTy = DataLayout.getIntPtrType(getLLVMContext(), /*addrspace*/ 0);
auto CI = static_cast<ClangImporter*>(&*Context.getClangModuleLoader());
assert(CI && "no clang module loader");
auto &clangASTContext = CI->getClangASTContext();
ObjCBoolTy = Int1Ty;
if (clangASTContext.getTargetInfo().useSignedCharForObjCBool())
ObjCBoolTy = Int8Ty;
RefCountedStructTy =
llvm::StructType::create(getLLVMContext(), "swift.refcounted");
RefCountedPtrTy = RefCountedStructTy->getPointerTo(/*addrspace*/ 0);
RefCountedNull = llvm::ConstantPointerNull::get(RefCountedPtrTy);
// For now, native weak references are just a pointer.
WeakReferencePtrTy =
createStructPointerType(*this, "swift.weak", { RefCountedPtrTy });
// Native unowned references are just a pointer.
UnownedReferencePtrTy =
createStructPointerType(*this, "swift.unowned", { RefCountedPtrTy });
// A type metadata record is the structure pointed to by the canonical
// address point of a type metadata. This is at least one word, and
// potentially more than that, past the start of the actual global
// structure.
TypeMetadataStructTy = createStructType(*this, "swift.type", {
MetadataKindTy // MetadataKind Kind;
});
TypeMetadataPtrTy = TypeMetadataStructTy->getPointerTo(DefaultAS);
// A protocol descriptor describes a protocol. It is not type metadata in
// and of itself, but is referenced in the structure of existential type
// metadata records.
ProtocolDescriptorStructTy = createStructType(*this, "swift.protocol", {
Int8PtrTy, // objc isa
Int8PtrTy, // name
Int8PtrTy, // inherited protocols
Int8PtrTy, // required objc instance methods
Int8PtrTy, // required objc class methods
Int8PtrTy, // optional objc instance methods
Int8PtrTy, // optional objc class methods
Int8PtrTy, // objc properties
Int32Ty, // size
Int32Ty, // flags
Int16Ty, // minimum witness count
Int16Ty, // default witness count
Int32Ty // padding
});
ProtocolDescriptorPtrTy = ProtocolDescriptorStructTy->getPointerTo();
// A tuple type metadata record has a couple extra fields.
auto tupleElementTy = createStructType(*this, "swift.tuple_element_type", {
TypeMetadataPtrTy, // Metadata *Type;
SizeTy // size_t Offset;
});
TupleTypeMetadataPtrTy = createStructPointerType(*this, "swift.tuple_type", {
TypeMetadataStructTy, // (base)
SizeTy, // size_t NumElements;
Int8PtrTy, // const char *Labels;
llvm::ArrayType::get(tupleElementTy, 0) // Element Elements[];
});
// A full type metadata record is basically just an adjustment to the
// address point of a type metadata. Resilience may cause
// additional data to be laid out prior to this address point.
FullTypeMetadataStructTy = createStructType(*this, "swift.full_type", {
WitnessTablePtrTy,
TypeMetadataStructTy
});
FullTypeMetadataPtrTy = FullTypeMetadataStructTy->getPointerTo(DefaultAS);
// A metadata pattern is a structure from which generic type
// metadata are allocated. We leave this struct type intentionally
// opaque, because the compiler basically never needs to access
// anything from one.
TypeMetadataPatternStructTy =
llvm::StructType::create(getLLVMContext(), "swift.type_pattern");
TypeMetadataPatternPtrTy =
TypeMetadataPatternStructTy->getPointerTo(DefaultAS);
DeallocatingDtorTy = llvm::FunctionType::get(VoidTy, RefCountedPtrTy, false);
llvm::Type *dtorPtrTy = DeallocatingDtorTy->getPointerTo();
// A full heap metadata is basically just an additional small prefix
// on a full metadata, used for metadata corresponding to heap
// allocations.
FullHeapMetadataStructTy =
createStructType(*this, "swift.full_heapmetadata", {
dtorPtrTy,
WitnessTablePtrTy,
TypeMetadataStructTy
});
FullHeapMetadataPtrTy = FullHeapMetadataStructTy->getPointerTo(DefaultAS);
// A full box metadata is non-type heap metadata for a heap allocation of a
// single value. The box tracks the offset to the value inside the box.
FullBoxMetadataStructTy =
createStructType(*this, "swift.full_boxmetadata", {
dtorPtrTy,
WitnessTablePtrTy,
TypeMetadataStructTy,
Int32Ty,
CaptureDescriptorPtrTy,
});
FullBoxMetadataPtrTy = FullBoxMetadataStructTy->getPointerTo(DefaultAS);
llvm::Type *refCountedElts[] = { TypeMetadataPtrTy, Int32Ty, Int32Ty };
RefCountedStructTy->setBody(refCountedElts);
PtrSize = Size(DataLayout.getPointerSize(DefaultAS));
FunctionPairTy = createStructType(*this, "swift.function", {
FunctionPtrTy,
RefCountedPtrTy,
});
OpaqueTy = llvm::StructType::create(LLVMContext, "swift.opaque");
OpaquePtrTy = OpaqueTy->getPointerTo(DefaultAS);
ProtocolConformanceRecordTy
= createStructType(*this, "swift.protocol_conformance", {
RelativeAddressTy,
RelativeAddressTy,
RelativeAddressTy,
Int32Ty
});
ProtocolConformanceRecordPtrTy
= ProtocolConformanceRecordTy->getPointerTo(DefaultAS);
NominalTypeDescriptorTy
= llvm::StructType::create(LLVMContext, "swift.type_descriptor");
NominalTypeDescriptorPtrTy
= NominalTypeDescriptorTy->getPointerTo(DefaultAS);
TypeMetadataRecordTy
= createStructType(*this, "swift.type_metadata_record", {
RelativeAddressTy,
Int32Ty
});
TypeMetadataRecordPtrTy
= TypeMetadataRecordTy->getPointerTo(DefaultAS);
FieldDescriptorTy
= llvm::StructType::create(LLVMContext, "swift.field_descriptor");
FieldDescriptorPtrTy = FieldDescriptorTy->getPointerTo(DefaultAS);
FixedBufferTy = nullptr;
for (unsigned i = 0; i != MaxNumValueWitnesses; ++i)
ValueWitnessTys[i] = nullptr;
ObjCPtrTy = llvm::StructType::create(getLLVMContext(), "objc_object")
->getPointerTo(DefaultAS);
BridgeObjectPtrTy = llvm::StructType::create(getLLVMContext(), "swift.bridge")
->getPointerTo(DefaultAS);
ObjCClassStructTy = llvm::StructType::create(LLVMContext, "objc_class");
ObjCClassPtrTy = ObjCClassStructTy->getPointerTo(DefaultAS);
llvm::Type *objcClassElts[] = {
ObjCClassPtrTy,
ObjCClassPtrTy,
OpaquePtrTy,
OpaquePtrTy,
IntPtrTy
};
ObjCClassStructTy->setBody(objcClassElts);
ObjCSuperStructTy = llvm::StructType::create(LLVMContext, "objc_super");
ObjCSuperPtrTy = ObjCSuperStructTy->getPointerTo(DefaultAS);
llvm::Type *objcSuperElts[] = {
ObjCPtrTy,
ObjCClassPtrTy
};
ObjCSuperStructTy->setBody(objcSuperElts);
ObjCBlockStructTy = llvm::StructType::create(LLVMContext, "objc_block");
ObjCBlockPtrTy = ObjCBlockStructTy->getPointerTo(DefaultAS);
llvm::Type *objcBlockElts[] = {
ObjCClassPtrTy, // isa
Int32Ty, // flags
Int32Ty, // reserved
FunctionPtrTy, // invoke function pointer
Int8PtrTy, // TODO: block descriptor pointer.
// We will probably need a struct type for that at some
// point too.
};
ObjCBlockStructTy->setBody(objcBlockElts);
auto ErrorStructTy = llvm::StructType::create(LLVMContext, "swift.error");
// ErrorStruct is currently opaque to the compiler.
ErrorPtrTy = ErrorStructTy->getPointerTo(DefaultAS);
llvm::Type *openedErrorTriple[] = {
OpaquePtrTy,
TypeMetadataPtrTy,
WitnessTablePtrTy,
};
OpenedErrorTripleTy = llvm::StructType::get(getLLVMContext(),
openedErrorTriple,
/*packed*/ false);
OpenedErrorTriplePtrTy = OpenedErrorTripleTy->getPointerTo(DefaultAS);
InvariantMetadataID = LLVMContext.getMDKindID("invariant.load");
InvariantNode = llvm::MDNode::get(LLVMContext, {});
DereferenceableID = LLVMContext.getMDKindID("dereferenceable");
C_CC = llvm::CallingConv::C;
// TODO: use "tinycc" on platforms that support it
DefaultCC = SWIFT_LLVM_CC(DefaultCC);
// If it is an interpreter, don't use try to use any
// advanced calling conventions and use instead a
// more conservative C calling convention. This
// makes sure that none of the registers eventually
// used by the dynamic linker are used by generated code.
// TODO: Check that the deployment target supports the new
// calling convention. Older versions of the runtime library
// may not contain the entries using the new calling convention.
// Only use the new calling conventions on platforms that support it.
auto Arch = Triple.getArch();
(void)Arch;
if (SWIFT_RT_USE_RegisterPreservingCC &&
Arch == llvm::Triple::ArchType::aarch64)
RegisterPreservingCC = SWIFT_LLVM_CC(RegisterPreservingCC);
else
RegisterPreservingCC = DefaultCC;
SwiftCC = SWIFT_LLVM_CC(SwiftCC);
UseSwiftCC = (SwiftCC == llvm::CallingConv::Swift);
if (IRGen.Opts.DebugInfoKind > IRGenDebugInfoKind::None)
DebugInfo = new IRGenDebugInfo(IRGen.Opts, *CI, *this, Module, SF);
initClangTypeConverter();
IsSwiftErrorInRegister =
clang::CodeGen::swiftcall::isSwiftErrorLoweredInRegister(
ClangCodeGen->CGM());
}
IRGenModule::~IRGenModule() {
destroyClangTypeConverter();
delete &Types;
delete DebugInfo;
}
static bool isReturnAttribute(llvm::Attribute::AttrKind Attr);
// Explicitly listing these constants is an unfortunate compromise for
// making the database file much more compact.
//
// They have to be non-local because otherwise we'll get warnings when
// a particular x-macro expansion doesn't use one.
namespace RuntimeConstants {
const auto ReadNone = llvm::Attribute::ReadNone;
const auto ReadOnly = llvm::Attribute::ReadOnly;
const auto NoReturn = llvm::Attribute::NoReturn;
const auto NoUnwind = llvm::Attribute::NoUnwind;
const auto ZExt = llvm::Attribute::ZExt;
} // namespace RuntimeConstants
// We don't use enough attributes to justify generalizing the
// RuntimeFunctions.def FUNCTION macro. Instead, special case the one attribute
// associated with the return type not the function type.
static bool isReturnAttribute(llvm::Attribute::AttrKind Attr) {
return Attr == llvm::Attribute::ZExt;
}
llvm::Constant *swift::getRuntimeFn(llvm::Module &Module,
llvm::Constant *&cache,
char const *name,
llvm::CallingConv::ID cc,
llvm::ArrayRef<llvm::Type*> retTypes,
llvm::ArrayRef<llvm::Type*> argTypes,
ArrayRef<Attribute::AttrKind> attrs) {
if (cache)
return cache;
llvm::Type *retTy;
if (retTypes.size() == 1)
retTy = *retTypes.begin();
else
retTy = llvm::StructType::get(Module.getContext(),
{retTypes.begin(), retTypes.end()},
/*packed*/ false);
auto fnTy = llvm::FunctionType::get(retTy,
{argTypes.begin(), argTypes.end()},
/*isVararg*/ false);
cache = Module.getOrInsertFunction(name, fnTy);
// Add any function attributes and set the calling convention.
if (auto fn = dyn_cast<llvm::Function>(cache)) {
fn->setCallingConv(cc);
if (::useDllStorage(llvm::Triple(Module.getTargetTriple())) &&
(fn->getLinkage() == llvm::GlobalValue::ExternalLinkage ||
fn->getLinkage() == llvm::GlobalValue::AvailableExternallyLinkage))
fn->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
llvm::AttrBuilder buildFnAttr;
llvm::AttrBuilder buildRetAttr;
for (auto Attr : attrs) {
if (isReturnAttribute(Attr))
buildRetAttr.addAttribute(Attr);
else
buildFnAttr.addAttribute(Attr);
}
// FIXME: getting attributes here without setting them does
// nothing. This cannot be fixed until the attributes are correctly specified.
fn->getAttributes().
addAttributes(Module.getContext(),
llvm::AttributeSet::FunctionIndex,
llvm::AttributeSet::get(Module.getContext(),
llvm::AttributeSet::FunctionIndex,
buildFnAttr));
fn->getAttributes().
addAttributes(Module.getContext(),
llvm::AttributeSet::ReturnIndex,
llvm::AttributeSet::get(Module.getContext(),
llvm::AttributeSet::ReturnIndex,
buildRetAttr));
}
return cache;
}
llvm::Constant *swift::getWrapperFn(llvm::Module &Module,
llvm::Constant *&cache,
char const *name,
char const *symbol,
llvm::CallingConv::ID cc,
llvm::ArrayRef<llvm::Type *> retTypes,
llvm::ArrayRef<llvm::Type *> argTypes,
ArrayRef<Attribute::AttrKind> attrs) {
assert(symbol && "Symbol name should be defined for a wrapper function");
// Wrapper names should have a prefix to distinguish them from the
// actual runtime functions.
llvm::SmallString<128> wrapperNameStr;
llvm::raw_svector_ostream buffer(wrapperNameStr);
buffer << SWIFT_WRAPPER_PREFIX;
buffer << name;
const char *wrapperName = wrapperNameStr.c_str();
auto fn = getRuntimeFn(Module, cache, wrapperName, cc,
retTypes, argTypes, attrs);
auto *fun = dyn_cast<llvm::Function>(fn);
assert(fun && "Wrapper should be an llvm::Function");
// Do not inline wrappers, because this would result in a code size increase.
fun->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoInline);
assert(fun->hasFnAttribute(llvm::Attribute::NoInline) &&
"Wrappers should not be inlined");
if (fun->empty()) {
// All wrappers should have ODR linkage so that a linker can detect them
// and leave only one copy.
fun->setLinkage(llvm::Function::LinkOnceODRLinkage);
fun->setVisibility(llvm::Function::HiddenVisibility);
fun->setDLLStorageClass(llvm::Function::DefaultStorageClass);
fun->setDoesNotThrow();
// Add the body of a wrapper.
// It simply invokes the actual implementation of the runtime entry
// by means of indirect call through a pointer stored in the
// global variable.
llvm::IRBuilder<> Builder(Module.getContext());
llvm::BasicBlock *bb =
llvm::BasicBlock::Create(Module.getContext(), "entry", fun);
Builder.SetInsertPoint(bb);
auto fnTy = fun->getFunctionType();
auto fnPtrTy = llvm::PointerType::getUnqual(fnTy);
auto *globalFnPtr = new llvm::GlobalVariable(
Module, fnPtrTy, false, llvm::GlobalValue::ExternalLinkage, nullptr,
symbol);
if (::useDllStorage(llvm::Triple(Module.getTargetTriple())))
globalFnPtr->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
// Forward all arguments.
llvm::SmallVector<llvm::Value *, 4> args;
for (auto &arg: fun->args()) {
args.push_back(&arg);
}
auto fnPtr = Builder.CreateLoad(globalFnPtr, "load");
auto call = Builder.CreateCall(fnPtr, args);
call->setCallingConv(cc);
call->setTailCall(true);
auto VoidTy = llvm::Type::getVoidTy(Module.getContext());
if (retTypes.size() == 1 && *retTypes.begin() == VoidTy)
Builder.CreateRetVoid();
else
Builder.CreateRet(call);
}
return fn;
}
#define QUOTE(...) __VA_ARGS__
#define STR(X) #X
#define FUNCTION_FOR_CONV_DefaultCC(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION_FOR_CONV_C_CC(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION_FOR_CONV_RegisterPreservingCC(ID, NAME, CC, RETURNS, ARGS, \
ATTRS) \
FUNCTION_WITH_GLOBAL_SYMBOL_IMPL(ID, NAME, SWIFT_RT_ENTRY_REF(NAME), CC, \
QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
FUNCTION_FOR_CONV_##CC(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), \
QUOTE(ATTRS))
#define FUNCTION_WITH_GLOBAL_SYMBOL_FOR_CONV_DefaultCC(ID, NAME, SYMBOL, CC, \
RETURNS, ARGS, ATTRS) \
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION_WITH_GLOBAL_SYMBOL_FOR_CONV_C_CC(ID, NAME, SYMBOL, CC, \
RETURNS, ARGS, ATTRS) \
FUNCTION_IMPL(ID, NAME, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION_WITH_GLOBAL_SYMBOL_FOR_CONV_RegisterPreservingCC( \
ID, NAME, SYMBOL, CC, RETURNS, ARGS, ATTRS) \
FUNCTION_WITH_GLOBAL_SYMBOL_IMPL(ID, NAME, SYMBOL, CC, QUOTE(RETURNS), \
QUOTE(ARGS), QUOTE(ATTRS))
#define FUNCTION_WITH_GLOBAL_SYMBOL_AND_IMPL(ID, NAME, SYMBOL, IMPL, CC, \
RETURNS, ARGS, ATTRS) \
FUNCTION_WITH_GLOBAL_SYMBOL_FOR_CONV_##CC( \
ID, NAME, SYMBOL, CC, QUOTE(RETURNS), QUOTE(ARGS), QUOTE(ATTRS))
#define RETURNS(...) \
{ __VA_ARGS__ }
#define ARGS(...) { __VA_ARGS__ }
#define NO_ARGS {}
#define ATTRS(...) { __VA_ARGS__ }
#define NO_ATTRS {}
#define FUNCTION_IMPL(ID, NAME, CC, RETURNS, ARGS, ATTRS) \
llvm::Constant *IRGenModule::get##ID##Fn() { \
using namespace RuntimeConstants; \
return getRuntimeFn(Module, ID##Fn, #NAME, CC, RETURNS, ARGS, ATTRS); \
}
#define FUNCTION_WITH_GLOBAL_SYMBOL_IMPL(ID, NAME, SYMBOL_NAME, CC, RETURNS, \
ARGS, ATTRS) \
llvm::Constant *IRGenModule::get##ID##Fn() { \
using namespace RuntimeConstants; \
return getWrapperFn(Module, ID##Fn, #NAME, STR(SYMBOL_NAME), CC, RETURNS, \
ARGS, ATTRS); \
}
#include "swift/Runtime/RuntimeFunctions.def"
std::pair<llvm::GlobalVariable *, llvm::Constant *>
IRGenModule::createStringConstant(StringRef Str,
bool willBeRelativelyAddressed, StringRef sectionName) {
// If not, create it. This implicitly adds a trailing null.
auto init = llvm::ConstantDataArray::getString(LLVMContext, Str);
auto global = new llvm::GlobalVariable(Module, init->getType(), true,
llvm::GlobalValue::PrivateLinkage,
init);
// FIXME: ld64 crashes resolving relative references to coalesceable symbols.
// rdar://problem/22674524
// If we intend to relatively address this string, don't mark it with
// unnamed_addr to prevent it from going into the cstrings section and getting
// coalesced.
if (!willBeRelativelyAddressed)
global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
if (!sectionName.empty())
global->setSection(sectionName);
// Drill down to make an i8*.
auto zero = llvm::ConstantInt::get(SizeTy, 0);
llvm::Constant *indices[] = { zero, zero };
auto address = llvm::ConstantExpr::getInBoundsGetElementPtr(
global->getValueType(), global, indices);
return { global, address };
}
llvm::Constant *IRGenModule::getEmptyTupleMetadata() {
if (EmptyTupleMetadata)
return EmptyTupleMetadata;
EmptyTupleMetadata = Module.getOrInsertGlobal(
MANGLE_AS_STRING(METADATA_SYM(EMPTY_TUPLE_MANGLING)),
FullTypeMetadataStructTy);
if (useDllStorage())
cast<llvm::GlobalVariable>(EmptyTupleMetadata)
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
return EmptyTupleMetadata;
}
llvm::Constant *IRGenModule::getObjCEmptyCachePtr() {
if (ObjCEmptyCachePtr)
return ObjCEmptyCachePtr;
if (ObjCInterop) {
// struct objc_cache _objc_empty_cache;
ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache",
OpaquePtrTy->getElementType());
if (useDllStorage())
cast<llvm::GlobalVariable>(ObjCEmptyCachePtr)
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
} else {
// FIXME: Remove even the null value per rdar://problem/18801263
ObjCEmptyCachePtr = llvm::ConstantPointerNull::get(OpaquePtrTy);
}
return ObjCEmptyCachePtr;
}
llvm::Constant *IRGenModule::getObjCEmptyVTablePtr() {
// IMP _objc_empty_vtable;
// On recent Darwin platforms, this symbol is defined at
// runtime as an absolute symbol with the value of null. Older ObjCs
// didn't guarantee _objc_empty_vtable to be nil, but Swift doesn't
// deploy far enough back for that to be a concern.
// FIXME: When !ObjCInterop, we should remove even the null value per
// rdar://problem/18801263
if (!ObjCEmptyVTablePtr)
ObjCEmptyVTablePtr = llvm::ConstantPointerNull::get(OpaquePtrTy);
return ObjCEmptyVTablePtr;
}
Address IRGenModule::getAddrOfObjCISAMask() {
// This symbol is only exported by the runtime if the platform uses
// isa masking.
assert(TargetInfo.hasISAMasking());
if (!ObjCISAMaskPtr) {
ObjCISAMaskPtr = Module.getOrInsertGlobal("swift_isaMask", IntPtrTy);
if (useDllStorage())
cast<llvm::GlobalVariable>(ObjCISAMaskPtr)
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
}
return Address(ObjCISAMaskPtr, getPointerAlignment());
}
ModuleDecl *IRGenModule::getSwiftModule() const {
return IRGen.SIL.getSwiftModule();
}
Lowering::TypeConverter &IRGenModule::getSILTypes() const {
return IRGen.SIL.Types;
}
clang::CodeGen::CodeGenModule &IRGenModule::getClangCGM() const {
return ClangCodeGen->CGM();
}
llvm::Module *IRGenModule::getModule() const {
return ClangCodeGen->GetModule();
}
llvm::Module *IRGenModule::releaseModule() {
return ClangCodeGen->ReleaseModule();
}
bool IRGenerator::canEmitWitnessTableLazily(SILWitnessTable *wt) {
if (Opts.UseJIT)
return false;
NominalTypeDecl *ConformingTy =
wt->getConformance()->getType()->getNominalOrBoundGenericNominal();
switch (ConformingTy->getEffectiveAccess()) {
case Accessibility::Private:
case Accessibility::FilePrivate:
return true;
case Accessibility::Internal:
return PrimaryIGM->getSILModule().isWholeModule();
default:
return false;
}
llvm_unreachable("switch does not handle all cases");
}
void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
if (SILWitnessTable *wt = SIL.lookUpWitnessTable(Conf)) {
// Add it to the queue if it hasn't already been put there.
if (canEmitWitnessTableLazily(wt) &&
LazilyEmittedWitnessTables.insert(wt).second) {
LazyWitnessTables.push_back(wt);
}
}
}
llvm::AttributeSet IRGenModule::getAllocAttrs() {
if (AllocAttrs.isEmpty()) {
AllocAttrs = llvm::AttributeSet::get(LLVMContext,
llvm::AttributeSet::ReturnIndex,
llvm::Attribute::NoAlias);
AllocAttrs = AllocAttrs.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoUnwind);
}
return AllocAttrs;
}
/// Construct initial attributes from options.
llvm::AttributeSet IRGenModule::constructInitialAttributes() {
llvm::AttributeSet attrsUpdated;
// Add DisableFPElim.
if (!IRGen.Opts.DisableFPElim) {
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex,
"no-frame-pointer-elim", "false");
} else {
attrsUpdated = attrsUpdated.addAttribute(
LLVMContext, llvm::AttributeSet::FunctionIndex,
"no-frame-pointer-elim", "true");
attrsUpdated = attrsUpdated.addAttribute(
LLVMContext, llvm::AttributeSet::FunctionIndex,
"no-frame-pointer-elim-non-leaf");
}
// Add target-cpu and target-features if they are non-null.
auto *Clang = static_cast<ClangImporter *>(Context.getClangModuleLoader());
clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts();
std::string &CPU = ClangOpts.CPU;
if (CPU != "")
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex, "target-cpu", CPU);
std::vector<std::string> &Features = ClangOpts.Features;
if (!Features.empty()) {
SmallString<64> allFeatures;
interleave(Features, [&](const std::string &s) {
allFeatures.append(s);
}, [&]{
allFeatures.push_back(',');
});
attrsUpdated = attrsUpdated.addAttribute(LLVMContext,
llvm::AttributeSet::FunctionIndex, "target-features",
allFeatures);
}
return attrsUpdated;
}
llvm::Constant *IRGenModule::getSize(Size size) {
return llvm::ConstantInt::get(SizeTy, size.getValue());
}
static void appendEncodedName(raw_ostream &os, StringRef name) {
if (clang::isValidIdentifier(name)) {
os << "_" << name;
} else {
for (auto c : name)
os.write_hex(static_cast<uint8_t>(c));
}
}
static void appendEncodedName(llvm::SmallVectorImpl<char> &buf,
StringRef name) {
llvm::raw_svector_ostream os{buf};
appendEncodedName(os, name);
}
static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl<char> &buf,
StringRef name) {
llvm::raw_svector_ostream os{buf};
os << "_swift_FORCE_LOAD_$";
appendEncodedName(os, name);
return os.str();
}
llvm::SmallString<32> getTargetDependentLibraryOption(const llvm::Triple &T,
StringRef library) {
llvm::SmallString<32> buffer;
if (T.isWindowsMSVCEnvironment() || T.isWindowsItaniumEnvironment()) {
bool quote = library.find(' ') != StringRef::npos;
buffer += "/DEFAULTLIB:";
if (quote)
buffer += '"';
buffer += library;
if (!library.endswith_lower(".lib"))
buffer += ".lib";
if (quote)
buffer += '"';
} else if (T.isPS4()) {
bool quote = library.find(' ') != StringRef::npos;
buffer += "\01";
if (quote)
buffer += '"';
buffer += library;
if (quote)
buffer += '"';
} else {
buffer += "-l";
buffer += library;
}
return buffer;
}
void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
llvm::LLVMContext &ctx = Module.getContext();
switch (linkLib.getKind()) {
case LibraryKind::Library: {
llvm::SmallString<32> opt =
getTargetDependentLibraryOption(Triple, linkLib.getName());
AutolinkEntries.push_back(
llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
break;
}
case LibraryKind::Framework: {
// If we're supposed to disable autolinking of this framework, bail out.
auto &frameworks = IRGen.Opts.DisableAutolinkFrameworks;
if (std::find(frameworks.begin(), frameworks.end(), linkLib.getName())
!= frameworks.end())
return;
llvm::Metadata *args[] = {
llvm::MDString::get(ctx, "-framework"),
llvm::MDString::get(ctx, linkLib.getName())
};
AutolinkEntries.push_back(llvm::MDNode::get(ctx, args));
break;
}
}
if (linkLib.shouldForceLoad()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, linkLib.getName());
auto symbolAddr = Module.getOrInsertGlobal(buf.str(), Int1Ty);
if (useDllStorage())
cast<llvm::GlobalVariable>(symbolAddr)
->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
buf += "_$";
appendEncodedName(buf, IRGen.Opts.ModuleName);
if (!Module.getGlobalVariable(buf.str())) {
auto ref = new llvm::GlobalVariable(Module, symbolAddr->getType(),
/*isConstant=*/true,
llvm::GlobalValue::WeakAnyLinkage,
symbolAddr, buf.str());
ref->setVisibility(llvm::GlobalValue::HiddenVisibility);
auto casted = llvm::ConstantExpr::getBitCast(ref, Int8PtrTy);
LLVMUsed.push_back(casted);
}
}
}
static bool replaceModuleFlagsEntry(llvm::LLVMContext &Ctx,
llvm::Module &Module, StringRef EntryName,
llvm::Module::ModFlagBehavior Behavior,
llvm::Metadata *Val) {
auto *ModuleFlags = Module.getModuleFlagsMetadata();
for (unsigned I = 0, E = ModuleFlags->getNumOperands(); I != E; ++I) {
llvm::MDNode *Op = ModuleFlags->getOperand(I);
llvm::MDString *ID = cast<llvm::MDString>(Op->getOperand(1));
if (ID->getString().equals(EntryName)) {
// Create the new entry.
llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx);
llvm::Metadata *Ops[3] = {llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int32Ty, Behavior)),
llvm::MDString::get(Ctx, EntryName), Val};
ModuleFlags->setOperand(I, llvm::MDNode::get(Ctx, Ops));
return true;
}
}
llvm_unreachable("Could not replace old linker options entry?");
}
void IRGenModule::emitAutolinkInfo() {
// FIXME: This constant should be vended by LLVM somewhere.
static const char * const LinkerOptionsFlagName = "Linker Options";
// Collect the linker options already in the module (from ClangCodeGen).
auto *LinkerOptions = Module.getModuleFlag(LinkerOptionsFlagName);
if (LinkerOptions)
for (const auto &LinkOption : cast<llvm::MDNode>(LinkerOptions)->operands())
AutolinkEntries.push_back(LinkOption);
// Remove duplicates.
llvm::SmallPtrSet<llvm::Metadata*, 4> knownAutolinkEntries;
AutolinkEntries.erase(std::remove_if(AutolinkEntries.begin(),
AutolinkEntries.end(),
[&](llvm::Metadata *entry) -> bool {
return !knownAutolinkEntries.insert(
entry).second;
}),
AutolinkEntries.end());
if ((TargetInfo.OutputObjectFormat == llvm::Triple::COFF &&
!Triple.isOSCygMing()) ||
TargetInfo.OutputObjectFormat == llvm::Triple::MachO || Triple.isPS4()) {
llvm::LLVMContext &ctx = Module.getContext();
if (!LinkerOptions) {
// Create a new linker flag entry.
Module.addModuleFlag(llvm::Module::AppendUnique, LinkerOptionsFlagName,
llvm::MDNode::get(ctx, AutolinkEntries));
} else {
// Replace the old linker flag entry.
bool FoundOldEntry = replaceModuleFlagsEntry(
ctx, Module, LinkerOptionsFlagName, llvm::Module::AppendUnique,
llvm::MDNode::get(ctx, AutolinkEntries));
(void)FoundOldEntry;
assert(FoundOldEntry && "Could not replace old linker options entry?");
}
} else {
assert((TargetInfo.OutputObjectFormat == llvm::Triple::ELF ||
Triple.isOSCygMing()) &&
"expected ELF output format or COFF format for Cygwin/MinGW");
// Merge the entries into null-separated string.
llvm::SmallString<64> EntriesString;
for (auto &EntryNode : AutolinkEntries) {
const llvm::MDNode *MD = cast<llvm::MDNode>(EntryNode);
for (auto &Entry : MD->operands()) {
const llvm::MDString *MS = cast<llvm::MDString>(Entry);
EntriesString += MS->getString();
EntriesString += '\0';
}
}
auto EntriesConstant = llvm::ConstantDataArray::getString(
LLVMContext, EntriesString, /*AddNull=*/false);
auto var =
new llvm::GlobalVariable(*getModule(), EntriesConstant->getType(), true,
llvm::GlobalValue::PrivateLinkage,
EntriesConstant, "_swift1_autolink_entries");
var->setSection(".swift1_autolink_entries");
var->setAlignment(getPointerAlignment().getValue());
addUsedGlobal(var);
}
if (!IRGen.Opts.ForceLoadSymbolName.empty()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, IRGen.Opts.ForceLoadSymbolName);
auto symbol =
new llvm::GlobalVariable(Module, Int1Ty, /*isConstant=*/false,
llvm::GlobalValue::CommonLinkage,
llvm::Constant::getNullValue(Int1Ty),
buf.str());
if (useDllStorage())
symbol->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
}
}
void IRGenModule::cleanupClangCodeGenMetadata() {
// Remove llvm.ident that ClangCodeGen might have left in the module.
auto *LLVMIdent = Module.getNamedMetadata("llvm.ident");
if (LLVMIdent)
Module.eraseNamedMetadata(LLVMIdent);
// LLVM's object-file emission collects a fixed set of keys for the
// image info.
// Using "Objective-C Garbage Collection" as the key here is a hack,
// but LLVM's object-file emission isn't general enough to collect
// arbitrary keys to put in the image info.
const char *ObjectiveCGarbageCollection = "Objective-C Garbage Collection";
if (Module.getModuleFlag(ObjectiveCGarbageCollection)) {
bool FoundOldEntry = replaceModuleFlagsEntry(
Module.getContext(), Module, ObjectiveCGarbageCollection,
llvm::Module::Override,
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int32Ty, (uint32_t)(swiftVersion << 8))));
(void)FoundOldEntry;
assert(FoundOldEntry && "Could not replace old module flag entry?");
} else
Module.addModuleFlag(llvm::Module::Override,
ObjectiveCGarbageCollection,
(uint32_t)(swiftVersion << 8));
}
bool IRGenModule::finalize() {
const char *ModuleHashVarName = "llvm.swift_module_hash";
if (IRGen.Opts.OutputKind == IRGenOutputKind::ObjectFile &&
!Module.getGlobalVariable(ModuleHashVarName)) {
// Create a global variable into which we will store the hash of the
// module (used for incremental compilation).
// We have to create the variable now (before we emit the global lists).
// But we want to calculate the hash later because later we can do it
// multi-threaded.
llvm::MD5::MD5Result zero{};
ArrayRef<uint8_t> ZeroArr(reinterpret_cast<uint8_t *>(&zero), sizeof(zero));
auto *ZeroConst = llvm::ConstantDataArray::get(Module.getContext(), ZeroArr);
ModuleHash = new llvm::GlobalVariable(Module, ZeroConst->getType(), true,
llvm::GlobalValue::PrivateLinkage,
ZeroConst, ModuleHashVarName);
switch (TargetInfo.OutputObjectFormat) {
case llvm::Triple::MachO:
// On Darwin the linker ignores the __LLVM segment.
ModuleHash->setSection("__LLVM,__swift_modhash");
break;
case llvm::Triple::ELF:
case llvm::Triple::COFF:
ModuleHash->setSection(".swift_modhash");
break;
default:
llvm_unreachable("Don't know how to emit the module hash for the selected"
"object format.");
}
addUsedGlobal(ModuleHash);
}
emitLazyPrivateDefinitions();
// Finalize clang IR-generation.
finalizeClangCodeGen();
// If that failed, report failure up and skip the final clean-up.
if (!ClangCodeGen->GetModule())
return false;
emitAutolinkInfo();
emitGlobalLists();
if (DebugInfo)
DebugInfo->finalize();
cleanupClangCodeGenMetadata();
return true;
}
/// Emit lazy definitions that have to be emitted in this specific
/// IRGenModule.
void IRGenModule::emitLazyPrivateDefinitions() {
emitLazyObjCProtocolDefinitions();
}
void IRGenModule::unimplemented(SourceLoc loc, StringRef message) {
Context.Diags.diagnose(loc, diag::irgen_unimplemented, message);
}
void IRGenModule::fatal_unimplemented(SourceLoc loc, StringRef message) {
Context.Diags.diagnose(loc, diag::irgen_unimplemented, message);
llvm::report_fatal_error(llvm::Twine("unimplemented IRGen feature! ") +
message);
}
void IRGenModule::error(SourceLoc loc, const Twine &message) {
SmallVector<char, 128> buffer;
Context.Diags.diagnose(loc, diag::irgen_failure,
message.toStringRef(buffer));
}
bool IRGenModule::useDllStorage() { return ::useDllStorage(Triple); }
void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) {
assert(GenModules.count(SF) == 0);
GenModules[SF] = IGM;
if (!PrimaryIGM) {
PrimaryIGM = IGM;
}
Queue.push_back(IGM);
}
IRGenModule *IRGenerator::getGenModule(DeclContext *ctxt) {
if (GenModules.size() == 1 || !ctxt) {
return getPrimaryIGM();
}
SourceFile *SF = ctxt->getParentSourceFile();
if (!SF) {
return getPrimaryIGM();
}
IRGenModule *IGM = GenModules[SF];
assert(IGM);
return IGM;
}
IRGenModule *IRGenerator::getGenModule(SILFunction *f) {
if (GenModules.size() == 1) {
return getPrimaryIGM();
}
if (DeclContext *ctxt = f->getDeclContext()) {
if (SourceFile *SF = ctxt->getParentSourceFile()) {
IRGenModule *IGM = GenModules[SF];
assert(IGM);
return IGM;
}
}
// We have no source file for the function.
// Let's use the IGM from which the function is referenced the first time.
if (IRGenModule *IGM = DefaultIGMForFunction[f])
return IGM;
return getPrimaryIGM();
}