forked from OSchip/llvm-project
Add bitmaps for strong / weak ivar layout (GNUstep runtime).
llvm-svn: 141085
This commit is contained in:
parent
03efe84d0a
commit
cdd207e43e
|
@ -160,6 +160,10 @@ protected:
|
|||
llvm::PointerType *PtrToIntTy;
|
||||
/// LLVM type for Objective-C BOOL type.
|
||||
llvm::Type *BoolTy;
|
||||
/// 32-bit integer type, to save us needing to look it up every time it's used.
|
||||
llvm::IntegerType *Int32Ty;
|
||||
/// 64-bit integer type, to save us needing to look it up every time it's used.
|
||||
llvm::IntegerType *Int64Ty;
|
||||
/// Metadata kind used to tie method lookups to message sends. The GNUstep
|
||||
/// runtime provides some LLVM passes that can use this to do things like
|
||||
/// automatic IMP caching and speculative inlining.
|
||||
|
@ -191,7 +195,7 @@ protected:
|
|||
/// The element types must match the types of the structure elements in the
|
||||
/// first argument.
|
||||
llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty,
|
||||
std::vector<llvm::Constant*> &V,
|
||||
llvm::ArrayRef<llvm::Constant*> V,
|
||||
StringRef Name="",
|
||||
llvm::GlobalValue::LinkageTypes linkage
|
||||
=llvm::GlobalValue::InternalLinkage) {
|
||||
|
@ -203,7 +207,7 @@ protected:
|
|||
/// elements that the array type declares, of the type specified as the array
|
||||
/// element type.
|
||||
llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty,
|
||||
std::vector<llvm::Constant*> &V,
|
||||
llvm::ArrayRef<llvm::Constant*> V,
|
||||
StringRef Name="",
|
||||
llvm::GlobalValue::LinkageTypes linkage
|
||||
=llvm::GlobalValue::InternalLinkage) {
|
||||
|
@ -214,7 +218,7 @@ protected:
|
|||
/// 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,
|
||||
std::vector<llvm::Constant*> &V,
|
||||
llvm::ArrayRef<llvm::Constant*> V,
|
||||
StringRef Name="",
|
||||
llvm::GlobalValue::LinkageTypes linkage
|
||||
=llvm::GlobalValue::InternalLinkage) {
|
||||
|
@ -375,6 +379,8 @@ private:
|
|||
llvm::Constant *Protocols,
|
||||
llvm::Constant *IvarOffsets,
|
||||
llvm::Constant *Properties,
|
||||
llvm::Constant *StrongIvarBitmap,
|
||||
llvm::Constant *WeakIvarBitmap,
|
||||
bool isMeta=false);
|
||||
/// Generates a method list. This is used by protocols to define the required
|
||||
/// and optional methods.
|
||||
|
@ -402,12 +408,24 @@ protected:
|
|||
llvm::Value *&Receiver,
|
||||
llvm::Value *cmd,
|
||||
llvm::MDNode *node) = 0;
|
||||
/// Looks up the method for sending a message to a superclass. This mechanism
|
||||
/// differs between the GCC and GNU runtimes, so this method must be
|
||||
/// overridden in subclasses.
|
||||
/// Looks up the method for sending a message to a superclass. This
|
||||
/// mechanism differs between the GCC and GNU runtimes, so this method must
|
||||
/// be overridden in subclasses.
|
||||
virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF,
|
||||
llvm::Value *ObjCSuper,
|
||||
llvm::Value *cmd) = 0;
|
||||
/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
|
||||
/// stored in a 64-bit value with the low bit set to 1 and the remaining 63
|
||||
/// bits set to their values, LSB first, while larger ones are stored in a
|
||||
/// structure of this / form:
|
||||
///
|
||||
/// struct { int32_t length; int32_t values[length]; };
|
||||
///
|
||||
/// The values in the array are stored in host-endian format, with the least
|
||||
/// significant bit being assumed to come first in the bitfield. Therefore,
|
||||
/// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] },
|
||||
/// while a bitfield / with the 63rd bit set will be 1<<64.
|
||||
llvm::Constant *MakeBitField(llvm::SmallVectorImpl<bool> &bits);
|
||||
public:
|
||||
CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
|
||||
unsigned protocolClassVersion);
|
||||
|
@ -696,6 +714,9 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
|
|||
PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
|
||||
PtrTy = PtrToInt8Ty;
|
||||
|
||||
Int32Ty = llvm::Type::getInt32Ty(VMContext);
|
||||
Int64Ty = llvm::Type::getInt64Ty(VMContext);
|
||||
|
||||
// Object type
|
||||
QualType UnqualIdTy = CGM.getContext().getObjCIdType();
|
||||
ASTIdTy = CanQualType();
|
||||
|
@ -1246,8 +1267,7 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const StringRef &ClassName,
|
|||
Methods.clear();
|
||||
Methods.push_back(llvm::ConstantPointerNull::get(
|
||||
llvm::PointerType::getUnqual(ObjCMethodListTy)));
|
||||
Methods.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
|
||||
MethodTypes.size()));
|
||||
Methods.push_back(llvm::ConstantInt::get(Int32Ty, MethodTypes.size()));
|
||||
Methods.push_back(MethodArray);
|
||||
|
||||
// Create an instance of the structure
|
||||
|
@ -1307,6 +1327,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
|
|||
llvm::Constant *Protocols,
|
||||
llvm::Constant *IvarOffsets,
|
||||
llvm::Constant *Properties,
|
||||
llvm::Constant *StrongIvarBitmap,
|
||||
llvm::Constant *WeakIvarBitmap,
|
||||
bool isMeta) {
|
||||
// Set up the class structure
|
||||
// Note: Several of these are char*s when they should be ids. This is
|
||||
|
@ -1334,6 +1356,8 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
|
|||
LongTy, // abi_version
|
||||
IvarOffsets->getType(), // ivar_offsets
|
||||
Properties->getType(), // properties
|
||||
Int64Ty, // strong_pointers
|
||||
Int64Ty, // weak_pointers
|
||||
NULL);
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
|
||||
// Fill in the structure
|
||||
|
@ -1358,9 +1382,11 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure(
|
|||
Elements.push_back(NULLPtr);
|
||||
Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
|
||||
Elements.push_back(NULLPtr);
|
||||
Elements.push_back(Zero);
|
||||
Elements.push_back(llvm::ConstantInt::get(LongTy, 1));
|
||||
Elements.push_back(IvarOffsets);
|
||||
Elements.push_back(Properties);
|
||||
Elements.push_back(StrongIvarBitmap);
|
||||
Elements.push_back(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.
|
||||
|
@ -1460,8 +1486,7 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
|
|||
// The isa pointer must be set to a magic number so the runtime knows it's
|
||||
// the correct layout.
|
||||
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
|
||||
ProtocolVersion), IdTy));
|
||||
llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
|
||||
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
|
||||
Elements.push_back(ProtocolList);
|
||||
Elements.push_back(MethodList);
|
||||
|
@ -1621,8 +1646,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
|
|||
// The isa pointer must be set to a magic number so the runtime knows it's
|
||||
// the correct layout.
|
||||
Elements.push_back(llvm::ConstantExpr::getIntToPtr(
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
|
||||
ProtocolVersion), IdTy));
|
||||
llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
|
||||
Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
|
||||
Elements.push_back(ProtocolList);
|
||||
Elements.push_back(InstanceMethodList);
|
||||
|
@ -1681,6 +1705,46 @@ void CGObjCGNU::GenerateProtocolHolderCategory(void) {
|
|||
PtrTy, PtrTy, PtrTy, NULL), Elements), PtrTy));
|
||||
}
|
||||
|
||||
/// Libobjc2 uses a bitfield representation where small(ish) bitfields are
|
||||
/// stored in a 64-bit value with the low bit set to 1 and the remaining 63
|
||||
/// bits set to their values, LSB first, while larger ones are stored in a
|
||||
/// structure of this / form:
|
||||
///
|
||||
/// struct { int32_t length; int32_t values[length]; };
|
||||
///
|
||||
/// The values in the array are stored in host-endian format, with the least
|
||||
/// significant bit being assumed to come first in the bitfield. Therefore, a
|
||||
/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a
|
||||
/// bitfield / with the 63rd bit set will be 1<<64.
|
||||
llvm::Constant *CGObjCGNU::MakeBitField(llvm::SmallVectorImpl<bool> &bits) {
|
||||
int bitCount = bits.size();
|
||||
if (bitCount < 64) {
|
||||
uint64_t val = 1;
|
||||
for (int i=0 ; i<bitCount ; ++i) {
|
||||
if (bits[i]) val |= 1<<(i+1);
|
||||
}
|
||||
return llvm::ConstantInt::get(Int64Ty, val);
|
||||
}
|
||||
llvm::SmallVector<llvm::Constant*, 8> values;
|
||||
int v=0;
|
||||
while (v < bitCount) {
|
||||
int32_t word = 0;
|
||||
for (int i=0 ; (i<32) && (v<bitCount) ; ++i) {
|
||||
if (bits[v]) word |= 1<<i;
|
||||
v++;
|
||||
}
|
||||
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,
|
||||
NULL), fields);
|
||||
return llvm::ConstantExpr::getPtrToInt(GS, Int64Ty);
|
||||
}
|
||||
|
||||
void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
|
||||
std::string ClassName = OCD->getClassInterface()->getNameAsString();
|
||||
std::string CategoryName = OCD->getNameAsString();
|
||||
|
@ -1845,6 +1909,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|||
SmallVector<llvm::Constant*, 16> IvarOffsets;
|
||||
|
||||
std::vector<llvm::Constant*> IvarOffsetValues;
|
||||
SmallVector<bool, 16> WeakIvars;
|
||||
SmallVector<bool, 16> StrongIvars;
|
||||
|
||||
int superInstanceSize = !SuperClassDecl ? 0 :
|
||||
Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity();
|
||||
|
@ -1887,7 +1953,23 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|||
IVD->getNameAsString());
|
||||
IvarOffsets.push_back(OffsetValue);
|
||||
IvarOffsetValues.push_back(OffsetVar);
|
||||
Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime();
|
||||
switch (lt) {
|
||||
case Qualifiers::OCL_Strong:
|
||||
StrongIvars.push_back(true);
|
||||
WeakIvars.push_back(false);
|
||||
break;
|
||||
case Qualifiers::OCL_Weak:
|
||||
StrongIvars.push_back(false);
|
||||
WeakIvars.push_back(true);
|
||||
break;
|
||||
default:
|
||||
StrongIvars.push_back(false);
|
||||
WeakIvars.push_back(false);
|
||||
}
|
||||
}
|
||||
llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars);
|
||||
llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars);
|
||||
llvm::GlobalVariable *IvarOffsetArray =
|
||||
MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets");
|
||||
|
||||
|
@ -1954,7 +2036,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|||
// setting up the alias. These are: The base address for the global, the
|
||||
// ivar array (second field), the ivar in this list (set for each ivar), and
|
||||
// the offset (third field in ivar structure)
|
||||
llvm::Type *IndexTy = llvm::Type::getInt32Ty(VMContext);
|
||||
llvm::Type *IndexTy = Int32Ty;
|
||||
llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
|
||||
llvm::ConstantInt::get(IndexTy, 1), 0,
|
||||
llvm::ConstantInt::get(IndexTy, 2) };
|
||||
|
@ -1983,10 +2065,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|||
}
|
||||
++ivarIndex;
|
||||
}
|
||||
llvm::Constant *Zero64 = llvm::ConstantInt::get(Int64Ty, 0);
|
||||
//Generate metaclass for class methods
|
||||
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
|
||||
NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
|
||||
empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr, true);
|
||||
empty, empty, empty), ClassMethodList, NULLPtr,
|
||||
NULLPtr, NULLPtr, Zero64, Zero64, true);
|
||||
|
||||
// Generate the class structure
|
||||
llvm::Constant *ClassStruct =
|
||||
|
@ -1994,7 +2078,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
|
|||
ClassName.c_str(), 0,
|
||||
llvm::ConstantInt::get(LongTy, instanceSize), IvarList,
|
||||
MethodList, GenerateProtocolList(Protocols), IvarOffsetArray,
|
||||
Properties);
|
||||
Properties, StrongIvarBitmap, WeakIvarBitmap);
|
||||
|
||||
// Resolve the class aliases, if they exist.
|
||||
if (ClassPtrAlias) {
|
||||
|
@ -2118,7 +2202,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
|
|||
for (unsigned int i=0 ; i<SelectorCount ; i++) {
|
||||
|
||||
llvm::Constant *Idxs[] = {Zeros[0],
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]};
|
||||
llvm::ConstantInt::get(Int32Ty, i), Zeros[0]};
|
||||
// FIXME: We're generating redundant loads and stores here!
|
||||
llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList,
|
||||
makeArrayRef(Idxs, 2));
|
||||
|
@ -2396,7 +2480,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
|
|||
// GCC-compiled class.
|
||||
if (CGM.getLangOptions().PICLevel) {
|
||||
llvm::GlobalVariable *IvarOffsetGV = new llvm::GlobalVariable(TheModule,
|
||||
llvm::Type::getInt32Ty(VMContext), false,
|
||||
Int32Ty, false,
|
||||
llvm::GlobalValue::PrivateLinkage, OffsetGuess, Name+".guess");
|
||||
IvarOffsetPointer = new llvm::GlobalVariable(TheModule,
|
||||
IvarOffsetGV->getType(), false, llvm::GlobalValue::LinkOnceAnyLinkage,
|
||||
|
|
Loading…
Reference in New Issue