Improve handling of emitting 'null' pointers to data members.

llvm-svn: 95066
This commit is contained in:
Anders Carlsson 2010-02-02 05:17:25 +00:00
parent a4a2e5dd5b
commit e8bfe412ec
5 changed files with 117 additions and 50 deletions

View File

@ -911,7 +911,24 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
return C;
}
static inline bool isDataMemberPointerType(QualType T) {
static bool containsPointerToDataMember(CodeGenTypes &Types, QualType T) {
// No need to check for member pointers when not compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus)
return false;
T = Types.getContext().getBaseElementType(T);
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
// FIXME: It would be better if there was a way to explicitly compute the
// record layout instead of converting to a type.
Types.ConvertTagDeclType(RD);
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
return Layout.containsPointerToDataMember();
}
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>())
return !MPT->getPointeeType()->isFunctionType();
@ -919,45 +936,58 @@ static inline bool isDataMemberPointerType(QualType T) {
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
// No need to check for member pointers when not compiling C++.
if (!getContext().getLangOptions().CPlusPlus)
if (!containsPointerToDataMember(getTypes(), T))
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) {
QualType ElementTy = CAT->getElementType();
// FIXME: Handle arrays of structs that contain member pointers.
if (isDataMemberPointerType(Context.getBaseElementType(ElementTy))) {
llvm::Constant *Element = EmitNullConstant(ElementTy);
uint64_t NumElements = CAT->getSize().getZExtValue();
std::vector<llvm::Constant *> Array(NumElements);
for (uint64_t i = 0; i != NumElements; ++i)
Array[i] = Element;
llvm::Constant *Element = EmitNullConstant(ElementTy);
unsigned NumElements = CAT->getSize().getZExtValue();
std::vector<llvm::Constant *> Array(NumElements);
for (unsigned i = 0; i != NumElements; ++i)
Array[i] = Element;
const llvm::ArrayType *ATy =
cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
return llvm::ConstantArray::get(ATy, Array);
}
const llvm::ArrayType *ATy =
cast<llvm::ArrayType>(getTypes().ConvertTypeForMem(T));
return llvm::ConstantArray::get(ATy, Array);
}
if (const RecordType *RT = T->getAs<RecordType>()) {
const RecordDecl *RD = RT->getDecl();
// FIXME: It would be better if there was a way to explicitly compute the
// record layout instead of converting to a type.
Types.ConvertTagDeclType(RD);
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
assert(!RD->getNumBases() &&
"FIXME: Handle zero-initializing structs with bases and "
"pointers to data members.");
const llvm::StructType *STy =
cast<llvm::StructType>(getTypes().ConvertTypeForMem(T));
unsigned NumElements = STy->getNumElements();
std::vector<llvm::Constant *> Elements(NumElements);
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
if (Layout.containsMemberPointer()) {
assert(0 && "FIXME: No support for structs with member pointers yet!");
for (RecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I) {
const FieldDecl *FD = *I;
unsigned FieldNo = getTypes().getLLVMFieldNo(FD);
Elements[FieldNo] = EmitNullConstant(FD->getType());
}
// Now go through all other fields and zero them out.
for (unsigned i = 0; i != NumElements; ++i) {
if (!Elements[i])
Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
}
return llvm::ConstantStruct::get(STy, Elements);
}
// FIXME: Handle structs that contain member pointers.
if (isDataMemberPointerType(T))
return llvm::Constant::getAllOnesValue(getTypes().ConvertTypeForMem(T));
return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T));
assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() &&
"Should only see pointers to data members here!");
// Itanium C++ ABI 2.3:
// A NULL pointer is represented as -1.
return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1,
/*isSigned=*/true);
}
llvm::Constant *

View File

