From a1dee5300b3a0ad0c6e763d83d528ab0e6fc9c78 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sun, 22 Aug 2010 10:59:02 +0000 Subject: [PATCH] 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 --- clang/lib/CodeGen/CGCXX.cpp | 41 ++- clang/lib/CodeGen/CGCXXABI.h | 23 +- clang/lib/CodeGen/CGExpr.cpp | 36 +-- clang/lib/CodeGen/CGExprAgg.cpp | 55 ---- clang/lib/CodeGen/CGExprCXX.cpp | 3 +- clang/lib/CodeGen/CGExprConstant.cpp | 18 +- clang/lib/CodeGen/CGExprScalar.cpp | 29 +- clang/lib/CodeGen/CodeGenFunction.cpp | 2 +- clang/lib/CodeGen/ItaniumCXXABI.cpp | 260 +++++++----------- clang/lib/CodeGen/MicrosoftCXXABI.cpp | 2 +- clang/lib/CodeGen/TargetInfo.cpp | 27 +- .../CodeGenCXX/member-function-pointers.cpp | 52 ++-- clang/test/CodeGenCXX/x86_32-arguments.cpp | 2 +- 13 files changed, 229 insertions(+), 321 deletions(-) diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 2d7b27b18b57..b805d136c4f6 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -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(MPT->getClass()->getAs()->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) { diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index 8478df48160e..d0bb0e864f96 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -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); }; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 753af76bf24d..55abaa31cd13 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -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()); } 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(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(ND)) + if (MD->isInstance()) { + llvm::Value *V = CGM.getCXXABI().EmitMemberFunctionPointer(MD); + return MakeAddrLValue(V, MD->getType(), Alignment); + } if (const FunctionDecl *FD = dyn_cast(ND)) return EmitFunctionDeclLValue(*this, E, FD); - // FIXME: the qualifier check does not seem sufficient here - if (E->getQualifier()) { - const FieldDecl *FD = cast(ND); + // If we're emitting a field as an independent lvalue, we're + // actually emitting a member pointer. + if (const FieldDecl *FD = dyn_cast(ND)) { llvm::Value *V = CGM.EmitPointerToDataMember(FD); return MakeAddrLValue(V, FD->getType(), Alignment); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index b75aeb13b898..890a07f9fb29 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -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(), - 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() - ->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(E->getSubExpr()); - const CXXMethodDecl *MD = cast(DRE->getDecl()); - - CGF.CGM.getCXXABI().EmitMemberFunctionPointer(CGF, MD, DestPtr, VolatileDest); -} - void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); } diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index fb5414016a9d..ad65b105f626 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -160,8 +160,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, cast(MPT->getClass()->getAs()->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; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index e0335b6559b4..b97e725ae8ec 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -460,7 +460,7 @@ public: llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { if (const MemberPointerType *MPT = - E->getType()->getAs()) { + E->getType()->getAs()) { QualType T = MPT->getPointeeType(); DeclRefExpr *DRE = cast(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()); + case CastExpr::CK_NullToMemberPointer: { + const MemberPointerType *MPT = E->getType()->getAs(); + 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(); + // 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; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index d65c22a723a2..38a49ee138dd 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -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()); + 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(), + CGF, LHS, RHS, LHSTy->getAs(), E->getOpcode() == BinaryOperator::NE); } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ca4e69822935..91442fa362e0 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -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() { diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index cd8b278fb554..efaddf217b48 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -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(); - 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(Src)) + return EmitMemberFunctionPointerConversion(cast(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(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(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(); + 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"); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index b719c7adf9e3..f894f662acbe 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -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; diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 5ea77be07b74..b98b2191a17e 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -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()) { // 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()) { // 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()) 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()) 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()) 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()) 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) ? diff --git a/clang/test/CodeGenCXX/member-function-pointers.cpp b/clang/test/CodeGenCXX/member-function-pointers.cpp index c0756fa14431..fa1977ed46ab 100644 --- a/clang/test/CodeGenCXX/member-function-pointers.cpp +++ b/clang/test/CodeGenCXX/member-function-pointers.cpp @@ -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(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; } diff --git a/clang/test/CodeGenCXX/x86_32-arguments.cpp b/clang/test/CodeGenCXX/x86_32-arguments.cpp index 023b7297c7d7..e94e2cade59c 100644 --- a/clang/test/CodeGenCXX/x86_32-arguments.cpp +++ b/clang/test/CodeGenCXX/x86_32-arguments.cpp @@ -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;