forked from OSchip/llvm-project
[ms-cxxabi] Emit non-virtual member function pointers
Without any conversion, this is pretty straightforward. Most of the fields can be zeros. The order is: - field offset or pointer - nonvirtual adjustment (for MI functions) - vbptr offset (for unspecified) - virtual adjustment offset (for virtual inheritance) Differential Revision: http://llvm-reviews.chandlerc.com/D699 llvm-svn: 180985
This commit is contained in:
parent
a80ea12703
commit
7d0efb57d3
|
@ -139,6 +139,12 @@ private:
|
|||
llvm::Value *VirtualBaseAdjustmentOffset,
|
||||
llvm::Value *VBPtrOffset /* optional */);
|
||||
|
||||
/// \brief Emits a full member pointer with the fields common to data and
|
||||
/// function member pointers.
|
||||
llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
|
||||
bool IsMemberFunction,
|
||||
const CXXRecordDecl *RD);
|
||||
|
||||
public:
|
||||
virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
|
||||
|
||||
|
@ -148,6 +154,8 @@ public:
|
|||
|
||||
virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset);
|
||||
virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
|
||||
virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
|
||||
|
||||
virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
|
||||
llvm::Value *L,
|
||||
|
@ -427,10 +435,9 @@ static bool hasOnlyOneField(MSInheritanceModel Inheritance) {
|
|||
|
||||
// Only member pointers to functions need a this adjustment, since it can be
|
||||
// combined with the field offset for data pointers.
|
||||
static bool hasNonVirtualBaseAdjustmentField(const MemberPointerType *MPT,
|
||||
static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction,
|
||||
MSInheritanceModel Inheritance) {
|
||||
return (MPT->isMemberFunctionPointer() &&
|
||||
Inheritance >= MSIM_Multiple);
|
||||
return (IsMemberFunction && Inheritance >= MSIM_Multiple);
|
||||
}
|
||||
|
||||
static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) {
|
||||
|
@ -472,9 +479,10 @@ MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
|
|||
else
|
||||
fields.push_back(CGM.IntTy); // FieldOffset
|
||||
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
|
||||
Inheritance))
|
||||
fields.push_back(CGM.IntTy);
|
||||
if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
fields.push_back(CGM.IntTy);
|
||||
if (hasVirtualBaseAdjustmentField(Inheritance))
|
||||
fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset
|
||||
|
@ -500,9 +508,10 @@ GetNullMemberPointerFields(const MemberPointerType *MPT,
|
|||
fields.push_back(getAllOnesInt()); // FieldOffset
|
||||
}
|
||||
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
|
||||
Inheritance))
|
||||
fields.push_back(getZeroInt());
|
||||
if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
fields.push_back(getZeroInt());
|
||||
if (hasVirtualBaseAdjustmentField(Inheritance))
|
||||
fields.push_back(getAllOnesInt());
|
||||
|
@ -520,27 +529,87 @@ MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
|
|||
}
|
||||
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset) {
|
||||
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
|
||||
MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
|
||||
bool IsMemberFunction,
|
||||
const CXXRecordDecl *RD)
|
||||
{
|
||||
MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
|
||||
|
||||
// Single inheritance class member pointer are represented as scalars instead
|
||||
// of aggregates.
|
||||
if (hasOnlyOneField(Inheritance))
|
||||
return FirstField;
|
||||
|
||||
llvm::SmallVector<llvm::Constant *, 4> fields;
|
||||
fields.push_back(llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()));
|
||||
fields.push_back(FirstField);
|
||||
|
||||
if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
|
||||
fields.push_back(getZeroInt());
|
||||
|
||||
if (hasVBPtrOffsetField(Inheritance)) {
|
||||
int64_t VBPtrOffset =
|
||||
getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
|
||||
if (VBPtrOffset == -1)
|
||||
VBPtrOffset = 0;
|
||||
fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset));
|
||||
}
|
||||
assert(!hasNonVirtualBaseAdjustmentField(MPT, Inheritance));
|
||||
// The virtual base field starts out zero. It is adjusted by conversions to
|
||||
// member pointer types of a more derived class. See http://llvm.org/PR15713
|
||||
|
||||
// The rest of the fields are adjusted by conversions to a more derived class.
|
||||
if (hasVirtualBaseAdjustmentField(Inheritance))
|
||||
fields.push_back(getZeroInt());
|
||||
if (fields.size() == 1)
|
||||
return fields[0];
|
||||
|
||||
return llvm::ConstantStruct::getAnon(fields);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
|
||||
CharUnits offset) {
|
||||
const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
|
||||
llvm::Constant *FirstField =
|
||||
llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
|
||||
return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
|
||||
assert(MD->isInstance() && "Member function must not be static!");
|
||||
MD = MD->getCanonicalDecl();
|
||||
const CXXRecordDecl *RD = MD->getParent();
|
||||
CodeGenTypes &Types = CGM.getTypes();
|
||||
|
||||
llvm::Constant *FirstField;
|
||||
if (MD->isVirtual()) {
|
||||
// FIXME: We have to instantiate a thunk that loads the vftable and jumps to
|
||||
// the right offset.
|
||||
FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
|
||||
} else {
|
||||
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
|
||||
llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (Types.isFuncTypeConvertible(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
|
||||
} else {
|
||||
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
|
||||
// function type is incomplete.
|
||||
Ty = CGM.PtrDiffTy;
|
||||
}
|
||||
FirstField = CGM.GetAddrOfFunction(MD, Ty);
|
||||
FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
|
||||
}
|
||||
|
||||
// The rest of the fields are common with data member pointers.
|
||||
return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
|
||||
// FIXME PR15875: Implement member pointer conversions for Constants.
|
||||
const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
|
||||
return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy),
|
||||
/*IsMemberFunction=*/true, RD);
|
||||
}
|
||||
|
||||
/// Member pointers are the same if they're either bitwise identical *or* both
|
||||
/// null. Null-ness for function members is determined by the first field,
|
||||
/// while for data member pointers we must compare all fields.
|
||||
|
@ -760,10 +829,10 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
|||
// We need to extract values.
|
||||
unsigned I = 0;
|
||||
FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
|
||||
if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
|
||||
NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
|
||||
if (hasVBPtrOffsetField(Inheritance))
|
||||
VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
|
||||
if (hasVirtualBaseAdjustmentField(Inheritance))
|
||||
VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
|
||||
|
||||
struct B1 {
|
||||
void foo();
|
||||
int b;
|
||||
};
|
||||
struct B2 { };
|
||||
struct Single : B1 { };
|
||||
struct Multiple : B1, B2 { };
|
||||
struct B2 {
|
||||
void foo();
|
||||
};
|
||||
struct Single : B1 {
|
||||
void foo();
|
||||
};
|
||||
struct Multiple : B1, B2 {
|
||||
void foo();
|
||||
};
|
||||
struct Virtual : virtual B1 {
|
||||
int v;
|
||||
void foo();
|
||||
};
|
||||
|
||||
struct POD {
|
||||
|
@ -30,7 +38,7 @@ struct NonZeroVBPtr : POD, Virtual {
|
|||
|
||||
struct Unspecified;
|
||||
|
||||
// Check that we can lower the LLVM types and get the initializers right.
|
||||
// Check that we can lower the LLVM types and get the null initializers right.
|
||||
int Single ::*s_d_memptr;
|
||||
int Polymorphic::*p_d_memptr;
|
||||
int Multiple ::*m_d_memptr;
|
||||
|
@ -54,6 +62,49 @@ void (Virtual ::*v_f_memptr)();
|
|||
// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4
|
||||
// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4
|
||||
|
||||
// We can define Unspecified after locking in the inheritance model.
|
||||
struct Unspecified : Virtual {
|
||||
void foo();
|
||||
int u;
|
||||
};
|
||||
|
||||
struct UnspecWithVBPtr;
|
||||
int UnspecWithVBPtr::*forceUnspecWithVBPtr;
|
||||
struct UnspecWithVBPtr : B1, virtual B2 {
|
||||
int u;
|
||||
void foo();
|
||||
};
|
||||
|
||||
// Test emitting non-virtual member pointers in a non-constexpr setting.
|
||||
void EmitNonVirtualMemberPointers() {
|
||||
void (Single ::*s_f_memptr)() = &Single::foo;
|
||||
void (Multiple ::*m_f_memptr)() = &Multiple::foo;
|
||||
void (Virtual ::*v_f_memptr)() = &Virtual::foo;
|
||||
void (Unspecified::*u_f_memptr)() = &Unspecified::foo;
|
||||
void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;
|
||||
// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 {
|
||||
// CHECK: alloca i8*, align 4
|
||||
// CHECK: alloca { i8*, i32 }, align 4
|
||||
// CHECK: alloca { i8*, i32, i32 }, align 4
|
||||
// CHECK: alloca { i8*, i32, i32, i32 }, align 4
|
||||
// CHECK: store i8* bitcast (void (%{{.*}}*)* @"\01?foo@Single@@QAEXXZ" to i8*), i8** %{{.*}}, align 4
|
||||
// CHECK: store { i8*, i32 }
|
||||
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Multiple@@QAEXXZ" to i8*), i32 0 },
|
||||
// CHECK: { i8*, i32 }* %{{.*}}, align 4
|
||||
// CHECK: store { i8*, i32, i32 }
|
||||
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 },
|
||||
// CHECK: { i8*, i32, i32 }* %{{.*}}, align 4
|
||||
// CHECK: store { i8*, i32, i32, i32 }
|
||||
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 },
|
||||
// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4
|
||||
// CHECK: store { i8*, i32, i32, i32 }
|
||||
// CHECK: { i8* bitcast (void (%{{.*}}*)* @"\01?foo@UnspecWithVBPtr@@QAEXXZ" to i8*),
|
||||
// CHECK: i32 0, i32 4, i32 0 },
|
||||
// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4
|
||||
// CHECK: ret void
|
||||
// CHECK: }
|
||||
}
|
||||
|
||||
void podMemPtrs() {
|
||||
int POD::*memptr;
|
||||
memptr = &POD::a;
|
||||
|
|
Loading…
Reference in New Issue