Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2769,6 +2769,8 @@ LValue CIRGenFunction::emitLValue(const Expr *E) {
return emitStmtExprLValue(cast<StmtExpr>(E));
case Expr::ChooseExprClass:
return emitLValue(cast<ChooseExpr>(E)->getChosenSubExpr());
case Expr::CXXTypeidExprClass:
return emitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
}

llvm_unreachable("NYI");
Expand Down Expand Up @@ -3489,3 +3491,21 @@ RValue CIRGenFunction::emitPseudoObjectRValue(const PseudoObjectExpr *expr,
LValue CIRGenFunction::emitPseudoObjectLValue(const PseudoObjectExpr *expr) {
return emitPseudoObjectExpr(*this, expr, true, AggValueSlot::ignored()).lv;
}

LValue CIRGenFunction::emitCXXTypeidLValue(const CXXTypeidExpr *E) {
// Emit the typeid expression, which returns a !u8i pointer to the type_info
// object.
mlir::Value typeInfoPtr = emitCXXTypeidExpr(E);

// Cast the !u8i pointer to a pointer to the actual type_info type.
auto typeInfoTy = convertTypeForMem(E->getType());
auto typeInfoPtrTy = builder.getPointerTo(typeInfoTy);
typeInfoPtr = builder.createBitcast(getLoc(E->getSourceRange()), typeInfoPtr,
typeInfoPtrTy);

// Create an LValue from the pointer with natural alignment.
Address addr(typeInfoPtr, typeInfoTy,
getContext().getTypeAlignInChars(E->getType()));

return makeAddrLValue(addr, E->getType(), AlignmentSource::Decl);
}
51 changes: 51 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1809,3 +1809,54 @@ 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());

// 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);

// The RTTI descriptor is a GlobalViewAttr. Extract the symbol and look up
// the GlobalOp to get its symbol type, then create a GetGlobalOp.
auto globalView = mlir::cast<cir::GlobalViewAttr>(typeInfo);
auto *globalOp = mlir::SymbolTable::lookupSymbolIn(CGM.getModule(),
globalView.getSymbol());
assert(globalOp && "RTTI global not found");
auto global = mlir::cast<cir::GlobalOp>(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());
}

// 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())) {
// TODO: Implement vtable lookup for polymorphic types.
// This requires emitting code similar to dynamic_cast that looks up the
// type_info pointer from the vtable.
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);

auto globalView = mlir::cast<cir::GlobalViewAttr>(typeInfo);
auto *globalOp = mlir::SymbolTable::lookupSymbolIn(CGM.getModule(),
globalView.getSymbol());
assert(globalOp && "RTTI global not found");
auto global = mlir::cast<cir::GlobalOp>(globalOp);

auto ptrTy = builder.getPointerTo(global.getSymType());
return cir::GetGlobalOp::create(builder, loc, ptrTy, globalView.getSymbol());
}
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
119 changes: 119 additions & 0 deletions clang/test/CIR/CodeGen/typeid-lvalue.cpp
Original file line number Diff line number Diff line change
@@ -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<unsigned long long>(__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)
}