https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/176063
>From e34e57207761112870da5cc0eed122c646cf9064 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Wed, 14 Jan 2026 15:01:08 -0800 Subject: [PATCH 1/3] [CIR] Upstream support for calling through method pointers This adds support to CIR for calling functions through pointer to method pointers with the Itanium ABI for x86_64 targets. The ARM-specific handling of method pointers is not-yet implemented. --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 30 ++++ clang/include/clang/CIR/Dialect/IR/CIROps.td | 54 ++++++ .../CIR/Dialect/IR/CIRTypeConstraints.td | 8 + clang/include/clang/CIR/MissingFeatures.h | 6 + clang/lib/CIR/CodeGen/CIRGenCall.h | 2 + clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 7 +- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 44 +++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 + clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 47 ++++++ .../CIR/Dialect/Transforms/CXXABILowering.cpp | 12 +- .../Transforms/TargetLowering/CIRCXXABI.h | 8 + .../TargetLowering/LowerItaniumCXXABI.cpp | 154 +++++++++++++++++- .../CIR/CodeGen/pointer-to-member-func.cpp | 84 ++++++++++ 13 files changed, 451 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index eadf3dd6ee0f0..2aaae86240cf2 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -710,6 +710,36 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { cir::YieldOp createYield(mlir::Location loc, mlir::ValueRange value = {}) { return cir::YieldOp::create(*this, loc, value); } + + struct GetMethodResults { + mlir::Value callee; + mlir::Value adjustedThis; + }; + + GetMethodResults createGetMethod(mlir::Location loc, mlir::Value method, + mlir::Value objectPtr) { + // Build the callee function type. + auto methodFuncTy = + mlir::cast<cir::MethodType>(method.getType()).getMemberFuncTy(); + auto methodFuncInputTypes = methodFuncTy.getInputs(); + + auto objectPtrTy = mlir::cast<cir::PointerType>(objectPtr.getType()); + mlir::Type adjustedThisTy = getVoidPtrTy(objectPtrTy.getAddrSpace()); + + llvm::SmallVector<mlir::Type> calleeFuncInputTypes{adjustedThisTy}; + calleeFuncInputTypes.insert(calleeFuncInputTypes.end(), + methodFuncInputTypes.begin(), + methodFuncInputTypes.end()); + cir::FuncType calleeFuncTy = + methodFuncTy.clone(calleeFuncInputTypes, methodFuncTy.getReturnType()); + // TODO(cir): consider the address space of the callee. + assert(!cir::MissingFeatures::addressSpace()); + cir::PointerType calleeTy = getPointerTo(calleeFuncTy); + + auto op = cir::GetMethodOp::create(*this, loc, calleeTy, adjustedThisTy, + method, objectPtr); + return {op.getCallee(), op.getAdjustedThis()}; + } }; } // namespace cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index ceb9899a00ac4..07950d6e42f63 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3805,6 +3805,60 @@ def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> { let hasLLVMLowering = false; } +//===----------------------------------------------------------------------===// +// GetMethodOp +//===----------------------------------------------------------------------===// + +def CIR_GetMethodOp : CIR_Op<"get_method"> { + let summary = "Resolve a method to a function pointer as callee"; + let description = [{ + The `cir.get_method` operation takes a pointer to method (!cir.method) and + a pointer to a class object (!cir.ptr<!cir.record>>) as input, and + yields a function pointer that points to the actual function corresponding + to the input method. The operation also applies any necessary adjustments to + the input object pointer for calling the method and yields the adjusted + pointer. + + This operation is generated when calling a method through a pointer-to- + member-function in C++: + + ```cpp + // Foo *object; + // int arg; + // void (Foo::*method)(int); + + (object->*method)(arg); + ``` + + The code above will generate CIR similar to: + + ```mlir + %callee, %this = cir.get_method %method, %object + cir.call %callee(%this, %arg) + ``` + + The method type must match the callee type. That is: + - The return type of the method must match the return type of the callee. + - The first parameter of the callee must have type `!cir.ptr<!cir.void>`. + - Types of other parameters of the callee must match the parameters of the + method. + }]; + + let arguments = (ins CIR_MethodType:$method, CIR_PtrToRecordType:$object); + let results = (outs CIR_PtrToFunc:$callee, CIR_VoidPtrType:$adjusted_this); + + let assemblyFormat = [{ + $method `,` $object + `:` `(` qualified(type($method)) `,` qualified(type($object)) `)` + `->` `(` qualified(type($callee)) `,` qualified(type($adjusted_this)) `)` + attr-dict + }]; + + let hasVerifier = 1; + let hasLLVMLowering = false; + let hasCXXABILowering = true; +} + //===----------------------------------------------------------------------===// // VecCreate //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 3b2ec5276a677..1a5bae13c96df 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -191,6 +191,12 @@ def CIR_AnyComplexOrIntOrBoolOrFloatType def CIR_AnyRecordType : CIR_TypeBase<"::cir::RecordType", "record type">; +//===----------------------------------------------------------------------===// +// Function Type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyFuncType : CIR_TypeBase<"::cir::FuncType", "function type">; + //===----------------------------------------------------------------------===// // Array Type predicates //===----------------------------------------------------------------------===// @@ -253,6 +259,8 @@ def CIR_PtrToComplexType : CIR_PtrToType<CIR_AnyComplexType>; def CIR_PtrToRecordType : CIR_PtrToType<CIR_AnyRecordType>; +def CIR_PtrToFunc : CIR_PtrToType<CIR_AnyFuncType>; + def CIR_PtrToArray : CIR_PtrToType<CIR_AnyArrayType>; //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 9336fafea04cd..70b92757a4eee 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -194,6 +194,11 @@ struct MissingFeatures { static bool lowerModuleCodeGenOpts() { return false; } static bool lowerModuleLangOpts() { return false; } + // Extra checks for lowerGetMethod in ItaniumCXXABI + static bool emitCFICheck() { return false; } + static bool emitVFEInfo() { return false; } + static bool emitWPDInfo() { return false; } + // Misc static bool aarch64SIMDIntrinsics() { return false; } static bool aarch64SMEIntrinsics() { return false; } @@ -211,6 +216,7 @@ struct MissingFeatures { static bool aggValueSlotVolatile() { return false; } static bool alignCXXRecordDecl() { return false; } static bool allocToken() { return false; } + static bool appleArm64CXXABI() { return false; } static bool appleKext() { return false; } static bool armComputeVolatileBitfields() { return false; } static bool asmGoto() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h index 55b3d9765c5c5..347bd4a7c8266 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -33,6 +33,8 @@ class CIRGenCalleeInfo { CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy, clang::GlobalDecl calleeDecl) : calleeProtoTy(calleeProtoTy), calleeDecl(calleeDecl) {} + CIRGenCalleeInfo(const clang::FunctionProtoType *calleeProtoTy) + : calleeProtoTy(calleeProtoTy) {} CIRGenCalleeInfo(clang::GlobalDecl calleeDecl) : calleeProtoTy(nullptr), calleeDecl(calleeDecl) {} diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index cd13498e3702f..ca6357e2ba138 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -2303,11 +2303,8 @@ RValue CIRGenFunction::emitCXXMemberCallExpr(const CXXMemberCallExpr *ce, ReturnValueSlot returnValue) { const Expr *callee = ce->getCallee()->IgnoreParens(); - if (isa<BinaryOperator>(callee)) { - cgm.errorNYI(ce->getSourceRange(), - "emitCXXMemberCallExpr: C++ binary operator"); - return RValue::get(nullptr); - } + if (isa<BinaryOperator>(callee)) + return emitCXXMemberPointerCallExpr(ce, returnValue); const auto *me = cast<MemberExpr>(callee); const auto *md = cast<CXXMethodDecl>(me->getMemberDecl()); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index eb894c2fb30ee..98cf75f0d69e0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -75,6 +75,50 @@ static MemberCallInfo commonBuildCXXMemberOrOperatorCall( return {required, prefixSize}; } +RValue +CIRGenFunction::emitCXXMemberPointerCallExpr(const CXXMemberCallExpr *ce, + ReturnValueSlot returnValue) { + const BinaryOperator *bo = + cast<BinaryOperator>(ce->getCallee()->IgnoreParens()); + const Expr *baseExpr = bo->getLHS(); + const Expr *memFnExpr = bo->getRHS(); + + const auto *mpt = memFnExpr->getType()->castAs<MemberPointerType>(); + const auto *fpt = mpt->getPointeeType()->castAs<FunctionProtoType>(); + + // Emit the 'this' pointer. + Address thisAddr = Address::invalid(); + if (bo->getOpcode() == BO_PtrMemI) + thisAddr = emitPointerWithAlignment(baseExpr); + else + thisAddr = emitLValue(baseExpr).getAddress(); + + assert(!cir::MissingFeatures::emitTypeCheck()); + + // Get the member function pointer. + mlir::Value memFnPtr = emitScalarExpr(memFnExpr); + + // Resolve the member function pointer to the actual callee and adjust the + // "this" pointer for call. + mlir::Location loc = getLoc(ce->getExprLoc()); + auto [/*mlir::Value*/ calleePtr, /*mlir::Value*/ adjustedThis] = + builder.createGetMethod(loc, memFnPtr, thisAddr.getPointer()); + + // Prepare the call arguments. + CallArgList argsList; + argsList.add(RValue::get(adjustedThis), getContext().VoidPtrTy); + emitCallArgs(argsList, fpt, ce->arguments()); + + RequiredArgs required = RequiredArgs::getFromProtoWithExtraSlots(fpt, 1); + + // Build the call. + CIRGenCallee callee(fpt, calleePtr.getDefiningOp()); + assert(!cir::MissingFeatures::opCallMustTail()); + return emitCall(cgm.getTypes().arrangeCXXMethodCall(argsList, fpt, required, + /*PrefixSize=*/0), + callee, returnValue, argsList, nullptr, loc); +} + RValue CIRGenFunction::emitCXXMemberOrOperatorMemberCallExpr( const CallExpr *ce, const CXXMethodDecl *md, ReturnValueSlot returnValue, bool hasQualifier, NestedNameSpecifier qualifier, bool isArrow, diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 5fe1d9a4f2b76..6b47bc9975fcf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1553,6 +1553,9 @@ class CIRGenFunction : public CIRGenTypeCache { clang::NestedNameSpecifier qualifier, bool isArrow, const clang::Expr *base); + RValue emitCXXMemberPointerCallExpr(const CXXMemberCallExpr *ce, + ReturnValueSlot returnValue); + mlir::Value emitCXXNewExpr(const CXXNewExpr *e); void emitNewArrayInitializer(const CXXNewExpr *e, QualType elementType, diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 6c4607abb40e7..1dec653e421c4 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2666,6 +2666,53 @@ LogicalResult cir::GetRuntimeMemberOp::verify() { return mlir::success(); } +//===----------------------------------------------------------------------===// +// GetMethodOp Definitions +//===----------------------------------------------------------------------===// + +LogicalResult cir::GetMethodOp::verify() { + cir::MethodType methodTy = getMethod().getType(); + + // Assume objectTy is !cir.ptr<!T> + cir::PointerType objectPtrTy = getObject().getType(); + mlir::Type objectTy = objectPtrTy.getPointee(); + + if (methodTy.getClassTy() != objectTy) + return emitError() << "method class type and object type do not match"; + + // Assume methodFuncTy is !cir.func<!Ret (!Args)> + auto calleeTy = mlir::cast<cir::FuncType>(getCallee().getType().getPointee()); + cir::FuncType methodFuncTy = methodTy.getMemberFuncTy(); + + // We verify at here that calleeTy is !cir.func<!Ret (!cir.ptr<!void>, !Args)> + // Note that the first parameter type of the callee is !cir.ptr<!void> instead + // of !cir.ptr<!T> because the "this" pointer may be adjusted before calling + // the callee. + + if (methodFuncTy.getReturnType() != calleeTy.getReturnType()) + return emitError() + << "method return type and callee return type do not match"; + + llvm::ArrayRef<mlir::Type> calleeArgsTy = calleeTy.getInputs(); + llvm::ArrayRef<mlir::Type> methodFuncArgsTy = methodFuncTy.getInputs(); + + if (calleeArgsTy.empty()) + return emitError() << "callee parameter list lacks receiver object ptr"; + + auto calleeThisArgPtrTy = mlir::dyn_cast<cir::PointerType>(calleeArgsTy[0]); + if (!calleeThisArgPtrTy || + !mlir::isa<cir::VoidType>(calleeThisArgPtrTy.getPointee())) { + return emitError() + << "the first parameter of callee must be a void pointer"; + } + + if (calleeArgsTy.slice(1) != methodFuncArgsTy) + return emitError() + << "callee parameters and method parameters do not match"; + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // GetMemberOp Definitions //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index 145f8574893f4..469dddbb118e3 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -59,7 +59,7 @@ class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern { // Do not match on operations that have dedicated ABI lowering rewrite rules if (llvm::isa<cir::AllocaOp, cir::BaseDataMemberOp, cir::ConstantOp, cir::CmpOp, cir::DerivedDataMemberOp, cir::FuncOp, - cir::GetRuntimeMemberOp, cir::GlobalOp>(op)) + cir::GetMethodOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op)) return mlir::failure(); const mlir::TypeConverter *typeConverter = getTypeConverter(); @@ -252,6 +252,16 @@ mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRGetMethodOpABILowering::matchAndRewrite( + cir::GetMethodOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResults[2]; + lowerModule->getCXXABI().lowerGetMethod( + op, loweredResults, adaptor.getMethod(), adaptor.getObject(), rewriter); + rewriter.replaceOp(op, loweredResults); + return mlir::success(); +} + mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite( cir::GetRuntimeMemberOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index 0dedfa7221f5f..69d8b682ab4c5 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -66,6 +66,14 @@ class CIRCXXABI { mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const = 0; + /// Lower the given cir.get_method op to a sequence of more "primitive" CIR + /// operations that act on the ABI types. The lowered result values will be + /// stored in the given loweredResults array. + virtual void + lowerGetMethod(cir::GetMethodOp op, mlir::Value (&loweredResults)[2], + mlir::Value loweredMethod, mlir::Value loweredObjectPtr, + mlir::ConversionPatternRewriter &rewriter) const = 0; + /// Lower the given cir.base_data_member op to a sequence of more "primitive" /// CIR operations that act on the ABI types. virtual mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op, diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index d944fa3294684..d581e18b5e37a 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -30,8 +30,12 @@ namespace cir { namespace { class LowerItaniumCXXABI : public CIRCXXABI { +protected: + bool useARMMethodPtrABI; + public: - LowerItaniumCXXABI(LowerModule &lm) : CIRCXXABI(lm) {} + LowerItaniumCXXABI(LowerModule &lm, bool useARMMethodPtrABI = false) + : CIRCXXABI(lm), useARMMethodPtrABI(useARMMethodPtrABI) {} /// Lower the given data member pointer type to its ABI type. The returned /// type is also a CIR type. @@ -56,6 +60,10 @@ class LowerItaniumCXXABI : public CIRCXXABI { mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const override; + void lowerGetMethod(cir::GetMethodOp op, mlir::Value (&loweredResults)[2], + mlir::Value loweredMethod, mlir::Value loweredObjectPtr, + mlir::ConversionPatternRewriter &rewriter) const override; + mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op, mlir::Value loweredSrc, mlir::OpBuilder &builder) const override; @@ -72,7 +80,26 @@ class LowerItaniumCXXABI : public CIRCXXABI { } // namespace std::unique_ptr<CIRCXXABI> createItaniumCXXABI(LowerModule &lm) { - return std::make_unique<LowerItaniumCXXABI>(lm); + switch (lm.getCXXABIKind()) { + // Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't + // include the other 32-bit ARM oddities: constructor/destructor return values + // and array cookies. + case clang::TargetCXXABI::GenericAArch64: + case clang::TargetCXXABI::AppleARM64: + // TODO: this isn't quite right, clang uses AppleARM64CXXABI which inherits + // from ARMCXXABI. We'll have to follow suit. + assert(!cir::MissingFeatures::appleArm64CXXABI()); + return std::make_unique<LowerItaniumCXXABI>(lm, + /*useARMMethodPtrABI=*/true); + + case clang::TargetCXXABI::GenericItanium: + return std::make_unique<LowerItaniumCXXABI>(lm); + + case clang::TargetCXXABI::Microsoft: + llvm_unreachable("Microsoft ABI is not Itanium-based"); + default: + llvm_unreachable("Other Itanium ABI?"); + } } static cir::IntType getPtrDiffCIRTy(LowerModule &lm) { @@ -197,6 +224,129 @@ mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember( cir::CastKind::bitcast, memberBytesPtr); } +void LowerItaniumCXXABI::lowerGetMethod( + cir::GetMethodOp op, mlir::Value (&loweredResults)[2], + mlir::Value loweredMethod, mlir::Value loweredObjectPtr, + mlir::ConversionPatternRewriter &rewriter) const { + // In the Itanium and ARM ABIs, method pointers have the form: + // struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; + // + // In the Itanium ABI: + // - method pointers are virtual if (memptr.ptr & 1) is nonzero + // - the this-adjustment is (memptr.adj) + // - the virtual offset is (memptr.ptr - 1) + // + // In the ARM ABI: + // - method pointers are virtual if (memptr.adj & 1) is nonzero + // - the this-adjustment is (memptr.adj >> 1) + // - the virtual offset is (memptr.ptr) + // ARM uses 'adj' for the virtual flag because Thumb functions + // may be only single-byte aligned. + // + // If the member is virtual, the adjusted 'this' pointer points + // to a vtable pointer from which the virtual offset is applied. + // + // If the member is non-virtual, memptr.ptr is the address of + // the function to call. + + mlir::Value &callee = loweredResults[0]; + mlir::Value &adjustedThis = loweredResults[1]; + mlir::Type calleePtrTy = op.getCallee().getType(); + + cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lm); + mlir::Value ptrdiffOne = cir::ConstantOp::create( + rewriter, op.getLoc(), cir::IntAttr::get(ptrdiffCIRTy, 1)); + + mlir::Value adj = cir::ExtractMemberOp::create( + rewriter, op.getLoc(), ptrdiffCIRTy, loweredMethod, 1); + if (useARMMethodPtrABI) { + op.emitError("ARM method ptr abi NYI"); + return; + } + + // Apply the adjustment to the 'this' pointer. + mlir::Type thisVoidPtrTy = + cir::PointerType::get(cir::VoidType::get(rewriter.getContext()), + op.getObject().getType().getAddrSpace()); + mlir::Value thisVoidPtr = + cir::CastOp::create(rewriter, op.getLoc(), thisVoidPtrTy, + cir::CastKind::bitcast, loweredObjectPtr); + adjustedThis = cir::PtrStrideOp::create(rewriter, op.getLoc(), thisVoidPtrTy, + thisVoidPtr, adj); + + // Load the "ptr" field of the member function pointer and determine if it + // points to a virtual function. + mlir::Value methodPtrField = cir::ExtractMemberOp::create( + rewriter, op.getLoc(), ptrdiffCIRTy, loweredMethod, 0); + mlir::Value virtualBit = cir::BinOp::create( + rewriter, op.getLoc(), cir::BinOpKind::And, methodPtrField, ptrdiffOne); + mlir::Value isVirtual; + if (useARMMethodPtrABI) + llvm_unreachable("ARM method ptr abi NYI"); + else + isVirtual = cir::CmpOp::create(rewriter, op.getLoc(), cir::CmpOpKind::eq, + virtualBit, ptrdiffOne); + + assert(!cir::MissingFeatures::emitCFICheck()); + assert(!cir::MissingFeatures::emitVFEInfo()); + assert(!cir::MissingFeatures::emitWPDInfo()); + + auto buildVirtualCallee = [&](mlir::OpBuilder &b, mlir::Location loc) { + // Load vtable pointer. + // Note that vtable pointer always point to the global address space. + auto vtablePtrTy = + cir::PointerType::get(cir::IntType::get(b.getContext(), 8, true)); + auto vtablePtrPtrTy = cir::PointerType::get( + vtablePtrTy, op.getObject().getType().getAddrSpace()); + auto vtablePtrPtr = cir::CastOp::create( + b, loc, vtablePtrPtrTy, cir::CastKind::bitcast, adjustedThis); + assert(!cir::MissingFeatures::opTBAA()); + mlir::Value vtablePtr = + cir::LoadOp::create(b, loc, vtablePtrPtr, /*isDeref=*/false, + /*isVolatile=*/false, + /*alignment=*/mlir::IntegerAttr(), + /*sync_scope=*/cir::SyncScopeKindAttr{}, + /*mem_order=*/cir::MemOrderAttr()); + + // Get the vtable offset. + mlir::Value vtableOffset = methodPtrField; + assert(!useARMMethodPtrABI && "ARM method ptr abi NYI"); + vtableOffset = cir::BinOp::create(b, loc, cir::BinOpKind::Sub, vtableOffset, + ptrdiffOne); + + assert(!cir::MissingFeatures::emitCFICheck()); + assert(!cir::MissingFeatures::emitVFEInfo()); + assert(!cir::MissingFeatures::emitWPDInfo()); + + // Apply the offset to the vtable pointer and get the pointer to the target + // virtual function. Then load that pointer to get the callee. + mlir::Value vfpAddr = cir::PtrStrideOp::create( + rewriter, op.getLoc(), vtablePtrTy, vtablePtr, vtableOffset); + auto vfpPtrTy = cir::PointerType::get(calleePtrTy); + mlir::Value vfpPtr = cir::CastOp::create(rewriter, op.getLoc(), vfpPtrTy, + cir::CastKind::bitcast, vfpAddr); + auto fnPtr = cir::LoadOp::create(b, loc, vfpPtr, + /*isDeref=*/false, /*isVolatile=*/false, + /*alignment=*/mlir::IntegerAttr(), + /*sync_scope=*/cir::SyncScopeKindAttr{}, + /*mem_order=*/cir::MemOrderAttr()); + + cir::YieldOp::create(b, loc, fnPtr.getResult()); + assert(!cir::MissingFeatures::emitCFICheck()); + }; + + callee = + cir::TernaryOp::create( + rewriter, op.getLoc(), isVirtual, /*thenBuilder=*/buildVirtualCallee, + /*elseBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + auto fnPtr = cir::CastOp::create( + b, loc, calleePtrTy, cir::CastKind::int_to_ptr, methodPtrField); + cir::YieldOp::create(b, loc, fnPtr.getResult()); + }) + .getResult(); +} + static mlir::Value lowerDataMemberCast(mlir::Operation *op, mlir::Value loweredSrc, std::int64_t offset, diff --git a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp index 47c5871e72290..ad081d0d06dbc 100644 --- a/clang/test/CIR/CodeGen/pointer-to-member-func.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-member-func.cpp @@ -38,3 +38,87 @@ auto make_non_virtual() -> void (Foo::*)(int) { // OGCG: define {{.*}} { i64, i64 } @_Z16make_non_virtualv() // OGCG: ret { i64, i64 } { i64 ptrtoint (ptr @_ZN3Foo2m1Ei to i64), i64 0 } + +void call(Foo *obj, void (Foo::*func)(int), int arg) { + (obj->*func)(arg); +} + +// CIR-BEFORE: cir.func {{.*}} @_Z4callP3FooMS_FviEi +// CIR-BEFORE: %[[OBJ:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.ptr<!rec_Foo>>, !cir.ptr<!rec_Foo> +// CIR-BEFORE: %[[FUNC:.*]] = cir.load{{.*}} : !cir.ptr<!cir.method<!cir.func<(!s32i)> in !rec_Foo>>, !cir.method<!cir.func<(!s32i)> in !rec_Foo> +// CIR-BEFORE: %[[CALLEE:.*]], %[[THIS:.*]] = cir.get_method %[[FUNC]], %[[OBJ]] : (!cir.method<!cir.func<(!s32i)> in !rec_Foo>, !cir.ptr<!rec_Foo>) -> (!cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>>, !cir.ptr<!void>) +// CIR-BEFORE: %[[ARG:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-BEFORE: cir.call %[[CALLEE]](%[[THIS]], %[[ARG]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>>, !cir.ptr<!void>, !s32i) -> () + +// CIR-AFTER: cir.func {{.*}} @_Z4callP3FooMS_FviEi +// CIR-AFTER: %[[OBJ:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!cir.ptr<!rec_Foo>>, !cir.ptr<!rec_Foo> +// CIR-AFTER: %[[FUNC:.*]] = cir.load{{.*}} : !cir.ptr<!rec_anon_struct>, !rec_anon_struct +// CIR-AFTER: %[[VIRT_BIT:.*]] = cir.const #cir.int<1> : !s64i +// CIR-AFTER: %[[ADJ:.*]] = cir.extract_member %[[FUNC]][1] : !rec_anon_struct -> !s64i +// CIR-AFTER: %[[THIS:.*]] = cir.cast bitcast %[[OBJ]] : !cir.ptr<!rec_Foo> -> !cir.ptr<!void> +// CIR-AFTER: %[[ADJUSTED_THIS:.*]] = cir.ptr_stride %[[THIS]], %[[ADJ]] : (!cir.ptr<!void>, !s64i) -> !cir.ptr<!void> +// CIR-AFTER: %[[METHOD_PTR:.*]] = cir.extract_member %[[FUNC]][0] : !rec_anon_struct -> !s64i +// CIR-AFTER: %[[VIRT_BIT_TEST:.*]] = cir.binop(and, %[[METHOD_PTR]], %[[VIRT_BIT]]) : !s64i +// CIR-AFTER: %[[IS_VIRTUAL:.*]] = cir.cmp(eq, %[[VIRT_BIT_TEST]], %[[VIRT_BIT]]) : !s64i, !cir.bool +// CIR-AFTER: %[[CALLEE:.*]] = cir.ternary(%[[IS_VIRTUAL]], true { +// CIR-AFTER: %[[VTABLE_PTR:.*]] = cir.cast bitcast %[[ADJUSTED_THIS]] : !cir.ptr<!void> -> !cir.ptr<!cir.ptr<!s8i>> +// CIR-AFTER: %[[VTABLE:.*]] = cir.load %[[VTABLE_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!s8i> +// CIR-AFTER: %[[OFFSET:.*]] = cir.binop(sub, %[[METHOD_PTR]], %[[VIRT_BIT]]) : !s64i +// CIR-AFTER: %[[VTABLE_SLOT:.*]] = cir.ptr_stride %[[VTABLE]], %[[OFFSET]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i> +// CIR-AFTER: %[[VIRTUAL_FN_PTR:.*]] = cir.cast bitcast %[[VTABLE_SLOT]] : !cir.ptr<!s8i> -> !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>>> +// CIR-AFTER: %[[VIRTUAL_FN_PTR_LOAD:.*]] = cir.load %[[VIRTUAL_FN_PTR]] : !cir.ptr<!cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>>>, !cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>> +// CIR-AFTER: cir.yield %[[VIRTUAL_FN_PTR_LOAD]] : !cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>> +// CIR-AFTER: }, false { +// CIR-AFTER: %[[CALLEE_PTR:.*]] = cir.cast int_to_ptr %[[METHOD_PTR]] : !s64i -> !cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>> +// CIR-AFTER: cir.yield %[[CALLEE_PTR]] : !cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>> +// CIR-AFTER: }) : (!cir.bool) -> !cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>> +// CIR-AFTER: %[[ARG:.*]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s32i>, !s32i +// CIR-AFTER: cir.call %[[CALLEE]](%[[ADJUSTED_THIS]], %[[ARG]]) : (!cir.ptr<!cir.func<(!cir.ptr<!void>, !s32i)>>, !cir.ptr<!void>, !s32i) -> () + +// LLVM: define {{.*}} @_Z4callP3FooMS_FviEi +// LLVM: %[[OBJ:.*]] = load ptr, ptr %{{.*}} +// LLVM: %[[MEMFN_PTR:.*]] = load { i64, i64 }, ptr %{{.*}} +// LLVM: %[[THIS_ADJ:.*]] = extractvalue { i64, i64 } %[[MEMFN_PTR]], 1 +// LLVM: %[[ADJUSTED_THIS:.*]] = getelementptr i8, ptr %[[OBJ]], i64 %[[THIS_ADJ]] +// LLVM: %[[PTR_FIELD:.*]] = extractvalue { i64, i64 } %[[MEMFN_PTR]], 0 +// LLVM: %[[VIRT_BIT:.*]] = and i64 %[[PTR_FIELD]], 1 +// LLVM: %[[IS_VIRTUAL:.*]] = icmp eq i64 %[[VIRT_BIT]], 1 +// LLVM: br i1 %[[IS_VIRTUAL]], label %[[HANDLE_VIRTUAL:.*]], label %[[HANDLE_NON_VIRTUAL:.*]] +// LLVM: [[HANDLE_VIRTUAL]]: +// LLVM: %[[VTABLE:.*]] = load ptr, ptr %[[ADJUSTED_THIS]] +// LLVM: %[[OFFSET:.*]] = sub i64 %[[PTR_FIELD]], 1 +// LLVM: %[[VTABLE_SLOT:.*]] = getelementptr i8, ptr %[[VTABLE]], i64 %[[OFFSET]] +// LLVM: %[[VIRTUAL_FN_PTR:.*]] = load ptr, ptr %[[VTABLE_SLOT]] +// LLVM: br label %[[CONTINUE:.*]] +// LLVM: [[HANDLE_NON_VIRTUAL]]: +// LLVM: %[[FUNC_PTR:.*]] = inttoptr i64 %[[PTR_FIELD]] to ptr +// LLVM: br label %[[CONTINUE]] +// LLVM: [[CONTINUE]]: +// LLVM: %[[CALLEE_PTR:.*]] = phi ptr [ %[[FUNC_PTR]], %[[HANDLE_NON_VIRTUAL]] ], [ %[[VIRTUAL_FN_PTR]], %[[HANDLE_VIRTUAL]] ] +// LLVM: %[[ARG:.*]] = load i32, ptr %{{.+}} +// LLVM: call void %[[CALLEE_PTR]](ptr %[[ADJUSTED_THIS]], i32 %[[ARG]]) +// LLVM: } + +// OGCG: define {{.*}} @_Z4callP3FooMS_FviEi +// OGCG: %[[OBJ:.*]] = load ptr, ptr %{{.*}} +// OGCG: %[[MEMFN_PTR:.*]] = load { i64, i64 }, ptr %{{.*}} +// OGCG: %[[THIS_ADJ:.*]] = extractvalue { i64, i64 } %[[MEMFN_PTR]], 1 +// OGCG: %[[ADJUSTED_THIS:.*]] = getelementptr inbounds i8, ptr %[[OBJ]], i64 %[[THIS_ADJ]] +// OGCG: %[[PTR_FIELD:.*]] = extractvalue { i64, i64 } %[[MEMFN_PTR]], 0 +// OGCG: %[[VIRT_BIT:.*]] = and i64 %[[PTR_FIELD]], 1 +// OGCG: %[[IS_VIRTUAL:.*]] = icmp ne i64 %[[VIRT_BIT]], 0 +// OGCG: br i1 %[[IS_VIRTUAL]], label %[[HANDLE_VIRTUAL:.*]], label %[[HANDLE_NON_VIRTUAL:.*]] +// OGCG: [[HANDLE_VIRTUAL]]: +// OGCG: %[[VTABLE:.*]] = load ptr, ptr %[[ADJUSTED_THIS]] +// OGCG: %[[OFFSET:.*]] = sub i64 %[[PTR_FIELD]], 1 +// OGCG: %[[VTABLE_SLOT:.*]] = getelementptr i8, ptr %[[VTABLE]], i64 %[[OFFSET]] +// OGCG: %[[VIRTUAL_FN_PTR:.*]] = load ptr, ptr %[[VTABLE_SLOT]] +// OGCG: br label %[[CONTINUE:.*]] +// OGCG: [[HANDLE_NON_VIRTUAL]]: +// OGCG: %[[FUNC_PTR:.*]] = inttoptr i64 %[[PTR_FIELD]] to ptr +// OGCG: br label %[[CONTINUE]] +// OGCG: [[CONTINUE]]: +// OGCG: %[[CALLEE_PTR:.*]] = phi ptr [ %[[VIRTUAL_FN_PTR]], %[[HANDLE_VIRTUAL]] ], [ %[[FUNC_PTR]], %[[HANDLE_NON_VIRTUAL]] ] +// OGCG: %[[ARG:.*]] = load i32, ptr %{{.+}} +// OGCG: call void %[[CALLEE_PTR]](ptr {{.*}} %[[ADJUSTED_THIS]], i32 {{.*}} %[[ARG]]) +// OGCG: } >From b2e55c2bdf32637c7e69b57dfcdd23e424fab1eb Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 16 Jan 2026 13:58:43 -0800 Subject: [PATCH 2/3] Use ImplicitLocOpBuilder --- .../TargetLowering/LowerItaniumCXXABI.cpp | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index d581e18b5e37a..80d29b977c549 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -23,6 +23,7 @@ #include "CIRCXXABI.h" #include "LowerModule.h" #include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/IR/ImplicitLocOpBuilder.h" #include "llvm/Support/ErrorHandling.h" namespace cir { @@ -249,16 +250,17 @@ void LowerItaniumCXXABI::lowerGetMethod( // If the member is non-virtual, memptr.ptr is the address of // the function to call. + mlir::ImplicitLocOpBuilder locBuilder(op.getLoc(), rewriter); mlir::Value &callee = loweredResults[0]; mlir::Value &adjustedThis = loweredResults[1]; mlir::Type calleePtrTy = op.getCallee().getType(); cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lm); - mlir::Value ptrdiffOne = cir::ConstantOp::create( - rewriter, op.getLoc(), cir::IntAttr::get(ptrdiffCIRTy, 1)); + mlir::Value ptrdiffOne = + cir::ConstantOp::create(locBuilder, cir::IntAttr::get(ptrdiffCIRTy, 1)); - mlir::Value adj = cir::ExtractMemberOp::create( - rewriter, op.getLoc(), ptrdiffCIRTy, loweredMethod, 1); + mlir::Value adj = + cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredMethod, 1); if (useARMMethodPtrABI) { op.emitError("ARM method ptr abi NYI"); return; @@ -266,26 +268,25 @@ void LowerItaniumCXXABI::lowerGetMethod( // Apply the adjustment to the 'this' pointer. mlir::Type thisVoidPtrTy = - cir::PointerType::get(cir::VoidType::get(rewriter.getContext()), + cir::PointerType::get(cir::VoidType::get(locBuilder.getContext()), op.getObject().getType().getAddrSpace()); - mlir::Value thisVoidPtr = - cir::CastOp::create(rewriter, op.getLoc(), thisVoidPtrTy, - cir::CastKind::bitcast, loweredObjectPtr); - adjustedThis = cir::PtrStrideOp::create(rewriter, op.getLoc(), thisVoidPtrTy, - thisVoidPtr, adj); + mlir::Value thisVoidPtr = cir::CastOp::create( + locBuilder, thisVoidPtrTy, cir::CastKind::bitcast, loweredObjectPtr); + adjustedThis = + cir::PtrStrideOp::create(locBuilder, thisVoidPtrTy, thisVoidPtr, adj); // Load the "ptr" field of the member function pointer and determine if it // points to a virtual function. - mlir::Value methodPtrField = cir::ExtractMemberOp::create( - rewriter, op.getLoc(), ptrdiffCIRTy, loweredMethod, 0); + mlir::Value methodPtrField = + cir::ExtractMemberOp::create(locBuilder, ptrdiffCIRTy, loweredMethod, 0); mlir::Value virtualBit = cir::BinOp::create( rewriter, op.getLoc(), cir::BinOpKind::And, methodPtrField, ptrdiffOne); mlir::Value isVirtual; if (useARMMethodPtrABI) llvm_unreachable("ARM method ptr abi NYI"); else - isVirtual = cir::CmpOp::create(rewriter, op.getLoc(), cir::CmpOpKind::eq, - virtualBit, ptrdiffOne); + isVirtual = cir::CmpOp::create(locBuilder, cir::CmpOpKind::eq, virtualBit, + ptrdiffOne); assert(!cir::MissingFeatures::emitCFICheck()); assert(!cir::MissingFeatures::emitVFEInfo()); @@ -320,10 +321,10 @@ void LowerItaniumCXXABI::lowerGetMethod( // Apply the offset to the vtable pointer and get the pointer to the target // virtual function. Then load that pointer to get the callee. - mlir::Value vfpAddr = cir::PtrStrideOp::create( - rewriter, op.getLoc(), vtablePtrTy, vtablePtr, vtableOffset); + mlir::Value vfpAddr = cir::PtrStrideOp::create(locBuilder, vtablePtrTy, + vtablePtr, vtableOffset); auto vfpPtrTy = cir::PointerType::get(calleePtrTy); - mlir::Value vfpPtr = cir::CastOp::create(rewriter, op.getLoc(), vfpPtrTy, + mlir::Value vfpPtr = cir::CastOp::create(locBuilder, vfpPtrTy, cir::CastKind::bitcast, vfpAddr); auto fnPtr = cir::LoadOp::create(b, loc, vfpPtr, /*isDeref=*/false, /*isVolatile=*/false, @@ -337,7 +338,7 @@ void LowerItaniumCXXABI::lowerGetMethod( callee = cir::TernaryOp::create( - rewriter, op.getLoc(), isVirtual, /*thenBuilder=*/buildVirtualCallee, + locBuilder, isVirtual, /*thenBuilder=*/buildVirtualCallee, /*elseBuilder=*/ [&](mlir::OpBuilder &b, mlir::Location loc) { auto fnPtr = cir::CastOp::create( >From 7c06428caa5b8141410d6bcc39b3a90dc8cf138f Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Fri, 16 Jan 2026 14:14:37 -0800 Subject: [PATCH 3/3] Use separate args for lowerGetMethod callee and thisArg --- .../lib/CIR/Dialect/Transforms/CXXABILowering.cpp | 7 ++++--- .../Dialect/Transforms/TargetLowering/CIRCXXABI.h | 2 +- .../TargetLowering/LowerItaniumCXXABI.cpp | 15 +++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index 469dddbb118e3..a8d08fb90221c 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -255,10 +255,11 @@ mlir::LogicalResult CIRDerivedDataMemberOpABILowering::matchAndRewrite( mlir::LogicalResult CIRGetMethodOpABILowering::matchAndRewrite( cir::GetMethodOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - mlir::Value loweredResults[2]; + mlir::Value callee; + mlir::Value thisArg; lowerModule->getCXXABI().lowerGetMethod( - op, loweredResults, adaptor.getMethod(), adaptor.getObject(), rewriter); - rewriter.replaceOp(op, loweredResults); + op, callee, thisArg, adaptor.getMethod(), adaptor.getObject(), rewriter); + rewriter.replaceOp(op, {callee, thisArg}); return mlir::success(); } diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index 69d8b682ab4c5..b2166aac0b7bd 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -70,7 +70,7 @@ class CIRCXXABI { /// operations that act on the ABI types. The lowered result values will be /// stored in the given loweredResults array. virtual void - lowerGetMethod(cir::GetMethodOp op, mlir::Value (&loweredResults)[2], + lowerGetMethod(cir::GetMethodOp op, mlir::Value &callee, mlir::Value &thisArg, mlir::Value loweredMethod, mlir::Value loweredObjectPtr, mlir::ConversionPatternRewriter &rewriter) const = 0; diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index 80d29b977c549..d22024d6dc573 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -61,8 +61,9 @@ class LowerItaniumCXXABI : public CIRCXXABI { mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const override; - void lowerGetMethod(cir::GetMethodOp op, mlir::Value (&loweredResults)[2], - mlir::Value loweredMethod, mlir::Value loweredObjectPtr, + void lowerGetMethod(cir::GetMethodOp op, mlir::Value &callee, + mlir::Value &thisArg, mlir::Value loweredMethod, + mlir::Value loweredObjectPtr, mlir::ConversionPatternRewriter &rewriter) const override; mlir::Value lowerBaseDataMember(cir::BaseDataMemberOp op, @@ -226,7 +227,7 @@ mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember( } void LowerItaniumCXXABI::lowerGetMethod( - cir::GetMethodOp op, mlir::Value (&loweredResults)[2], + cir::GetMethodOp op, mlir::Value &callee, mlir::Value &thisArg, mlir::Value loweredMethod, mlir::Value loweredObjectPtr, mlir::ConversionPatternRewriter &rewriter) const { // In the Itanium and ARM ABIs, method pointers have the form: @@ -251,8 +252,6 @@ void LowerItaniumCXXABI::lowerGetMethod( // the function to call. mlir::ImplicitLocOpBuilder locBuilder(op.getLoc(), rewriter); - mlir::Value &callee = loweredResults[0]; - mlir::Value &adjustedThis = loweredResults[1]; mlir::Type calleePtrTy = op.getCallee().getType(); cir::IntType ptrdiffCIRTy = getPtrDiffCIRTy(lm); @@ -272,7 +271,7 @@ void LowerItaniumCXXABI::lowerGetMethod( op.getObject().getType().getAddrSpace()); mlir::Value thisVoidPtr = cir::CastOp::create( locBuilder, thisVoidPtrTy, cir::CastKind::bitcast, loweredObjectPtr); - adjustedThis = + thisArg = cir::PtrStrideOp::create(locBuilder, thisVoidPtrTy, thisVoidPtr, adj); // Load the "ptr" field of the member function pointer and determine if it @@ -299,8 +298,8 @@ void LowerItaniumCXXABI::lowerGetMethod( cir::PointerType::get(cir::IntType::get(b.getContext(), 8, true)); auto vtablePtrPtrTy = cir::PointerType::get( vtablePtrTy, op.getObject().getType().getAddrSpace()); - auto vtablePtrPtr = cir::CastOp::create( - b, loc, vtablePtrPtrTy, cir::CastKind::bitcast, adjustedThis); + auto vtablePtrPtr = cir::CastOp::create(b, loc, vtablePtrPtrTy, + cir::CastKind::bitcast, thisArg); assert(!cir::MissingFeatures::opTBAA()); mlir::Value vtablePtr = cir::LoadOp::create(b, loc, vtablePtrPtr, /*isDeref=*/false, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
