https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/221784
>From 67742996b965d34ac08ddab634f0af01a3fd439f Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Mon, 7 Sep 2026 22:15:37 +0530 Subject: [PATCH 1/2] [CIR] Support pointer-to-data-member binary operators for aggregates Implement support for pointer-to-data-member binary operators (.* and ->*) when the result is an aggregate type. Issue #221783 --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 11 +- .../CIR/CodeGen/pointer-to-data-member.cpp | 123 ++++++++++++++++++ 2 files changed, 130 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 16bfdae8cb0f1..4f59b3004094e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -427,12 +427,15 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { void VisitPredefinedExpr(const PredefinedExpr *e) { emitAggLoadOfLValue(e); } void VisitBinaryOperator(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitBinaryOperator"); + if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) + VisitPointerToDataMemberBinaryOperator(e); + else + cgf.cgm.errorNYI(e->getSourceRange(), + "AggExprEmitter: VisitBinaryOperator"); } void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitPointerToDataMemberBinaryOperator"); + LValue lv = cgf.emitPointerToDataMemberBinaryExpr(e); + emitFinalDestCopy(e->getType(), lv); } void VisitBinComma(const BinaryOperator *e) { cgf.emitIgnoredExpr(e->getLHS()); diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp index 9ad8a6fe58cc5..16d16c45fca70 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp @@ -480,3 +480,126 @@ void useHasField() { // LLVM: %[[GET_MEM:.*]] = getelementptr i8, ptr %[[LOAD_ARG]], i64 0 // LLVM: store i32 1, ptr %[[GET_MEM]] +struct Inner { + int x; + int y; +}; + +struct Outer { + int a; + Inner inner; +}; + +Inner test_agg_dot(const Outer &o, Inner Outer::*p) { + return o.*p; +} + +// CIR-BEFORE-LABEL: cir.func {{.*}} @_Z12test_agg_dotRK5OuterMS_5Inner( +// CIR-BEFORE-SAME: %[[O_ARG:.*]]: !cir.ptr<!rec_Outer> +// CIR-BEFORE-SAME: %[[P_ARG:.*]]: !cir.data_member<!rec_Inner in !rec_Outer> +// CIR-BEFORE: %[[O_ADDR:.*]] = cir.alloca "o" {{.*}} init const : !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-BEFORE: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} init : !cir.ptr<!cir.data_member<!rec_Inner in !rec_Outer>> +// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.store %[[O_ARG]], %[[O_ADDR]] +// CIR-BEFORE: cir.store %[[P_ARG]], %[[P_ADDR]] +// CIR-BEFORE: %[[O:.*]] = cir.load %[[O_ADDR]] +// CIR-BEFORE: %[[P:.*]] = cir.load{{.*}} %[[P_ADDR]] +// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[O]][%[[P]] : !cir.data_member<!rec_Inner in !rec_Outer>] : !cir.ptr<!rec_Outer> -> !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.copy %[[RT_MEMBER]] to %[[RETVAL_ADDR]] : !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.return + +// CIR-AFTER-LABEL: cir.func {{.*}} @_Z12test_agg_dotRK5OuterMS_5Inner( +// CIR-AFTER-SAME: %[[O_ARG:.*]]: !cir.ptr<!rec_Outer> +// CIR-AFTER-SAME: %[[P_ARG:.*]]: !s64i +// CIR-AFTER: %[[O_ADDR:.*]] = cir.alloca "o" {{.*}} init const : !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-AFTER: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} init : !cir.ptr<!s64i> +// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.store %[[O_ARG]], %[[O_ADDR]] : !cir.ptr<!rec_Outer>, !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-AFTER: cir.store %[[P_ARG]], %[[P_ADDR]] : !s64i, !cir.ptr<!s64i> +// CIR-AFTER: %[[O:.*]] = cir.load %[[O_ADDR]] : !cir.ptr<!cir.ptr<!rec_Outer>>, !cir.ptr<!rec_Outer> +// CIR-AFTER: %[[P:.*]] = cir.load{{.*}} %[[P_ADDR]] : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[O]] : !cir.ptr<!rec_Outer> -> !cir.ptr<!s8i> +// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[P]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i> +// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.copy %[[MEMBER_ADDR]] to %[[RETVAL_ADDR]] : !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.return + +// LLVM-LABEL: define {{.*}} @_Z12test_agg_dotRK5OuterMS_5Inner( +// LLVM: %[[RETVAL_ADDR:.*]] = alloca %struct.Inner +// LLVM: %[[O_ADDR:.*]] = alloca ptr +// LLVM: %[[P_ADDR:.*]] = alloca i64 +// LLVM: store ptr %[[O_ARG:.*]], ptr %[[O_ADDR]] +// LLVM: store i64 %[[P_ARG:.*]], ptr %[[P_ADDR]] +// LLVM: %[[O:.*]] = load ptr, ptr %[[O_ADDR]] +// LLVM: %[[P:.*]] = load i64, ptr %[[P_ADDR]] +// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[O]], i64 %[[P]] +// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RETVAL_ADDR]], ptr align 4 %[[RT_MEMBER]], i64 8, i1 false) + +// OGCG-LABEL: define {{.*}} @_Z12test_agg_dotRK5OuterMS_5Inner( +// OGCG: %[[RETVAL_ADDR:.*]] = alloca %struct.Inner +// OGCG: %[[O_ADDR:.*]] = alloca ptr +// OGCG: %[[P_ADDR:.*]] = alloca i64 +// OGCG: store ptr %[[O_ARG:.*]], ptr %[[O_ADDR]] +// OGCG: store i64 %[[P_ARG:.*]], ptr %[[P_ADDR]] +// OGCG: %[[O:.*]] = load ptr, ptr %[[O_ADDR]] +// OGCG: %[[P:.*]] = load i64, ptr %[[P_ADDR]] +// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[O]], i64 %[[P]] +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RETVAL_ADDR]], ptr align 4 %[[RT_MEMBER]], i64 8, i1 false) + +Inner test_agg_arrow(const Outer *o, Inner Outer::*p) { + return o->*p; +} + +// CIR-BEFORE-LABEL: cir.func {{.*}} @_Z14test_agg_arrowPK5OuterMS_5Inner( +// CIR-BEFORE-SAME: %[[O_ARG:.*]]: !cir.ptr<!rec_Outer> +// CIR-BEFORE-SAME: %[[P_ARG:.*]]: !cir.data_member<!rec_Inner in !rec_Outer> +// CIR-BEFORE: %[[O_ADDR:.*]] = cir.alloca "o" {{.*}} init const : !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-BEFORE: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} init : !cir.ptr<!cir.data_member<!rec_Inner in !rec_Outer>> +// CIR-BEFORE: %[[RETVAL_ADDR:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.store %[[O_ARG]], %[[O_ADDR]] +// CIR-BEFORE: cir.store %[[P_ARG]], %[[P_ADDR]] +// CIR-BEFORE: %[[O:.*]] = cir.load{{.*}} %[[O_ADDR]] +// CIR-BEFORE: %[[P:.*]] = cir.load{{.*}} %[[P_ADDR]] +// CIR-BEFORE: %[[RT_MEMBER:.*]] = cir.get_runtime_member %[[O]][%[[P]] : !cir.data_member<!rec_Inner in !rec_Outer>] : !cir.ptr<!rec_Outer> -> !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.copy %[[RT_MEMBER]] to %[[RETVAL_ADDR]] : !cir.ptr<!rec_Inner> +// CIR-BEFORE: cir.return + +// CIR-AFTER-LABEL: cir.func {{.*}} @_Z14test_agg_arrowPK5OuterMS_5Inner( +// CIR-AFTER-SAME: %[[O_ARG:.*]]: !cir.ptr<!rec_Outer> +// CIR-AFTER-SAME: %[[P_ARG:.*]]: !s64i +// CIR-AFTER: %[[O_ADDR:.*]] = cir.alloca "o" {{.*}} init const : !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-AFTER: %[[P_ADDR:.*]] = cir.alloca "p" {{.*}} init : !cir.ptr<!s64i> +// CIR-AFTER: %[[RETVAL_ADDR:.*]] = cir.alloca "__retval" {{.*}} : !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.store %[[O_ARG]], %[[O_ADDR]] : !cir.ptr<!rec_Outer>, !cir.ptr<!cir.ptr<!rec_Outer>> +// CIR-AFTER: cir.store %[[P_ARG]], %[[P_ADDR]] : !s64i, !cir.ptr<!s64i> +// CIR-AFTER: %[[O:.*]] = cir.load{{.*}} %[[O_ADDR]] : !cir.ptr<!cir.ptr<!rec_Outer>>, !cir.ptr<!rec_Outer> +// CIR-AFTER: %[[P:.*]] = cir.load{{.*}} %[[P_ADDR]] : !cir.ptr<!s64i>, !s64i +// CIR-AFTER: %[[BYTE_PTR:.*]] = cir.cast bitcast %[[O]] : !cir.ptr<!rec_Outer> -> !cir.ptr<!s8i> +// CIR-AFTER: %[[BYTE_PTR_STRIDE:.*]] = cir.ptr_stride %[[BYTE_PTR]], %[[P]] : (!cir.ptr<!s8i>, !s64i) -> !cir.ptr<!s8i> +// CIR-AFTER: %[[MEMBER_ADDR:.*]] = cir.cast bitcast %[[BYTE_PTR_STRIDE]] : !cir.ptr<!s8i> -> !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.copy %[[MEMBER_ADDR]] to %[[RETVAL_ADDR]] : !cir.ptr<!rec_Inner> +// CIR-AFTER: cir.return + +// LLVM-LABEL: define {{.*}} @_Z14test_agg_arrowPK5OuterMS_5Inner( +// LLVM: %[[RETVAL_ADDR:.*]] = alloca %struct.Inner +// LLVM: %[[O_ADDR:.*]] = alloca ptr +// LLVM: %[[P_ADDR:.*]] = alloca i64 +// LLVM: store ptr %[[O_ARG:.*]], ptr %[[O_ADDR]] +// LLVM: store i64 %[[P_ARG:.*]], ptr %[[P_ADDR]] +// LLVM: %[[O:.*]] = load ptr, ptr %[[O_ADDR]] +// LLVM: %[[P:.*]] = load i64, ptr %[[P_ADDR]] +// LLVM: %[[RT_MEMBER:.*]] = getelementptr i8, ptr %[[O]], i64 %[[P]] +// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RETVAL_ADDR]], ptr align 4 %[[RT_MEMBER]], i64 8, i1 false) + +// OGCG-LABEL: define {{.*}} @_Z14test_agg_arrowPK5OuterMS_5Inner( +// OGCG: %[[RETVAL_ADDR:.*]] = alloca %struct.Inner +// OGCG: %[[O_ADDR:.*]] = alloca ptr +// OGCG: %[[P_ADDR:.*]] = alloca i64 +// OGCG: store ptr %[[O_ARG:.*]], ptr %[[O_ADDR]] +// OGCG: store i64 %[[P_ARG:.*]], ptr %[[P_ADDR]] +// OGCG: %[[O:.*]] = load ptr, ptr %[[O_ADDR]] +// OGCG: %[[P:.*]] = load i64, ptr %[[P_ADDR]] +// OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[O]], i64 %[[P]] +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RETVAL_ADDR]], ptr align 4 %[[RT_MEMBER]], i64 8, i1 false) + + >From f992732dfa99c04fbd30306ff024f751e68b3b6c Mon Sep 17 00:00:00 2001 From: amanmaurya92 <[email protected]> Date: Wed, 9 Sep 2026 13:10:22 +0530 Subject: [PATCH 2/2] [CIR] Address review feedback on pointer-to-data-member for aggregates - Use errorUnsupported instead of errorNYI in AggExprEmitter - Clean up trailing blank lines in pointer-to-data-member test --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 3 +-- clang/test/CIR/CodeGen/pointer-to-data-member.cpp | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 4f59b3004094e..869f2d94a0a3e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -430,8 +430,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { if (e->getOpcode() == BO_PtrMemD || e->getOpcode() == BO_PtrMemI) VisitPointerToDataMemberBinaryOperator(e); else - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitBinaryOperator"); + cgf.cgm.errorUnsupported(e, "aggregate binary expression"); } void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *e) { LValue lv = cgf.emitPointerToDataMemberBinaryExpr(e); diff --git a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp index 16d16c45fca70..15a60b93f6bd1 100644 --- a/clang/test/CIR/CodeGen/pointer-to-data-member.cpp +++ b/clang/test/CIR/CodeGen/pointer-to-data-member.cpp @@ -601,5 +601,3 @@ Inner test_agg_arrow(const Outer *o, Inner Outer::*p) { // OGCG: %[[P:.*]] = load i64, ptr %[[P_ADDR]] // OGCG: %[[RT_MEMBER:.*]] = getelementptr inbounds i8, ptr %[[O]], i64 %[[P]] // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[RETVAL_ADDR]], ptr align 4 %[[RT_MEMBER]], i64 8, i1 false) - - _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
