//===--- 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/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/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/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 "GenEnum.h" #include "GenType.h" #include "IRGenModule.h" #include "IRGenDebugInfo.h" #include "StructLayout.h" #include 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 types, bool packed = false) { return llvm::StructType::create(IGM.getLLVMContext(), ArrayRef(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 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(&*Loader); assert(Importer && "No clang module loader!"); auto &ClangContext = Importer->getClangASTContext(); auto &CGO = Importer->getClangCodeGenOpts(); CGO.OptimizationLevel = Opts.shouldOptimize() ? 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: case IRGenDebugInfoKind::DwarfTypes: CGO.DebugTypeExtRefs = true; 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; } IRGenModule::IRGenModule(IRGenerator &irgen, std::unique_ptr &&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), 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()); Int64Ty = llvm::Type::getInt64Ty(getLLVMContext()); Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); SizeTy = DataLayout.getIntPtrType(getLLVMContext(), /*addrspace*/ 0); auto CI = static_cast(&*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, // mandatory requirement count Int16Ty, // total requirement count Int32Ty // requirements array }); ProtocolDescriptorPtrTy = ProtocolDescriptorStructTy->getPointerTo(); ProtocolRequirementStructTy = createStructType(*this, "swift.protocol_requirement", { Int32Ty, // flags Int32Ty // default implementation }); // 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); // 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(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); MethodDescriptorStructTy = createStructType(*this, "swift.method_descriptor", { RelativeAddressTy, Int32Ty }); TypeMetadataRecordTy = createStructType(*this, "swift.type_metadata_record", { RelativeAddressTy }); 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); WitnessTablePtrPtrTy = WitnessTablePtrTy->getPointerTo(DefaultAS); WitnessTableSliceTy = createStructType(*this, "swift.witness_table_slice", {WitnessTablePtrPtrTy, SizeTy}); 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 = llvm::CallingConv::Swift; if (IRGen.Opts.DebugInfoKind > IRGenDebugInfoKind::None) DebugInfo = IRGenDebugInfo::createIRGenDebugInfo(IRGen.Opts, *CI, *this, Module, SF); initClangTypeConverter(); 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()); } IRGenModule::~IRGenModule() { destroyClangTypeConverter(); destroyMetadataLayoutMap(); 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; const auto FirstParamReturned = llvm::Attribute::Returned; } // 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; } llvm::Constant *swift::getRuntimeFn(llvm::Module &Module, llvm::Constant *&cache, const char *name, llvm::CallingConv::ID cc, llvm::ArrayRef retTypes, llvm::ArrayRef argTypes, ArrayRef 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(cache)) { fn->setCallingConv(cc); if (::useDllStorage(llvm::Triple(Module.getTargetTriple())) && ((fn->getLinkage() == llvm::GlobalValue::ExternalLinkage && fn->isDeclaration()) || fn->getLinkage() == llvm::GlobalValue::AvailableExternallyLinkage)) fn->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); llvm::AttrBuilder buildFnAttr; llvm::AttrBuilder buildRetAttr; llvm::AttrBuilder buildFirstParamAttr; for (auto Attr : attrs) { if (isReturnAttribute(Attr)) buildRetAttr.addAttribute(Attr); else if (isReturnedAttribute(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; } llvm::Constant *swift::getWrapperFn(llvm::Module &Module, llvm::Constant *&cache, char const *name, char const *symbol, llvm::CallingConv::ID cc, llvm::ArrayRef retTypes, llvm::ArrayRef argTypes, ArrayRef 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(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::AttributeList::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 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); for (auto Attr : attrs) if (isReturnedAttribute(Attr)) { call->addParamAttr(0, llvm::Attribute::Returned); } 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_SwiftCC(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_SwiftCC(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 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(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(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(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 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 (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); } } } void IRGenerator::addClassForEagerInitialization(ClassDecl *ClassDecl) { if (!ClassDecl->getAttrs().hasAttribute()) return; // Exclude some classes where those attributes make no sense but could be set // for some reason. Just to be on the safe side. Type ClassTy = ClassDecl->getDeclaredType(); if (ClassTy->is()) return; if (ClassTy->hasArchetype()) return; if (ClassDecl->hasClangNode()) return; ClassesForEagerInitialization.push_back(ClassDecl); } llvm::AttributeList IRGenModule::getAllocAttrs() { if (AllocAttrs.isEmpty()) { AllocAttrs = llvm::AttributeList::get(LLVMContext, llvm::AttributeList::ReturnIndex, llvm::Attribute::NoAlias); AllocAttrs = AllocAttrs.addAttribute(LLVMContext, 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"; } /// Construct initial function attributes from options. void IRGenModule::constructInitialFnAttributes(llvm::AttrBuilder &Attrs, OptimizationMode FuncOptMode) { // Add DisableFPElim. if (!IRGen.Opts.DisableFPElim) { Attrs.addAttribute("no-frame-pointer-elim", "false"); } else { Attrs.addAttribute("no-frame-pointer-elim", "true"); Attrs.addAttribute("no-frame-pointer-elim-non-leaf"); } // Add target-cpu and target-features if they are non-null. auto *Clang = static_cast(Context.getClangModuleLoader()); clang::TargetOptions &ClangOpts = Clang->getTargetInfo().getTargetOpts(); std::string &CPU = ClangOpts.CPU; if (CPU != "") Attrs.addAttribute("target-cpu", CPU); std::vector Features; for (auto &F : ClangOpts.Features) if (!shouldRemoveTargetFeature(F)) Features.push_back(F); if (!Features.empty()) { SmallString<64> allFeatures; // Sort so that the target features string is canonical. std::sort(Features.begin(), Features.end()); interleave(Features, [&](const std::string &s) { allFeatures.append(s); }, [&]{ allFeatures.push_back(','); }); Attrs.addAttribute("target-features", allFeatures); } if (FuncOptMode == OptimizationMode::NotSet) FuncOptMode = IRGen.Opts.OptMode; if (FuncOptMode == OptimizationMode::ForSize) Attrs.addAttribute(llvm::Attribute::MinSize); } llvm::AttributeList IRGenModule::constructInitialAttributes() { llvm::AttrBuilder b; constructInitialFnAttributes(b); return llvm::AttributeList::get(LLVMContext, llvm::AttributeList::FunctionIndex, b); } llvm::Constant *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(c)); } } static void appendEncodedName(llvm::SmallVectorImpl &buf, StringRef name) { llvm::raw_svector_ostream os{buf}; appendEncodedName(os, name); } static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl &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(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(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() { // Collect the linker options already in the module (from ClangCodeGen). // FIXME: This constant should be vended by LLVM somewhere. auto *Metadata = Module.getOrInsertNamedMetadata("llvm.linker.options"); for (llvm::MDNode *LinkOption : Metadata->operands()) AutolinkEntries.push_back(LinkOption); // Remove duplicates. llvm::SmallPtrSet knownAutolinkEntries; AutolinkEntries.erase(std::remove_if(AutolinkEntries.begin(), AutolinkEntries.end(), [&](llvm::MDNode *entry) -> bool { return !knownAutolinkEntries.insert( entry).second; }), AutolinkEntries.end()); if ((TargetInfo.OutputObjectFormat == llvm::Triple::COFF && !Triple.isOSCygMing()) || TargetInfo.OutputObjectFormat == llvm::Triple::MachO || Triple.isPS4()) { // On platforms that support autolinking, continue to use the metadata. Metadata->clearOperands(); for (auto *Entry : AutolinkEntries) Metadata->addOperand(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(EntryNode); for (auto &Entry : MD->operands()) { const llvm::MDString *MS = cast(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 ZeroArr(reinterpret_cast(&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(); } 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 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(); }