From 8a6ea813424dabc71bf4514942e487bd0268a317 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sat, 19 Nov 2016 08:17:24 +0000 Subject: [PATCH] Introduce a helper class for building complex constant initializers. NFC. I've adopted this in most of the places it makes sense, but v-tables and CGObjCMac will need a second pass. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@287437 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclObjC.h | 3 + lib/CodeGen/CGBlocks.cpp | 70 ++-- lib/CodeGen/CGCUDANV.cpp | 35 +- lib/CodeGen/CGObjCGNU.cpp | 716 ++++++++++++++++---------------- lib/CodeGen/CGOpenMPRuntime.cpp | 95 +++-- lib/CodeGen/CodeGenModule.cpp | 85 ++-- lib/CodeGen/ConstantBuilder.h | 274 ++++++++++++ 7 files changed, 770 insertions(+), 508 deletions(-) create mode 100644 lib/CodeGen/ConstantBuilder.h diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 5f1207d55e..1c3139355c 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -870,6 +870,9 @@ public: PropertyControl getPropertyImplementation() const { return PropertyControl(PropertyImplementation); } + bool isOptional() const { + return getPropertyImplementation() == PropertyControl::Optional; + } void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { PropertyIvarDecl = Ivar; diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 658dfc600c..3b494bb20a 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -16,6 +16,7 @@ #include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantBuilder.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/SmallSet.h" #include "llvm/IR/CallSite.h" @@ -77,63 +78,63 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { ASTContext &C = CGM.getContext(); - llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy); - llvm::Type *i8p = nullptr; + llvm::IntegerType *ulong = + cast(CGM.getTypes().ConvertType(C.UnsignedLongTy)); + llvm::PointerType *i8p = nullptr; if (CGM.getLangOpts().OpenCL) i8p = llvm::Type::getInt8PtrTy( CGM.getLLVMContext(), C.getTargetAddressSpace(LangAS::opencl_constant)); else - i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); + i8p = CGM.VoidPtrTy; - SmallVector elements; + ConstantBuilder builder(CGM); + auto elements = builder.beginStruct(); // reserved - elements.push_back(llvm::ConstantInt::get(ulong, 0)); + elements.addInt(ulong, 0); // Size // FIXME: What is the right way to say this doesn't fit? We should give // a user diagnostic in that case. Better fix would be to change the // API to size_t. - elements.push_back(llvm::ConstantInt::get(ulong, - blockInfo.BlockSize.getQuantity())); + elements.addInt(ulong, blockInfo.BlockSize.getQuantity()); // Optional copy/dispose helpers. if (blockInfo.NeedsCopyDispose) { // copy_func_helper_decl - elements.push_back(buildCopyHelper(CGM, blockInfo)); + elements.add(buildCopyHelper(CGM, blockInfo)); // destroy_func_decl - elements.push_back(buildDisposeHelper(CGM, blockInfo)); + elements.add(buildDisposeHelper(CGM, blockInfo)); } // Signature. Mandatory ObjC-style method descriptor @encode sequence. std::string typeAtEncoding = CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr()); - elements.push_back(llvm::ConstantExpr::getBitCast( + elements.add(llvm::ConstantExpr::getBitCast( CGM.GetAddrOfConstantCString(typeAtEncoding).getPointer(), i8p)); // GC layout. if (C.getLangOpts().ObjC1) { if (CGM.getLangOpts().getGC() != LangOptions::NonGC) - elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + elements.add(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); else - elements.push_back(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo)); + elements.add(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo)); } else - elements.push_back(llvm::Constant::getNullValue(i8p)); - - llvm::Constant *init = llvm::ConstantStruct::getAnon(elements); + elements.addNullPointer(i8p); unsigned AddrSpace = 0; if (C.getLangOpts().OpenCL) AddrSpace = C.getTargetAddressSpace(LangAS::opencl_constant); + llvm::GlobalVariable *global = - new llvm::GlobalVariable(CGM.getModule(), init->getType(), true, - llvm::GlobalValue::InternalLinkage, - init, "__block_descriptor_tmp", nullptr, - llvm::GlobalValue::NotThreadLocal, - AddrSpace); + elements.finishAndCreateGlobal("__block_descriptor_tmp", + CGM.getPointerAlign(), + /*constant*/ true, + llvm::GlobalValue::InternalLinkage, + AddrSpace); return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } @@ -1080,36 +1081,31 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, assert(blockInfo.CanBeGlobal); // Generate the constants for the block literal initializer. - llvm::Constant *fields[BlockHeaderSize]; + ConstantBuilder builder(CGM); + auto fields = builder.beginStruct(); // isa - fields[0] = CGM.getNSConcreteGlobalBlock(); + fields.add(CGM.getNSConcreteGlobalBlock()); // __flags BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; - fields[1] = llvm::ConstantInt::get(CGM.IntTy, flags.getBitMask()); + fields.addInt(CGM.IntTy, flags.getBitMask()); // Reserved - fields[2] = llvm::Constant::getNullValue(CGM.IntTy); + fields.addInt(CGM.IntTy, 0); // Function - fields[3] = blockFn; + fields.add(blockFn); // Descriptor - fields[4] = buildBlockDescriptor(CGM, blockInfo); - - llvm::Constant *init = llvm::ConstantStruct::getAnon(fields); - - llvm::GlobalVariable *literal = - new llvm::GlobalVariable(CGM.getModule(), - init->getType(), - /*constant*/ true, - llvm::GlobalVariable::InternalLinkage, - init, - "__block_literal_global"); - literal->setAlignment(blockInfo.BlockAlign.getQuantity()); + fields.add(buildBlockDescriptor(CGM, blockInfo)); + + llvm::Constant *literal = + fields.finishAndCreateGlobal("__block_literal_global", + blockInfo.BlockAlign, + /*constant*/ true); // Return a constant of the appropriately-casted type. llvm::Type *requiredType = diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp index b598330abe..b6344310c1 100644 --- a/lib/CodeGen/CGCUDANV.cpp +++ b/lib/CodeGen/CGCUDANV.cpp @@ -15,6 +15,7 @@ #include "CGCUDARuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantBuilder.h" #include "clang/AST/Decl.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" @@ -29,7 +30,8 @@ namespace { class CGNVCUDARuntime : public CGCUDARuntime { private: - llvm::Type *IntTy, *SizeTy, *VoidTy; + llvm::IntegerType *IntTy, *SizeTy; + llvm::Type *VoidTy; llvm::PointerType *CharPtrTy, *VoidPtrTy, *VoidPtrPtrTy; /// Convenience reference to LLVM Context @@ -95,9 +97,9 @@ CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM) CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); - IntTy = Types.ConvertType(Ctx.IntTy); - SizeTy = Types.ConvertType(Ctx.getSizeType()); - VoidTy = llvm::Type::getVoidTy(Context); + IntTy = CGM.IntTy; + SizeTy = CGM.SizeTy; + VoidTy = CGM.VoidTy; CharPtrTy = llvm::PointerType::getUnqual(Types.ConvertType(Ctx.CharTy)); VoidPtrTy = cast(Types.ConvertType(Ctx.VoidPtrTy)); @@ -296,16 +298,21 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { CGM.getTriple().isMacOSX() ? "__NV_CUDA,__fatbin" : ".nvFatBinSegment"; // Create initialized wrapper structure that points to the loaded GPU binary - llvm::Constant *Values[] = { - llvm::ConstantInt::get(IntTy, 0x466243b1), // Fatbin wrapper magic. - llvm::ConstantInt::get(IntTy, 1), // Fatbin version. - makeConstantString(GpuBinaryOrErr.get()->getBuffer(), // Data. - "", FatbinConstantName, 8), - llvm::ConstantPointerNull::get(VoidPtrTy)}; // Unused in fatbin v1. - llvm::GlobalVariable *FatbinWrapper = new llvm::GlobalVariable( - TheModule, FatbinWrapperTy, true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantStruct::get(FatbinWrapperTy, Values), - "__cuda_fatbin_wrapper"); + ConstantBuilder Builder(CGM); + auto Values = Builder.beginStruct(FatbinWrapperTy); + // Fatbin wrapper magic. + Values.addInt(IntTy, 0x466243b1); + // Fatbin version. + Values.addInt(IntTy, 1); + // Data. + Values.add(makeConstantString(GpuBinaryOrErr.get()->getBuffer(), + "", FatbinConstantName, 8)); + // Unused in fatbin v1. + Values.add(llvm::ConstantPointerNull::get(VoidPtrTy)); + llvm::GlobalVariable *FatbinWrapper = + Values.finishAndCreateGlobal("__cuda_fatbin_wrapper", + CGM.getPointerAlign(), + /*constant*/ true); FatbinWrapper->setSection(FatbinSectionName); // GpuBinaryHandle = __cudaRegisterFatBinary(&FatbinWrapper); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index f0f9f6d67f..7fdd1bda16 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -18,6 +18,7 @@ #include "CGCleanup.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -190,47 +191,17 @@ protected: /// Generates a global structure, initialized by the elements in the vector. /// The element types must match the types of the structure elements in the /// first argument. - llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty, - ArrayRef V, + llvm::GlobalVariable *MakeGlobal(llvm::Constant *C, CharUnits Align, StringRef Name="", llvm::GlobalValue::LinkageTypes linkage =llvm::GlobalValue::InternalLinkage) { - llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); - auto GV = new llvm::GlobalVariable(TheModule, Ty, false, + auto GV = new llvm::GlobalVariable(TheModule, C->getType(), false, linkage, C, Name); GV->setAlignment(Align.getQuantity()); return GV; } - /// Generates a global array. The vector must contain the same number of - /// elements that the array type declares, of the type specified as the array - /// element type. - llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty, - ArrayRef V, - CharUnits Align, - StringRef Name="", - llvm::GlobalValue::LinkageTypes linkage - =llvm::GlobalValue::InternalLinkage) { - llvm::Constant *C = llvm::ConstantArray::get(Ty, V); - auto GV = new llvm::GlobalVariable(TheModule, Ty, false, - linkage, C, Name); - GV->setAlignment(Align.getQuantity()); - return GV; - } - - /// Generates a global array, inferring the array type from the specified - /// element type and the size of the initialiser. - llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty, - ArrayRef V, - CharUnits Align, - StringRef Name="", - llvm::GlobalValue::LinkageTypes linkage - =llvm::GlobalValue::InternalLinkage) { - llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size()); - return MakeGlobal(ArrayTy, V, Align, Name, linkage); - } - /// Returns a property name and encoding string. llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD, const Decl *Container) { @@ -251,7 +222,7 @@ protected: } /// Push the property attributes into two structure fields. - void PushPropertyAttributes(std::vector &Fields, + void PushPropertyAttributes(ConstantBuilder::StructBuilder &Fields, ObjCPropertyDecl *property, bool isSynthesized=true, bool isDynamic=true) { int attrs = property->getPropertyAttributes(); @@ -263,7 +234,7 @@ protected: attrs &= ~ObjCPropertyDecl::OBJC_PR_strong; } // The first flags field has the same attribute values as clang uses internally - Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff)); + Fields.addInt(Int8Ty, attrs & 0xff); attrs >>= 8; attrs <<= 2; // For protocol properties, synthesized and dynamic have no meaning, so we @@ -273,10 +244,10 @@ protected: attrs |= isDynamic ? (1<<1) : 0; // The second field is the next four fields left shifted by two, with the // low bit set to indicate whether the field is synthesized or dynamic. - Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff)); + Fields.addInt(Int8Ty, attrs & 0xff); // Two padding fields - Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0)); - Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0)); + Fields.addInt(Int8Ty, 0); + Fields.addInt(Int8Ty, 0); } /// Ensures that the value has the required type, by inserting a bitcast if @@ -1233,14 +1204,15 @@ llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) { llvm::Constant *typeName = ExportUniqueString(className, "__objc_eh_typename_"); - std::vector fields; - fields.push_back(BVtable); - fields.push_back(typeName); - llvm::Constant *TI = - MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, nullptr), - fields, CGM.getPointerAlign(), - "__objc_eh_typeinfo_" + className, - llvm::GlobalValue::LinkOnceODRLinkage); + ConstantBuilder builder(CGM); + auto fields = builder.beginStruct(); + fields.add(BVtable); + fields.add(typeName); + llvm::Constant *TI = + fields.finishAndCreateGlobal("__objc_eh_typeinfo_" + className, + CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::LinkOnceODRLinkage); return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty); } @@ -1270,13 +1242,13 @@ ConstantAddress CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { else if (isa->getType() != PtrToIdTy) isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); - std::vector Ivars; - Ivars.push_back(isa); - Ivars.push_back(MakeConstantString(Str)); - Ivars.push_back(llvm::ConstantInt::get(IntTy, Str.size())); - llvm::Constant *ObjCStr = MakeGlobal( - llvm::StructType::get(PtrToIdTy, PtrToInt8Ty, IntTy, nullptr), - Ivars, Align, ".objc_str"); + ConstantBuilder Builder(CGM); + auto Fields = Builder.beginStruct(); + Fields.add(isa); + Fields.add(MakeConstantString(Str)); + Fields.addInt(IntTy, Str.size()); + llvm::Constant *ObjCStr = + Fields.finishAndCreateGlobal(".objc_str", Align); ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty); ObjCStrings[Str] = ObjCStr; ConstantStrings.push_back(ObjCStr); @@ -1551,13 +1523,20 @@ GenerateMethodList(StringRef ClassName, bool isClassMethodList) { if (MethodSels.empty()) return NULLPtr; + + ConstantBuilder Builder(CGM); + + auto MethodList = Builder.beginStruct(); + MethodList.addNullPointer(CGM.Int8PtrTy); + MethodList.addInt(Int32Ty, MethodTypes.size()); + // Get the method structure type. llvm::StructType *ObjCMethodTy = llvm::StructType::get( PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types IMPTy, //Method pointer nullptr); - std::vector Methods; + auto Methods = MethodList.beginArray(); for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) { llvm::Constant *Method = TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName, @@ -1567,34 +1546,14 @@ GenerateMethodList(StringRef ClassName, llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString()); Method = llvm::ConstantExpr::getBitCast(Method, IMPTy); - Methods.push_back( + Methods.add( llvm::ConstantStruct::get(ObjCMethodTy, {C, MethodTypes[i], Method})); } - - // Array of method structures - llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy, - Methods.size()); - llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy, - Methods); - - // Structure containing list pointer, array and array count - llvm::StructType *ObjCMethodListTy = llvm::StructType::create(VMContext); - llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(ObjCMethodListTy); - ObjCMethodListTy->setBody( - NextPtrTy, - IntTy, - ObjCMethodArrayTy, - nullptr); - - Methods.clear(); - Methods.push_back(llvm::ConstantPointerNull::get( - llvm::PointerType::getUnqual(ObjCMethodListTy))); - Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size())); - Methods.push_back(MethodArray); + MethodList.add(Methods.finish()); // Create an instance of the structure - return MakeGlobal(ObjCMethodListTy, Methods, CGM.getPointerAlign(), - ".objc_method_list"); + return MethodList.finishAndCreateGlobal(".objc_method_list", + CGM.getPointerAlign()); } /// Generates an IvarList. Used in construction of a objc_class. @@ -1602,35 +1561,36 @@ llvm::Constant *CGObjCGNU:: GenerateIvarList(ArrayRef IvarNames, ArrayRef IvarTypes, ArrayRef IvarOffsets) { - if (IvarNames.size() == 0) + if (IvarNames.empty()) return NULLPtr; - // Get the method structure type. + + ConstantBuilder Builder(CGM); + + // Structure containing array count followed by array. + auto IvarList = Builder.beginStruct(); + IvarList.addInt(IntTy, (int)IvarNames.size()); + + // Get the ivar structure type. llvm::StructType *ObjCIvarTy = llvm::StructType::get( PtrToInt8Ty, PtrToInt8Ty, IntTy, nullptr); - std::vector Ivars; + + // Array of ivar structures. + auto Ivars = IvarList.beginArray(ObjCIvarTy); for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) { - Ivars.push_back(llvm::ConstantStruct::get( - ObjCIvarTy, {IvarNames[i], IvarTypes[i], IvarOffsets[i]})); + auto Ivar = Ivars.beginStruct(ObjCIvarTy); + Ivar.add(IvarNames[i]); + Ivar.add(IvarTypes[i]); + Ivar.add(IvarOffsets[i]); + Ivars.add(Ivar.finish()); } - - // Array of method structures - llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy, - IvarNames.size()); - - llvm::Constant *Elements[] = { - llvm::ConstantInt::get(IntTy, (int)IvarNames.size()), - llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars)}; - // Structure containing array and array count - llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy, - ObjCIvarArrayTy, - nullptr); + IvarList.add(Ivars.finish()); // Create an instance of the structure - return MakeGlobal(ObjCIvarListTy, Elements, CGM.getPointerAlign(), - ".objc_ivar_list"); + return IvarList.finishAndCreateGlobal(".objc_ivar_list", + CGM.getPointerAlign()); } /// Generate a class structure @@ -1678,34 +1638,55 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( IntPtrTy, // strong_pointers IntPtrTy, // weak_pointers nullptr); - llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0); + + ConstantBuilder Builder(CGM); + auto Elements = Builder.beginStruct(ClassTy); + // Fill in the structure - std::vector Elements; - Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty)); - Elements.push_back(SuperClass); - Elements.push_back(MakeConstantString(Name, ".class_name")); - Elements.push_back(Zero); - Elements.push_back(llvm::ConstantInt::get(LongTy, info)); + + // isa + Elements.add(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty)); + // super_class + Elements.add(SuperClass); + // name + Elements.add(MakeConstantString(Name, ".class_name")); + // version + Elements.addInt(LongTy, 0); + // info + Elements.addInt(LongTy, info); + // instance_size if (isMeta) { llvm::DataLayout td(&TheModule); - Elements.push_back( - llvm::ConstantInt::get(LongTy, - td.getTypeSizeInBits(ClassTy) / - CGM.getContext().getCharWidth())); + Elements.addInt(LongTy, + td.getTypeSizeInBits(ClassTy) / + CGM.getContext().getCharWidth()); } else - Elements.push_back(InstanceSize); - Elements.push_back(IVars); - Elements.push_back(Methods); - Elements.push_back(NULLPtr); - Elements.push_back(NULLPtr); - Elements.push_back(NULLPtr); - Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); - Elements.push_back(NULLPtr); - Elements.push_back(llvm::ConstantInt::get(LongTy, 1)); - Elements.push_back(IvarOffsets); - Elements.push_back(Properties); - Elements.push_back(StrongIvarBitmap); - Elements.push_back(WeakIvarBitmap); + Elements.add(InstanceSize); + // ivars + Elements.add(IVars); + // methods + Elements.add(Methods); + // These are all filled in by the runtime, so we pretend + // dtable + Elements.add(NULLPtr); + // subclass_list + Elements.add(NULLPtr); + // sibling_class + Elements.add(NULLPtr); + // protocols + Elements.add(llvm::ConstantExpr::getBitCast(Protocols, PtrTy)); + // gc_object_type + Elements.add(NULLPtr); + // abi_version + Elements.addInt(LongTy, 1); + // ivar_offsets + Elements.add(IvarOffsets); + // properties + Elements.add(Properties); + // strong_pointers + Elements.add(StrongIvarBitmap); + // weak_pointers + Elements.add(WeakIvarBitmap); // Create an instance of the structure // This is now an externally visible symbol, so that we can speed up class // messages in the next ABI. We may already have some weak references to @@ -1714,13 +1695,13 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( std::string(Name)); llvm::GlobalVariable *ClassRef = TheModule.getNamedGlobal(ClassSym); llvm::Constant *Class = - MakeGlobal(ClassTy, Elements, CGM.getPointerAlign(), ClassSym, - llvm::GlobalValue::ExternalLinkage); + Elements.finishAndCreateGlobal(ClassSym, CGM.getPointerAlign(), false, + llvm::GlobalValue::ExternalLinkage); if (ClassRef) { - ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class, + ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class, ClassRef->getType())); - ClassRef->removeFromParent(); - Class->setName(ClassSym); + ClassRef->removeFromParent(); + Class->setName(ClassSym); } return Class; } @@ -1729,38 +1710,33 @@ llvm::Constant *CGObjCGNU:: GenerateProtocolMethodList(ArrayRef MethodNames, ArrayRef MethodTypes) { // Get the method structure type. - llvm::StructType *ObjCMethodDescTy = llvm::StructType::get( - PtrToInt8Ty, // Really a selector, but the runtime does the casting for us. - PtrToInt8Ty, - nullptr); - std::vector Methods; + llvm::StructType *ObjCMethodDescTy = + llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty }); + ConstantBuilder Builder(CGM); + auto MethodList = Builder.beginStruct(); + MethodList.addInt(IntTy, MethodNames.size()); + auto Methods = MethodList.beginArray(ObjCMethodDescTy); for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) { - Methods.push_back(llvm::ConstantStruct::get( - ObjCMethodDescTy, {MethodNames[i], MethodTypes[i]})); - } - llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy, - MethodNames.size()); - llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, - Methods); - llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get( - IntTy, ObjCMethodArrayTy, nullptr); - Methods.clear(); - Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size())); - Methods.push_back(Array); - return MakeGlobal(ObjCMethodDescListTy, Methods, CGM.getPointerAlign(), - ".objc_method_list"); + auto Method = Methods.beginStruct(ObjCMethodDescTy); + Method.add(MethodNames[i]); + Method.add(MethodTypes[i]); + Methods.add(Method.finish()); + } + MethodList.add(Methods.finish()); + return MethodList.finishAndCreateGlobal(".objc_method_list", + CGM.getPointerAlign()); } // Create the protocol list structure used in classes, categories and so on -llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRefProtocols){ - llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty, - Protocols.size()); - llvm::StructType *ProtocolListTy = llvm::StructType::get( - PtrTy, //Should be a recurisve pointer, but it's always NULL here. - SizeTy, - ProtocolArrayTy, - nullptr); - std::vector Elements; +llvm::Constant * +CGObjCGNU::GenerateProtocolList(ArrayRef Protocols) { + + ConstantBuilder Builder(CGM); + auto ProtocolList = Builder.beginStruct(); + ProtocolList.add(NULLPtr); + ProtocolList.addInt(LongTy, Protocols.size()); + + auto Elements = ProtocolList.beginArray(PtrToInt8Ty); for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); iter != endIter ; iter++) { llvm::Constant *protocol = nullptr; @@ -1773,16 +1749,11 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRefProtocols){ } llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol, PtrToInt8Ty); - Elements.push_back(Ptr); + Elements.add(Ptr); } - llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, - Elements); - Elements.clear(); - Elements.push_back(NULLPtr); - Elements.push_back(llvm::ConstantInt::get(LongTy, Protocols.size())); - Elements.push_back(ProtocolArray); - return MakeGlobal(ProtocolListTy, Elements, CGM.getPointerAlign(), - ".objc_protocol_list"); + ProtocolList.add(Elements.finish()); + return ProtocolList.finishAndCreateGlobal(".objc_protocol_list", + CGM.getPointerAlign()); } llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, @@ -1793,33 +1764,28 @@ llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } -llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( - const std::string &ProtocolName) { - SmallVector EmptyStringVector; - SmallVector EmptyConstantVector; - - llvm::Constant *ProtocolList = GenerateProtocolList(EmptyStringVector); - llvm::Constant *MethodList = - GenerateProtocolMethodList(EmptyConstantVector, EmptyConstantVector); +llvm::Constant * +CGObjCGNU::GenerateEmptyProtocol(const std::string &ProtocolName) { + llvm::Constant *ProtocolList = GenerateProtocolList({}); + llvm::Constant *MethodList = GenerateProtocolMethodList({}, {}); // Protocols are objects containing lists of the methods implemented and // protocols adopted. - llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, - PtrToInt8Ty, - ProtocolList->getType(), - MethodList->getType(), - MethodList->getType(), - MethodList->getType(), - MethodList->getType(), - nullptr); + ConstantBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. - llvm::Constant *Elements[] = { - llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy), - MakeConstantString(ProtocolName, ".objc_protocol_name"), ProtocolList, - MethodList, MethodList, MethodList, MethodList}; - return MakeGlobal(ProtocolTy, Elements, CGM.getPointerAlign(), - ".objc_protocol"); + Elements.add(llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); + + Elements.add(MakeConstantString(ProtocolName, ".objc_protocol_name")); + Elements.add(ProtocolList); + Elements.add(MethodList); + Elements.add(MethodList); + Elements.add(MethodList); + Elements.add(MethodList); + return Elements.finishAndCreateGlobal(".objc_protocol", + CGM.getPointerAlign()); } void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { @@ -1886,142 +1852,143 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { // The isSynthesized value is always set to 0 in a protocol. It exists to // simplify the runtime library by allowing it to use the same data // structures for protocol metadata everywhere. - llvm::StructType *PropertyMetadataTy = llvm::StructType::get( - PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, - PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, nullptr); - std::vector Properties; - std::vector OptionalProperties; - // Add all of the property methods need adding to the method list and to the - // property metadata list. - for (auto *property : PD->instance_properties()) { - std::vector Fields; + llvm::Constant *PropertyList; + llvm::Constant *OptionalPropertyList; + { + llvm::StructType *propertyMetadataTy = + llvm::StructType::get(CGM.getLLVMContext(), + { PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, + PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); + + unsigned numReqProperties = 0, numOptProperties = 0; + for (auto property : PD->instance_properties()) { + if (property->isOptional()) + numOptProperties++; + else + numReqProperties++; + } - Fields.push_back(MakePropertyEncodingString(property, nullptr)); - PushPropertyAttributes(Fields, property); + ConstantBuilder reqPropertyListBuilder(CGM); + auto reqPropertiesList = reqPropertyListBuilder.beginStruct(); + reqPropertiesList.addInt(IntTy, numReqProperties); + reqPropertiesList.add(NULLPtr); + auto reqPropertiesArray = reqPropertiesList.beginArray(propertyMetadataTy); + + ConstantBuilder optPropertyListBuilder(CGM); + auto optPropertiesList = optPropertyListBuilder.beginStruct(); + optPropertiesList.addInt(IntTy, numOptProperties); + optPropertiesList.add(NULLPtr); + auto optPropertiesArray = optPropertiesList.beginArray(propertyMetadataTy); + + // Add all of the property methods need adding to the method list and to the + // property metadata list. + for (auto *property : PD->instance_properties()) { + auto &propertiesArray = + (property->isOptional() ? optPropertiesArray : reqPropertiesArray); + auto fields = propertiesArray.beginStruct(propertyMetadataTy); + + fields.add(MakePropertyEncodingString(property, nullptr)); + PushPropertyAttributes(fields, property); + + if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { + std::string typeStr; + Context.getObjCEncodingForMethodDecl(getter, typeStr); + llvm::Constant *typeEncoding = MakeConstantString(typeStr); + InstanceMethodTypes.push_back(typeEncoding); + fields.add(MakeConstantString(getter->getSelector().getAsString())); + fields.add(typeEncoding); + } else { + fields.add(NULLPtr); + fields.add(NULLPtr); + } + if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { + std::string typeStr; + Context.getObjCEncodingForMethodDecl(setter, typeStr); + llvm::Constant *typeEncoding = MakeConstantString(typeStr); + InstanceMethodTypes.push_back(typeEncoding); + fields.add(MakeConstantString(setter->getSelector().getAsString())); + fields.add(typeEncoding); + } else { + fields.add(NULLPtr); + fields.add(NULLPtr); + } - if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { - std::string TypeStr; - Context.getObjCEncodingForMethodDecl(getter,TypeStr); - llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); - Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); - Fields.push_back(TypeEncoding); - } else { - Fields.push_back(NULLPtr); - Fields.push_back(NULLPtr); - } - if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { - std::string TypeStr; - Context.getObjCEncodingForMethodDecl(setter,TypeStr); - llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); - InstanceMethodTypes.push_back(TypeEncoding); - Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); - Fields.push_back(TypeEncoding); - } else { - Fields.push_back(NULLPtr); - Fields.push_back(NULLPtr); - } - if (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) { - OptionalProperties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); - } else { - Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); + propertiesArray.add(fields.finish()); } + + reqPropertiesList.add(reqPropertiesArray.finish()); + PropertyList = + reqPropertiesList.finishAndCreateGlobal(".objc_property_list", + CGM.getPointerAlign()); + + optPropertiesList.add(optPropertiesArray.finish()); + OptionalPropertyList = + optPropertiesList.finishAndCreateGlobal(".objc_property_list", + CGM.getPointerAlign()); } - llvm::Constant *PropertyArray = llvm::ConstantArray::get( - llvm::ArrayType::get(PropertyMetadataTy, Properties.size()), Properties); - llvm::Constant* PropertyListInitFields[] = - {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; - - llvm::Constant *PropertyListInit = - llvm::ConstantStruct::getAnon(PropertyListInitFields); - llvm::Constant *PropertyList = new llvm::GlobalVariable(TheModule, - PropertyListInit->getType(), false, llvm::GlobalValue::InternalLinkage, - PropertyListInit, ".objc_property_list"); - - llvm::Constant *OptionalPropertyArray = - llvm::ConstantArray::get(llvm::ArrayType::get(PropertyMetadataTy, - OptionalProperties.size()) , OptionalProperties); - llvm::Constant* OptionalPropertyListInitFields[] = { - llvm::ConstantInt::get(IntTy, OptionalProperties.size()), NULLPtr, - OptionalPropertyArray }; - - llvm::Constant *OptionalPropertyListInit = - llvm::ConstantStruct::getAnon(OptionalPropertyListInitFields); - llvm::Constant *OptionalPropertyList = new llvm::GlobalVariable(TheModule, - OptionalPropertyListInit->getType(), false, - llvm::GlobalValue::InternalLinkage, OptionalPropertyListInit, - ".objc_property_list"); // Protocols are objects containing lists of the methods implemented and // protocols adopted. - llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy, - PtrToInt8Ty, - ProtocolList->getType(), - InstanceMethodList->getType(), - ClassMethodList->getType(), - OptionalInstanceMethodList->getType(), - OptionalClassMethodList->getType(), - PropertyList->getType(), - OptionalPropertyList->getType(), - nullptr); // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. - llvm::Constant *Elements[] = { + ConstantBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + Elements.add( llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy), - MakeConstantString(ProtocolName, ".objc_protocol_name"), ProtocolList, - InstanceMethodList, ClassMethodList, OptionalInstanceMethodList, - OptionalClassMethodList, PropertyList, OptionalPropertyList}; + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); + Elements.add( + MakeConstantString(ProtocolName, ".objc_protocol_name")); + Elements.add(ProtocolList); + Elements.add(InstanceMethodList); + Elements.add(ClassMethodList); + Elements.add(OptionalInstanceMethodList); + Elements.add(OptionalClassMethodList); + Elements.add(PropertyList); + Elements.add(OptionalPropertyList); ExistingProtocols[ProtocolName] = - llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements, - CGM.getPointerAlign(), ".objc_protocol"), IdTy); + llvm::ConstantExpr::getBitCast( + Elements.finishAndCreateGlobal(".objc_protocol", CGM.getPointerAlign()), + IdTy); } void CGObjCGNU::GenerateProtocolHolderCategory() { // Collect information about instance methods SmallVector MethodSels; SmallVector MethodTypes; - std::vector Elements; + ConstantBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; const std::string CategoryName = "AnotherHack"; - Elements.push_back(MakeConstantString(CategoryName)); - Elements.push_back(MakeConstantString(ClassName)); + Elements.add(MakeConstantString(CategoryName)); + Elements.add(MakeConstantString(ClassName)); // Instance method list - Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( + Elements.add(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy)); // Class method list - Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList( + Elements.add(llvm::ConstantExpr::getBitCast(GenerateMethodList( ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy)); + // Protocol list - llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrTy, - ExistingProtocols.size()); - llvm::StructType *ProtocolListTy = llvm::StructType::get( - PtrTy, //Should be a recurisve pointer, but it's always NULL here. - SizeTy, - ProtocolArrayTy, - nullptr); - std::vector ProtocolElements; - for (llvm::StringMapIterator iter = - ExistingProtocols.begin(), endIter = ExistingProtocols.end(); + ConstantBuilder ProtocolListBuilder(CGM); + auto ProtocolList = ProtocolListBuilder.beginStruct(); + ProtocolList.add(NULLPtr); + ProtocolList.addInt(LongTy, ExistingProtocols.size()); + auto ProtocolElements = ProtocolList.beginArray(PtrTy); + for (auto iter = ExistingProtocols.begin(), endIter = ExistingProtocols.end(); iter != endIter ; iter++) { llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(iter->getValue(), PtrTy); - ProtocolElements.push_back(Ptr); - } - llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, - ProtocolElements); - ProtocolElements.clear(); - ProtocolElements.push_back(NULLPtr); - ProtocolElements.push_back(llvm::ConstantInt::get(LongTy, - ExistingProtocols.size())); - ProtocolElements.push_back(ProtocolArray); - Elements.push_back(llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolListTy, - ProtocolElements, CGM.getPointerAlign(), - ".objc_protocol_list"), PtrTy)); + ProtocolElements.add(Ptr); + } + ProtocolList.add(ProtocolElements.finish()); + Elements.add(llvm::ConstantExpr::getBitCast( + ProtocolList.finishAndCreateGlobal(".objc_protocol_list", + CGM.getPointerAlign()), + PtrTy)); Categories.push_back(llvm::ConstantExpr::getBitCast( - MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, - PtrTy, PtrTy, PtrTy, nullptr), Elements, CGM.getPointerAlign()), + Elements.finishAndCreateGlobal("", CGM.getPointerAlign()), PtrTy)); } @@ -2056,13 +2023,16 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef bits) { } values.push_back(llvm::ConstantInt::get(Int32Ty, word)); } - llvm::ArrayType *arrayTy = llvm::ArrayType::get(Int32Ty, values.size()); - llvm::Constant *array = llvm::ConstantArray::get(arrayTy, values); - llvm::Constant *fields[2] = { - llvm::ConstantInt::get(Int32Ty, values.size()), - array }; - llvm::Constant *GS = MakeGlobal(llvm::StructType::get(Int32Ty, arrayTy, - nullptr), fields, CharUnits::fromQuantity(4)); + + ConstantBuilder builder(CGM); + auto fields = builder.beginStruct(); + fields.addInt(Int32Ty, values.size()); + auto array = fields.beginArray(); + for (auto v : values) array.add(v); + fields.add(array.finish()); + + llvm::Constant *GS = + fields.finishAndCreateGlobal("", CharUnits::fromQuantity(4)); llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy); return ptr; } @@ -2098,23 +2068,25 @@ void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { E = Protos.end(); I != E; ++I) Protocols.push_back((*I)->getNameAsString()); - llvm::Constant *Elements[] = { - MakeConstantString(CategoryName), MakeConstantString(ClassName), - // Instance method list - llvm::ConstantExpr::getBitCast( + ConstantBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + Elements.add(MakeConstantString(CategoryName)); + Elements.add(MakeConstantString(ClassName)); + // Instance method list + Elements.add(llvm::ConstantExpr::getBitCast( GenerateMethodList(ClassName, CategoryName, InstanceMethodSels, InstanceMethodTypes, false), - PtrTy), - // Class method list - llvm::ConstantExpr::getBitCast(GenerateMethodList(ClassName, CategoryName, - ClassMethodSels, - ClassMethodTypes, true), - PtrTy), - // Protocol list - llvm::ConstantExpr::getBitCast(GenerateProtocolList(Protocols), PtrTy)}; + PtrTy)); + // Class method list + Elements.add(llvm::ConstantExpr::getBitCast( + GenerateMethodList(ClassName, CategoryName, + ClassMethodSels, ClassMethodTypes, true), + PtrTy)); + // Protocol list + Elements.add(llvm::ConstantExpr::getBitCast( + GenerateProtocolList(Protocols), PtrTy)); Categories.push_back(llvm::ConstantExpr::getBitCast( - MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, - PtrTy, PtrTy, PtrTy, nullptr), Elements, CGM.getPointerAlign()), + Elements.finishAndCreateGlobal("", CGM.getPointerAlign()), PtrTy)); } @@ -2124,23 +2096,35 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI ASTContext &Context = CGM.getContext(); // Property metadata: name, attributes, attributes2, padding1, padding2, // setter name, setter types, getter name, getter types. - llvm::StructType *PropertyMetadataTy = llvm::StructType::get( - PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, - PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, nullptr); - std::vector Properties; + llvm::StructType *propertyMetadataTy = + llvm::StructType::get(CGM.getLLVMContext(), + { PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, + PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); + + unsigned numProperties = 0; + for (auto *propertyImpl : OID->property_impls()) { + (void) propertyImpl; + numProperties++; + } + + ConstantBuilder builder(CGM); + auto propertyList = builder.beginStruct(); + propertyList.addInt(IntTy, numProperties); + propertyList.add(NULLPtr); + auto properties = propertyList.beginArray(propertyMetadataTy); // Add all of the property methods need adding to the method list and to the // property metadata list. for (auto *propertyImpl : OID->property_impls()) { - std::vector Fields; + auto fields = properties.beginStruct(propertyMetadataTy); ObjCPropertyDecl *property = propertyImpl->getPropertyDecl(); bool isSynthesized = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); bool isDynamic = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); - Fields.push_back(MakePropertyEncodingString(property, OID)); - PushPropertyAttributes(Fields, property, isSynthesized, isDynamic); + fields.add(MakePropertyEncodingString(property, OID)); + PushPropertyAttributes(fields, property, isSynthesized, isDynamic); if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(getter,TypeStr); @@ -2149,11 +2133,11 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI InstanceMethodTypes.push_back(TypeEncoding); InstanceMethodSels.push_back(getter->getSelector()); } - Fields.push_back(MakeConstantString(getter->getSelector().getAsString())); - Fields.push_back(TypeEncoding); + fields.add(MakeConstantString(getter->getSelector().getAsString())); + fields.add(TypeEncoding); } else { - Fields.push_back(NULLPtr); - Fields.push_back(NULLPtr); + fields.add(NULLPtr); + fields.add(NULLPtr); } if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) { std::string TypeStr; @@ -2163,26 +2147,18 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI InstanceMethodTypes.push_back(TypeEncoding); InstanceMethodSels.push_back(setter->getSelector()); } - Fields.push_back(MakeConstantString(setter->getSelector().getAsString())); - Fields.push_back(TypeEncoding); + fields.add(MakeConstantString(setter->getSelector().getAsString())); + fields.add(TypeEncoding); } else { - Fields.push_back(NULLPtr); - Fields.push_back(NULLPtr); + fields.add(NULLPtr); + fields.add(NULLPtr); } - Properties.push_back(llvm::ConstantStruct::get(PropertyMetadataTy, Fields)); - } - llvm::ArrayType *PropertyArrayTy = - llvm::ArrayType::get(PropertyMetadataTy, Properties.size()); - llvm::Constant *PropertyArray = llvm::ConstantArray::get(PropertyArrayTy, - Properties); - llvm::Constant* PropertyListInitFields[] = - {llvm::ConstantInt::get(IntTy, Properties.size()), NULLPtr, PropertyArray}; - - llvm::Constant *PropertyListInit = - llvm::ConstantStruct::getAnon(PropertyListInitFields); - return new llvm::GlobalVariable(TheModule, PropertyListInit->getType(), false, - llvm::GlobalValue::InternalLinkage, PropertyListInit, - ".objc_property_list"); + properties.add(fields.finish()); + } + propertyList.add(properties.finish()); + + return propertyList.finishAndCreateGlobal(".objc_property_list", + CGM.getPointerAlign()); } void CGObjCGNU::RegisterAlias(const ObjCCompatibleAliasDecl *OAD) { @@ -2231,7 +2207,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { SmallVector IvarTypes; SmallVector IvarOffsets; - std::vector IvarOffsetValues; + ConstantBuilder IvarOffsetBuilder(CGM); + auto IvarOffsetValues = IvarOffsetBuilder.beginArray(PtrToIntTy); SmallVector WeakIvars; SmallVector StrongIvars; @@ -2275,7 +2252,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { "__objc_ivar_offset_value_" + ClassName +"." + IVD->getNameAsString()); IvarOffsets.push_back(OffsetValue); - IvarOffsetValues.push_back(OffsetVar); + IvarOffsetValues.add(OffsetVar); Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); switch (lt) { case Qualifiers::OCL_Strong: @@ -2294,8 +2271,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); llvm::GlobalVariable *IvarOffsetArray = - MakeGlobalArray(PtrToIntTy, IvarOffsetValues, CGM.getPointerAlign(), - ".ivar.offsets"); + IvarOffsetValues.finishAndCreateGlobal(".ivar.offsets", + CGM.getPointerAlign()); // Collect information about instance methods SmallVector InstanceMethodSels; @@ -2461,21 +2438,18 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { if (StringClass.empty()) StringClass = "NXConstantString"; Elements.push_back(MakeConstantString(StringClass, - ".objc_static_class_name")); + ".objc_static_class_name")); Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, - ConstantStrings)); - llvm::StructType *StaticsListTy = - llvm::StructType::get(PtrToInt8Ty, StaticsArrayTy, nullptr); - llvm::Type *StaticsListPtrTy = - llvm::PointerType::getUnqual(StaticsListTy); - Statics = MakeGlobal(StaticsListTy, Elements, CGM.getPointerAlign(), - ".objc_statics"); + ConstantStrings)); + Statics = MakeGlobal(llvm::ConstantStruct::getAnon(Elements), + CGM.getPointerAlign(), ".objc_statics"); + llvm::Type *StaticsListPtrTy = Statics->getType(); llvm::ArrayType *StaticsListArrayTy = llvm::ArrayType::get(StaticsListPtrTy, 2); Elements.clear(); Elements.push_back(Statics); Elements.push_back(llvm::Constant::getNullValue(StaticsListPtrTy)); - Statics = MakeGlobal(StaticsListArrayTy, Elements, + Statics = MakeGlobal(llvm::ConstantArray::get(StaticsListArrayTy, Elements), CGM.getPointerAlign(), ".objc_statics_ptr"); Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy); } @@ -2489,7 +2463,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Elements.clear(); // Pointer to an array of selectors used in this module. - std::vector Selectors; + ConstantBuilder SelectorBuilder(CGM); + auto Selectors = SelectorBuilder.beginArray(SelStructTy); std::vector SelectorAliases; for (SelectorMap::iterator iter = SelectorTable.begin(), iterEnd = SelectorTable.end(); iter != iterEnd ; ++iter) { @@ -2505,10 +2480,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { if (!i->first.empty()) SelectorTypeEncoding = MakeConstantString(i->first, ".objc_sel_types"); - Elements.push_back(SelName); - Elements.push_back(SelectorTypeEncoding); - Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); - Elements.clear(); + auto SelStruct = Selectors.beginStruct(SelStructTy); + SelStruct.add(SelName); + SelStruct.add(SelectorTypeEncoding); + Selectors.add(SelStruct.finish()); // Store the selector alias for later replacement SelectorAliases.push_back(i->second); @@ -2519,16 +2494,18 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // because the selector list has a length field. Unfortunately, the GCC // runtime decides to ignore the length field and expects a NULL terminator, // and GCC cooperates with this by always setting the length to 0. - Elements.push_back(NULLPtr); - Elements.push_back(NULLPtr); - Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); - Elements.clear(); + { + auto SelStruct = Selectors.beginStruct(SelStructTy); + SelStruct.add(NULLPtr); + SelStruct.add(NULLPtr); + Selectors.add(SelStruct.finish()); + } // Number of static selectors Elements.push_back(llvm::ConstantInt::get(LongTy, SelectorCount)); llvm::GlobalVariable *SelectorList = - MakeGlobalArray(SelStructTy, Selectors, CGM.getPointerAlign(), - ".objc_selector_list"); + Selectors.finishAndCreateGlobal(".objc_selector_list", + CGM.getPointerAlign()); Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelStructPtrTy)); @@ -2562,7 +2539,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Elements.push_back(ClassList); // Construct the symbol table llvm::Constant *SymTab = - MakeGlobal(SymTabTy, Elements, CGM.getPointerAlign()); + MakeGlobal(llvm::ConstantStruct::get(SymTabTy, Elements), + CGM.getPointerAlign()); // The symbol table is contained in a module which has some version-checking // constants @@ -2603,7 +2581,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { break; } - llvm::Value *Module = MakeGlobal(ModuleTy, Elements, CGM.getPointerAlign()); + llvm::Value *Module = + MakeGlobal(llvm::ConstantStruct::get(ModuleTy, Elements), + CGM.getPointerAlign()); // Create the load function calling the runtime entry point with the module // structure diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 6e663bb46b..1e38e6e9ad 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -15,6 +15,7 @@ #include "CGCleanup.h" #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" +#include "ConstantBuilder.h" #include "clang/AST/Decl.h" #include "clang/AST/StmtOpenMP.h" #include "llvm/ADT/ArrayRef.h" @@ -906,18 +907,19 @@ Address CGOpenMPRuntime::getOrCreateDefaultLocation(unsigned Flags) { DefaultOpenMPPSource = llvm::ConstantExpr::getBitCast(DefaultOpenMPPSource, CGM.Int8PtrTy); } - auto DefaultOpenMPLocation = new llvm::GlobalVariable( - CGM.getModule(), IdentTy, /*isConstant*/ true, - llvm::GlobalValue::PrivateLinkage, /*Initializer*/ nullptr); + + ConstantBuilder builder(CGM); + auto fields = builder.beginStruct(IdentTy); + fields.addInt(CGM.Int32Ty, 0); + fields.addInt(CGM.Int32Ty, Flags); + fields.addInt(CGM.Int32Ty, 0); + fields.addInt(CGM.Int32Ty, 0); + fields.add(DefaultOpenMPPSource); + auto DefaultOpenMPLocation = + fields.finishAndCreateGlobal("", Align, /*isConstant*/ true, + llvm::GlobalValue::PrivateLinkage); DefaultOpenMPLocation->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - DefaultOpenMPLocation->setAlignment(Align.getQuantity()); - - llvm::Constant *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0, true); - llvm::Constant *Values[] = {Zero, - llvm::ConstantInt::get(CGM.Int32Ty, Flags), - Zero, Zero, DefaultOpenMPPSource}; - llvm::Constant *Init = llvm::ConstantStruct::get(IdentTy, Values); - DefaultOpenMPLocation->setInitializer(Init); + OpenMPDefaultLocMap[Flags] = Entry = DefaultOpenMPLocation; } return Address(Entry, Align); @@ -2810,9 +2812,10 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() { ".omp_offloading.entries_end"); // Create all device images - llvm::SmallVector DeviceImagesEntires; auto *DeviceImageTy = cast( CGM.getTypes().ConvertTypeForMem(getTgtDeviceImageQTy())); + ConstantBuilder DeviceImagesBuilder(CGM); + auto DeviceImagesEntries = DeviceImagesBuilder.beginArray(DeviceImageTy); for (unsigned i = 0; i < Devices.size(); ++i) { StringRef T = Devices[i].getTriple(); @@ -2824,22 +2827,19 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() { M, CGM.Int8Ty, /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, /*Initializer=*/nullptr, Twine(".omp_offloading.img_end.") + Twine(T)); - llvm::Constant *Dev = - llvm::ConstantStruct::get(DeviceImageTy, ImgBegin, ImgEnd, - HostEntriesBegin, HostEntriesEnd, nullptr); - DeviceImagesEntires.push_back(Dev); + auto Dev = DeviceImagesEntries.beginStruct(DeviceImageTy); + Dev.add(ImgBegin); + Dev.add(ImgEnd); + Dev.add(HostEntriesBegin); + Dev.add(HostEntriesEnd); + DeviceImagesEntries.add(Dev.finish()); } // Create device images global array. - llvm::ArrayType *DeviceImagesInitTy = - llvm::ArrayType::get(DeviceImageTy, DeviceImagesEntires.size()); - llvm::Constant *DeviceImagesInit = - llvm::ConstantArray::get(DeviceImagesInitTy, DeviceImagesEntires); - - llvm::GlobalVariable *DeviceImages = new llvm::GlobalVariable( - M, DeviceImagesInitTy, /*isConstant=*/true, - llvm::GlobalValue::InternalLinkage, DeviceImagesInit, - ".omp_offloading.device_images"); + llvm::GlobalVariable *DeviceImages = + DeviceImagesEntries.finishAndCreateGlobal(".omp_offloading.device_images", + CGM.getPointerAlign(), + /*isConstant=*/true); DeviceImages->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); // This is a Zero array to be used in the creation of the constant expressions @@ -2849,16 +2849,18 @@ CGOpenMPRuntime::createOffloadingBinaryDescriptorRegistration() { // Create the target region descriptor. auto *BinaryDescriptorTy = cast( CGM.getTypes().ConvertTypeForMem(getTgtBinaryDescriptorQTy())); - llvm::Constant *TargetRegionsDescriptorInit = llvm::ConstantStruct::get( - BinaryDescriptorTy, llvm::ConstantInt::get(CGM.Int32Ty, Devices.size()), - llvm::ConstantExpr::getGetElementPtr(DeviceImagesInitTy, DeviceImages, - Index), - HostEntriesBegin, HostEntriesEnd, nullptr); - - auto *Desc = new llvm::GlobalVariable( - M, BinaryDescriptorTy, /*isConstant=*/true, - llvm::GlobalValue::InternalLinkage, TargetRegionsDescriptorInit, - ".omp_offloading.descriptor"); + ConstantBuilder DescBuilder(CGM); + auto DescInit = DescBuilder.beginStruct(BinaryDescriptorTy); + DescInit.addInt(CGM.Int32Ty, Devices.size()); + DescInit.add(llvm::ConstantExpr::getGetElementPtr(DeviceImages->getValueType(), + DeviceImages, + Index)); + DescInit.add(HostEntriesBegin); + DescInit.add(HostEntriesEnd); + + auto *Desc = DescInit.finishAndCreateGlobal(".omp_offloading.descriptor", + CGM.getPointerAlign(), + /*isConstant=*/true); // Emit code to register or unregister the descriptor at execution // startup or closing, respectively. @@ -2906,19 +2908,24 @@ void CGOpenMPRuntime::createOffloadEntry(llvm::Constant *ID, Str->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); llvm::Constant *StrPtr = llvm::ConstantExpr::getBitCast(Str, CGM.Int8PtrTy); + // We can't have any padding between symbols, so we need to have 1-byte + // alignment. + auto Align = CharUnits::fromQuantity(1); + // Create the entry struct. - llvm::Constant *EntryInit = llvm::ConstantStruct::get( - TgtOffloadEntryType, AddrPtr, StrPtr, - llvm::ConstantInt::get(CGM.SizeTy, Size), nullptr); - llvm::GlobalVariable *Entry = new llvm::GlobalVariable( - M, TgtOffloadEntryType, true, llvm::GlobalValue::ExternalLinkage, - EntryInit, ".omp_offloading.entry"); + ConstantBuilder EntryBuilder(CGM); + auto EntryInit = EntryBuilder.beginStruct(TgtOffloadEntryType); + EntryInit.add(AddrPtr); + EntryInit.add(StrPtr); + EntryInit.addInt(CGM.SizeTy, Size); + llvm::GlobalVariable *Entry = + EntryInit.finishAndCreateGlobal(".omp_offloading.entry", + Align, + /*constant*/ true, + llvm::GlobalValue::ExternalLinkage); // The entry has to be created in the section the linker expects it to be. Entry->setSection(".omp_offloading.entries"); - // We can't have any padding between symbols, so we need to have 1-byte - // alignment. - Entry->setAlignment(1); } void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 0e93e403af..c931bbff06 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -24,6 +24,7 @@ #include "CodeGenFunction.h" #include "CodeGenPGO.h" #include "CodeGenTBAA.h" +#include "ConstantBuilder.h" #include "CoverageMappingGen.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -731,6 +732,8 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority) { } void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { + if (Fns.empty()) return; + // Ctor function type is void()*. llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false); llvm::Type *CtorPFTy = llvm::PointerType::getUnqual(CtorFTy); @@ -740,24 +743,22 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { Int32Ty, llvm::PointerType::getUnqual(CtorFTy), VoidPtrTy, nullptr); // Construct the constructor and destructor arrays. - SmallVector Ctors; + ConstantBuilder builder(*this); + auto ctors = builder.beginArray(CtorStructTy); for (const auto &I : Fns) { - llvm::Constant *S[] = { - llvm::ConstantInt::get(Int32Ty, I.Priority, false), - llvm::ConstantExpr::getBitCast(I.Initializer, CtorPFTy), - (I.AssociatedData - ? llvm::ConstantExpr::getBitCast(I.AssociatedData, VoidPtrTy) - : llvm::Constant::getNullValue(VoidPtrTy))}; - Ctors.push_back(llvm::ConstantStruct::get(CtorStructTy, S)); - } - - if (!Ctors.empty()) { - llvm::ArrayType *AT = llvm::ArrayType::get(CtorStructTy, Ctors.size()); - new llvm::GlobalVariable(TheModule, AT, false, - llvm::GlobalValue::AppendingLinkage, - llvm::ConstantArray::get(AT, Ctors), - GlobalName); + auto ctor = ctors.beginStruct(CtorStructTy); + ctor.addInt(Int32Ty, I.Priority); + ctor.add(llvm::ConstantExpr::getBitCast(I.Initializer, CtorPFTy)); + if (I.AssociatedData) + ctor.add(llvm::ConstantExpr::getBitCast(I.AssociatedData, VoidPtrTy)); + else + ctor.addNullPointer(VoidPtrTy); + ctors.add(ctor.finish()); } + + (void) ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::AppendingLinkage); Fns.clear(); } @@ -3190,15 +3191,14 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { auto *STy = cast(getTypes().ConvertType(CFTy)); - llvm::Constant *Fields[4]; + ConstantBuilder Builder(*this); + auto Fields = Builder.beginStruct(STy); // Class pointer. - Fields[0] = cast(CFConstantStringClassRef); + Fields.add(cast(CFConstantStringClassRef)); // Flags. - llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); - Fields[1] = isUTF16 ? llvm::ConstantInt::get(Ty, 0x07d0) - : llvm::ConstantInt::get(Ty, 0x07C8); + Fields.addInt(IntTy, isUTF16 ? 0x07d0 : 0x07C8); // String pointer. llvm::Constant *C = nullptr; @@ -3232,25 +3232,24 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { : "__TEXT,__cstring,cstring_literals"); // String. - Fields[2] = + llvm::Constant *Str = llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros); if (isUTF16) // Cast the UTF16 string to the correct type. - Fields[2] = llvm::ConstantExpr::getBitCast(Fields[2], Int8PtrTy); + Str = llvm::ConstantExpr::getBitCast(Str, Int8PtrTy); + Fields.add(Str); // String length. - Ty = getTypes().ConvertType(getContext().LongTy); - Fields[3] = llvm::ConstantInt::get(Ty, StringLength); + auto Ty = getTypes().ConvertType(getContext().LongTy); + Fields.addInt(cast(Ty), StringLength); CharUnits Alignment = getPointerAlign(); // The struct. - C = llvm::ConstantStruct::get(STy, Fields); - GV = new llvm::GlobalVariable(getModule(), C->getType(), /*isConstant=*/false, - llvm::GlobalVariable::PrivateLinkage, C, - "_unnamed_cfstring_"); - GV->setAlignment(Alignment.getQuantity()); + GV = Fields.finishAndCreateGlobal("_unnamed_cfstring_", Alignment, + /*isConstant=*/false, + llvm::GlobalVariable::PrivateLinkage); switch (getTriple().getObjectFormat()) { case llvm::Triple::UnknownObjectFormat: llvm_unreachable("unknown file format"); @@ -3338,19 +3337,18 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { NSConstantStringType = cast(getTypes().ConvertType(NSTy)); } - llvm::Constant *Fields[3]; + ConstantBuilder Builder(*this); + auto Fields = Builder.beginStruct(NSConstantStringType); // Class pointer. - Fields[0] = cast(V); + Fields.add(cast(V)); // String pointer. llvm::Constant *C = llvm::ConstantDataArray::getString(VMContext, Entry.first()); - llvm::GlobalValue::LinkageTypes Linkage; - bool isConstant; - Linkage = llvm::GlobalValue::PrivateLinkage; - isConstant = !LangOpts.WritableStrings; + llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::PrivateLinkage; + bool isConstant = !LangOpts.WritableStrings; auto *GV = new llvm::GlobalVariable(getModule(), C->getType(), isConstant, Linkage, C, ".str"); @@ -3359,20 +3357,17 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { // of the string is via this class initializer. CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); GV->setAlignment(Align.getQuantity()); - Fields[1] = - llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros); + Fields.add( + llvm::ConstantExpr::getGetElementPtr(GV->getValueType(), GV, Zeros)); // String length. - llvm::Type *Ty = getTypes().ConvertType(getContext().UnsignedIntTy); - Fields[2] = llvm::ConstantInt::get(Ty, StringLength); + Fields.addInt(IntTy, StringLength); // The struct. CharUnits Alignment = getPointerAlign(); - C = llvm::ConstantStruct::get(NSConstantStringType, Fields); - GV = new llvm::GlobalVariable(getModule(), C->getType(), true, - llvm::GlobalVariable::PrivateLinkage, C, - "_unnamed_nsstring_"); - GV->setAlignment(Alignment.getQuantity()); + GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment, + /*constant*/ true, + llvm::GlobalVariable::PrivateLinkage); const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip"; const char *NSStringNonFragileABISection = "__DATA,__objc_stringobj,regular,no_dead_strip"; diff --git a/lib/CodeGen/ConstantBuilder.h b/lib/CodeGen/ConstantBuilder.h new file mode 100644 index 0000000000..798bf913fd --- /dev/null +++ b/lib/CodeGen/ConstantBuilder.h @@ -0,0 +1,274 @@ +//===----- ConstantBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class provides a convenient interface for building complex +// global initializers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H +#define LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Constants.h" + +#include "CodeGenModule.h" + +namespace clang { +namespace CodeGen { + +class ConstantBuilder; + +/// A convenience builder class for complex constant initializers, +/// especially for anonymous global structures used by various language +/// runtimes. +/// +/// The basic usage pattern is expected to be something like: +/// ConstantBuilder builder(CGM); +/// auto toplevel = builder.beginStruct(); +/// toplevel.addInt(CGM.SizeTy, widgets.size()); +/// auto widgetArray = builder.beginArray(); +/// for (auto &widget : widgets) { +/// auto widgetDesc = widgetArray.beginStruct(); +/// widgetDesc.addInt(CGM.SizeTy, widget.getPower()); +/// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName())); +/// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl())); +/// widgetArray.add(widgetDesc.finish()); +/// } +/// toplevel.add(widgetArray.finish()); +/// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, +/// /*constant*/ true); +class ConstantBuilder { + CodeGenModule &CGM; + llvm::SmallVector Buffer; + bool Frozen = false; + +public: + explicit ConstantBuilder(CodeGenModule &CGM) : CGM(CGM) {} + + ~ConstantBuilder() { + assert(Buffer.empty() && "didn't claim all values out of buffer"); + } + + class ArrayBuilder; + class StructBuilder; + + class AggregateBuilder { + protected: + ConstantBuilder &Builder; + AggregateBuilder *Parent; + size_t Begin; + bool Finished = false; + bool Frozen = false; + + AggregateBuilder(ConstantBuilder &builder, AggregateBuilder *parent) + : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) { + if (parent) { + assert(!parent->Frozen && "parent already has child builder active"); + parent->Frozen = true; + } else { + assert(!builder.Frozen && "builder already has child builder active"); + builder.Frozen = true; + } + } + + ~AggregateBuilder() { + assert(Finished && "didn't claim value from aggregate builder"); + } + + void markFinished() { + assert(!Frozen && "child builder still active"); + assert(!Finished && "builder already finished"); + Finished = true; + if (Parent) { + assert(Parent->Frozen && + "parent not frozen while child builder active"); + Parent->Frozen = false; + } else { + assert(Builder.Frozen && + "builder not frozen while child builder active"); + Builder.Frozen = false; + } + } + + public: + // Not copyable. + AggregateBuilder(const AggregateBuilder &) = delete; + AggregateBuilder &operator=(const AggregateBuilder &) = delete; + + // Movable, mostly to allow returning. But we have to write this out + // properly to satisfy the assert in the destructor. + AggregateBuilder(AggregateBuilder &&other) + : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), + Finished(other.Finished), Frozen(other.Frozen) { + other.Finished = false; + } + AggregateBuilder &operator=(AggregateBuilder &&other) = delete; + + void add(llvm::Constant *value) { + assert(!Finished && "cannot add more values after finishing builder"); + Builder.Buffer.push_back(value); + } + + void addSize(CharUnits size) { + add(Builder.CGM.getSize(size)); + } + + void addInt(llvm::IntegerType *intTy, uint64_t value, + bool isSigned = false) { + add(llvm::ConstantInt::get(intTy, value, isSigned)); + } + + void addNullPointer(llvm::PointerType *ptrTy) { + add(llvm::ConstantPointerNull::get(ptrTy)); + } + + ArrayRef getGEPIndicesToCurrentPosition( + llvm::SmallVectorImpl &indices) { + getGEPIndicesTo(indices, Builder.Buffer.size()); + return indices; + } + + ArrayBuilder beginArray(llvm::Type *eltTy = nullptr); + StructBuilder beginStruct(llvm::StructType *structTy = nullptr); + + private: + void getGEPIndicesTo(llvm::SmallVectorImpl &indices, + size_t position) const { + // Recurse on the parent builder if present. + if (Parent) { + Parent->getGEPIndicesTo(indices, Begin); + + // Otherwise, add an index to drill into the first level of pointer. + } else { + assert(indices.empty()); + indices.push_back(llvm::ConstantInt::get(Builder.CGM.SizeTy, 0)); + } + + assert(position >= Begin); + indices.push_back(llvm::ConstantInt::get(Builder.CGM.SizeTy, + position - Begin)); + } + }; + + class ArrayBuilder : public AggregateBuilder { + llvm::Type *EltTy; + friend class ConstantBuilder; + ArrayBuilder(ConstantBuilder &builder, AggregateBuilder *parent, + llvm::Type *eltTy) + : AggregateBuilder(builder, parent), EltTy(eltTy) {} + public: + size_t size() const { + assert(!Finished); + assert(!Frozen); + assert(Begin <= Builder.Buffer.size()); + return Builder.Buffer.size() - Begin; + } + + /// Form an array constant from the values that have been added to this + /// builder. + llvm::Constant *finish() { + markFinished(); + + auto &buffer = Builder.Buffer; + assert((Begin < buffer.size() || + (Begin == buffer.size() && EltTy)) + && "didn't add any array elements without element type"); + auto elts = llvm::makeArrayRef(buffer).slice(Begin); + auto eltTy = EltTy ? EltTy : elts[0]->getType(); + auto type = llvm::ArrayType::get(eltTy, elts.size()); + auto constant = llvm::ConstantArray::get(type, elts); + buffer.erase(buffer.begin() + Begin, buffer.end()); + return constant; + } + + template + llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { + assert(!Parent && "finishing non-root builder"); + return Builder.createGlobal(finish(), std::forward(args)...); + } + }; + + ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { + return ArrayBuilder(*this, nullptr, eltTy); + } + + class StructBuilder : public AggregateBuilder { + llvm::StructType *Ty; + friend class ConstantBuilder; + StructBuilder(ConstantBuilder &builder, AggregateBuilder *parent, + llvm::StructType *ty) + : AggregateBuilder(builder, parent), Ty(ty) {} + public: + /// Finish the struct. + llvm::Constant *finish(bool packed = false) { + markFinished(); + + auto &buffer = Builder.Buffer; + assert(Begin < buffer.size() && "didn't add any struct elements?"); + auto elts = llvm::makeArrayRef(buffer).slice(Begin); + + llvm::Constant *constant; + if (Ty) { + constant = llvm::ConstantStruct::get(Ty, elts); + } else { + constant = llvm::ConstantStruct::getAnon(elts, packed); + } + + buffer.erase(buffer.begin() + Begin, buffer.end()); + return constant; + } + + template + llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { + assert(!Parent && "finishing non-root builder"); + return Builder.createGlobal(finish(), std::forward(args)...); + } + }; + + StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { + return StructBuilder(*this, nullptr, structTy); + } + + llvm::GlobalVariable *createGlobal(llvm::Constant *initializer, + StringRef name, + CharUnits alignment, + bool constant = false, + llvm::GlobalValue::LinkageTypes linkage + = llvm::GlobalValue::InternalLinkage, + unsigned addressSpace = 0) { + auto GV = new llvm::GlobalVariable(CGM.getModule(), + initializer->getType(), + constant, + linkage, + initializer, + name, + /*insert before*/ nullptr, + llvm::GlobalValue::NotThreadLocal, + addressSpace); + GV->setAlignment(alignment.getQuantity()); + return GV; + } +}; + +inline ConstantBuilder::ArrayBuilder +ConstantBuilder::AggregateBuilder::beginArray(llvm::Type *eltTy) { + return ArrayBuilder(Builder, this, eltTy); +} + +inline ConstantBuilder::StructBuilder +ConstantBuilder::AggregateBuilder::beginStruct(llvm::StructType *structTy) { + return StructBuilder(Builder, this, structTy); +} + +} // end namespace CodeGen +} // end namespace clang + +#endif -- 2.40.0