forked from OSchip/llvm-project
Experiment with using first-class aggregates to represent member function
pointers. I find the resulting code to be substantially cleaner, and it makes it very easy to use the same APIs for data member pointers (which I have conscientiously avoided here), and it avoids a plethora of potential inefficiencies due to excessive memory copying, but we'll have to see if it actually works. llvm-svn: 111776
This commit is contained in:
parent
131d97d809
commit
a1dee5300b
|
@ -330,6 +330,11 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF,
|
|||
<< S;
|
||||
}
|
||||
|
||||
static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM,
|
||||
QualType T) {
|
||||
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
|
||||
}
|
||||
|
||||
llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
llvm::Value *&This,
|
||||
llvm::Value *MemPtr,
|
||||
|
@ -341,32 +346,16 @@ llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
|||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
|
||||
const llvm::FunctionType *FTy =
|
||||
CGF.CGM.getTypes().GetFunctionType(
|
||||
CGF.CGM.getTypes().getFunctionInfo(RD, FPT),
|
||||
FPT->isVariadic());
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
|
||||
FPT->isVariadic());
|
||||
return llvm::Constant::getNullValue(FTy->getPointerTo());
|
||||
}
|
||||
|
||||
void CGCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest) {
|
||||
llvm::Value *CGCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src) {
|
||||
ErrorUnsupportedABI(CGF, "member function pointer conversions");
|
||||
}
|
||||
|
||||
void CGCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const MemberPointerType *MPT,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest) {
|
||||
ErrorUnsupportedABI(CGF, "null member function pointers");
|
||||
}
|
||||
|
||||
void CGCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const CXXMethodDecl *MD,
|
||||
llvm::Value *DestPtr,
|
||||
bool VolatileDest) {
|
||||
ErrorUnsupportedABI(CGF, "member function pointers");
|
||||
return GetBogusMemberPointer(CGM, E->getType());
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
|
@ -390,16 +379,18 @@ CGCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF,
|
|||
llvm::Constant *
|
||||
CGCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C,
|
||||
const CastExpr *E) {
|
||||
return 0;
|
||||
return GetBogusMemberPointer(CGM, E->getType());
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
CGCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) {
|
||||
return 0;
|
||||
return GetBogusMemberPointer(CGM, QualType(MPT, 0));
|
||||
}
|
||||
|
||||
llvm::Constant *CGCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
|
||||
return 0;
|
||||
return GetBogusMemberPointer(CGM,
|
||||
CGM.getContext().getMemberPointerType(MD->getType(),
|
||||
MD->getParent()->getTypeForDecl()));
|
||||
}
|
||||
|
||||
bool CGCXXABI::RequiresNonZeroInitializer(QualType T) {
|
||||
|
|
|
@ -34,7 +34,13 @@ namespace CodeGen {
|
|||
|
||||
/// Implements C++ ABI-specific code generation functions.
|
||||
class CGCXXABI {
|
||||
protected:
|
||||
CodeGenModule &CGM;
|
||||
|
||||
CGCXXABI(CodeGenModule &CGM) : CGM(CGM) {}
|
||||
|
||||
public:
|
||||
|
||||
virtual ~CGCXXABI();
|
||||
|
||||
/// Gets the mangle context.
|
||||
|
@ -46,18 +52,11 @@ public:
|
|||
llvm::Value *MemPtr,
|
||||
const MemberPointerType *MPT);
|
||||
|
||||
virtual void
|
||||
virtual llvm::Value *
|
||||
EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest);
|
||||
llvm::Value *Src);
|
||||
|
||||
virtual void EmitNullMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const MemberPointerType *MPT,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest);
|
||||
|
||||
// Manipulations on constant expressions.
|
||||
|
||||
/// \brief Returns true if zero-initializing the given type requires
|
||||
|
@ -73,10 +72,6 @@ public:
|
|||
EmitNullMemberFunctionPointer(const MemberPointerType *MPT);
|
||||
|
||||
virtual llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
|
||||
virtual void EmitMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const CXXMethodDecl *MD,
|
||||
llvm::Value *DestPtr,
|
||||
bool VolatileDest);
|
||||
|
||||
virtual llvm::Value *
|
||||
EmitMemberFunctionPointerComparison(CodeGenFunction &CGF,
|
||||
|
@ -87,7 +82,7 @@ public:
|
|||
|
||||
virtual llvm::Value *
|
||||
EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF,
|
||||
llvm::Value *Addr,
|
||||
llvm::Value *MemPtr,
|
||||
const MemberPointerType *MPT);
|
||||
};
|
||||
|
||||
|
|
|
@ -67,10 +67,8 @@ llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty,
|
|||
llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) {
|
||||
QualType BoolTy = getContext().BoolTy;
|
||||
if (E->getType()->isMemberFunctionPointerType()) {
|
||||
LValue LV = EmitAggExprToLValue(E);
|
||||
|
||||
return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF,
|
||||
LV.getAddress(),
|
||||
llvm::Value *MemPtr = EmitScalarExpr(E);
|
||||
return CGM.getCXXABI().EmitMemberFunctionPointerIsNotNull(CGF, MemPtr,
|
||||
E->getType()->getAs<MemberPointerType>());
|
||||
}
|
||||
if (!E->getType()->isAnyComplexType())
|
||||
|
@ -614,18 +612,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) {
|
|||
|
||||
if (LV.isSimple()) {
|
||||
llvm::Value *Ptr = LV.getAddress();
|
||||
const llvm::Type *EltTy =
|
||||
cast<llvm::PointerType>(Ptr->getType())->getElementType();
|
||||
|
||||
// Simple scalar l-value.
|
||||
//
|
||||
// FIXME: We shouldn't have to use isSingleValueType here.
|
||||
if (EltTy->isSingleValueType())
|
||||
return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
|
||||
LV.getAlignment(), ExprType));
|
||||
// Functions are l-values that don't require loading.
|
||||
if (ExprType->isFunctionType())
|
||||
return RValue::get(Ptr);
|
||||
|
||||
// Everything needs a load.
|
||||
return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(),
|
||||
LV.getAlignment(), ExprType));
|
||||
|
||||
assert(ExprType->isFunctionType() && "Unknown scalar value");
|
||||
return RValue::get(Ptr);
|
||||
}
|
||||
|
||||
if (LV.isVectorElt()) {
|
||||
|
@ -1177,12 +1172,19 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
|||
return LV;
|
||||
}
|
||||
|
||||
// If we're emitting an instance method as an independent lvalue,
|
||||
// we're actually emitting a member pointer.
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
|
||||
if (MD->isInstance()) {
|
||||
llvm::Value *V = CGM.getCXXABI().EmitMemberFunctionPointer(MD);
|
||||
return MakeAddrLValue(V, MD->getType(), Alignment);
|
||||
}
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
|
||||
return EmitFunctionDeclLValue(*this, E, FD);
|
||||
|
||||
// FIXME: the qualifier check does not seem sufficient here
|
||||
if (E->getQualifier()) {
|
||||
const FieldDecl *FD = cast<FieldDecl>(ND);
|
||||
// If we're emitting a field as an independent lvalue, we're
|
||||
// actually emitting a member pointer.
|
||||
if (const FieldDecl *FD = dyn_cast<FieldDecl>(ND)) {
|
||||
llvm::Value *V = CGM.EmitPointerToDataMember(FD);
|
||||
return MakeAddrLValue(V, FD->getType(), Alignment);
|
||||
}
|
||||
|
|
|
@ -108,7 +108,6 @@ public:
|
|||
void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO);
|
||||
void VisitBinAssign(const BinaryOperator *E);
|
||||
void VisitBinComma(const BinaryOperator *E);
|
||||
void VisitUnaryAddrOf(const UnaryOperator *E);
|
||||
|
||||
void VisitObjCMessageExpr(ObjCMessageExpr *E);
|
||||
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
|
||||
|
@ -287,46 +286,9 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
|||
Visit(E->getSubExpr());
|
||||
break;
|
||||
|
||||
case CastExpr::CK_NullToMemberPointer: {
|
||||
// If the subexpression's type is the C++0x nullptr_t, emit the
|
||||
// subexpression, which may have side effects.
|
||||
if (E->getSubExpr()->getType()->isNullPtrType())
|
||||
Visit(E->getSubExpr());
|
||||
|
||||
CGF.CGM.getCXXABI().EmitNullMemberFunctionPointer(CGF,
|
||||
E->getType()->getAs<MemberPointerType>(),
|
||||
DestPtr, VolatileDest);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
llvm_unreachable("there are no lvalue bit-casts on aggregates");
|
||||
break;
|
||||
|
||||
case CastExpr::CK_BitCast: {
|
||||
// This must be a member function pointer cast.
|
||||
Visit(E->getSubExpr());
|
||||
break;
|
||||
}
|
||||
|
||||
case CastExpr::CK_DerivedToBaseMemberPointer:
|
||||
case CastExpr::CK_BaseToDerivedMemberPointer: {
|
||||
QualType SrcType = E->getSubExpr()->getType();
|
||||
|
||||
llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp");
|
||||
CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified());
|
||||
|
||||
// Note that the AST doesn't distinguish between checked and
|
||||
// unchecked member pointer conversions, so we always have to
|
||||
// implement checked conversions here. This is inefficient for
|
||||
// ABIs where an actual null check is thus required; fortunately,
|
||||
// the Itanium and ARM ABIs ignore the adjustment value when
|
||||
// considering null-ness.
|
||||
CGF.CGM.getCXXABI().EmitMemberFunctionPointerConversion(CGF, E, Src,
|
||||
DestPtr, VolatileDest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,23 +324,6 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) {
|
|||
/*IgnoreResult=*/false, IsInitializer);
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
|
||||
// We have a member function pointer.
|
||||
assert(E->getType()->getAs<MemberPointerType>()
|
||||
->getPointeeType()->isFunctionProtoType() &&
|
||||
"Unexpected member pointer type!");
|
||||
|
||||
// The creation of member function pointers has no side effects; if
|
||||
// there is no destination pointer, we have nothing to do.
|
||||
if (!DestPtr)
|
||||
return;
|
||||
|
||||
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
|
||||
|
||||
CGF.CGM.getCXXABI().EmitMemberFunctionPointer(CGF, MD, DestPtr, VolatileDest);
|
||||
}
|
||||
|
||||
void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) {
|
||||
CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest);
|
||||
}
|
||||
|
|
|
@ -160,8 +160,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
|
|||
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
|
||||
|
||||
// Get the member function pointer.
|
||||
llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn");
|
||||
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
|
||||
llvm::Value *MemFnPtr = EmitScalarExpr(MemFnExpr);
|
||||
|
||||
// Emit the 'this' pointer.
|
||||
llvm::Value *This;
|
||||
|
|
|
@ -460,7 +460,7 @@ public:
|
|||
|
||||
llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) {
|
||||
if (const MemberPointerType *MPT =
|
||||
E->getType()->getAs<MemberPointerType>()) {
|
||||
E->getType()->getAs<MemberPointerType>()) {
|
||||
QualType T = MPT->getPointeeType();
|
||||
DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
|
||||
|
||||
|
@ -533,13 +533,21 @@ public:
|
|||
llvm::StructType::get(C->getType()->getContext(), Types, false);
|
||||
return llvm::ConstantStruct::get(STy, Elts);
|
||||
}
|
||||
case CastExpr::CK_NullToMemberPointer:
|
||||
return CGM.getCXXABI().EmitNullMemberFunctionPointer(
|
||||
E->getType()->getAs<MemberPointerType>());
|
||||
case CastExpr::CK_NullToMemberPointer: {
|
||||
const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
|
||||
if (MPT->getPointeeType()->isFunctionType())
|
||||
return CGM.getCXXABI().EmitNullMemberFunctionPointer(MPT);
|
||||
return CGM.EmitNullConstant(E->getType());
|
||||
}
|
||||
|
||||
case CastExpr::CK_BaseToDerivedMemberPointer: {
|
||||
Expr *SubExpr = E->getSubExpr();
|
||||
const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>();
|
||||
|
||||
// TODO: support data-member conversions here!
|
||||
if (!MPT->getPointeeType()->isFunctionType())
|
||||
return 0;
|
||||
|
||||
Expr *SubExpr = E->getSubExpr();
|
||||
llvm::Constant *C =
|
||||
CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF);
|
||||
if (!C) return 0;
|
||||
|
|
|
@ -238,6 +238,9 @@ public:
|
|||
|
||||
|
||||
Value *VisitUnaryAddrOf(const UnaryOperator *E) {
|
||||
// If the sub-expression is an instance member reference,
|
||||
// EmitDeclRefLValue will magically emit it with the appropriate
|
||||
// value as the "address".
|
||||
return EmitLValue(E->getSubExpr()).getAddress();
|
||||
}
|
||||
Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); }
|
||||
|
@ -995,11 +998,31 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
|||
return EmitLValue(E).getAddress();
|
||||
|
||||
case CastExpr::CK_NullToMemberPointer:
|
||||
// If the subexpression's type is the C++0x nullptr_t, emit the
|
||||
// subexpression, which may have side effects.
|
||||
if (E->getType()->isNullPtrType())
|
||||
(void) Visit(E);
|
||||
|
||||
if (CE->getType()->isMemberFunctionPointerType())
|
||||
return CGF.CGM.getCXXABI().EmitNullMemberFunctionPointer(
|
||||
CE->getType()->getAs<MemberPointerType>());
|
||||
|
||||
return CGF.CGM.EmitNullConstant(DestTy);
|
||||
|
||||
case CastExpr::CK_BaseToDerivedMemberPointer:
|
||||
case CastExpr::CK_DerivedToBaseMemberPointer: {
|
||||
Value *Src = Visit(E);
|
||||
|
||||
// Note that the AST doesn't distinguish between checked and
|
||||
// unchecked member pointer conversions, so we always have to
|
||||
// implement checked conversions here. This is inefficient when
|
||||
// actual control flow may be required in order to perform the
|
||||
// check, which it is for data member pointers (but not member
|
||||
// function pointers on Itanium and ARM).
|
||||
|
||||
if (CE->getType()->isMemberFunctionPointerType())
|
||||
return CGF.CGM.getCXXABI().EmitMemberFunctionPointerConversion(CGF, CE,
|
||||
Src);
|
||||
|
||||
// See if we need to adjust the pointer.
|
||||
const CXXRecordDecl *BaseDecl =
|
||||
|
@ -1804,10 +1827,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc,
|
|||
if (LHSTy->isMemberFunctionPointerType()) {
|
||||
assert(E->getOpcode() == BinaryOperator::EQ ||
|
||||
E->getOpcode() == BinaryOperator::NE);
|
||||
Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr();
|
||||
Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr();
|
||||
Value *LHS = CGF.EmitScalarExpr(E->getLHS());
|
||||
Value *RHS = CGF.EmitScalarExpr(E->getRHS());
|
||||
Result = CGF.CGM.getCXXABI().EmitMemberFunctionPointerComparison(
|
||||
CGF, LHSPtr, RHSPtr, LHSTy->getAs<MemberPointerType>(),
|
||||
CGF, LHS, RHS, LHSTy->getAs<MemberPointerType>(),
|
||||
E->getOpcode() == BinaryOperator::NE);
|
||||
} else if (!LHSTy->isAnyComplexType()) {
|
||||
Value *LHS = Visit(E->getLHS());
|
||||
|
|
|
@ -77,7 +77,7 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
|
|||
|
||||
bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
|
||||
return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() ||
|
||||
T->isMemberFunctionPointerType() || T->isObjCObjectType();
|
||||
T->isObjCObjectType();
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitReturnBlock() {
|
||||
|
|
|
@ -31,12 +31,11 @@ using namespace CodeGen;
|
|||
namespace {
|
||||
class ItaniumCXXABI : public CodeGen::CGCXXABI {
|
||||
protected:
|
||||
CodeGenModule &CGM;
|
||||
CodeGen::MangleContext MangleCtx;
|
||||
bool IsARM;
|
||||
public:
|
||||
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
|
||||
CGM(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { }
|
||||
CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()), IsARM(IsARM) { }
|
||||
|
||||
CodeGen::MangleContext &getMangleContext() {
|
||||
return MangleCtx;
|
||||
|
@ -50,27 +49,15 @@ public:
|
|||
llvm::Value *MemFnPtr,
|
||||
const MemberPointerType *MPT);
|
||||
|
||||
void EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest);
|
||||
llvm::Value *EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src);
|
||||
|
||||
llvm::Constant *EmitMemberFunctionPointerConversion(llvm::Constant *C,
|
||||
const CastExpr *E);
|
||||
|
||||
void EmitNullMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const MemberPointerType *MPT,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest);
|
||||
|
||||
llvm::Constant *EmitNullMemberFunctionPointer(const MemberPointerType *MPT);
|
||||
|
||||
void EmitMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const CXXMethodDecl *MD,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest);
|
||||
|
||||
llvm::Constant *EmitMemberFunctionPointer(const CXXMethodDecl *MD);
|
||||
|
||||
llvm::Value *EmitMemberFunctionPointerComparison(CodeGenFunction &CGF,
|
||||
|
@ -104,57 +91,6 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) {
|
|||
|
||||
void ItaniumCXXABI::GetMemberFunctionPointer(const CXXMethodDecl *MD,
|
||||
llvm::Constant *(&MemPtr)[2]) {
|
||||
assert(MD->isInstance() && "Member function must not be static!");
|
||||
|
||||
MD = MD->getCanonicalDecl();
|
||||
|
||||
CodeGenTypes &Types = CGM.getTypes();
|
||||
const llvm::Type *ptrdiff_t =
|
||||
Types.ConvertType(CGM.getContext().getPointerDiffType());
|
||||
|
||||
// Get the function pointer (or index if this is a virtual function).
|
||||
if (MD->isVirtual()) {
|
||||
uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
|
||||
|
||||
// FIXME: We shouldn't use / 8 here.
|
||||
uint64_t PointerWidthInBytes =
|
||||
CGM.getContext().Target.getPointerWidth(0) / 8;
|
||||
uint64_t VTableOffset = (Index * PointerWidthInBytes);
|
||||
|
||||
if (IsARM) {
|
||||
// ARM C++ ABI 3.2.1:
|
||||
// This ABI specifies that adj contains twice the this
|
||||
// adjustment, plus 1 if the member function is virtual. The
|
||||
// least significant bit of adj then makes exactly the same
|
||||
// discrimination as the least significant bit of ptr does for
|
||||
// Itanium.
|
||||
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1);
|
||||
} else {
|
||||
// Itanium C++ ABI 2.3:
|
||||
// For a virtual function, [the pointer field] is 1 plus the
|
||||
// virtual table offset (in bytes) of the function,
|
||||
// represented as a ptrdiff_t.
|
||||
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
}
|
||||
} else {
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic());
|
||||
} else {
|
||||
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
|
||||
// function type is incomplete.
|
||||
Ty = ptrdiff_t;
|
||||
}
|
||||
|
||||
llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty);
|
||||
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,9 +137,8 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
|||
llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual");
|
||||
llvm::BasicBlock *FnEnd = CGF.createBasicBlock("memptr.end");
|
||||
|
||||
// Load memptr.adj, which is in the second field.
|
||||
llvm::Value *RawAdj = Builder.CreateStructGEP(MemFnPtr, 1);
|
||||
RawAdj = Builder.CreateLoad(RawAdj, "memptr.adj");
|
||||
// Extract memptr.adj, which is in the second field.
|
||||
llvm::Value *RawAdj = Builder.CreateExtractValue(MemFnPtr, 1, "memptr.adj");
|
||||
|
||||
// Compute the true adjustment.
|
||||
llvm::Value *Adj = RawAdj;
|
||||
|
@ -217,8 +152,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
|||
This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted");
|
||||
|
||||
// Load the function pointer.
|
||||
llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0);
|
||||
llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "memptr.ptr");
|
||||
llvm::Value *FnAsInt = Builder.CreateExtractValue(MemFnPtr, 0, "memptr.ptr");
|
||||
|
||||
// If the LSB in the function pointer is 1, the function pointer points to
|
||||
// a virtual function.
|
||||
|
@ -266,14 +200,16 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
|
|||
}
|
||||
|
||||
/// Perform a derived-to-base or base-to-derived member pointer conversion.
|
||||
void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest) {
|
||||
llvm::Value *
|
||||
ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
||||
const CastExpr *E,
|
||||
llvm::Value *Src) {
|
||||
assert(E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer ||
|
||||
E->getCastKind() == CastExpr::CK_BaseToDerivedMemberPointer);
|
||||
|
||||
if (isa<llvm::Constant>(Src))
|
||||
return EmitMemberFunctionPointerConversion(cast<llvm::Constant>(Src), E);
|
||||
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
const MemberPointerType *SrcTy =
|
||||
|
@ -283,17 +219,6 @@ void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
|||
const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl();
|
||||
const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl();
|
||||
|
||||
llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr");
|
||||
SrcPtr = Builder.CreateLoad(SrcPtr);
|
||||
|
||||
llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj");
|
||||
SrcAdj = Builder.CreateLoad(SrcAdj);
|
||||
|
||||
llvm::Value *DstPtr = Builder.CreateStructGEP(Dest, 0, "dst.ptr");
|
||||
Builder.CreateStore(SrcPtr, DstPtr, VolatileDest);
|
||||
|
||||
llvm::Value *DstAdj = Builder.CreateStructGEP(Dest, 1, "dst.adj");
|
||||
|
||||
bool DerivedToBase =
|
||||
E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer;
|
||||
|
||||
|
@ -303,24 +228,33 @@ void ItaniumCXXABI::EmitMemberFunctionPointerConversion(CodeGenFunction &CGF,
|
|||
else
|
||||
BaseDecl = SrcDecl, DerivedDecl = DestDecl;
|
||||
|
||||
if (llvm::Constant *Adj =
|
||||
CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
|
||||
E->path_begin(),
|
||||
E->path_end())) {
|
||||
// The this-adjustment is left-shifted by 1 on ARM.
|
||||
if (IsARM) {
|
||||
uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue();
|
||||
Offset <<= 1;
|
||||
Adj = llvm::ConstantInt::get(Adj->getType(), Offset);
|
||||
}
|
||||
llvm::Constant *Adj =
|
||||
CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl,
|
||||
E->path_begin(),
|
||||
E->path_end());
|
||||
if (!Adj) return Src;
|
||||
|
||||
if (DerivedToBase)
|
||||
SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
|
||||
else
|
||||
SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
|
||||
}
|
||||
llvm::Value *SrcPtr = Builder.CreateExtractValue(Src, 0, "src.ptr");
|
||||
llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj");
|
||||
|
||||
llvm::Value *Result = llvm::UndefValue::get(Src->getType());
|
||||
Result = Builder.CreateInsertValue(Result, SrcPtr, 0);
|
||||
|
||||
Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
|
||||
// The this-adjustment is left-shifted by 1 on ARM.
|
||||
if (IsARM) {
|
||||
uint64_t Offset = cast<llvm::ConstantInt>(Adj)->getZExtValue();
|
||||
Offset <<= 1;
|
||||
Adj = llvm::ConstantInt::get(Adj->getType(), Offset);
|
||||
}
|
||||
|
||||
llvm::Value *DstAdj;
|
||||
if (DerivedToBase)
|
||||
DstAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
|
||||
else
|
||||
DstAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
|
||||
|
||||
Result = Builder.CreateInsertValue(Result, DstAdj, 1);
|
||||
return Result;
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
|
@ -366,53 +300,73 @@ ItaniumCXXABI::EmitMemberFunctionPointerConversion(llvm::Constant *C,
|
|||
}
|
||||
|
||||
|
||||
void ItaniumCXXABI::EmitNullMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const MemberPointerType *MPT,
|
||||
llvm::Value *Dest,
|
||||
bool VolatileDest) {
|
||||
// Should this be "unabstracted" and implemented in terms of the
|
||||
// Constant version?
|
||||
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
const llvm::IntegerType *PtrDiffTy = CGF.IntPtrTy;
|
||||
llvm::Value *Zero = llvm::ConstantInt::get(PtrDiffTy, 0);
|
||||
|
||||
llvm::Value *Ptr = Builder.CreateStructGEP(Dest, 0, "ptr");
|
||||
Builder.CreateStore(Zero, Ptr, VolatileDest);
|
||||
|
||||
llvm::Value *Adj = Builder.CreateStructGEP(Dest, 1, "adj");
|
||||
Builder.CreateStore(Zero, Adj, VolatileDest);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
ItaniumCXXABI::EmitNullMemberFunctionPointer(const MemberPointerType *MPT) {
|
||||
return CGM.EmitNullConstant(QualType(MPT, 0));
|
||||
const llvm::Type *ptrdiff_t =
|
||||
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
|
||||
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
llvm::Constant *Values[2] = { Zero, Zero };
|
||||
return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2,
|
||||
/*Packed=*/false);
|
||||
}
|
||||
|
||||
llvm::Constant *
|
||||
ItaniumCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) {
|
||||
llvm::Constant *Values[2];
|
||||
GetMemberFunctionPointer(MD, Values);
|
||||
assert(MD->isInstance() && "Member function must not be static!");
|
||||
MD = MD->getCanonicalDecl();
|
||||
|
||||
CodeGenTypes &Types = CGM.getTypes();
|
||||
const llvm::Type *ptrdiff_t =
|
||||
Types.ConvertType(CGM.getContext().getPointerDiffType());
|
||||
|
||||
// Get the function pointer (or index if this is a virtual function).
|
||||
llvm::Constant *MemPtr[2];
|
||||
if (MD->isVirtual()) {
|
||||
uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD);
|
||||
|
||||
// FIXME: We shouldn't use / 8 here.
|
||||
uint64_t PointerWidthInBytes =
|
||||
CGM.getContext().Target.getPointerWidth(0) / 8;
|
||||
uint64_t VTableOffset = (Index * PointerWidthInBytes);
|
||||
|
||||
if (IsARM) {
|
||||
// ARM C++ ABI 3.2.1:
|
||||
// This ABI specifies that adj contains twice the this
|
||||
// adjustment, plus 1 if the member function is virtual. The
|
||||
// least significant bit of adj then makes exactly the same
|
||||
// discrimination as the least significant bit of ptr does for
|
||||
// Itanium.
|
||||
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1);
|
||||
} else {
|
||||
// Itanium C++ ABI 2.3:
|
||||
// For a virtual function, [the pointer field] is 1 plus the
|
||||
// virtual table offset (in bytes) of the function,
|
||||
// represented as a ptrdiff_t.
|
||||
MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
}
|
||||
} else {
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty;
|
||||
// Check whether the function has a computable LLVM signature.
|
||||
if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) {
|
||||
// The function has a computable LLVM signature; use the correct type.
|
||||
Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic());
|
||||
} else {
|
||||
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
|
||||
// function type is incomplete.
|
||||
Ty = ptrdiff_t;
|
||||
}
|
||||
|
||||
llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty);
|
||||
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t);
|
||||
MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0);
|
||||
}
|
||||
|
||||
return llvm::ConstantStruct::get(CGM.getLLVMContext(),
|
||||
Values, 2, /*Packed=*/false);
|
||||
}
|
||||
|
||||
void ItaniumCXXABI::EmitMemberFunctionPointer(CodeGenFunction &CGF,
|
||||
const CXXMethodDecl *MD,
|
||||
llvm::Value *DestPtr,
|
||||
bool VolatileDest) {
|
||||
llvm::Constant *Values[2];
|
||||
GetMemberFunctionPointer(MD, Values);
|
||||
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "memptr.ptr");
|
||||
Builder.CreateStore(Values[0], DstPtr, VolatileDest);
|
||||
|
||||
llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "memptr.adj");
|
||||
Builder.CreateStore(Values[1], AdjPtr, VolatileDest);
|
||||
MemPtr, 2, /*Packed=*/false);
|
||||
}
|
||||
|
||||
/// The comparison algorithm is pretty easy: the member pointers are
|
||||
|
@ -427,10 +381,8 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF,
|
|||
bool Inequality) {
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
llvm::Value *LPtr = Builder.CreateLoad(Builder.CreateStructGEP(L, 0),
|
||||
"lhs.memptr.ptr");
|
||||
llvm::Value *RPtr = Builder.CreateLoad(Builder.CreateStructGEP(R, 0),
|
||||
"rhs.memptr.ptr");
|
||||
llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr");
|
||||
llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr");
|
||||
|
||||
// The Itanium tautology is:
|
||||
// (L == R) <==> (L.ptr == R.ptr /\ (L.ptr == 0 \/ L.adj == R.adj))
|
||||
|
@ -465,10 +417,8 @@ ItaniumCXXABI::EmitMemberFunctionPointerComparison(CodeGenFunction &CGF,
|
|||
|
||||
// This condition tests whether L.adj == R.adj. If this isn't
|
||||
// true, the pointers are unequal unless they're both null.
|
||||
llvm::Value *LAdj = Builder.CreateLoad(Builder.CreateStructGEP(L, 1),
|
||||
"lhs.memptr.adj");
|
||||
llvm::Value *RAdj = Builder.CreateLoad(Builder.CreateStructGEP(R, 1),
|
||||
"rhs.memptr.adj");
|
||||
llvm::Value *LAdj = Builder.CreateExtractValue(L, 1, "lhs.memptr.adj");
|
||||
llvm::Value *RAdj = Builder.CreateExtractValue(R, 1, "rhs.memptr.adj");
|
||||
llvm::Value *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj");
|
||||
|
||||
// Null member function pointers on ARM clear the low bit of Adj,
|
||||
|
@ -498,8 +448,7 @@ ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF,
|
|||
CGBuilderTy &Builder = CGF.Builder;
|
||||
|
||||
// In Itanium, a member function pointer is null if 'ptr' is null.
|
||||
llvm::Value *Ptr =
|
||||
Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 0), "memptr.ptr");
|
||||
llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr");
|
||||
|
||||
llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0);
|
||||
llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool");
|
||||
|
@ -507,8 +456,7 @@ ItaniumCXXABI::EmitMemberFunctionPointerIsNotNull(CodeGenFunction &CGF,
|
|||
// In ARM, it's that, plus the low bit of 'adj' must be zero.
|
||||
if (IsARM) {
|
||||
llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1);
|
||||
llvm::Value *Adj =
|
||||
Builder.CreateLoad(Builder.CreateStructGEP(MemPtr, 1), "memptr.adj");
|
||||
llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj");
|
||||
llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit");
|
||||
llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero,
|
||||
"memptr.notvirtual");
|
||||
|
|
|
@ -112,7 +112,7 @@ class MicrosoftCXXABI : public CGCXXABI {
|
|||
MicrosoftMangleContext MangleCtx;
|
||||
public:
|
||||
MicrosoftCXXABI(CodeGenModule &CGM)
|
||||
: MangleCtx(CGM.getContext(), CGM.getDiags()) {}
|
||||
: CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()) {}
|
||||
|
||||
MicrosoftMangleContext &getMangleContext() {
|
||||
return MangleCtx;
|
||||
|
|
|
@ -36,6 +36,11 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
|
|||
}
|
||||
}
|
||||
|
||||
static bool isAggregateTypeForABI(QualType T) {
|
||||
return CodeGenFunction::hasAggregateLLVMType(T) ||
|
||||
T->isMemberFunctionPointerType();
|
||||
}
|
||||
|
||||
ABIInfo::~ABIInfo() {}
|
||||
|
||||
ASTContext &ABIInfo::getContext() const {
|
||||
|
@ -218,7 +223,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
|
|||
FT = AT->getElementType();
|
||||
}
|
||||
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
|
||||
if (!isAggregateTypeForABI(FT)) {
|
||||
Found = FT.getTypePtr();
|
||||
} else {
|
||||
Found = isSingleElementStruct(FT, Context);
|
||||
|
@ -314,7 +319,7 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
|||
}
|
||||
|
||||
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
if (CodeGenFunction::hasAggregateLLVMType(Ty))
|
||||
if (isAggregateTypeForABI(Ty))
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
|
||||
// Treat an enum type as its underlying type.
|
||||
|
@ -467,7 +472,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const {
|
|||
return ABIArgInfo::getDirect();
|
||||
}
|
||||
|
||||
if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
|
||||
if (isAggregateTypeForABI(RetTy)) {
|
||||
if (const RecordType *RT = RetTy->getAs<RecordType>()) {
|
||||
// Structures with either a non-trivial destructor or a non-trivial
|
||||
// copy constructor are always indirect.
|
||||
|
@ -557,7 +562,7 @@ ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const {
|
|||
|
||||
ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
// FIXME: Set alignment on indirect arguments.
|
||||
if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
|
||||
if (isAggregateTypeForABI(Ty)) {
|
||||
// Structures with flexible arrays are always indirect.
|
||||
if (const RecordType *RT = Ty->getAs<RecordType>()) {
|
||||
// Structures with either a non-trivial destructor or a non-trivial
|
||||
|
@ -1094,7 +1099,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
|
|||
ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
|
||||
// If this is a scalar LLVM value then assume LLVM will pass it in the right
|
||||
// place naturally.
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
|
||||
if (!isAggregateTypeForABI(Ty)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
|
||||
Ty = EnumTy->getDecl()->getIntegerType();
|
||||
|
@ -1109,7 +1114,7 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const {
|
|||
ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const {
|
||||
// If this is a scalar LLVM value then assume LLVM will pass it in the right
|
||||
// place naturally.
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
|
||||
if (!isAggregateTypeForABI(Ty)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
|
||||
Ty = EnumTy->getDecl()->getIntegerType();
|
||||
|
@ -2079,7 +2084,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
|||
}
|
||||
|
||||
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
|
||||
if (!isAggregateTypeForABI(Ty)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
|
||||
Ty = EnumTy->getDecl()->getIntegerType();
|
||||
|
@ -2205,7 +2210,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
|
|||
if (RetTy->isVoidType())
|
||||
return ABIArgInfo::getIgnore();
|
||||
|
||||
if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) {
|
||||
if (!isAggregateTypeForABI(RetTy)) {
|
||||
// Treat an enum type as its underlying type.
|
||||
if (const EnumType *EnumTy = RetTy->getAs<EnumType>())
|
||||
RetTy = EnumTy->getDecl()->getIntegerType();
|
||||
|
@ -2295,7 +2300,7 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
|
|||
if (RetTy->isVoidType())
|
||||
return ABIArgInfo::getIgnore();
|
||||
|
||||
if (CodeGenFunction::hasAggregateLLVMType(RetTy))
|
||||
if (isAggregateTypeForABI(RetTy))
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
|
||||
// Treat an enum type as its underlying type.
|
||||
|
@ -2370,7 +2375,7 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
|
|||
ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
|
||||
if (RetTy->isVoidType())
|
||||
return ABIArgInfo::getIgnore();
|
||||
if (CodeGenFunction::hasAggregateLLVMType(RetTy))
|
||||
if (isAggregateTypeForABI(RetTy))
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
|
||||
return (isPromotableIntegerType(RetTy) ?
|
||||
|
@ -2378,7 +2383,7 @@ ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
|
|||
}
|
||||
|
||||
ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
if (CodeGenFunction::hasAggregateLLVMType(Ty))
|
||||
if (isAggregateTypeForABI(Ty))
|
||||
return ABIArgInfo::getIndirect(0);
|
||||
|
||||
return (isPromotableIntegerType(Ty) ?
|
||||
|
|
|
@ -29,50 +29,42 @@ void (C::*pc2)() = &C::f;
|
|||
void (A::*pc3)() = &A::vf1;
|
||||
|
||||
void f() {
|
||||
// CHECK: store i64 0, i64* getelementptr inbounds (%0* @pa, i32 0, i32 0)
|
||||
// CHECK: store i64 0, i64* getelementptr inbounds (%0* @pa, i32 0, i32 1)
|
||||
// CHECK: store %0 zeroinitializer, %0* @pa
|
||||
pa = 0;
|
||||
|
||||
// CHECK: volatile store i64 0, i64* getelementptr inbounds (%0* @vpa, i32 0, i32 0)
|
||||
// CHECK: volatile store i64 0, i64* getelementptr inbounds (%0* @vpa, i32 0, i32 1)
|
||||
// Is this okay? What are LLVM's volatile semantics for structs?
|
||||
// CHECK: volatile store %0 zeroinitializer, %0* @vpa
|
||||
vpa = 0;
|
||||
|
||||
// CHECK: store i64 {{.*}}, i64* getelementptr inbounds (%0* @pc, i32 0, i32 0)
|
||||
// CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = add i64 {{.*}}, 16
|
||||
// CHECK: store i64 [[ADJ]], i64* getelementptr inbounds (%0* @pc, i32 0, i32 1)
|
||||
// CHECK: [[TMP:%.*]] = load %0* @pa, align 8
|
||||
// CHECK: [[TMPPTR:%.*]] = extractvalue %0 [[TMP]], 0
|
||||
// CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1
|
||||
// CHECK: [[RES0:%.*]] = insertvalue %0 undef, i64 [[TMPPTR]], 0
|
||||
// CHECK: [[ADJ:%.*]] = add i64 [[TMPADJ]], 16
|
||||
// CHECK: [[RES1:%.*]] = insertvalue %0 [[RES0]], i64 [[ADJ]], 1
|
||||
// CHECK: store %0 [[RES1]], %0* @pc, align 8
|
||||
pc = pa;
|
||||
|
||||
// CHECK: store i64 {{.*}}, i64* getelementptr inbounds (%0* @pa, i32 0, i32 0)
|
||||
// CHECK: [[ADJ:%[a-zA-Z0-9\.]+]] = sub i64 {{.*}}, 16
|
||||
// CHECK: store i64 [[ADJ]], i64* getelementptr inbounds (%0* @pa, i32 0, i32 1)
|
||||
// CHECK: [[TMP:%.*]] = load %0* @pc, align 8
|
||||
// CHECK: [[TMPPTR:%.*]] = extractvalue %0 [[TMP]], 0
|
||||
// CHECK: [[TMPADJ:%.*]] = extractvalue %0 [[TMP]], 1
|
||||
// CHECK: [[RES0:%.*]] = insertvalue %0 undef, i64 [[TMPPTR]], 0
|
||||
// CHECK: [[ADJ:%.*]] = sub i64 [[TMPADJ]], 16
|
||||
// CHECK: [[RES1:%.*]] = insertvalue %0 [[RES0]], i64 [[ADJ]], 1
|
||||
// CHECK: store %0 [[RES1]], %0* @pa, align 8
|
||||
pa = static_cast<void (A::*)()>(pc);
|
||||
}
|
||||
|
||||
void f2() {
|
||||
// CHECK: [[pa2ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 0
|
||||
// CHECK: store i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64* [[pa2ptr]]
|
||||
// CHECK: [[pa2adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa2, i32 0, i32 1
|
||||
// CHECK: store i64 0, i64* [[pa2adj]]
|
||||
// CHECK: store %0 { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }
|
||||
void (A::*pa2)() = &A::f;
|
||||
|
||||
// CHECK: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
|
||||
// CHECK: store i64 1, i64* [[pa3ptr]]
|
||||
// CHECK: [[pa3adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 1
|
||||
// CHECK: store i64 0, i64* [[pa3adj]]
|
||||
// CHECK-LP32: [[pa3ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 0
|
||||
// CHECK-LP32: store i32 1, i32* [[pa3ptr]]
|
||||
// CHECK-LP32: [[pa3adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa3, i32 0, i32 1
|
||||
// CHECK-LP32: store i32 0, i32* [[pa3adj]]
|
||||
// CHECK: store %0 { i64 1, i64 0 }
|
||||
// CHECK-LP32: store %0 { i32 1, i32 0 }
|
||||
void (A::*pa3)() = &A::vf1;
|
||||
|
||||
// CHECK: [[pa4ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 0
|
||||
// CHECK: store i64 9, i64* [[pa4ptr]]
|
||||
// CHECK: [[pa4adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 1
|
||||
// CHECK: store i64 0, i64* [[pa4adj]]
|
||||
// CHECK-LP32: [[pa4ptr:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 0
|
||||
// CHECK-LP32: store i32 5, i32* [[pa4ptr]]
|
||||
// CHECK-LP32: [[pa4adj:%[a-zA-Z0-9\.]+]] = getelementptr inbounds %0* %pa4, i32 0, i32 1
|
||||
// CHECK-LP32: store i32 0, i32* [[pa4adj]]
|
||||
// CHECK: store %0 { i64 9, i64 0 }
|
||||
// CHECK-LP32: store %0 { i32 5, i32 0 }
|
||||
void (A::*pa4)() = &A::vf2;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ struct s5 { s5(); int &x; };
|
|||
s5 f5() { return s5(); }
|
||||
|
||||
// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a)
|
||||
// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval %a)
|
||||
// CHECK: define i64 @_Z4f6_1M2s6FivE(%{{.*}} byval)
|
||||
// FIXME: It would be nice to avoid byval on the previous case.
|
||||
struct s6 {};
|
||||
typedef int s6::* s6_mdp;
|
||||
|
|
Loading…
Reference in New Issue