https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/153243
>From 5e3ab0b4e314b970eb1f1d61aa2d05a0de2cfc55 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <akay...@nvidia.com> Date: Thu, 7 Aug 2025 17:15:17 -0700 Subject: [PATCH 1/2] [CIR] Add lowering for the cir.vtable.address_point operation This adds support for lowering the cir.vtable.address_point operation to the LLVM dialect, as well as type converter support for the cir.vptr type. --- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 47 ++++++++++++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.h | 10 ++++ .../CIR/CodeGen/virtual-function-calls.cpp | 26 +++++++++- 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index ad5f52034f92a..f9486addcb4ac 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2083,6 +2083,10 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS); }); + converter.addConversion([&](cir::VPtrType type) -> mlir::Type { + assert(!cir::MissingFeatures::addressSpace()); + return mlir::LLVM::LLVMPointerType::get(type.getContext()); + }); converter.addConversion([&](cir::ArrayType type) -> mlir::Type { mlir::Type ty = convertTypeForMemory(converter, dataLayout, type.getElementType()); @@ -2314,6 +2318,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMSwitchFlatOpLowering, CIRToLLVMTrapOpLowering, CIRToLLVMUnaryOpLowering, + CIRToLLVMUnreachableOpLowering, CIRToLLVMVecCmpOpLowering, CIRToLLVMVecCreateOpLowering, CIRToLLVMVecExtractOpLowering, @@ -2322,7 +2327,8 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMVecShuffleOpLowering, CIRToLLVMVecSplatOpLowering, CIRToLLVMVecTernaryOpLowering, - CIRToLLVMUnreachableOpLowering + CIRToLLVMVTableAddrPointOpLowering + // clang-format on >(converter, patterns.getContext()); processCIRAttrs(module); @@ -2400,6 +2406,45 @@ mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite( return mlir::success(); } +static mlir::Value +getValueForVTableSymbol(mlir::Operation *op, + mlir::ConversionPatternRewriter &rewriter, + const mlir::TypeConverter *converter, + mlir::FlatSymbolRefAttr nameAttr, mlir::Type &eltType) { + auto module = op->getParentOfType<mlir::ModuleOp>(); + mlir::Operation *symbol = mlir::SymbolTable::lookupSymbolIn(module, nameAttr); + if (auto llvmSymbol = mlir::dyn_cast<mlir::LLVM::GlobalOp>(symbol)) + eltType = llvmSymbol.getType(); + else if (auto cirSymbol = mlir::dyn_cast<cir::GlobalOp>(symbol)) + eltType = converter->convertType(cirSymbol.getSymType()); + + return mlir::LLVM::AddressOfOp::create( + rewriter, op->getLoc(), + mlir::LLVM::LLVMPointerType::get(op->getContext()), nameAttr.getValue()); +} + +mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( + cir::VTableAddrPointOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + const mlir::TypeConverter *converter = getTypeConverter(); + mlir::Type targetType = converter->convertType(op.getType()); + llvm::SmallVector<mlir::LLVM::GEPArg> offsets; + mlir::Type eltType; + mlir::Value symAddr = getValueForVTableSymbol(op, rewriter, converter, + op.getNameAttr(), eltType); + offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{ + 0, op.getAddressPointAttr().getIndex(), + op.getAddressPointAttr().getOffset()}; + + assert(eltType && "Shouldn't ever be missing an eltType here"); + mlir::LLVM::GEPNoWrapFlags inboundsNuw = + mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw; + rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, targetType, eltType, + symAddr, offsets, inboundsNuw); + + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite( cir::StackSaveOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index a6d2d6559005b..6fbe0079b90d0 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -457,6 +457,16 @@ class CIRToLLVMBaseClassAddrOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVTableAddrPointOpLowering + : public mlir::OpConversionPattern<cir::VTableAddrPointOp> { +public: + using mlir::OpConversionPattern<cir::VTableAddrPointOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VTableAddrPointOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMStackSaveOpLowering : public mlir::OpConversionPattern<cir::StackSaveOp> { public: diff --git a/clang/test/CIR/CodeGen/virtual-function-calls.cpp b/clang/test/CIR/CodeGen/virtual-function-calls.cpp index f3b134b135c85..004b6dab30563 100644 --- a/clang/test/CIR/CodeGen/virtual-function-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-function-calls.cpp @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG struct A { A(); @@ -14,7 +18,11 @@ A::A() {} // CIR: cir.global "private" external @_ZTV1A : !rec_anon_struct -// CIR: cir.func dso_local @_ZN1AC2Ev(%arg0: !cir.ptr<!rec_A> {{.*}}) +// LLVM: @_ZTV1A = external global { [3 x ptr] } + +// OGCG: @_ZTV1A = external unnamed_addr constant { [3 x ptr] } + +// CIR: cir.func{{.*}} @_ZN1AC2Ev(%arg0: !cir.ptr<!rec_A> {{.*}}) // CIR: %[[THIS_ADDR:.*]] = cir.alloca !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>>, ["this", init] // CIR: cir.store %arg0, %[[THIS_ADDR]] : !cir.ptr<!rec_A>, !cir.ptr<!cir.ptr<!rec_A>> // CIR: %[[THIS:.*]] = cir.load %[[THIS_ADDR]] : !cir.ptr<!cir.ptr<!rec_A>>, !cir.ptr<!rec_A> @@ -22,3 +30,19 @@ A::A() {} // CIR: %[[THIS_VPTR_PTR:.*]] = cir.cast(bitcast, %[[THIS]] : !cir.ptr<!rec_A>), !cir.ptr<!cir.vptr> // CIR: cir.store align(8) %[[VPTR]], %[[THIS_VPTR_PTR]] : !cir.vptr, !cir.ptr<!cir.vptr> // CIR: cir.return + +// LLVM: define{{.*}} void @_ZN1AC2Ev(ptr %[[ARG0:.*]]) +// LLVM: %[[THIS_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[THIS_ADDR]] +// LLVM: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1A, i64 16), ptr %[[THIS]] + +// OGCG: define{{.*}} void @_ZN1AC2Ev(ptr {{.*}} %[[ARG0:.*]]) +// OGCG: %[[THIS_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG0]], ptr %[[THIS_ADDR]] +// OGCG: %[[THIS:.*]] = load ptr, ptr %[[THIS_ADDR]] +// OGCG: store ptr getelementptr inbounds inrange(-16, 8) ({ [3 x ptr] }, ptr @_ZTV1A, i32 0, i32 0, i32 2), ptr %[[THIS]] + +// NOTE: The GEP in OGCG looks very different from the one generated with CIR, +// but it is equivalent. The OGCG GEP indexes by base pointer, then +// structure, then array, whereas the CIR GEP indexes by byte offset. >From 7ac51e76d5a41ec77b95e3ef4b2470b99e1661fc Mon Sep 17 00:00:00 2001 From: Andy Kaylor <akay...@nvidia.com> Date: Wed, 13 Aug 2025 16:52:07 -0700 Subject: [PATCH 2/2] Address feedback --- clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index f9486addcb4ac..c3715c28f6890 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2413,10 +2413,14 @@ getValueForVTableSymbol(mlir::Operation *op, mlir::FlatSymbolRefAttr nameAttr, mlir::Type &eltType) { auto module = op->getParentOfType<mlir::ModuleOp>(); mlir::Operation *symbol = mlir::SymbolTable::lookupSymbolIn(module, nameAttr); - if (auto llvmSymbol = mlir::dyn_cast<mlir::LLVM::GlobalOp>(symbol)) + if (auto llvmSymbol = mlir::dyn_cast<mlir::LLVM::GlobalOp>(symbol)) { eltType = llvmSymbol.getType(); - else if (auto cirSymbol = mlir::dyn_cast<cir::GlobalOp>(symbol)) + } else if (auto cirSymbol = mlir::dyn_cast<cir::GlobalOp>(symbol)) { eltType = converter->convertType(cirSymbol.getSymType()); + } else { + op->emitError() << "unexpected symbol type for " << symbol; + return {}; + } return mlir::LLVM::AddressOfOp::create( rewriter, op->getLoc(), @@ -2432,6 +2436,9 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( mlir::Type eltType; mlir::Value symAddr = getValueForVTableSymbol(op, rewriter, converter, op.getNameAttr(), eltType); + if (!symAddr) + return op.emitError() << "Unable to get value for vtable symbol"; + offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{ 0, op.getAddressPointAttr().getIndex(), op.getAddressPointAttr().getOffset()}; @@ -2441,7 +2448,6 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw; rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, targetType, eltType, symAddr, offsets, inboundsNuw); - return mlir::success(); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits