Skip to content

Commit d2cc038

Browse files
committed
[CIR] Add support for typeid l-value emission
Implements support for typeid expressions as l-values, matching traditional CodeGen behavior. The typeid operator returns a const reference to std::type_info, which requires creating an l-value from the RTTI descriptor. Key changes: - CIRGenExprCXX: Add emitCXXTypeidExpr to emit GetGlobalOp for RTTI descriptors - CIRGenExpr: Add emitCXXTypeidLValue to create l-value from typeid expression - Refactored duplicate RTTI lookup code into helper lambda - Added comprehensive tests covering type operands, expression operands, and polymorphic types Tests include CIR, LLVM (via CIR), and OGCG (Original CodeGen) output verification. Note: Polymorphic typeid (vtable lookup) is not yet implemented and guarded with llvm_unreachable. ghstack-source-id: be0adc5 Pull-Request: #2001
1 parent c267261 commit d2cc038

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,3 +1809,48 @@ mlir::Value CIRGenFunction::emitDynamicCast(Address ThisAddr,
18091809
return CGM.getCXXABI().emitDynamicCast(*this, loc, srcRecordTy, destRecordTy,
18101810
destCirTy, isRefCast, ThisAddr);
18111811
}
1812+
1813+
mlir::Value CIRGenFunction::emitCXXTypeidExpr(const CXXTypeidExpr *E) {
1814+
auto loc = getLoc(E->getSourceRange());
1815+
1816+
// Helper to create a GetGlobalOp from an RTTI descriptor attribute.
1817+
auto createGetGlobalForRTTI = [&](mlir::Attribute typeInfo) -> mlir::Value {
1818+
auto globalView = mlir::cast<cir::GlobalViewAttr>(typeInfo);
1819+
auto *globalOp = mlir::SymbolTable::lookupSymbolIn(CGM.getModule(),
1820+
globalView.getSymbol());
1821+
assert(globalOp && "RTTI global not found");
1822+
auto global = mlir::cast<cir::GlobalOp>(globalOp);
1823+
1824+
// The result type of GetGlobalOp is a pointer to the global's symbol type.
1825+
auto ptrTy = builder.getPointerTo(global.getSymType());
1826+
return cir::GetGlobalOp::create(builder, loc, ptrTy,
1827+
globalView.getSymbol());
1828+
};
1829+
1830+
// If this is a type operand, just get the address of the RTTI descriptor.
1831+
if (E->isTypeOperand()) {
1832+
QualType operandTy = E->getTypeOperand(getContext());
1833+
mlir::Attribute typeInfo = CGM.getAddrOfRTTIDescriptor(loc, operandTy);
1834+
return createGetGlobalForRTTI(typeInfo);
1835+
}
1836+
1837+
// C++ [expr.typeid]p2:
1838+
// When typeid is applied to a glvalue expression whose type is a
1839+
// polymorphic class type, the result refers to a std::type_info object
1840+
// representing the type of the most derived object (that is, the dynamic
1841+
// type) to which the glvalue refers.
1842+
1843+
// If the operand is already the most derived object, no need to look up
1844+
// vtable.
1845+
if (E->isPotentiallyEvaluated() && !E->isMostDerived(getContext())) {
1846+
// This requires emitting code similar to dynamic_cast that looks up the
1847+
// type_info pointer from the vtable. Note that this path also needs to
1848+
// handle null checking when E->hasNullCheck() is true.
1849+
llvm_unreachable("NYI: typeid with polymorphic types (vtable lookup)");
1850+
}
1851+
1852+
// For non-polymorphic types, just return the static RTTI descriptor.
1853+
QualType operandTy = E->getExprOperand()->getType();
1854+
mlir::Attribute typeInfo = CGM.getAddrOfRTTIDescriptor(loc, operandTy);
1855+
return createGetGlobalForRTTI(typeInfo);
1856+
}

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,12 @@ class CIRGenFunction : public CIRGenTypeCache {
21342134

21352135
mlir::Value emitDynamicCast(Address ThisAddr, const CXXDynamicCastExpr *DCE);
21362136

2137+
/// Emit the operand of a typeid expression as an mlir::Value.
2138+
mlir::Value emitCXXTypeidExpr(const CXXTypeidExpr *E);
2139+
2140+
/// Emit a typeid expression as an l-value.
2141+
LValue emitCXXTypeidLValue(const CXXTypeidExpr *E);
2142+
21372143
/// Emits try/catch information for the current EH stack.
21382144
void emitEHResumeBlock(bool isCleanup, mlir::Block *ehResumeBlock,
21392145
mlir::Location loc);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
3+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM
5+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.og.ll
6+
// RUN: FileCheck --input-file=%t.og.ll %s --check-prefix=OGCG
7+
8+
namespace std {
9+
class type_info {
10+
public:
11+
virtual ~type_info();
12+
const char* name() const { return __name; }
13+
bool operator==(const type_info& __arg) const {
14+
return __name == __arg.__name;
15+
}
16+
17+
bool operator!=(const type_info& __arg) const {
18+
return !operator==(__arg);
19+
}
20+
21+
bool before(const type_info& __arg) const {
22+
return __name < __arg.__name;
23+
}
24+
25+
unsigned long hash_code() const {
26+
return reinterpret_cast<unsigned long long>(__name);
27+
}
28+
protected:
29+
const char *__name;
30+
};
31+
}
32+
33+
// Test 1: Non-polymorphic type - simple struct
34+
struct Simple {
35+
int x;
36+
};
37+
38+
void test_simple_type(const std::type_info*& out) {
39+
// CIR-LABEL: cir.func {{.*}}@_Z16test_simple_type
40+
out = &typeid(Simple);
41+
// CIR: cir.get_global @_ZTI6Simple
42+
43+
// LLVM-LABEL: define {{.*}}@_Z16test_simple_type
44+
// LLVM: store ptr @_ZTI6Simple
45+
46+
// OGCG-LABEL: define {{.*}}@_Z16test_simple_type
47+
// OGCG: store ptr @_ZTI6Simple
48+
}
49+
50+
// Test 2: Non-polymorphic type - expression operand
51+
void test_expression_operand(const std::type_info*& out) {
52+
// CIR-LABEL: cir.func {{.*}}@_Z23test_expression_operand
53+
Simple s;
54+
out = &typeid(s);
55+
// CIR: cir.get_global @_ZTI6Simple
56+
57+
// LLVM-LABEL: define {{.*}}@_Z23test_expression_operand
58+
// LLVM: store ptr @_ZTI6Simple
59+
60+
// OGCG-LABEL: define {{.*}}@_Z23test_expression_operand
61+
// OGCG: store ptr @_ZTI6Simple
62+
}
63+
64+
// Test 3: Polymorphic base class
65+
struct Base {
66+
virtual ~Base() = default;
67+
};
68+
69+
struct Derived : Base {
70+
int y;
71+
};
72+
73+
// Test with non-polymorphic lookup (type operand)
74+
void test_polymorphic_type(const std::type_info*& out) {
75+
// CIR-LABEL: cir.func {{.*}}@_Z21test_polymorphic_type
76+
out = &typeid(Base);
77+
// CIR: cir.get_global @_ZTI4Base
78+
79+
// LLVM-LABEL: define {{.*}}@_Z21test_polymorphic_type
80+
// LLVM: store ptr @_ZTI4Base
81+
82+
// OGCG-LABEL: define {{.*}}@_Z21test_polymorphic_type
83+
// OGCG: store ptr @_ZTI4Base
84+
}
85+
86+
// Test 4: Built-in type
87+
void test_builtin_type(const std::type_info*& out) {
88+
// CIR-LABEL: cir.func {{.*}}@_Z17test_builtin_type
89+
out = &typeid(int);
90+
// CIR: cir.get_global @_ZTIi
91+
92+
// LLVM-LABEL: define {{.*}}@_Z17test_builtin_type
93+
// LLVM: store ptr @_ZTIi
94+
95+
// OGCG-LABEL: define {{.*}}@_Z17test_builtin_type
96+
// OGCG: store ptr @_ZTIi
97+
}
98+
99+
// Test 5: Passing typeid as function argument
100+
void consume_type_info(const std::type_info& ti) {
101+
// CIR-LABEL: cir.func {{.*}}@_Z17consume_type_info
102+
103+
// LLVM-LABEL: define {{.*}}@_Z17consume_type_info
104+
105+
// OGCG-LABEL: define {{.*}}@_Z17consume_type_info
106+
}
107+
108+
void test_function_argument() {
109+
// CIR-LABEL: cir.func {{.*}}@_Z22test_function_argumentv
110+
consume_type_info(typeid(int));
111+
// CIR: cir.get_global @_ZTIi
112+
// CIR: cir.call @_Z17consume_type_info
113+
114+
// LLVM-LABEL: define {{.*}}@_Z22test_function_argumentv
115+
// LLVM: call {{.*}}@_Z17consume_type_infoRKSt9type_info(ptr @_ZTIi)
116+
117+
// OGCG-LABEL: define {{.*}}@_Z22test_function_argumentv
118+
// OGCG: call {{.*}}@_Z17consume_type_infoRKSt9type_info(ptr {{.*}}@_ZTIi)
119+
}

0 commit comments

Comments
 (0)