[MS ABI] Fix the preferred alignment of member pointers

Member pointers in the MS ABI have different alignment depending on
whether they were created on the stack or live in a record.

llvm-svn: 235681
This commit is contained in:
David Majnemer 2015-04-24 01:25:05 +00:00
parent 37ea57862f
commit e154456d4a
4 changed files with 43 additions and 39 deletions

View File

@ -1797,11 +1797,16 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
TypeInfo TI = getTypeInfo(T);
unsigned ABIAlign = TI.Align;
T = T->getBaseElementTypeUnsafe();
// The preferred alignment of member pointers is that of a pointer.
if (T->isMemberPointerType())
return getPreferredTypeAlign(getPointerDiffType().getTypePtr());
if (Target->getTriple().getArch() == llvm::Triple::xcore)
return ABIAlign; // Never overalign on XCore.
// Double and long long should be naturally aligned if possible.
T = T->getBaseElementTypeUnsafe();
if (const ComplexType *CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
if (const EnumType *ET = T->getAs<EnumType>())

View File

@ -1813,8 +1813,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
ArgVals.push_back(ValueAndIsPtr(V, HavePointer));
} else {
// Load scalar value from indirect argument.
CharUnits Alignment = getContext().getTypeAlignInChars(Ty);
V = EmitLoadOfScalar(V, false, Alignment.getQuantity(), Ty,
V = EmitLoadOfScalar(V, false, ArgI.getIndirectAlign(), Ty,
Arg->getLocStart());
if (isPromoted)

View File

@ -80,20 +80,20 @@ int UnspecSingle::*us_d_memptr;
// CHECK: @"\01?p_d_memptr@@3PQPolymorphic@@HQ1@" = global i32 0, align 4
// CHECK: @"\01?m_d_memptr@@3PQMultiple@@HQ1@" = global i32 -1, align 4
// CHECK: @"\01?v_d_memptr@@3PQVirtual@@HQ1@" = global { i32, i32 }
// CHECK: { i32 0, i32 -1 }, align 8
// CHECK: { i32 0, i32 -1 }, align 4
// CHECK: @"\01?n_d_memptr@@3PQNonZeroVBPtr@@HQ1@" = global { i32, i32 }
// CHECK: { i32 0, i32 -1 }, align 8
// CHECK: { i32 0, i32 -1 }, align 4
// CHECK: @"\01?u_d_memptr@@3PQUnspecified@@HQ1@" = global { i32, i32, i32 }
// CHECK: { i32 0, i32 0, i32 -1 }, align 8
// CHECK: { i32 0, i32 0, i32 -1 }, align 4
// CHECK: @"\01?us_d_memptr@@3PQUnspecSingle@@HQ1@" = global { i32, i32, i32 }
// CHECK: { i32 0, i32 0, i32 -1 }, align 8
// CHECK: { i32 0, i32 0, i32 -1 }, align 4
void (Single ::*s_f_memptr)();
void (Multiple::*m_f_memptr)();
void (Virtual ::*v_f_memptr)();
// CHECK: @"\01?s_f_memptr@@3P8Single@@AEXXZQ1@" = global i8* null, align 4
// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 8
// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 8
// CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4
// CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4
// We can define Unspecified after locking in the inheritance model.
struct Unspecified : Multiple, Virtual {
@ -115,13 +115,13 @@ void (UnspecSingle::*us_f_mp)() = &UnspecSingle::foo;
// CHECK: @"\01?s_f_mp@Const@@3P8Single@@AEXXZQ2@" =
// CHECK: global i8* bitcast ({{.*}} @"\01?foo@Single@@QAEXXZ" to i8*), align 4
// CHECK: @"\01?m_f_mp@Const@@3P8Multiple@@AEXXZQ2@" =
// CHECK: global { i8*, i32 } { i8* bitcast ({{.*}} @"\01?foo@B2@@QAEXXZ" to i8*), i32 4 }, align 8
// CHECK: global { i8*, i32 } { i8* bitcast ({{.*}} @"\01?foo@B2@@QAEXXZ" to i8*), i32 4 }, align 4
// CHECK: @"\01?v_f_mp@Const@@3P8Virtual@@AEXXZQ2@" =
// CHECK: global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 8
// CHECK: global { i8*, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Virtual@@QAEXXZ" to i8*), i32 0, i32 0 }, align 4
// CHECK: @"\01?u_f_mp@Const@@3P8Unspecified@@AEXXZQ2@" =
// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, align 8
// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@Unspecified@@QAEXXZ" to i8*), i32 0, i32 12, i32 0 }, align 4
// CHECK: @"\01?us_f_mp@Const@@3P8UnspecSingle@@AEXXZQ2@" =
// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@UnspecSingle@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 8
// CHECK: global { i8*, i32, i32, i32 } { i8* bitcast ({{.*}} @"\01?foo@UnspecSingle@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 }, align 4
}
namespace CastParam {
@ -143,11 +143,11 @@ void (A::*ptr1)(void *) = (void (A::*)(void *)) &A::foo;
// Try a reinterpret_cast followed by a memptr conversion.
void (C::*ptr2)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) &A::foo;
// CHECK: @"\01?ptr2@CastParam@@3P8C@1@AEXPAX@ZQ21@" =
// CHECK: global { i8*, i32 } { i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), i32 4 }, align 8
// CHECK: global { i8*, i32 } { i8* bitcast (void ({{.*}})* @"\01?foo@A@CastParam@@QAEXPAU12@@Z" to i8*), i32 4 }, align 4
void (C::*ptr3)(void *) = (void (C::*)(void *)) (void (A::*)(void *)) (void (A::*)(A *)) 0;
// CHECK: @"\01?ptr3@CastParam@@3P8C@1@AEXPAX@ZQ21@" =
// CHECK: global { i8*, i32 } zeroinitializer, align 8
// CHECK: global { i8*, i32 } zeroinitializer, align 4
struct D : C {
virtual void isPolymorphic();
@ -180,23 +180,23 @@ void EmitNonVirtualMemberPointers() {
void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;
// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() {{.*}} {
// CHECK: alloca i8*, align 4
// CHECK: alloca { i8*, i32 }, align 8
// CHECK: alloca { i8*, i32, i32 }, align 8
// CHECK: alloca { i8*, i32, i32, i32 }, align 8
// 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 8
// 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 8
// 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 12, i32 0 },
// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 8
// 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 8
// CHECK: { i8*, i32, i32, i32 }* %{{.*}}, align 4
// CHECK: ret void
// CHECK: }
}
@ -243,9 +243,9 @@ void polymorphicMemPtrs() {
bool nullTestDataUnspecified(int Unspecified::*mp) {
return mp;
// CHECK: define zeroext i1 @"\01?nullTestDataUnspecified@@YA_NPQUnspecified@@H@Z"{{.*}} {
// CHECK: %{{.*}} = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 8
// CHECK: store { i32, i32, i32 } {{.*}} align 8
// CHECK: %[[mp:.*]] = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 8
// CHECK: %{{.*}} = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 4
// CHECK: store { i32, i32, i32 } {{.*}} align 4
// CHECK: %[[mp:.*]] = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 4
// CHECK: %[[mp0:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 0
// CHECK: %[[cmp0:.*]] = icmp ne i32 %[[mp0]], 0
// CHECK: %[[mp1:.*]] = extractvalue { i32, i32, i32 } %[[mp]], 1
@ -265,9 +265,9 @@ bool nullTestDataUnspecified(int Unspecified::*mp) {
bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) {
return mp;
// CHECK: define zeroext i1 @"\01?nullTestFunctionUnspecified@@YA_NP8Unspecified@@AEXXZ@Z"{{.*}} {
// CHECK: %{{.*}} = load { i8*, i32, i32, i32 }, { i8*, i32, i32, i32 }* %{{.*}}, align 8
// CHECK: store { i8*, i32, i32, i32 } {{.*}} align 8
// CHECK: %[[mp:.*]] = load { i8*, i32, i32, i32 }, { i8*, i32, i32, i32 }* %{{.*}}, align 8
// CHECK: %{{.*}} = load { i8*, i32, i32, i32 }, { i8*, i32, i32, i32 }* %{{.*}}, align 4
// CHECK: store { i8*, i32, i32, i32 } {{.*}} align 4
// CHECK: %[[mp:.*]] = load { i8*, i32, i32, i32 }, { i8*, i32, i32, i32 }* %{{.*}}, align 4
// CHECK: %[[mp0:.*]] = extractvalue { i8*, i32, i32, i32 } %[[mp]], 0
// CHECK: %[[cmp0:.*]] = icmp ne i8* %[[mp0]], null
// CHECK: ret i1 %[[cmp0]]
@ -280,7 +280,7 @@ int loadDataMemberPointerVirtual(Virtual *o, int Virtual::*memptr) {
// data pointer.
// CHECK: define i32 @"\01?loadDataMemberPointerVirtual@@YAHPAUVirtual@@PQ1@H@Z"{{.*}} {
// CHECK: %[[o:.*]] = load %{{.*}}*, %{{.*}}** %{{.*}}, align 4
// CHECK: %[[memptr:.*]] = load { i32, i32 }, { i32, i32 }* %{{.*}}, align 8
// CHECK: %[[memptr:.*]] = load { i32, i32 }, { i32, i32 }* %{{.*}}, align 4
// CHECK: %[[memptr0:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 0
// CHECK: %[[memptr1:.*]] = extractvalue { i32, i32 } %[[memptr:.*]], 1
// CHECK: %[[v6:.*]] = bitcast %{{.*}}* %[[o]] to i8*
@ -309,7 +309,7 @@ int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
// data pointer.
// CHECK: define i32 @"\01?loadDataMemberPointerUnspecified@@YAHPAUUnspecified@@PQ1@H@Z"{{.*}} {
// CHECK: %[[o:.*]] = load %{{.*}}*, %{{.*}}** %{{.*}}, align 4
// CHECK: %[[memptr:.*]] = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 8
// CHECK: %[[memptr:.*]] = load { i32, i32, i32 }, { i32, i32, i32 }* %{{.*}}, align 4
// CHECK: %[[memptr0:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 0
// CHECK: %[[memptr1:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 1
// CHECK: %[[memptr2:.*]] = extractvalue { i32, i32, i32 } %[[memptr:.*]], 2
@ -509,7 +509,7 @@ void (B2::*convertMultipleFuncToB2(void (Multiple::*mp)()))() {
//
// CHECK: define i32 @"\01?convertMultipleFuncToB2@@YAP8B2@@AEXXZP8Multiple@@AEXXZ@Z"{{.*}} {
// CHECK: store
// CHECK: %[[src:.*]] = load { i8*, i32 }, { i8*, i32 }* %{{.*}}, align 8
// CHECK: %[[src:.*]] = load { i8*, i32 }, { i8*, i32 }* %{{.*}}, align 4
// CHECK: extractvalue { i8*, i32 } %[[src]], 0
// CHECK: icmp ne i8* %{{.*}}, null
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
@ -534,7 +534,7 @@ void (D::*convertCToD(void (C::*mp)()))() {
return mp;
// CHECK: define void @"\01?convertCToD@Test1@@YAP8D@1@AEXXZP8C@1@AEXXZ@Z"{{.*}} {
// CHECK: store
// CHECK: load { i8*, i32, i32 }, { i8*, i32, i32 }* %{{.*}}, align 8
// CHECK: load { i8*, i32, i32 }, { i8*, i32, i32 }* %{{.*}}, align 4
// CHECK: extractvalue { i8*, i32, i32 } %{{.*}}, 0
// CHECK: icmp ne i8* %{{.*}}, null
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}

View File

@ -93,15 +93,15 @@ static_assert(sizeof(void (IncSingle::*)()) == kSingleFunctionSize, "");
static_assert(sizeof(void (IncMultiple::*)()) == kMultipleFunctionSize, "");
static_assert(sizeof(void (IncVirtual::*)()) == kVirtualFunctionSize, "");
static_assert(__alignof(int IncSingle::*) == kSingleDataAlign, "");
static_assert(__alignof(int IncMultiple::*) == kMultipleDataAlign, "");
static_assert(__alignof(int IncVirtual::*) == kVirtualDataAlign, "");
static_assert(__alignof(void (IncSingle::*)()) == kSingleFunctionAlign, "");
static_assert(__alignof(void (IncMultiple::*)()) == kMultipleFunctionAlign, "");
static_assert(__alignof(void (IncVirtual::*)()) == kVirtualFunctionAlign, "");
static_assert(__alignof(int IncSingle::*) == __alignof(void *), "");
static_assert(__alignof(int IncMultiple::*) == __alignof(void *), "");
static_assert(__alignof(int IncVirtual::*) == __alignof(void *), "");
static_assert(__alignof(void (IncSingle::*)()) == __alignof(void *), "");
static_assert(__alignof(void (IncMultiple::*)()) == __alignof(void *), "");
static_assert(__alignof(void (IncVirtual::*)()) == __alignof(void *), "");
// An incomplete type with an unspecified inheritance model seems to take one
// more slot than virtual. It's not clear what it's used for yet.
// more slot than virtual.
class IncUnspecified;
static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, "");
static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, "");