https://github.com/zwuis updated https://github.com/llvm/llvm-project/pull/208470
>From 2603e1a3f88dfabf5d2e2794274b308a2bcceebc Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <[email protected]> Date: Thu, 9 Jul 2026 22:15:15 +0800 Subject: [PATCH 1/2] Evaluate `typeid` operands which are the most derived objects --- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 19 +-- clang/lib/CodeGen/CGExprCXX.cpp | 22 +-- .../CIR/CodeGenCXX/typeid-most-derived.cpp | 134 ++++++++++++++++++ clang/test/CodeGenCXX/typeid-most-derived.cpp | 13 ++ 4 files changed, 169 insertions(+), 19 deletions(-) create mode 100644 clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index df60005d77259..0f0c5e6be13e9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -1916,9 +1916,8 @@ mlir::Value CIRGenFunction::emitDynamicCast(Address thisAddr, destCirTy, isRefCast, thisAddr); } -static mlir::Value emitCXXTypeidFromVTable(CIRGenFunction &cgf, const Expr *e, - mlir::Type typeInfoPtrTy, - bool hasNullCheck) { +static Address emitCXXTypeidOperand(CIRGenFunction &cgf, const Expr *e, + bool hasNullCheck) { Address thisPtr = cgf.emitLValue(e).getAddress(); QualType srcType = e->getType(); @@ -1940,7 +1939,7 @@ static mlir::Value emitCXXTypeidFromVTable(CIRGenFunction &cgf, const Expr *e, }); } - return cgf.cgm.getCXXABI().emitTypeid(cgf, srcType, thisPtr, typeInfoPtrTy); + return thisPtr; } mlir::Value CIRGenFunction::emitCXXTypeidExpr(const CXXTypeidExpr *e) { @@ -1958,11 +1957,13 @@ mlir::Value CIRGenFunction::emitCXXTypeidExpr(const CXXTypeidExpr *e) { // polymorphic class type, the result refers to a std::type_info object // representing the type of the most derived object (that is, the dynamic // type) to which the glvalue refers. - // If the operand is already most derived object, no need to look up vtable. - if (!e->isTypeOperand() && e->isPotentiallyEvaluated() && - !e->isMostDerived(getContext())) - return emitCXXTypeidFromVTable(*this, e->getExprOperand(), resultType, - e->hasNullCheck()); + if (!e->isTypeOperand() && e->isPotentiallyEvaluated()) { + Address thisPtr = + emitCXXTypeidOperand(*this, e->getExprOperand(), e->hasNullCheck()); + if (!e->isMostDerived(getContext())) + return cgm.getCXXABI().emitTypeid(*this, ty, thisPtr, resultType); + // If the operand is already most derived object, no need to look up vtable. + } auto typeInfo = cast<cir::GlobalViewAttr>(cgm.getAddrOfRTTIDescriptor(loc, ty)); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index ebbc0addfed2c..ec4ae54354623 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -2173,9 +2173,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { } } -static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, - llvm::Type *StdTypeInfoPtrTy, - bool HasNullCheck) { +static Address EmitTypeidOperand(CodeGenFunction &CGF, const Expr *E, + bool HasNullCheck) { // Get the vtable pointer. Address ThisPtr = CGF.EmitLValue(E).getAddress(); @@ -2205,8 +2204,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, CGF.EmitBlock(EndBlock); } - return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr, - StdTypeInfoPtrTy); + return ThisPtr; } llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { @@ -2230,17 +2228,21 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { return MaybeASCast(TypeInfo); } + const Expr *Operand = E->getExprOperand(); + QualType OperandTy = Operand->getType(); + // C++ [expr.typeid]p2: // When typeid is applied to a glvalue expression whose type is a // polymorphic class type, the result refers to a std::type_info object // representing the type of the most derived object (that is, the dynamic // type) to which the glvalue refers. - // If the operand is already most derived object, no need to look up vtable. - if (E->isPotentiallyEvaluated() && !E->isMostDerived(getContext())) - return EmitTypeidFromVTable(*this, E->getExprOperand(), PtrTy, - E->hasNullCheck()); + if (E->isPotentiallyEvaluated()) { + Address ThisPtr = EmitTypeidOperand(*this, Operand, E->hasNullCheck()); + if (!E->isMostDerived(getContext())) + return CGM.getCXXABI().EmitTypeid(*this, OperandTy, ThisPtr, PtrTy); + // If the operand is already most derived object, no need to look up vtable. + } - QualType OperandTy = E->getExprOperand()->getType(); return MaybeASCast(CGM.GetAddrOfRTTIDescriptor(OperandTy)); } diff --git a/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp b/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp new file mode 100644 index 0000000000000..369a0e4e3ab7a --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp @@ -0,0 +1,134 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir +// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR +// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR +// RUN: %clang_cc1 %s -triple %itanium_abi_triple -Wno-unused-value -std=c++11 -fclangir -emit-llvm -o - -std=c++11 | FileCheck %s --check-prefixes=CIR-TO-LLVM +// RUN: %clang_cc1 %s -triple %itanium_abi_triple -Wno-unused-value -std=c++11 -emit-llvm -o - -std=c++11 | FileCheck %s --check-prefixes=LLVM + +// FIXME: CIR-TO-LLVM output is incorrect. It should be same as LLVM output. + +namespace std { + class type_info {}; +} + +struct Base { + virtual int foo() { return 42; } + virtual ~Base(); +}; + +struct NonFinal : Base {}; +struct Final final : Base { + int foo() override { return 84; } +}; + +void func(); + +// Most derived +void base_by_value(Base b) { typeid(b); } +// CIR-LABEL: cir.func {{.*}}@_Z13base_by_value4Base +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z13base_by_value4Base +// LLVM-NOT: getelementptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z13base_by_value4Base +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void + +// Most derived +void final_ref(Final &f) { typeid(f); } +// CIR-LABEL: cir.func {{.*}}@_Z9final_refR5Final +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z9final_refR5Final +// LLVM-NOT: getelementptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z9final_refR5Final +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void + +// Most derived +void final_deref(Final *f) { typeid(*f); } +// CIR-LABEL: cir.func {{.*}}@_Z11final_derefP5Final +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.cmp +// CIR-NEXT: cir.if +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z11final_derefP5Final +// LLVM-NOT: getelementptr +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 +// LLVM-NOT: getelementptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z11final_derefP5Final +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: icmp eq {{.*}}, null +// CIR-TO-LLVM-NEXT: br i1 +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void + +// Most derived +void should_evaluate(Final &f) { typeid(func(), f); } +// CIR-LABEL: cir.func {{.*}}@_Z15should_evaluateR5Final +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.call @_Z4funcv +// CIR-NOT: cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z15should_evaluateR5Final +// LLVM-NOT: getelementptr +// LLVM: call void @_Z4funcv() +// LLVM-NOT: getelementptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z15should_evaluateR5Final +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: call void @_Z4funcv() +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void + +// Not most derived +void base_ref(Base &b) { typeid(b); } +// CIR-LABEL: cir.func {{.*}}@_Z8base_refR4Base +// CIR : cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z8base_refR4Base +// LLVM: getelementptr inbounds ptr, ptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z8base_refR4Base +// CIR-TO-LLVM: getelementptr ptr, ptr +// CIR-TO-LLVM: ret void + +// Not most derived +void base_deref(Base *b) { typeid(*b); } +// CIR-LABEL: cir.func {{.*}}@_Z10base_derefP4Base +// CIR : cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z10base_derefP4Base +// LLVM: getelementptr inbounds ptr, ptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z10base_derefP4Base +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void + +// Not most derived +void nonfinal_ref(NonFinal &d) { typeid(d); } +// CIR-LABEL: cir.func {{.*}}@_Z12nonfinal_refR8NonFinal +// CIR : cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z12nonfinal_refR8NonFinal +// LLVM: getelementptr inbounds ptr, ptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z12nonfinal_refR8NonFinal +// CIR-TO-LLVM: getelementptr ptr, ptr +// CIR-TO-LLVM: ret void + +// Not most derived +void nonfinal_deref(NonFinal *d) { typeid(*d); } +// CIR-LABEL: cir.func {{.*}}@_Z14nonfinal_derefP8NonFinal +// CIR : cir.vtable.get_vptr +// CIR: cir.return +// LLVM-LABEL: define {{.*}}void @_Z14nonfinal_derefP8NonFinal +// LLVM: getelementptr inbounds ptr, ptr +// LLVM: ret void +// CIR-TO-LLVM-LABEL: define {{.*}}void @_Z14nonfinal_derefP8NonFinal +// CIR-TO-LLVM-NOT: getelementptr +// CIR-TO-LLVM: ret void diff --git a/clang/test/CodeGenCXX/typeid-most-derived.cpp b/clang/test/CodeGenCXX/typeid-most-derived.cpp index 2b6bb850ff415..99c743acfcaaf 100644 --- a/clang/test/CodeGenCXX/typeid-most-derived.cpp +++ b/clang/test/CodeGenCXX/typeid-most-derived.cpp @@ -14,6 +14,8 @@ struct Final final : Base { int foo() override { return 84; } }; +void func(); + // Most derived void base_by_value(Base b) { typeid(b); } // CHECK-LABEL: define {{.*}}void @_Z13base_by_value4Base @@ -30,6 +32,17 @@ void final_ref(Final &f) { typeid(f); } void final_deref(Final *f) { typeid(*f); } // CHECK-LABEL: define {{.*}}void @_Z11final_derefP5Final // CHECK-NOT: %vtable +// CHECK: icmp eq {{.*}}, null +// CHECK-NEXT: br i1 +// CHECK-NOT: %vtable +// CHECK: ret void + +// Most derived +void should_evaluate(Final &f) { typeid(func(), f); } +// CHECK-LABEL: define {{.*}}void @_Z15should_evaluateR5Final +// CHECK-NOT: %vtable +// CHECK: call void @_Z4funcv() +// CHECK-NOT: %vtable // CHECK: ret void // Not most derived >From 8c34aeafb8d0f3a72228b4bc31703a66cef08119 Mon Sep 17 00:00:00 2001 From: Yanzuo Liu <[email protected]> Date: Thu, 9 Jul 2026 22:32:44 +0800 Subject: [PATCH 2/2] fix `// CHECK` labels --- clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp b/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp index 369a0e4e3ab7a..214eb8165d2cc 100644 --- a/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp +++ b/clang/test/CIR/CodeGenCXX/typeid-most-derived.cpp @@ -88,7 +88,7 @@ void should_evaluate(Final &f) { typeid(func(), f); } // Not most derived void base_ref(Base &b) { typeid(b); } // CIR-LABEL: cir.func {{.*}}@_Z8base_refR4Base -// CIR : cir.vtable.get_vptr +// CIR: cir.vtable.get_vptr // CIR: cir.return // LLVM-LABEL: define {{.*}}void @_Z8base_refR4Base // LLVM: getelementptr inbounds ptr, ptr @@ -100,7 +100,7 @@ void base_ref(Base &b) { typeid(b); } // Not most derived void base_deref(Base *b) { typeid(*b); } // CIR-LABEL: cir.func {{.*}}@_Z10base_derefP4Base -// CIR : cir.vtable.get_vptr +// CIR: cir.vtable.get_vptr // CIR: cir.return // LLVM-LABEL: define {{.*}}void @_Z10base_derefP4Base // LLVM: getelementptr inbounds ptr, ptr @@ -112,7 +112,7 @@ void base_deref(Base *b) { typeid(*b); } // Not most derived void nonfinal_ref(NonFinal &d) { typeid(d); } // CIR-LABEL: cir.func {{.*}}@_Z12nonfinal_refR8NonFinal -// CIR : cir.vtable.get_vptr +// CIR: cir.vtable.get_vptr // CIR: cir.return // LLVM-LABEL: define {{.*}}void @_Z12nonfinal_refR8NonFinal // LLVM: getelementptr inbounds ptr, ptr @@ -124,7 +124,7 @@ void nonfinal_ref(NonFinal &d) { typeid(d); } // Not most derived void nonfinal_deref(NonFinal *d) { typeid(*d); } // CIR-LABEL: cir.func {{.*}}@_Z14nonfinal_derefP8NonFinal -// CIR : cir.vtable.get_vptr +// CIR: cir.vtable.get_vptr // CIR: cir.return // LLVM-LABEL: define {{.*}}void @_Z14nonfinal_derefP8NonFinal // LLVM: getelementptr inbounds ptr, ptr _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
