//===--- IRGenModule.cpp - Swift Global LLVM IR Generation ----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements 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/ClangImporter/ClangImporter.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/Frontend/CodeGenOptions.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/Support/ErrorHandling.h" #include "GenType.h" #include "IRGenModule.h" #include "IRGenDebugInfo.h" #include "Linking.h" #include using namespace swift; using namespace irgen; using clang::CodeGen::CodeGenABITypes; 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) { return llvm::StructType::create(IGM.getLLVMContext(), ArrayRef(types.begin(), types.size()), name); }; /// 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 = new clang::CodeGenOptions; CGO->OptimizationLevel = Opts.OptLevel; CGO->DisableFPElim = Opts.DisableFPElim; auto &TO = ClangContext.getTargetInfo().getTargetOpts(); auto *ClangCodeGen = clang::CreateLLVMCodeGen(ClangContext.getDiagnostics(), ModuleName, *CGO, TO, LLVMContext); ClangCodeGen->Initialize(ClangContext); return ClangCodeGen; } IRGenModule::IRGenModule(ASTContext &Context, llvm::LLVMContext &LLVMContext, IRGenOptions &Opts, StringRef ModuleName, const llvm::DataLayout &DataLayout, SILModule *SILMod) : Context(Context), Opts(Opts), ClangCodeGen(createClangCodeGenerator(Context, LLVMContext, Opts, ModuleName)), Module(*ClangCodeGen->GetModule()), LLVMContext(Module.getContext()), DataLayout(DataLayout), SILMod(SILMod), TargetInfo(SwiftTargetInfo::get(*this)), DebugInfo(0), Types(*new TypeConverter(*this)) { 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); 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 }); // 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 }); ProtocolDescriptorPtrTy = ProtocolDescriptorStructTy->getPointerTo(); // A tuple type metadata record has a couple extra fields. auto tupleElementTy = createStructType(*this, "swift.tuple_element_type", { TypeMetadataPtrTy, // Metadata *Type; SizeTy // size_t Offset; }); TupleTypeMetadataPtrTy = createStructPointerType(*this, "swift.tuple_type", { TypeMetadataStructTy, // (base) SizeTy, // size_t NumElements; Int8PtrTy, // const char *Labels; llvm::ArrayType::get(tupleElementTy, 0) // Element Elements[]; }); // A full type metadata record is basically just an adjustment to the // address point of a type metadata. Resilience may cause // additional data to be laid out prior to this address point. FullTypeMetadataStructTy = createStructType(*this, "swift.full_type", { WitnessTablePtrTy, TypeMetadataStructTy }); FullTypeMetadataPtrTy = FullTypeMetadataStructTy->getPointerTo(DefaultAS); // A metadata pattern is a structure from which generic type // metadata are allocated. We leave this struct type intentionally // opaque, because the compiler basically never needs to access // anything from one. TypeMetadataPatternStructTy = llvm::StructType::create(getLLVMContext(), "swift.type_pattern"); TypeMetadataPatternPtrTy = TypeMetadataPatternStructTy->getPointerTo(DefaultAS); DeallocatingDtorTy = llvm::FunctionType::get(VoidTy, RefCountedPtrTy, false); llvm::Type *dtorPtrTy = DeallocatingDtorTy->getPointerTo(); // A full heap metadata is basically just an additional small prefix // on a full metadata, used for metadata corresponding to heap // allocations. FullHeapMetadataStructTy = createStructType(*this, "swift.full_heapmetadata", { dtorPtrTy, WitnessTablePtrTy, TypeMetadataStructTy }); FullHeapMetadataPtrTy = FullHeapMetadataStructTy->getPointerTo(DefaultAS); llvm::Type *refCountedElts[] = { TypeMetadataPtrTy, Int32Ty, Int32Ty }; RefCountedStructTy->setBody(refCountedElts); PtrSize = Size(DataLayout.getPointerSize(DefaultAS)); FunctionPairTy = createStructType(*this, "swift.function", { FunctionPtrTy, RefCountedPtrTy, }); WitnessFunctionPairTy = createStructType(*this, "swift.witness_function", { FunctionPtrTy, TypeMetadataPtrTy, }); OpaquePtrTy = llvm::StructType::create(LLVMContext, "swift.opaque") ->getPointerTo(DefaultAS); FixedBufferTy = nullptr; for (unsigned i = 0; i != MaxNumValueWitnesses; ++i) ValueWitnessTys[i] = nullptr; ObjCPtrTy = llvm::StructType::create(getLLVMContext(), "objc_object") ->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); // TODO: use "tinycc" on platforms that support it RuntimeCC = llvm::CallingConv::C; auto CI = static_cast(&*Context.getClangModuleLoader()); assert(CI && "no clang module loader"); auto &clangASTContext = CI->getClangASTContext(); ABITypes = new CodeGenABITypes(clangASTContext, Module, DataLayout); if (Opts.DebugInfo) { DebugInfo = new IRGenDebugInfo(Opts, *CI, *this, Module); } } IRGenModule::~IRGenModule() { delete &Types; if (DebugInfo) delete DebugInfo; delete ABITypes; } static llvm::Constant *getRuntimeFn(IRGenModule &IGM, llvm::Constant *&cache, char const *name, llvm::CallingConv::ID cc, std::initializer_list retTypes, std::initializer_list argTypes, std::initializer_list attrs = std::initializer_list()) { if (cache) return cache; llvm::Type *retTy; if (retTypes.size() == 1) retTy = *retTypes.begin(); else retTy = llvm::StructType::get(IGM.LLVMContext, {retTypes.begin(), retTypes.end()}, /*packed*/ false); auto fnTy = llvm::FunctionType::get(retTy, {argTypes.begin(), argTypes.end()}, /*isVararg*/ false); cache = IGM.Module.getOrInsertFunction(name, fnTy); // Add any function attributes and set the calling convention. if (auto fn = dyn_cast(cache)) { fn->setCallingConv(cc); llvm::AttrBuilder b; for (auto Attr : attrs) b.addAttribute(Attr); fn->getAttributes(). addAttributes(IGM.LLVMContext, llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(IGM.LLVMContext, llvm::AttributeSet::FunctionIndex, b)); } return cache; } // 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 NoUnwind = llvm::Attribute::NoUnwind; const auto C_CC = llvm::CallingConv::C; } #define RETURNS(...) { __VA_ARGS__ } #define ARGS(...) { __VA_ARGS__ } #define NO_ARGS {} #define ATTRS(...) { __VA_ARGS__ } #define NO_ATTRS {} #define FUNCTION(ID, NAME, CC, RETURNS, ARGS, ATTRS) \ llvm::Constant *IRGenModule::get##ID##Fn() { \ using namespace RuntimeConstants; \ return getRuntimeFn(*this, ID##Fn, #NAME, CC, \ RETURNS, ARGS, ATTRS); \ } #include "RuntimeFunctions.def" llvm::Constant *IRGenModule::getEmptyTupleMetadata() { if (EmptyTupleMetadata) return EmptyTupleMetadata; return EmptyTupleMetadata = Module.getOrInsertGlobal("_TMdT_", FullTypeMetadataStructTy); } llvm::Constant *IRGenModule::getObjCEmptyCachePtr() { if (ObjCEmptyCachePtr) return ObjCEmptyCachePtr; // struct objc_cache _objc_empty_cache; ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache", OpaquePtrTy->getElementType()); return ObjCEmptyCachePtr; } llvm::Constant *IRGenModule::getObjCEmptyVTablePtr() { if (ObjCEmptyVTablePtr) return ObjCEmptyVTablePtr; // IMP _objc_empty_vtable; // On recent Darwin platforms, this symbol is actually defined at // runtime as an absolute symbol with the value of null. On some // older platforms, that wasn't true, and it isn't clear that the // ObjC runtime is willing to make a *guarantee* that it's true, so // in general we still use the symbol. However, there are a number // of (non-ABI) environments that don't actually support absolute // symbols correctly, such as the iOS simulator, and for these we // have to fill in null directly. if (TargetInfo.ObjCUseNullForEmptyVTable) { ObjCEmptyVTablePtr = llvm::ConstantPointerNull::get(OpaquePtrTy); } else { ObjCEmptyVTablePtr = Module.getOrInsertGlobal("_objc_empty_vtable", OpaquePtrTy->getElementType()); } return ObjCEmptyVTablePtr; } llvm::Module *IRGenModule::getModule() const { return ClangCodeGen->GetModule(); } llvm::Module *IRGenModule::releaseModule() { return ClangCodeGen->ReleaseModule(); } llvm::Constant *IRGenModule::getSize(Size size) { return llvm::ConstantInt::get(SizeTy, size.getValue()); } void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) { llvm::LLVMContext &ctx = Module.getContext(); switch (linkLib.getKind()) { case LibraryKind::Library: { // FIXME: Use target-independent linker option. // Clang uses CGM.getTargetCodeGenInfo().getDependentLibraryOption(...). llvm::SmallString<32> buf; buf += "-l"; buf += linkLib.getName(); auto flag = llvm::MDString::get(ctx, buf); AutolinkEntries.push_back(llvm::MDNode::get(ctx, flag)); break; } case LibraryKind::Framework: llvm::Value *args[] = { llvm::MDString::get(ctx, "-framework"), llvm::MDString::get(ctx, linkLib.getName()) }; AutolinkEntries.push_back(llvm::MDNode::get(ctx, args)); break; } } // FIXME: This should just be the implementation of // llvm::array_pod_sort_comparator. The only difference is that it uses // std::less instead of operator<. template static int pointerPODSortComparator(T * const *lhs, T * const *rhs) { std::less lt; if (lt(*lhs, *rhs)) return -1; if (lt(*rhs, *lhs)) return -1; return 0; } static StringRef encodeForceLoadSymbolName(llvm::SmallVectorImpl &buf, StringRef name) { llvm::raw_svector_ostream os{buf}; os << "_swift_FORCE_LOAD_$"; if (clang::isValidIdentifier(name)) { os << "_" << name; } else { for (auto c : name) os.write_hex(static_cast(c)); } return os.str(); } void IRGenModule::emitAutolinkInfo() { // FIXME: This constant should be vended by LLVM somewhere. static const char * const LinkerOptionsFlagName = "Linker Options"; // Remove duplicates. llvm::array_pod_sort(AutolinkEntries.begin(), AutolinkEntries.end(), pointerPODSortComparator); auto newEnd = std::unique(AutolinkEntries.begin(), AutolinkEntries.end()); AutolinkEntries.erase(newEnd, AutolinkEntries.end()); llvm::LLVMContext &ctx = Module.getContext(); Module.addModuleFlag(llvm::Module::AppendUnique, LinkerOptionsFlagName, llvm::MDNode::get(ctx, AutolinkEntries)); if (!Opts.ForceLoadSymbolName.empty()) { llvm::SmallString<64> buf; encodeForceLoadSymbolName(buf, Opts.ForceLoadSymbolName); (void)new llvm::GlobalVariable(Module, Int1Ty, /*constant=*/true, llvm::GlobalVariable::LinkOnceAnyLinkage, llvm::Constant::getNullValue(Int1Ty), buf.str()); } } void IRGenModule::finalize() { emitGlobalLists(); emitAutolinkInfo(); if (DebugInfo) DebugInfo->finalize(); } 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)); }