blob: 8a7e346ca2e56cad686cefc7efec5eb37172aeae [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/Availability.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Module.h"
#include "swift/AST/DiagnosticsIRGen.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/IRGenRequests.h"
#include "swift/Basic/Dwarf.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/IRGen/IRGenPublic.h"
#include "swift/IRGen/Linking.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/Basic/CodeGenOptions.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/MDBuilder.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 "Callee.h"
#include "ConformanceDescription.h"
#include "GenDecl.h"
#include "GenEnum.h"
#include "GenMeta.h"
#include "GenPointerAuth.h"
#include "GenIntegerLiteral.h"
#include "GenType.h"
#include "IRGenModule.h"
#include "IRGenDebugInfo.h"
#include "ProtocolInfo.h"
#include "StructLayout.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,
const IRGenOptions &Opts,
StringRef ModuleName,
StringRef PD) {
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.shouldOptimize() ? 3 : 0;
CGO.DiscardValueNames = !Opts.shouldProvideValueNames();
switch (Opts.DebugInfoLevel) {
case IRGenDebugInfoLevel::None:
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::NoDebugInfo);
break;
case IRGenDebugInfoLevel::LineTables:
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::DebugLineTablesOnly);
break;
case IRGenDebugInfoLevel::ASTTypes:
case IRGenDebugInfoLevel::DwarfTypes:
CGO.DebugTypeExtRefs = true;
CGO.setDebugInfo(clang::codegenoptions::DebugInfoKind::FullDebugInfo);
break;
}
switch (Opts.DebugInfoFormat) {
case IRGenDebugInfoFormat::None:
break;
case IRGenDebugInfoFormat::DWARF:
CGO.DebugCompilationDir = Opts.DebugCompilationDir;
CGO.DwarfVersion = Opts.DWARFVersion;
CGO.DwarfDebugFlags = Opts.getDebugFlags(PD);
break;
case IRGenDebugInfoFormat::CodeView:
CGO.EmitCodeView = true;
CGO.DebugCompilationDir = Opts.DebugCompilationDir;
// This actually contains the debug flags for codeview.
CGO.DwarfDebugFlags = Opts.getDebugFlags(PD);
break;
}
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;
}
#ifndef NDEBUG
static ValueDecl *lookupSimple(ModuleDecl *module, ArrayRef<StringRef> declPath) {
DeclContext *dc = module;
for (;; declPath = declPath.drop_front()) {
SmallVector<ValueDecl*, 1> results;
module->lookupMember(results, dc, module->getASTContext().getIdentifier(declPath.front()), Identifier());
if (results.size() != 1) return nullptr;
if (declPath.size() == 1) return results.front();
dc = dyn_cast<DeclContext>(results.front());
if (!dc) return nullptr;
}
}
static void checkPointerAuthWitnessDiscriminator(IRGenModule &IGM, ArrayRef<StringRef> declPath, uint16_t expected) {
auto &schema = IGM.getOptions().PointerAuth.ProtocolWitnesses;
if (!schema.isEnabled()) return;
auto decl = lookupSimple(IGM.getSwiftModule(), declPath);
assert(decl && "decl not found");
auto discriminator = PointerAuthInfo::getOtherDiscriminator(IGM, schema, SILDeclRef(decl));
assert(discriminator->getZExtValue() == expected && "discriminator value doesn't match");
}
static void checkPointerAuthAssociatedTypeDiscriminator(IRGenModule &IGM, ArrayRef<StringRef> declPath, uint16_t expected) {
auto &schema = IGM.getOptions().PointerAuth.ProtocolAssociatedTypeAccessFunctions;
if (!schema.isEnabled()) return;
auto decl = dyn_cast_or_null<AssociatedTypeDecl>(lookupSimple(IGM.getSwiftModule(), declPath));
assert(decl && "decl not found");
auto discriminator = PointerAuthInfo::getOtherDiscriminator(IGM, schema, AssociatedType(decl));
assert(discriminator->getZExtValue() == expected && "discriminator value doesn't match");
}
static void sanityCheckStdlib(IRGenModule &IGM) {
if (!IGM.getSwiftModule()->isStdlibModule()) return;
// Only run the sanity check when we're building the real stdlib.
if (!lookupSimple(IGM.getSwiftModule(), { "String" })) return;
checkPointerAuthAssociatedTypeDiscriminator(IGM, { "_ObjectiveCBridgeable", "_ObjectiveCType" }, SpecialPointerAuthDiscriminators::ObjectiveCTypeDiscriminator);
checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_bridgeToObjectiveC" }, SpecialPointerAuthDiscriminators::bridgeToObjectiveCDiscriminator);
checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_forceBridgeFromObjectiveC" }, SpecialPointerAuthDiscriminators::forceBridgeFromObjectiveCDiscriminator);
checkPointerAuthWitnessDiscriminator(IGM, { "_ObjectiveCBridgeable", "_conditionallyBridgeFromObjectiveC" }, SpecialPointerAuthDiscriminators::conditionallyBridgeFromObjectiveCDiscriminator);
}
#endif
IRGenModule::IRGenModule(IRGenerator &irgen,
std::unique_ptr<llvm::TargetMachine> &&target,
SourceFile *SF,
StringRef ModuleName, StringRef OutputFilename,
StringRef MainInputFilenameForDebugInfo,
StringRef PrivateDiscriminator)
: LLVMContext(new llvm::LLVMContext()),
IRGen(irgen), Context(irgen.SIL.getASTContext()),
// The LLVMContext (and the IGM itself) will get deleted by the IGMDeleter
// as long as the IGM is registered with the IRGenerator.
ClangCodeGen(createClangCodeGenerator(Context, *LLVMContext,
irgen.Opts,
ModuleName, PrivateDiscriminator)),
Module(*ClangCodeGen->GetModule()),
DataLayout(irgen.getClangDataLayout()),
Triple(irgen.getEffectiveClangTriple()), TargetMachine(std::move(target)),
silConv(irgen.SIL), OutputFilename(OutputFilename),
MainInputFilenameForDebugInfo(MainInputFilenameForDebugInfo),
TargetInfo(SwiftTargetInfo::get(*this)), DebugInfo(nullptr),
ModuleHash(nullptr), ObjCInterop(Context.LangOpts.EnableObjCInterop),
UseDarwinPreStableABIBit(Context.LangOpts.UseDarwinPreStableABIBit),
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());
Int32PtrTy = Int32Ty->getPointerTo();
Int64Ty = llvm::Type::getInt64Ty(getLLVMContext());
// SWIFT_ENABLE_TENSORFLOW
DoubleTy = llvm::Type::getDoubleTy(getLLVMContext());
FloatTy = llvm::Type::getFloatTy(getLLVMContext());
Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
SizeTy = DataLayout.getIntPtrType(getLLVMContext(), /*addrspace*/ 0);
// For the relative address type, we want to use the int32 bit type
// on most architectures, e.g. x86_64, because it produces valid
// fixups/relocations. The exception is 16-bit architectures,
// so we shorten the relative address type there.
if (SizeTy->getBitWidth()<32) {
RelativeAddressTy = SizeTy;
} else {
RelativeAddressTy = Int32Ty;
}
RelativeAddressPtrTy = RelativeAddressTy->getPointerTo();
FloatTy = llvm::Type::getFloatTy(getLLVMContext());
DoubleTy = llvm::Type::getDoubleTy(getLLVMContext());
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, references storage types are just pointers.
#define CHECKED_REF_STORAGE(Name, name, ...) \
Name##ReferencePtrTy = \
createStructPointerType(*this, "swift." #name, { RefCountedPtrTy });
#include "swift/AST/ReferenceStorage.def"
// 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);
TypeMetadataPtrPtrTy = TypeMetadataPtrTy->getPointerTo(DefaultAS);
TypeMetadataResponseTy = createStructType(*this, "swift.metadata_response", {
TypeMetadataPtrTy,
SizeTy
});
OffsetPairTy = llvm::StructType::get(getLLVMContext(), { SizeTy, SizeTy });
// The TypeLayout structure, including all possible trailing components.
FullTypeLayoutTy = createStructType(*this, "swift.full_type_layout", {
SizeTy, // size
SizeTy, // flags
SizeTy, // alignment
SizeTy // extra inhabitant flags (optional)
});
TypeLayoutTy = createStructType(*this, "swift.type_layout", {
SizeTy, // size
SizeTy, // stride
Int32Ty, // flags
Int32Ty // extra inhabitant count
});
// 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
Int32Ty, // total requirement count
Int32Ty, // requirements array
RelativeAddressTy, // superclass
RelativeAddressTy // associated type names
});
ProtocolDescriptorPtrTy = ProtocolDescriptorStructTy->getPointerTo();
ProtocolRequirementStructTy =
createStructType(*this, "swift.protocol_requirement", {
Int32Ty, // flags
RelativeAddressTy, // default implementation
});
// A tuple type metadata record has a couple extra fields.
auto tupleElementTy = createStructType(*this, "swift.tuple_element_type", {
TypeMetadataPtrTy, // Metadata *Type;
Int32Ty // int32_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.
static_assert(MetadataAdjustmentIndex::ValueType == 1,
"Adjustment index must be synchronized with this layout");
FullTypeMetadataStructTy = createStructType(*this, "swift.full_type", {
WitnessTablePtrTy,
TypeMetadataStructTy
});
FullTypeMetadataPtrTy = FullTypeMetadataStructTy->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.
static_assert(MetadataAdjustmentIndex::Class == 2,
"Adjustment index must be synchronized with this layout");
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);
// This must match struct HeapObject in the runtime.
llvm::Type *refCountedElts[] = {TypeMetadataPtrTy, IntPtrTy};
RefCountedStructTy->setBody(refCountedElts);
RefCountedStructSize =
Size(DataLayout.getStructLayout(RefCountedStructTy)->getSizeInBytes());
PtrSize = Size(DataLayout.getPointerSize(DefaultAS));
FunctionPairTy = createStructType(*this, "swift.function", {
FunctionPtrTy,
RefCountedPtrTy,
});
OpaqueTy = llvm::StructType::create(getLLVMContext(), "swift.opaque");
OpaquePtrTy = OpaqueTy->getPointerTo(DefaultAS);
NoEscapeFunctionPairTy = createStructType(*this, "swift.noescape.function", {
FunctionPtrTy,
OpaquePtrTy,
});
ProtocolRecordTy =
createStructType(*this, "swift.protocolref", {
RelativeAddressTy
});
ProtocolRecordPtrTy = ProtocolRecordTy->getPointerTo();
ProtocolConformanceDescriptorTy
= createStructType(*this, "swift.protocol_conformance_descriptor", {
RelativeAddressTy,
RelativeAddressTy,
RelativeAddressTy,
Int32Ty
});
ProtocolConformanceDescriptorPtrTy
= ProtocolConformanceDescriptorTy->getPointerTo(DefaultAS);
TypeContextDescriptorTy
= llvm::StructType::create(getLLVMContext(), "swift.type_descriptor");
TypeContextDescriptorPtrTy
= TypeContextDescriptorTy->getPointerTo(DefaultAS);
ClassContextDescriptorTy =
llvm::StructType::get(getLLVMContext(), {
Int32Ty, // context flags
Int32Ty, // parent
Int32Ty, // name
Int32Ty, // kind
Int32Ty, // accessor function
Int32Ty, // num fields
Int32Ty, // field offset vector
Int32Ty, // is_reflectable flag
Int32Ty, // (Generics Descriptor) argument offset
Int32Ty, // (Generics Descriptor) num params
Int32Ty, // (Generics Descriptor) num requirements
Int32Ty, // (Generics Descriptor) num key arguments
Int32Ty, // (Generics Descriptor) num extra arguments
Int32Ty, // (VTable Descriptor) offset
Int32Ty, // (VTable Descriptor) size
Int32Ty, // (Methods Descriptor) accessor
Int32Ty, // (Methods Descriptor) flags
}, /*packed=*/true);
MethodDescriptorStructTy
= createStructType(*this, "swift.method_descriptor", {
Int32Ty,
RelativeAddressTy,
});
MethodOverrideDescriptorStructTy
= createStructType(*this, "swift.method_override_descriptor", {
RelativeAddressTy,
RelativeAddressTy,
RelativeAddressTy
});
TypeMetadataRecordTy
= createStructType(*this, "swift.type_metadata_record", {
RelativeAddressTy
});
TypeMetadataRecordPtrTy
= TypeMetadataRecordTy->getPointerTo(DefaultAS);
FieldDescriptorTy
= llvm::StructType::create(getLLVMContext(), "swift.field_descriptor");
FieldDescriptorPtrTy = FieldDescriptorTy->getPointerTo(DefaultAS);
FieldDescriptorPtrPtrTy = FieldDescriptorPtrTy->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(getLLVMContext(), "objc_class");
ObjCClassPtrTy = ObjCClassStructTy->getPointerTo(DefaultAS);
llvm::Type *objcClassElts[] = {
ObjCClassPtrTy,
ObjCClassPtrTy,
OpaquePtrTy,
OpaquePtrTy,
IntPtrTy
};
ObjCClassStructTy->setBody(objcClassElts);
ObjCSuperStructTy = llvm::StructType::create(getLLVMContext(), "objc_super");
ObjCSuperPtrTy = ObjCSuperStructTy->getPointerTo(DefaultAS);
llvm::Type *objcSuperElts[] = {
ObjCPtrTy,
ObjCClassPtrTy
};
ObjCSuperStructTy->setBody(objcSuperElts);
ObjCBlockStructTy = llvm::StructType::create(getLLVMContext(), "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);
// Class _Nullable callback(Class _Nonnull cls, void * _Nullable arg);
llvm::Type *params[] = { ObjCClassPtrTy, Int8PtrTy };
ObjCUpdateCallbackTy = llvm::FunctionType::get(ObjCClassPtrTy, params, false);
// The full class stub structure, including a word before the address point.
ObjCFullResilientClassStubTy = createStructType(*this, "objc_full_class_stub", {
SizeTy, // zero padding to appease the linker
SizeTy, // isa pointer -- always 1
ObjCUpdateCallbackTy->getPointerTo() // the update callback
});
// What we actually export.
ObjCResilientClassStubTy = createStructType(*this, "objc_class_stub", {
SizeTy, // isa pointer -- always 1
ObjCUpdateCallbackTy->getPointerTo() // the update callback
});
auto ErrorStructTy = llvm::StructType::create(getLLVMContext(), "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);
WitnessTablePtrPtrTy = WitnessTablePtrTy->getPointerTo(DefaultAS);
// todo
OpaqueTypeDescriptorTy = TypeContextDescriptorTy;
OpaqueTypeDescriptorPtrTy = OpaqueTypeDescriptorTy->getPointerTo();
InvariantMetadataID = getLLVMContext().getMDKindID("invariant.load");
InvariantNode = llvm::MDNode::get(getLLVMContext(), {});
DereferenceableID = getLLVMContext().getMDKindID("dereferenceable");
C_CC = llvm::CallingConv::C;
// TODO: use "tinycc" on platforms that support it
DefaultCC = SWIFT_DEFAULT_LLVM_CC;
SwiftCC = llvm::CallingConv::Swift;
if (opts.DebugInfoLevel > IRGenDebugInfoLevel::None)
DebugInfo = IRGenDebugInfo::createIRGenDebugInfo(IRGen.Opts, *CI, *this,
Module,
MainInputFilenameForDebugInfo,
PrivateDiscriminator);
if (auto loader = Context.getClangModuleLoader()) {
ClangASTContext =
&static_cast<ClangImporter *>(loader)->getClangASTContext();
}
if (ClangASTContext) {
auto atomicBoolTy = ClangASTContext->getAtomicType(ClangASTContext->BoolTy);
AtomicBoolSize = Size(ClangASTContext->getTypeSize(atomicBoolTy));
AtomicBoolAlign = Alignment(ClangASTContext->getTypeSize(atomicBoolTy));
}
IsSwiftErrorInRegister =
clang::CodeGen::swiftcall::isSwiftErrorLoweredInRegister(
ClangCodeGen->CGM());
#ifndef NDEBUG
sanityCheckStdlib(*this);
#endif
DynamicReplacementsTy =
llvm::StructType::get(getLLVMContext(), {Int8PtrPtrTy, Int8PtrTy});
DynamicReplacementsPtrTy = DynamicReplacementsTy->getPointerTo(DefaultAS);
DynamicReplacementLinkEntryTy =
llvm::StructType::create(getLLVMContext(), "swift.dyn_repl_link_entry");
DynamicReplacementLinkEntryPtrTy =
DynamicReplacementLinkEntryTy->getPointerTo(DefaultAS);
llvm::Type *linkEntryFields[] = {
Int8PtrTy, // function pointer.
DynamicReplacementLinkEntryPtrTy // next.
};
DynamicReplacementLinkEntryTy->setBody(linkEntryFields);
DynamicReplacementKeyTy = createStructType(*this, "swift.dyn_repl_key",
{RelativeAddressTy, Int32Ty});
AsyncFunctionPointerTy = createStructType(*this, "swift.async_func_pointer",
{RelativeAddressTy, Int32Ty}, true);
SwiftContextTy = createStructType(*this, "swift.context", {});
auto *ContextPtrTy = llvm::PointerType::getUnqual(SwiftContextTy);
// This must match the definition of class AsyncTask in swift/ABI/Task.h.
SwiftTaskTy = createStructType(*this, "swift.task", {
RefCountedStructTy, // object header
Int8PtrTy, Int8PtrTy, // Job.SchedulerPrivate
SizeTy, // Job.Flags
FunctionPtrTy, // Job.RunJob/Job.ResumeTask
ContextPtrTy, // Task.ResumeContext
IntPtrTy // Task.Status
});
SwiftExecutorTy = createStructType(*this, "swift.executor", {});
AsyncFunctionPointerPtrTy = AsyncFunctionPointerTy->getPointerTo(DefaultAS);
SwiftContextPtrTy = SwiftContextTy->getPointerTo(DefaultAS);
SwiftTaskPtrTy = SwiftTaskTy->getPointerTo(DefaultAS);
SwiftExecutorPtrTy = SwiftExecutorTy->getPointerTo(DefaultAS);
SwiftJobTy = createStructType(*this, "swift.job", {
SizeTy, // flags
Int8PtrTy // execution function pointer
});
SwiftJobPtrTy = SwiftJobTy->getPointerTo();
// using TaskContinuationFunction =
// SWIFT_CC(swift)
// void (AsyncTask *, ExecutorRef, AsyncContext *);
TaskContinuationFunctionTy = llvm::FunctionType::get(
VoidTy, {SwiftTaskPtrTy, SwiftExecutorPtrTy, SwiftContextPtrTy},
/*isVarArg*/ false);
TaskContinuationFunctionPtrTy = TaskContinuationFunctionTy->getPointerTo();
AsyncTaskAndContextTy = createStructType(
*this, "swift.async_task_and_context",
{ SwiftTaskPtrTy, SwiftContextPtrTy });
AsyncContinuationContextTy = createStructType(
*this, "swift.async_continuation_context",
{SwiftContextPtrTy, SizeTy, ErrorPtrTy, OpaquePtrTy, SwiftExecutorPtrTy});
AsyncContinuationContextPtrTy = AsyncContinuationContextTy->getPointerTo();
DifferentiabilityWitnessTy = createStructType(
*this, "swift.differentiability_witness", {Int8PtrTy, Int8PtrTy});
}
IRGenModule::~IRGenModule() {
destroyMetadataLayoutMap();
destroyPointerAuthCaches();
delete &Types;
}
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 ArgMemOnly = llvm::Attribute::ArgMemOnly;
const auto NoReturn = llvm::Attribute::NoReturn;
const auto NoUnwind = llvm::Attribute::NoUnwind;
const auto ZExt = llvm::Attribute::ZExt;
const auto FirstParamReturned = llvm::Attribute::Returned;
RuntimeAvailability AlwaysAvailable(ASTContext &Context) {
return RuntimeAvailability::AlwaysAvailable;
}
bool
isDeploymentAvailabilityContainedIn(ASTContext &Context,
AvailabilityContext featureAvailability) {
auto deploymentAvailability =
AvailabilityContext::forDeploymentTarget(Context);
return deploymentAvailability.isContainedIn(featureAvailability);
}
RuntimeAvailability OpaqueTypeAvailability(ASTContext &Context) {
auto featureAvailability = Context.getOpaqueTypeAvailability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability
GetTypesInAbstractMetadataStateAvailability(ASTContext &context) {
auto featureAvailability =
context.getTypesInAbstractMetadataStateAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability DynamicReplacementAvailability(ASTContext &Context) {
auto featureAvailability = Context.getSwift51Availability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
return RuntimeAvailability::AvailableByCompatibilityLibrary;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability
CompareTypeContextDescriptorsAvailability(ASTContext &Context) {
auto featureAvailability =
Context.getCompareTypeContextDescriptorsAvailability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability
CompareProtocolConformanceDescriptorsAvailability(ASTContext &Context) {
auto featureAvailability =
Context.getCompareProtocolConformanceDescriptorsAvailability();
if (!isDeploymentAvailabilityContainedIn(Context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability
GetCanonicalSpecializedMetadataAvailability(ASTContext &context) {
auto featureAvailability =
context.getIntermodulePrespecializedGenericMetadataAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability
GetCanonicalPrespecializedGenericMetadataAvailability(ASTContext &context) {
auto featureAvailability =
context.getPrespecializedGenericMetadataAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability ConcurrencyAvailability(ASTContext &context) {
auto featureAvailability = context.getConcurrencyAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
RuntimeAvailability DifferentiationAvailability(ASTContext &context) {
auto featureAvailability = context.getDifferentiationAvailability();
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
return RuntimeAvailability::ConditionallyAvailable;
}
return RuntimeAvailability::AlwaysAvailable;
}
} // 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;
}
// Similar to the 'return' attribute we assume that the 'returned' attributed is
// associated with the first function parameter.
static bool isReturnedAttribute(llvm::Attribute::AttrKind Attr) {
return Attr == llvm::Attribute::Returned;
}
// SWIFT_ENABLE_TENSORFLOW
// Similar to the 'return' attribute we assume that the 'sret' attributed is
// associated with the first function parameter.
static bool isStructRetAttribute(llvm::Attribute::AttrKind Attr) {
return Attr == llvm::Attribute::StructRet;
}
namespace {
bool isStandardLibrary(const llvm::Module &M) {
if (auto *Flags = M.getNamedMetadata("swift.module.flags")) {
for (const auto *F : Flags->operands()) {
const auto *Key = dyn_cast_or_null<llvm::MDString>(F->getOperand(0));
if (!Key)
continue;
const auto *Value =
dyn_cast_or_null<llvm::ConstantAsMetadata>(F->getOperand(1));
if (!Value)
continue;
if (Key->getString() == "standard-library")
return cast<llvm::ConstantInt>(Value->getValue())->isOne();
}
}
return false;
}
}
bool IRGenModule::isStandardLibrary() const {
return ::isStandardLibrary(Module);
}
llvm::Constant *swift::getRuntimeFn(llvm::Module &Module,
llvm::Constant *&cache,
const char *name,
llvm::CallingConv::ID cc,
RuntimeAvailability availability,
llvm::ArrayRef<llvm::Type*> retTypes,
llvm::ArrayRef<llvm::Type*> argTypes,
ArrayRef<Attribute::AttrKind> attrs) {
if (cache)
return cache;
bool isWeakLinked = false;
std::string functionName(name);
switch (availability) {
case RuntimeAvailability::AlwaysAvailable:
// Nothing to do.
break;
case RuntimeAvailability::ConditionallyAvailable: {
isWeakLinked = true;
break;
}
case RuntimeAvailability::AvailableByCompatibilityLibrary: {
functionName.append("50");
break;
}
}
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);
auto addr = Module.getOrInsertFunction(functionName.c_str(), fnTy).getCallee();
auto fnptr = addr;
// Strip off any bitcast we might have due to this function being declared of
// a different type previously.
if (auto bitcast = dyn_cast<llvm::BitCastInst>(fnptr))
fnptr = cast<llvm::Constant>(bitcast->getOperand(0));
cache = cast<llvm::Constant>(addr);
// Add any function attributes and set the calling convention.
if (auto fn = dyn_cast<llvm::Function>(fnptr)) {
fn->setCallingConv(cc);
bool IsExternal =
fn->getLinkage() == llvm::GlobalValue::AvailableExternallyLinkage ||
(fn->getLinkage() == llvm::GlobalValue::ExternalLinkage &&
fn->isDeclaration());
if (!isStandardLibrary(Module) && IsExternal &&
::useDllStorage(llvm::Triple(Module.getTargetTriple())))
fn->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
if (IsExternal && isWeakLinked
&& !::useDllStorage(llvm::Triple(Module.getTargetTriple())))
fn->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
llvm::AttrBuilder buildFnAttr;
llvm::AttrBuilder buildRetAttr;
llvm::AttrBuilder buildFirstParamAttr;
for (auto Attr : attrs) {
if (isReturnAttribute(Attr))
buildRetAttr.addAttribute(Attr);
// SWIFT_ENABLE_TENSORFLOW
else if (isReturnedAttribute(Attr) || isStructRetAttribute(Attr))
buildFirstParamAttr.addAttribute(Attr);
else
buildFnAttr.addAttribute(Attr);
}
fn->addAttributes(llvm::AttributeList::FunctionIndex, buildFnAttr);
fn->addAttributes(llvm::AttributeList::ReturnIndex, buildRetAttr);
fn->addParamAttrs(0, buildFirstParamAttr);
}
return cache;
}
#define QUOTE(...) __VA_ARGS__
#define STR(X) #X
#define FUNCTION(ID, NAME, CC, AVAILABILITY, RETURNS, ARGS, ATTRS) \
FUNCTION_IMPL(ID, NAME, CC, AVAILABILITY, 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, AVAILABILITY, RETURNS, ARGS, ATTRS) \
llvm::Constant *IRGenModule::get##ID##Fn() { \
using namespace RuntimeConstants; \
return getRuntimeFn(Module, ID##Fn, #NAME, CC, \
AVAILABILITY(this->Context), \
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(getLLVMContext(), 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 };
}
#define KNOWN_METADATA_ACCESSOR(NAME, SYM) \
llvm::Constant *IRGenModule::get##NAME() { \
if (NAME) \
return NAME; \
NAME = Module.getOrInsertGlobal(SYM, FullTypeMetadataStructTy); \
if (useDllStorage() && !isStandardLibrary()) \
ApplyIRLinkage(IRLinkage::ExternalImport) \
.to(cast<llvm::GlobalVariable>(NAME)); \
return NAME; \
}
KNOWN_METADATA_ACCESSOR(EmptyTupleMetadata,
MANGLE_AS_STRING(METADATA_SYM(EMPTY_TUPLE_MANGLING)))
KNOWN_METADATA_ACCESSOR(AnyExistentialMetadata,
MANGLE_AS_STRING(METADATA_SYM(ANY_MANGLING)))
KNOWN_METADATA_ACCESSOR(AnyObjectExistentialMetadata,
MANGLE_AS_STRING(METADATA_SYM(ANYOBJECT_MANGLING)))
#undef KNOWN_METADATA_ACCESSOR
llvm::Constant *IRGenModule::getObjCEmptyCachePtr() {
if (ObjCEmptyCachePtr)
return ObjCEmptyCachePtr;
if (ObjCInterop) {
// struct objc_cache _objc_empty_cache;
ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache",
OpaquePtrTy->getElementType());
ApplyIRLinkage(IRLinkage::ExternalImport)
.to(cast<llvm::GlobalVariable>(ObjCEmptyCachePtr));
} 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);
ApplyIRLinkage(IRLinkage::ExternalImport)
.to(cast<llvm::GlobalVariable>(ObjCISAMaskPtr));
}
return Address(ObjCISAMaskPtr, getPointerAlignment());
}
ModuleDecl *IRGenModule::getSwiftModule() const {
return IRGen.SIL.getSwiftModule();
}
AvailabilityContext IRGenModule::getAvailabilityContext() const {
return AvailabilityContext::forDeploymentTarget(Context);
}
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();
}
GeneratedModule IRGenModule::intoGeneratedModule() && {
return GeneratedModule{
std::move(LLVMContext),
std::unique_ptr<llvm::Module>{ClangCodeGen->ReleaseModule()},
std::move(TargetMachine)
};
}
bool IRGenerator::canEmitWitnessTableLazily(SILWitnessTable *wt) {
if (Opts.UseJIT)
return false;
// Regardless of the access level, if the witness table is shared it means
// we can safely not emit it. Every other module which needs it will generate
// its own shared copy of it.
if (wt->getLinkage() == SILLinkage::Shared)
return true;
NominalTypeDecl *ConformingTy =
wt->getConformingType()->getNominalOrBoundGenericNominal();
switch (ConformingTy->getEffectiveAccess()) {
case AccessLevel::Private:
case AccessLevel::FilePrivate:
return true;
case AccessLevel::Internal:
return PrimaryIGM->getSILModule().isWholeModule();
default:
return false;
}
llvm_unreachable("switch does not handle all cases");
}
void IRGenerator::addLazyWitnessTable(const ProtocolConformance *Conf) {
if (auto *wt = SIL.lookUpWitnessTable(Conf, /*deserializeLazily=*/false)) {
// Add it to the queue if it hasn't already been put there.
if (canEmitWitnessTableLazily(wt) &&
LazilyEmittedWitnessTables.insert(wt).second) {
assert(!FinishedEmittingLazyDefinitions);
LazyWitnessTables.push_back(wt);
}
}
}
void IRGenerator::addClassForEagerInitialization(ClassDecl *ClassDecl) {
if (!ClassDecl->getAttrs().hasAttribute<StaticInitializeObjCMetadataAttr>())
return;
assert(!ClassDecl->isGenericContext());
assert(!ClassDecl->hasClangNode());
ClassesForEagerInitialization.push_back(ClassDecl);
}
llvm::AttributeList IRGenModule::getAllocAttrs() {
if (AllocAttrs.isEmpty()) {
AllocAttrs =
llvm::AttributeList::get(getLLVMContext(),
llvm::AttributeList::ReturnIndex,
llvm::Attribute::NoAlias);
AllocAttrs =
AllocAttrs.addAttribute(getLLVMContext(),
llvm::AttributeList::FunctionIndex,
llvm::Attribute::NoUnwind);
}
return AllocAttrs;
}
/// Disable thumb-mode until debugger support is there.
bool swift::irgen::shouldRemoveTargetFeature(StringRef feature) {
return feature == "+thumb-mode";
}
void IRGenModule::setHasNoFramePointer(llvm::AttrBuilder &Attrs) {
Attrs.addAttribute("frame-pointer", "none");
}
void IRGenModule::setHasNoFramePointer(llvm::Function *F) {
llvm::AttrBuilder b;
setHasNoFramePointer(b);
F->addAttributes(llvm::AttributeList::FunctionIndex, b);
}
/// Construct initial function attributes from options.
void IRGenModule::constructInitialFnAttributes(llvm::AttrBuilder &Attrs,
OptimizationMode FuncOptMode) {
// Add the default attributes for the Clang configuration.
clang::CodeGen::addDefaultFunctionDefinitionAttributes(getClangCGM(), Attrs);
// Add/remove MinSize based on the appropriate setting.
if (FuncOptMode == OptimizationMode::NotSet)
FuncOptMode = IRGen.Opts.OptMode;
if (FuncOptMode == OptimizationMode::ForSize) {
Attrs.addAttribute(llvm::Attribute::OptimizeForSize);
Attrs.addAttribute(llvm::Attribute::MinSize);
} else {
Attrs.removeAttribute(llvm::Attribute::MinSize);
Attrs.removeAttribute(llvm::Attribute::OptimizeForSize);
}
}
llvm::AttributeList IRGenModule::constructInitialAttributes() {
llvm::AttrBuilder b;
constructInitialFnAttributes(b);
return llvm::AttributeList::get(getLLVMContext(),
llvm::AttributeList::FunctionIndex, b);
}
llvm::ConstantInt *IRGenModule::getInt32(uint32_t value) {
return llvm::ConstantInt::get(Int32Ty, value);
}
llvm::ConstantInt *IRGenModule::getSize(Size size) {
return llvm::ConstantInt::get(SizeTy, size.getValue());
}
llvm::Constant *IRGenModule::getOpaquePtr(llvm::Constant *ptr) {
return llvm::ConstantExpr::getBitCast(ptr, Int8PtrTy);
}
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);
}
StringRef
swift::irgen::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) {
// The debugger gets the autolink information directly from
// the LinkLibraries of the module, so there's no reason to
// emit it into the IR of debugger expressions.
if (Context.LangOpts.DebuggerSupport)
return;
switch (linkLib.getKind()) {
case LibraryKind::Library: {
AutolinkEntries.emplace_back(linkLib);
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;
AutolinkEntries.emplace_back(linkLib);
break;
}
}
if (linkLib.shouldForceLoad()) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, linkLib.getName());
auto ForceImportThunk = cast<llvm::Function>(
Module.getOrInsertFunction(buf, llvm::FunctionType::get(VoidTy, false))
.getCallee());
const IRLinkage IRL =
llvm::Triple(Module.getTargetTriple()).isOSBinFormatCOFF()
? IRLinkage::ExternalImport
: IRLinkage::ExternalWeakImport;
ApplyIRLinkage(IRL).to(cast<llvm::GlobalValue>(ForceImportThunk));
buf += "_$";
appendEncodedName(buf, IRGen.Opts.ModuleName);
if (!Module.getGlobalVariable(buf.str())) {
auto ref = new llvm::GlobalVariable(Module, ForceImportThunk->getType(),
/*isConstant=*/true,
llvm::GlobalValue::WeakODRLinkage,
ForceImportThunk, buf.str());
ApplyIRLinkage(IRLinkage::InternalWeakODR).to(ref);
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?");
}
/// Returns true if the object file generated by \p IGM will be the "first"
/// object file in the module. This lets us determine where to put a symbol
/// that must be unique.
static bool isFirstObjectFileInModule(IRGenModule &IGM) {
if (IGM.getSILModule().isWholeModule())
return IGM.IRGen.getPrimaryIGM() == &IGM;
auto *file = cast<FileUnit>(IGM.getSILModule().getAssociatedContext());
auto *containingModule = file->getParentModule();
return containingModule->getFiles().front() == file;
}
static bool
doesTargetAutolinkUsingAutolinkExtract(const SwiftTargetInfo &TargetInfo,
const llvm::Triple &Triple) {
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF && !Triple.isPS4())
return true;
if (TargetInfo.OutputObjectFormat == llvm::Triple::Wasm)
return true;
if (Triple.isOSCygMing())
return true;
return false;
}
namespace {
struct AutolinkKind {
enum ValueTy {
LLVMLinkerOptions,
LLVMDependentLibraries,
SwiftAutoLinkExtract,
};
ValueTy Value;
AutolinkKind(ValueTy value) : Value(value) {}
AutolinkKind(const AutolinkKind &kind) : Value(kind.Value) {}
StringRef getSectionNameMetadata();
template <typename Vector, typename Set>
void collectEntriesFromLibraries(llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
ArrayRef<LinkLibrary> AutolinkEntries,
IRGenModule &IGM);
template <typename Vector, typename Set>
void writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
llvm::NamedMDNode *Metadata, IRGenModule &IGM);
static AutolinkKind create(const SwiftTargetInfo &TargetInfo,
llvm::Triple Triple, IRGenLLVMLTOKind LLVMLTOKind);
};
} // anonymous namespace
StringRef AutolinkKind::getSectionNameMetadata() {
// FIXME: This constant should be vended by LLVM somewhere.
switch (Value) {
case AutolinkKind::LLVMDependentLibraries:
return "llvm.dependent-libraries";
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::SwiftAutoLinkExtract:
return "llvm.linker.options";
}
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
template <typename Vector, typename Set>
void AutolinkKind::collectEntriesFromLibraries(
llvm::SetVector<llvm::MDNode *, Vector, Set> &Entries,
ArrayRef<LinkLibrary> AutolinkEntries, IRGenModule &IGM) {
llvm::LLVMContext &ctx = IGM.getLLVMContext();
switch (Value) {
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::SwiftAutoLinkExtract: {
// On platforms that support autolinking, continue to use the metadata.
for (LinkLibrary linkLib : AutolinkEntries) {
switch (linkLib.getKind()) {
case LibraryKind::Library: {
llvm::SmallString<32> opt =
getTargetDependentLibraryOption(IGM.Triple, linkLib.getName());
Entries.insert(llvm::MDNode::get(ctx, llvm::MDString::get(ctx, opt)));
continue;
}
case LibraryKind::Framework: {
llvm::Metadata *args[] = {llvm::MDString::get(ctx, "-framework"),
llvm::MDString::get(ctx, linkLib.getName())};
Entries.insert(llvm::MDNode::get(ctx, args));
continue;
}
}
llvm_unreachable("Unhandled LibraryKind in switch.");
}
return;
}
case AutolinkKind::LLVMDependentLibraries: {
for (LinkLibrary linkLib : AutolinkEntries) {
switch (linkLib.getKind()) {
case LibraryKind::Library: {
Entries.insert(llvm::MDNode::get(
ctx, llvm::MDString::get(ctx, linkLib.getName())));
continue;
}
case LibraryKind::Framework: {
llvm_unreachable(
"llvm.dependent-libraries doesn't support framework dependency");
}
}
llvm_unreachable("Unhandled LibraryKind in switch.");
}
return;
}
}
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
template <typename Vector, typename Set>
void AutolinkKind::writeEntries(llvm::SetVector<llvm::MDNode *, Vector, Set> Entries,
llvm::NamedMDNode *Metadata, IRGenModule &IGM) {
switch (Value) {
case AutolinkKind::LLVMLinkerOptions:
case AutolinkKind::LLVMDependentLibraries: {
// On platforms that support autolinking, continue to use the metadata.
Metadata->clearOperands();
for (auto *Entry : Entries)
Metadata->addOperand(Entry);
return;
}
case AutolinkKind::SwiftAutoLinkExtract: {
// Merge the entries into null-separated string.
llvm::SmallString<64> EntriesString;
for (auto EntryNode : Entries) {
const auto *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(
IGM.getLLVMContext(), EntriesString, /*AddNull=*/false);
// Mark the swift1_autolink_entries section with the SHF_EXCLUDE attribute
// to get the linker to drop it in the final linked binary.
// LLVM doesn't provide an interface to specify section attributs in the
// IR so we pass the attribute with inline assembly.
if (IGM.TargetInfo.OutputObjectFormat == llvm::Triple::ELF)
IGM.Module.appendModuleInlineAsm(".section .swift1_autolink_entries,"
"\"0x80000000\"");
auto var =
new llvm::GlobalVariable(*IGM.getModule(), EntriesConstant->getType(),
true, llvm::GlobalValue::PrivateLinkage,
EntriesConstant, "_swift1_autolink_entries");
var->setSection(".swift1_autolink_entries");
var->setAlignment(llvm::MaybeAlign(IGM.getPointerAlignment().getValue()));
disableAddressSanitizer(IGM, var);
IGM.addUsedGlobal(var);
return;
}
}
llvm_unreachable("Unhandled AutolinkKind in switch.");
}
AutolinkKind AutolinkKind::create(const SwiftTargetInfo &TargetInfo,
llvm::Triple Triple,
IRGenLLVMLTOKind LLVMLTOKind) {
// When performing LTO, we always use lld that supports auto linking
// mechanism with ELF. So embed dependent libraries names in
// "llvm.dependent-libraries" instead of "llvm.linker.options".
if (TargetInfo.OutputObjectFormat == llvm::Triple::ELF &&
LLVMLTOKind != IRGenLLVMLTOKind::None) {
return AutolinkKind::LLVMDependentLibraries;
}
if (doesTargetAutolinkUsingAutolinkExtract(TargetInfo, Triple)) {
return AutolinkKind::SwiftAutoLinkExtract;
}
return AutolinkKind::LLVMLinkerOptions;
}
void IRGenModule::emitAutolinkInfo() {
auto Autolink =
AutolinkKind::create(TargetInfo, Triple, IRGen.Opts.LLVMLTOKind);
StringRef AutolinkSectionName = Autolink.getSectionNameMetadata();
auto *Metadata = Module.getOrInsertNamedMetadata(AutolinkSectionName);
llvm::SmallSetVector<llvm::MDNode *, 4> Entries;
// Collect the linker options already in the module (from ClangCodeGen).
for (auto Entry : Metadata->operands()) {
Entries.insert(Entry);
}
Autolink.collectEntriesFromLibraries(Entries, AutolinkEntries, *this);
Autolink.writeEntries(Entries, Metadata, *this);
if (!IRGen.Opts.ForceLoadSymbolName.empty() &&
(Triple.supportsCOMDAT() || isFirstObjectFileInModule(*this))) {
llvm::SmallString<64> buf;
encodeForceLoadSymbolName(buf, IRGen.Opts.ForceLoadSymbolName);
auto ForceImportThunk =
llvm::Function::Create(llvm::FunctionType::get(VoidTy, false),
llvm::GlobalValue::ExternalLinkage, buf,
&Module);
ForceImportThunk->setAttributes(constructInitialAttributes());
ApplyIRLinkage(IRLinkage::ExternalExport).to(ForceImportThunk);
if (Triple.supportsCOMDAT())
if (auto *GO = cast<llvm::GlobalObject>(ForceImportThunk))
GO->setComdat(Module.getOrInsertComdat(ForceImportThunk->getName()));
auto BB = llvm::BasicBlock::Create(getLLVMContext(), "", ForceImportThunk);
llvm::IRBuilder<> IRB(BB);
IRB.CreateRetVoid();
}
}
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";
uint8_t Major, Minor;
std::tie(Major, Minor) = version::getSwiftNumericVersion();
uint32_t Value = (Major << 24) | (Minor << 16) | (swiftVersion << 8);
if (Module.getModuleFlag(ObjectiveCGarbageCollection)) {
bool FoundOldEntry = replaceModuleFlagsEntry(
Module.getContext(), Module, ObjectiveCGarbageCollection,
llvm::Module::Override,
llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(Int32Ty, Value)));
(void)FoundOldEntry;
assert(FoundOldEntry && "Could not replace old module flag entry?");
} else
Module.addModuleFlag(llvm::Module::Override,
ObjectiveCGarbageCollection,
Value);
}
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::Wasm:
ModuleHash->setSection(".swift_modhash");
break;
case llvm::Triple::COFF:
ModuleHash->setSection(".sw5hash");
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();
}
llvm::MDNode *IRGenModule::createProfileWeights(uint64_t TrueCount,
uint64_t FalseCount) const {
uint64_t MaxWeight = std::max(TrueCount, FalseCount);
uint64_t Scale = (MaxWeight > UINT32_MAX) ? UINT32_MAX : 1;
uint32_t ScaledTrueCount = (TrueCount / Scale) + 1;
uint32_t ScaledFalseCount = (FalseCount / Scale) + 1;
llvm::MDBuilder MDHelper(getLLVMContext());
return MDHelper.createBranchWeights(ScaledTrueCount, ScaledFalseCount);
}
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); }
bool IRGenModule::shouldPrespecializeGenericMetadata() {
auto canPrespecializeTarget =
(Triple.isOSDarwin() || Triple.isTvOS() || Triple.isOSLinux());
if (canPrespecializeTarget && isStandardLibrary()) {
return true;
}
auto &context = getSwiftModule()->getASTContext();
auto deploymentAvailability =
AvailabilityContext::forDeploymentTarget(context);
return IRGen.Opts.PrespecializeGenericMetadata &&
deploymentAvailability.isContainedIn(
context.getPrespecializedGenericMetadataAvailability()) &&
canPrespecializeTarget;
}
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();
}
auto found = DefaultIGMForFunction.find(f);
if (found != DefaultIGMForFunction.end())
return found->second;
if (auto *dc = f->getDeclContext())
return getGenModule(dc);
return getPrimaryIGM();
}
uint32_t swift::irgen::getSwiftABIVersion() {
return IRGenModule::swiftVersion;
}
llvm::Triple IRGenerator::getEffectiveClangTriple() {
auto CI = static_cast<ClangImporter *>(
&*SIL.getASTContext().getClangModuleLoader());
assert(CI && "no clang module loader");
return llvm::Triple(CI->getTargetInfo().getTargetOpts().Triple);
}
const llvm::DataLayout &IRGenerator::getClangDataLayout() {
return static_cast<ClangImporter *>(
SIL.getASTContext().getClangModuleLoader())
->getTargetInfo()
.getDataLayout();
}
TypeExpansionContext IRGenModule::getMaximalTypeExpansionContext() const {
return TypeExpansionContext::maximal(getSwiftModule(),
getSILModule().isWholeModule());
}
const TypeLayoutEntry &IRGenModule::getTypeLayoutEntry(SILType T) {
return Types.getTypeLayoutEntry(T);
}