@ -108,6 +108,9 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
return true;
}
// Check if we have a pointer to data member in this field.
CheckForPointerToDataMember(D->getType());
assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
uint64_t FieldOffsetInBytes = FieldOffset / 8;
@ -338,23 +341,34 @@ uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
return Types.getTargetData().getTypeAllocSize(Ty);
}
void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
// This record already contains a member pointer.
if (ContainsMemberPointer)
if (ContainsPointerToDataMember)
return;
// Can only have member pointers if we're compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus)
return;
QualType Ty = FD->getType();
if (Ty->isMemberPointerType()) {
// We have a member pointer!
ContainsMemberPointer = true;
return;
}
T = Types.getContext().getBaseElementType(T);
if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
if (!MPT->getPointeeType()->isFunctionType()) {
// We have a pointer to data member.
ContainsPointerToDataMember = true;
}
} else if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
// FIXME: It would be better if there was a way to explicitly compute the
// record layout instead of converting to a type.
Types.ConvertTagDeclType(RD);
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
if (Layout.containsPointerToDataMember())
ContainsPointerToDataMember = true;
}
}
CGRecordLayout *
@ -386,5 +400,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
}
return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
}

View File

@ -27,6 +27,7 @@ namespace clang {
class CXXRecordDecl;
class FieldDecl;
class RecordDecl;
class QualType;
namespace CodeGen {
class CGRecordLayout;
@ -38,9 +39,10 @@ class CGRecordLayoutBuilder {
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
/// ContainsMemberPointer - Whether one of the fields is a member pointer
/// or is a struct that contains a member pointer.
bool ContainsMemberPointer;
/// ContainsPointerToDataMember - Whether one of the fields in this record
/// layout is a pointer to data member, or a struct that contains pointer to
/// data member.
bool ContainsPointerToDataMember;
/// Alignment - Contains the alignment of the RecordDecl.
unsigned Alignment;
@ -78,7 +80,7 @@ class CGRecordLayoutBuilder {
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
CGRecordLayoutBuilder(CodeGenTypes &Types)
: Types(Types), Packed(false), ContainsMemberPointer(false)
: Types(Types), Packed(false), ContainsPointerToDataMember(false)
, Alignment(0), AlignmentAsLLVMStruct(1)
, BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
@ -123,8 +125,9 @@ class CGRecordLayoutBuilder {
unsigned getTypeAlignment(const llvm::Type *Ty) const;
uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
/// CheckForMemberPointer - Check if the field contains a member pointer.
void CheckForMemberPointer(const FieldDecl *FD);
/// CheckForPointerToDataMember - Check if the given type contains a pointer
/// to data member.
void CheckForPointerToDataMember(QualType T);
public:
/// ComputeLayout - Return the right record layout for a given record decl.

View File

@ -60,21 +60,24 @@ namespace CodeGen {
/// LLVMType - The LLVMType corresponding to this record layout.
const llvm::Type *LLVMType;
/// ContainsMemberPointer - Whether one of the fields in this record layout
/// is a member pointer, or a struct that contains a member pointer.
bool ContainsMemberPointer;
/// ContainsPointerToDataMember - Whether one of the fields in this record
/// layout is a pointer to data member, or a struct that contains pointer to
/// data member.
bool ContainsPointerToDataMember;
public:
CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
: LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember)
: LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) { }
/// getLLVMType - Return llvm type associated with this record.
const llvm::Type *getLLVMType() const {
return LLVMType;
}
bool containsMemberPointer() const {
return ContainsMemberPointer;
/// containsPointerToDataMember - Whether this struct contains pointers to
/// data members.
bool containsPointerToDataMember() const {
return ContainsPointerToDataMember;
}
};

View File

@ -17,6 +17,23 @@ namespace ZeroInit {
// CHECK: @_ZN8ZeroInit1bE = global i64 -1,
int A::* b = 0;
// CHECK: @_ZN8ZeroInit2saE = global %struct.anon { i64 -1 }
struct {
int A::*a;
} sa;
// CHECK: @_ZN8ZeroInit3ssaE = global [2 x %0] [%0 { [2 x i64] [i64 -1, i64 -1] }
struct {
int A::*aa[2];
} ssa[2];
// CHECK: @_ZN8ZeroInit2ssE = global %1 { %struct.anon { i64 -1 } }
struct {
struct {
int A::*pa;
} s;
} ss;
}
// PR5674