https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/171897
>From a858a130a933db2753b7f678c5d0893e8d09efed Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Tue, 9 Dec 2025 14:45:09 -0800 Subject: [PATCH 1/2] [CIR] Add support for data member comparison This adds support for handling data member pointer comparisons in CIR. --- .../Transforms/TargetLowering/CIRCXXABI.h | 4 ++ .../TargetLowering/LowerItaniumCXXABI.cpp | 12 ++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 11 +++- .../CodeGen/pointer-to-data-member-cmp.cpp | 58 +++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index 90f0ac3478f9d..a2439f1c24f10 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -53,6 +53,10 @@ class CIRCXXABI { lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const = 0; + + virtual mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs, + mlir::Value loweredRhs, + mlir::OpBuilder &builder) const = 0; }; /// Creates an Itanium-family ABI. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index ce4b0c7e92d09..abffb193798cc 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -47,6 +47,10 @@ class LowerItaniumCXXABI : public CIRCXXABI { lowerGetRuntimeMember(cir::GetRuntimeMemberOp op, mlir::Type loweredResultTy, mlir::Value loweredAddr, mlir::Value loweredMember, mlir::OpBuilder &builder) const override; + + mlir::Value lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs, + mlir::Value loweredRhs, + mlir::OpBuilder &builder) const override; }; } // namespace @@ -108,4 +112,12 @@ mlir::Operation *LowerItaniumCXXABI::lowerGetRuntimeMember( cir::CastKind::bitcast, memberBytesPtr); } +mlir::Value +LowerItaniumCXXABI::lowerDataMemberCmp(cir::CmpOp op, mlir::Value loweredLhs, + mlir::Value loweredRhs, + mlir::OpBuilder &builder) const { + return cir::CmpOp::create(builder, op.getLoc(), op.getKind(), loweredLhs, + loweredRhs); +} + } // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 6d01964ebac41..66a875810aa5c 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2569,8 +2569,17 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { mlir::Type type = cmpOp.getLhs().getType(); - assert(!cir::MissingFeatures::dataMemberType()); assert(!cir::MissingFeatures::methodType()); + if (mlir::isa<cir::DataMemberType>(type)) { + assert(lowerMod && "lowering module is not available"); + + mlir::Value loweredResult; + loweredResult = lowerMod->getCXXABI().lowerDataMemberCmp( + cmpOp, adaptor.getLhs(), adaptor.getRhs(), rewriter); + + rewriter.replaceOp(cmpOp, loweredResult); + return mlir::success(); + } if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) { bool isSigned = mlir::isa<cir::IntType>(type) diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp new file mode 100644 index 0000000000000..fa3491252cb5f --- /dev/null +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp @@ -0,0 +1,58 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir --check-prefix=CIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll --check-prefix=OGCG %s + +struct Foo { + int a; +}; + +struct Bar { + int a; +}; + +bool eq(int Foo::*x, int Foo::*y) { + return x == y; +} + +// CIR-LABEL: @_Z2eqM3FooiS0_ +// CIR: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-NEXT: %{{.+}} = cir.cmp(eq, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool +// CIR: } + +// LLVM-LABEL: @_Z2eqM3FooiS0_ +// LLVM: %[[#x:]] = load i64, ptr %{{.+}}, align 8 +// LLVM-NEXT: %[[#y:]] = load i64, ptr %{{.+}}, align 8 +// LLVM-NEXT: %{{.+}} = icmp eq i64 %[[#x]], %[[#y]] +// LLVM: } + +// OGCG-LABEL: @_Z2eqM3FooiS0_ +// OGCG: %[[#x:]] = load i64, ptr %{{.+}}, align 8 +// OGCG-NEXT: %[[#y:]] = load i64, ptr %{{.+}}, align 8 +// OGCG-NEXT: %{{.+}} = icmp eq i64 %[[#x]], %[[#y]] +// OGCG: } + +bool ne(int Foo::*x, int Foo::*y) { + return x != y; +} + +// CIR-LABEL: @_Z2neM3FooiS0_ +// CIR: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-NEXT: %{{.+}} = cir.cmp(ne, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool +// CIR: } + +// LLVM-LABEL: @_Z2neM3FooiS0_ +// LLVM: %[[#x:]] = load i64, ptr %{{.+}}, align 8 +// LLVM-NEXT: %[[#y:]] = load i64, ptr %{{.+}}, align 8 +// LLVM-NEXT: %{{.+}} = icmp ne i64 %[[#x]], %[[#y]] +// LLVM: } + +// OGCG-LABEL: @_Z2neM3FooiS0_ +// OGCG: %[[#x:]] = load i64, ptr %{{.+}}, align 8 +// OGCG-NEXT: %[[#y:]] = load i64, ptr %{{.+}}, align 8 +// OGCG-NEXT: %{{.+}} = icmp ne i64 %[[#x]], %[[#y]] +// OGCG: } >From c925f7b9bf512910546703bdb8984767dbe85039 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Thu, 18 Dec 2025 16:53:12 -0800 Subject: [PATCH 2/2] Move lowering to cxxabi pass --- .../CIR/Dialect/Transforms/CXXABILowering.cpp | 19 +++++++++- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 12 ------- .../CodeGen/pointer-to-data-member-cmp.cpp | 35 ++++++++++++------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index bcd9147b130e5..3ac171d060ca6 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -58,6 +58,7 @@ class CIROpCXXABILoweringPattern : public mlir::OpConversionPattern<Op> { CIR_CXXABI_LOWERING_PATTERN(CIRAllocaOpABILowering, cir::AllocaOp); CIR_CXXABI_LOWERING_PATTERN(CIRConstantOpABILowering, cir::ConstantOp); +CIR_CXXABI_LOWERING_PATTERN(CIRCmpOpABILowering, cir::CmpOp); CIR_CXXABI_LOWERING_PATTERN(CIRFuncOpABILowering, cir::FuncOp); CIR_CXXABI_LOWERING_PATTERN(CIRGetRuntimeMemberOpABILowering, cir::GetRuntimeMemberOp); @@ -86,7 +87,7 @@ class CIRGenericCXXABILoweringPattern : public mlir::ConversionPattern { matchAndRewrite(mlir::Operation *op, llvm::ArrayRef<mlir::Value> operands, mlir::ConversionPatternRewriter &rewriter) const override { // Do not match on operations that have dedicated ABI lowering rewrite rules - if (llvm::isa<cir::AllocaOp, cir::ConstantOp, cir::FuncOp, + if (llvm::isa<cir::AllocaOp, cir::ConstantOp, cir::CmpOp, cir::FuncOp, cir::GetRuntimeMemberOp, cir::GlobalOp>(op)) return mlir::failure(); @@ -174,6 +175,21 @@ mlir::LogicalResult CIRConstantOpABILowering::matchAndRewrite( llvm_unreachable("constant operand is not an CXXABI-dependent type"); } +mlir::LogicalResult CIRCmpOpABILowering::matchAndRewrite( + cir::CmpOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type type = op.getLhs().getType(); + assert((mlir::isa<cir::DataMemberType>(type)) && + "input to cmp in ABI lowering must be a data member"); + + assert(!cir::MissingFeatures::methodType()); + mlir::Value loweredResult = lowerModule->getCXXABI().lowerDataMemberCmp( + op, adaptor.getLhs(), adaptor.getRhs(), rewriter); + + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + mlir::LogicalResult CIRFuncOpABILowering::matchAndRewrite( cir::FuncOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -344,6 +360,7 @@ void CXXABILoweringPass::runOnOperation() { // clang-format off CIRAllocaOpABILowering, CIRConstantOpABILowering, + CIRCmpOpABILowering, CIRFuncOpABILowering, CIRGetRuntimeMemberOpABILowering, CIRGlobalOpABILowering diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 66a875810aa5c..7aebc7effc4d1 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2569,18 +2569,6 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { mlir::Type type = cmpOp.getLhs().getType(); - assert(!cir::MissingFeatures::methodType()); - if (mlir::isa<cir::DataMemberType>(type)) { - assert(lowerMod && "lowering module is not available"); - - mlir::Value loweredResult; - loweredResult = lowerMod->getCXXABI().lowerDataMemberCmp( - cmpOp, adaptor.getLhs(), adaptor.getRhs(), rewriter); - - rewriter.replaceOp(cmpOp, loweredResult); - return mlir::success(); - } - if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) { bool isSigned = mlir::isa<cir::IntType>(type) ? mlir::cast<cir::IntType>(type).isSigned() diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp index fa3491252cb5f..482a1aa3938d4 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member-cmp.cpp @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir %s -o %t.cir -// RUN: FileCheck --input-file=%t.cir --check-prefix=CIR %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-cir -mmlir -mlir-print-ir-before=cir-cxxabi-lowering %s -o %t.cir 2> %t-before.cir +// RUN: FileCheck --check-prefix=CIR-BEFORE --input-file=%t-before.cir %s +// RUN: FileCheck --check-prefix=CIR-AFTER --input-file=%t.cir %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --input-file=%t-cir.ll --check-prefix=LLVM %s // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++17 -emit-llvm %s -o %t.ll @@ -17,11 +18,16 @@ bool eq(int Foo::*x, int Foo::*y) { return x == y; } -// CIR-LABEL: @_Z2eqM3FooiS0_ -// CIR: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> -// CIR-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> -// CIR-NEXT: %{{.+}} = cir.cmp(eq, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool -// CIR: } +// CIR-BEFORE-LABEL: @_Z2eqM3FooiS0_ +// CIR-BEFORE: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-BEFORE-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-BEFORE-NEXT: %{{.+}} = cir.cmp(eq, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool +// CIR-BEFORE: } + +// CIR-AFTER-LABEL: @_Z2eqM3FooiS0_ +// CIR-AFTER: %[[#x:]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[#y:]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %{{.*}} = cir.cmp(eq, %[[#x]], %[[#y]]) : !s64i, !cir.bool // LLVM-LABEL: @_Z2eqM3FooiS0_ // LLVM: %[[#x:]] = load i64, ptr %{{.+}}, align 8 @@ -39,11 +45,16 @@ bool ne(int Foo::*x, int Foo::*y) { return x != y; } -// CIR-LABEL: @_Z2neM3FooiS0_ -// CIR: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> -// CIR-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> -// CIR-NEXT: %{{.+}} = cir.cmp(ne, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool -// CIR: } +// CIR-BEFORE-LABEL: @_Z2neM3FooiS0_ +// CIR-BEFORE: %[[#x:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-BEFORE-NEXT: %[[#y:]] = cir.load{{.*}} %{{.+}} : !cir.ptr<!cir.data_member<!s32i in !rec_Foo>>, !cir.data_member<!s32i in !rec_Foo> +// CIR-BEFORE-NEXT: %{{.+}} = cir.cmp(ne, %[[#x]], %[[#y]]) : !cir.data_member<!s32i in !rec_Foo>, !cir.bool +// CIR-BEFORE: } + +// CIR-AFTER-LABEL: @_Z2neM3FooiS0_ +// CIR-AFTER: %[[#x:]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[#y:]] = cir.load{{.*}} %{{.*}} : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %{{.*}} = cir.cmp(ne, %[[#x]], %[[#y]]) : !s64i, !cir.bool // LLVM-LABEL: @_Z2neM3FooiS0_ // LLVM: %[[#x:]] = load i64, ptr %{{.+}}, align 8 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
