From 7b7cb2f335af639db338dfd1b86f9301d0d7b516 Mon Sep 17 00:00:00 2001 From: Nathan Lanza Date: Fri, 21 Nov 2025 21:44:50 -0800 Subject: [PATCH] Update [ghstack-poisoned] --- clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 45 +++++++++ clang/lib/CIR/CodeGen/CIRGenFunction.h | 6 ++ clang/test/CIR/CodeGen/typeid-lvalue.cpp | 119 +++++++++++++++++++++++ 3 files changed, 170 insertions(+) create mode 100644 clang/test/CIR/CodeGen/typeid-lvalue.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 5f9f2993271a..2852036106e1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -1809,3 +1809,48 @@ mlir::Value CIRGenFunction::emitDynamicCast(Address ThisAddr, return CGM.getCXXABI().emitDynamicCast(*this, loc, srcRecordTy, destRecordTy, destCirTy, isRefCast, ThisAddr); } + +mlir::Value CIRGenFunction::emitCXXTypeidExpr(const CXXTypeidExpr *E) { + auto loc = getLoc(E->getSourceRange()); + + // Helper to create a GetGlobalOp from an RTTI descriptor attribute. + auto createGetGlobalForRTTI = [&](mlir::Attribute typeInfo) -> mlir::Value { + auto globalView = mlir::cast(typeInfo); + auto *globalOp = mlir::SymbolTable::lookupSymbolIn(CGM.getModule(), + globalView.getSymbol()); + assert(globalOp && "RTTI global not found"); + auto global = mlir::cast(globalOp); + + // The result type of GetGlobalOp is a pointer to the global's symbol type. + auto ptrTy = builder.getPointerTo(global.getSymType()); + return cir::GetGlobalOp::create(builder, loc, ptrTy, + globalView.getSymbol()); + }; + + // If this is a type operand, just get the address of the RTTI descriptor. + if (E->isTypeOperand()) { + QualType operandTy = E->getTypeOperand(getContext()); + mlir::Attribute typeInfo = CGM.getAddrOfRTTIDescriptor(loc, operandTy); + return createGetGlobalForRTTI(typeInfo); + } + + // 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 the most derived object, no need to look up + // vtable. + if (E->isPotentiallyEvaluated() && !E->isMostDerived(getContext())) { + // This requires emitting code similar to dynamic_cast that looks up the + // type_info pointer from the vtable. Note that this path also needs to + // handle null checking when E->hasNullCheck() is true. + llvm_unreachable("NYI: typeid with polymorphic types (vtable lookup)"); + } + + // For non-polymorphic types, just return the static RTTI descriptor. + QualType operandTy = E->getExprOperand()->getType(); + mlir::Attribute typeInfo = CGM.getAddrOfRTTIDescriptor(loc, operandTy); + return createGetGlobalForRTTI(typeInfo); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 2d62cbce0a87..670b90987fe1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2134,6 +2134,12 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitDynamicCast(Address ThisAddr, const CXXDynamicCastExpr *DCE); + /// Emit the operand of a typeid expression as an mlir::Value. + mlir::Value emitCXXTypeidExpr(const CXXTypeidExpr *E); + + /// Emit a typeid expression as an l-value. + LValue emitCXXTypeidLValue(const CXXTypeidExpr *E); + /// Emits try/catch information for the current EH stack. void emitEHResumeBlock(bool isCleanup, mlir::Block *ehResumeBlock, mlir::Location loc); diff --git a/clang/test/CIR/CodeGen/typeid-lvalue.cpp b/clang/test/CIR/CodeGen/typeid-lvalue.cpp new file mode 100644 index 000000000000..45e6e662b66e --- /dev/null +++ b/clang/test/CIR/CodeGen/typeid-lvalue.cpp @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.og.ll +// RUN: FileCheck --input-file=%t.og.ll %s --check-prefix=OGCG + +namespace std { + class type_info { + public: + virtual ~type_info(); + const char* name() const { return __name; } + bool operator==(const type_info& __arg) const { + return __name == __arg.__name; + } + + bool operator!=(const type_info& __arg) const { + return !operator==(__arg); + } + + bool before(const type_info& __arg) const { + return __name < __arg.__name; + } + + unsigned long hash_code() const { + return reinterpret_cast(__name); + } + protected: + const char *__name; + }; +} + +// Test 1: Non-polymorphic type - simple struct +struct Simple { + int x; +}; + +void test_simple_type(const std::type_info*& out) { + // CIR-LABEL: cir.func {{.*}}@_Z16test_simple_type + out = &typeid(Simple); + // CIR: cir.get_global @_ZTI6Simple + + // LLVM-LABEL: define {{.*}}@_Z16test_simple_type + // LLVM: store ptr @_ZTI6Simple + + // OGCG-LABEL: define {{.*}}@_Z16test_simple_type + // OGCG: store ptr @_ZTI6Simple +} + +// Test 2: Non-polymorphic type - expression operand +void test_expression_operand(const std::type_info*& out) { + // CIR-LABEL: cir.func {{.*}}@_Z23test_expression_operand + Simple s; + out = &typeid(s); + // CIR: cir.get_global @_ZTI6Simple + + // LLVM-LABEL: define {{.*}}@_Z23test_expression_operand + // LLVM: store ptr @_ZTI6Simple + + // OGCG-LABEL: define {{.*}}@_Z23test_expression_operand + // OGCG: store ptr @_ZTI6Simple +} + +// Test 3: Polymorphic base class +struct Base { + virtual ~Base() = default; +}; + +struct Derived : Base { + int y; +}; + +// Test with non-polymorphic lookup (type operand) +void test_polymorphic_type(const std::type_info*& out) { + // CIR-LABEL: cir.func {{.*}}@_Z21test_polymorphic_type + out = &typeid(Base); + // CIR: cir.get_global @_ZTI4Base + + // LLVM-LABEL: define {{.*}}@_Z21test_polymorphic_type + // LLVM: store ptr @_ZTI4Base + + // OGCG-LABEL: define {{.*}}@_Z21test_polymorphic_type + // OGCG: store ptr @_ZTI4Base +} + +// Test 4: Built-in type +void test_builtin_type(const std::type_info*& out) { + // CIR-LABEL: cir.func {{.*}}@_Z17test_builtin_type + out = &typeid(int); + // CIR: cir.get_global @_ZTIi + + // LLVM-LABEL: define {{.*}}@_Z17test_builtin_type + // LLVM: store ptr @_ZTIi + + // OGCG-LABEL: define {{.*}}@_Z17test_builtin_type + // OGCG: store ptr @_ZTIi +} + +// Test 5: Passing typeid as function argument +void consume_type_info(const std::type_info& ti) { + // CIR-LABEL: cir.func {{.*}}@_Z17consume_type_info + + // LLVM-LABEL: define {{.*}}@_Z17consume_type_info + + // OGCG-LABEL: define {{.*}}@_Z17consume_type_info +} + +void test_function_argument() { + // CIR-LABEL: cir.func {{.*}}@_Z22test_function_argumentv + consume_type_info(typeid(int)); + // CIR: cir.get_global @_ZTIi + // CIR: cir.call @_Z17consume_type_info + + // LLVM-LABEL: define {{.*}}@_Z22test_function_argumentv + // LLVM: call {{.*}}@_Z17consume_type_infoRKSt9type_info(ptr @_ZTIi) + + // OGCG-LABEL: define {{.*}}@_Z22test_function_argumentv + // OGCG: call {{.*}}@_Z17consume_type_infoRKSt9type_info(ptr {{.*}}@_ZTIi) +}