Author: Erich Keane Date: 2026-03-05T06:07:13-08:00 New Revision: c186db874b9037a77829bce4ebf89bed46efdbb8
URL: https://github.com/llvm/llvm-project/commit/c186db874b9037a77829bce4ebf89bed46efdbb8 DIFF: https://github.com/llvm/llvm-project/commit/c186db874b9037a77829bce4ebf89bed46efdbb8.diff LOG: [CIR] Implement 'typeid' operator lowering (#184449) This patch adds typeid lowering, which uses a lot of the infrastructure from dynamic_cast. However, this adds a `get_type_info` operation that gets the type info out of a vtable pointer as well, which lets the offset be handled by the ABI specific lowering code. Added: clang/test/CIR/CodeGenCXX/Inputs/typeinfo clang/test/CIR/CodeGenCXX/typeid-cxx11.cpp clang/test/CIR/CodeGenCXX/typeid-should-throw.cpp clang/test/CIR/CodeGenCXX/typeid.cpp Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/lib/CIR/CodeGen/CIRGenCXXABI.h clang/lib/CIR/CodeGen/CIRGenCall.cpp clang/lib/CIR/CodeGen/CIRGenException.cpp clang/lib/CIR/CodeGen/CIRGenExpr.cpp clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp clang/lib/CIR/CodeGen/CIRGenFunction.cpp clang/lib/CIR/CodeGen/CIRGenFunction.h clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp clang/lib/CIR/CodeGen/CIRGenModule.cpp clang/lib/CIR/CodeGen/CIRGenModule.h clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e6c9aae03705f..5db68b44c2804 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2830,7 +2830,7 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ called. The `vptr` operand must be a `!cir.ptr<!cir.vptr>` value, which would - have been returned by a previous call to `cir.vatble.get_vptr`. The + have been returned by a previous call to `cir.vtable.get_vptr`. The `index` operand is an index of the virtual function in the vtable. The return type is a pointer-to-pointer to the function type. @@ -2862,6 +2862,46 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ }]; } +//===----------------------------------------------------------------------===// +// VTableGetTypeInfoOp +//===----------------------------------------------------------------------===// + +def CIR_VTableGetTypeInfoOp : CIR_Op<"vtable.get_type_info", [ + Pure +]> { + let summary = "Get the address of the type_info from the vtable"; + let description = [{ + The `vtable.get_type_info` operation retreives the address of the dynamic + type_info/rtti object from an object's vtable. This is an ABI independent + abstraction of this operation. + + The `vptr` operand must be a `!cir.vptr` value, which would have been + returned by a previous call to `cir.vtable.get_vptr`. + + The return type is a loadable pointer to a `type_info` struct. + + Example: + ```mlir + %5 = cir.vtable.get_vptr %2 : !cir.ptr<!rec_A> -> !cir.ptr<!cir.vptr> + %6 = cir.load align(8) %5 : !cir.ptr<!cir.vptr>, !cir.vptr + %7 = cir.vtable.get_type_info %6 : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> + %8 = cir.load align(8) %7 : !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>>, !cir.ptr<!rec_std3A3Atype_info> + + ``` + }]; + + let arguments = (ins Arg<CIR_VPtrType, "vptr", [MemRead]>:$vptr); + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $vptr attr-dict `:` qualified(type($vptr)) `->` qualified(type($result)) + }]; + + let hasLLVMLowering = false; + let hasCXXABILowering = true; +} + + //===----------------------------------------------------------------------===// // VTTAddrPointOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 04042597490a0..c59185f5a14b0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -169,6 +169,10 @@ class CIRGenCXXABI { getAddrOfCXXCatchHandlerType(mlir::Location loc, QualType ty, QualType catchHandlerType) = 0; virtual CatchTypeInfo getCatchAllTypeInfo(); + virtual bool shouldTypeidBeNullChecked(QualType srcTy) = 0; + virtual mlir::Value emitTypeid(CIRGenFunction &cgf, QualType srcTy, + Address thisPtr, mlir::Type typeInfoPtrTy) = 0; + virtual void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) = 0; /// Get the implicit (second) parameter that comes after the "this" pointer, /// or nullptr if there is isn't one. diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index c92296352db4e..157dc3fdd56fb 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -1270,7 +1270,8 @@ void CallArg::copyInto(CIRGenFunction &cgf, Address addr, mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, - ArrayRef<mlir::Value> args) { + ArrayRef<mlir::Value> args, + mlir::NamedAttrList attrs) { // TODO(cir): set the calling convention to this runtime call. assert(!cir::MissingFeatures::opFuncCallingConv()); @@ -1278,6 +1279,9 @@ mlir::Value CIRGenFunction::emitRuntimeCall(mlir::Location loc, assert(call->getNumResults() <= 1 && "runtime functions have at most 1 result"); + if (!attrs.empty()) + call->setAttrs(attrs); + if (call->getNumResults() == 0) return nullptr; diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index be90e19d03c76..d5e176e18a11e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -193,7 +193,7 @@ static llvm::StringRef getPersonalityFn(CIRGenModule &cgm, auto funcTy = cir::FuncType::get({}, i32Ty, /*isVarArg=*/true); cir::FuncOp personalityFn = cgm.createRuntimeFunction( - funcTy, personality.personalityFn, mlir::ArrayAttr(), /*isLocal=*/true); + funcTy, personality.personalityFn, {}, /*isLocal=*/true); return personalityFn.getSymName(); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index d0fa9234c73c3..51dc297e86d01 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -1490,8 +1490,7 @@ LValue CIRGenFunction::emitCastLValue(const CastExpr *e) { LValue lv = emitLValue(e->getSubExpr()); // Propagate the volatile qualifier to LValue, if exists in e. if (e->changesVolatileQualification()) - cgm.errorNYI(e->getSourceRange(), - "emitCastLValue: NoOp changes volatile qual"); + lv.getQuals() = e->getType().getQualifiers(); if (lv.isSimple()) { Address v = lv.getAddress(); if (v.isValid()) { @@ -2821,3 +2820,7 @@ bool CIRGenFunction::isLValueSuitableForInlineAtomic(LValue lv) { cgm.errorNYI("LValueSuitableForInlineAtomic LangOpts MSVolatile"); return false; } + +LValue CIRGenFunction::emitCXXTypeidLValue(const CXXTypeidExpr *e) { + return makeNaturalAlignAddrLValue(emitCXXTypeidExpr(e), e->getType()); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index f5f3655802915..d4f354d5dd94d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -386,9 +386,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXScalarValueInitExpr"); } - void VisitCXXTypeidExpr(CXXTypeidExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitCXXTypeidExpr"); - } + void VisitCXXTypeidExpr(CXXTypeidExpr *e) { emitAggLoadOfLValue(e); } void VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *e) { Visit(e->getSubExpr()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 56a7539a841d1..97f496c89ab0f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -1334,3 +1334,67 @@ mlir::Value CIRGenFunction::emitDynamicCast(Address thisAddr, return cgm.getCXXABI().emitDynamicCast(*this, loc, srcRecordTy, destRecordTy, destCirTy, isRefCast, thisAddr); } + +static mlir::Value emitCXXTypeidFromVTable(CIRGenFunction &cgf, const Expr *e, + mlir::Type typeInfoPtrTy, + bool hasNullCheck) { + Address thisPtr = cgf.emitLValue(e).getAddress(); + QualType srcType = e->getType(); + + // C++ [class.cdtor]p4: + // If the operand of typeid refers to the object under construction or + // destruction and the static type of the operand is neither the constructor + // or destructor’s class nor one of its bases, the behavior is undefined. + assert(!cir::MissingFeatures::sanitizers()); + + if (hasNullCheck && cgf.cgm.getCXXABI().shouldTypeidBeNullChecked(srcType)) { + mlir::Value isThisNull = + cgf.getBuilder().createPtrIsNull(thisPtr.getPointer()); + // We don't really care about the value, we just want to make sure the + // 'true' side calls bad-type-id. + cir::IfOp::create( + cgf.getBuilder(), cgf.getLoc(e->getSourceRange()), isThisNull, + /*withElseRegion=*/false, [&](mlir::OpBuilder &, mlir::Location loc) { + cgf.cgm.getCXXABI().emitBadTypeidCall(cgf, loc); + }); + } + + return cgf.cgm.getCXXABI().emitTypeid(cgf, srcType, thisPtr, typeInfoPtrTy); +} + +mlir::Value CIRGenFunction::emitCXXTypeidExpr(const CXXTypeidExpr *e) { + mlir::Location loc = getLoc(e->getSourceRange()); + mlir::Type resultType = cir::PointerType::get(convertType(e->getType())); + QualType ty = e->isTypeOperand() ? e->getTypeOperand(getContext()) + : e->getExprOperand()->getType(); + + // If the non-default global var address space is not default, we need to do + // an address-space cast here. + assert(!cir::MissingFeatures::addressSpace()); + + // 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->isTypeOperand() && e->isPotentiallyEvaluated() && + !e->isMostDerived(getContext())) + return emitCXXTypeidFromVTable(*this, e->getExprOperand(), resultType, + e->hasNullCheck()); + + auto typeInfo = + cast<cir::GlobalViewAttr>(cgm.getAddrOfRTTIDescriptor(loc, ty)); + // `getAddrOfRTTIDescriptor` lies to us and always gives us a uint8ptr as its + // type, however we need the value of the actual global to call the + // get-global-op, so look it up here. + auto typeInfoGlobal = + cast<cir::GlobalOp>(cgm.getGlobalValue(typeInfo.getSymbol().getValue())); + auto getTypeInfo = cir::GetGlobalOp::create( + builder, loc, builder.getPointerTo(typeInfoGlobal.getSymType()), + typeInfoGlobal.getSymName()); + // The ABI is just generating these sometimes as ptr to u8, but they are + // simply a representation of the type_info. So we have to cast this, if + // necessary (createBitcast is a noop if the types match). + return builder.createBitcast(getTypeInfo, resultType); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index e3dca9bc0f3c7..2a7ee75b42dea 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -1412,10 +1412,9 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { } // Handle typeid(T). - if (base.dyn_cast<TypeInfoLValue>()) { - cgm.errorNYI("ConstantLValueEmitter: typeid"); - return {}; - } + if (TypeInfoLValue typeInfo = base.dyn_cast<TypeInfoLValue>()) + return cast<cir::GlobalViewAttr>(cgm.getAddrOfRTTIDescriptor( + cgm.getBuilder().getUnknownLoc(), QualType(typeInfo.getType(), 0))); // Otherwise, it must be an expression. return Visit(base.get<const Expr *>()); @@ -1479,8 +1478,12 @@ ConstantLValue ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *e) { ConstantLValue ConstantLValueEmitter::VisitCXXTypeidExpr(const CXXTypeidExpr *e) { - cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: cxx typeid expr"); - return {}; + if (e->isTypeOperand()) + return cast<cir::GlobalViewAttr>( + cgm.getAddrOfRTTIDescriptor(cgm.getLoc(e->getSourceRange()), + e->getTypeOperand(cgm.getASTContext()))); + return cast<cir::GlobalViewAttr>(cgm.getAddrOfRTTIDescriptor( + cgm.getLoc(e->getSourceRange()), e->getExprOperand()->getType())); } ConstantLValue ConstantLValueEmitter::VisitMaterializeTemporaryExpr( diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index e10c6d44cd35e..c64630db08965 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1092,6 +1092,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { CXXDefaultArgExprScope scope(*this, dae); return emitLValue(dae->getExpr()); } + case Expr::CXXTypeidExprClass: + return emitCXXTypeidLValue(cast<CXXTypeidExpr>(e)); case Expr::ParenExprClass: return emitLValue(cast<ParenExpr>(e)->getSubExpr()); case Expr::GenericSelectionExprClass: diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 56bdcfd7f8906..539d7839d1dfe 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1464,6 +1464,8 @@ class CIRGenFunction : public CIRGenTypeCache { cir::CaseOpKind kind, bool buildingTopLevelCase); + LValue emitCXXTypeidLValue(const CXXTypeidExpr *e); + mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s, mlir::Type condType, bool buildingTopLevelCase); @@ -1601,6 +1603,7 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::LogicalResult emitDoStmt(const clang::DoStmt &s); + mlir::Value emitCXXTypeidExpr(const CXXTypeidExpr *e); mlir::Value emitDynamicCast(Address thisAddr, const CXXDynamicCastExpr *dce); /// Emit an expression as an initializer for an object (variable, field, etc.) @@ -1638,7 +1641,8 @@ class CIRGenFunction : public CIRGenTypeCache { void emitReturnOfRValue(mlir::Location loc, RValue rv, QualType ty); mlir::Value emitRuntimeCall(mlir::Location loc, cir::FuncOp callee, - llvm::ArrayRef<mlir::Value> args = {}); + llvm::ArrayRef<mlir::Value> args = {}, + mlir::NamedAttrList attrs = {}); void emitInvariantStart(CharUnits size, mlir::Value addr, mlir::Location loc); diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index f195b9325a41c..fb9054c9f3bde 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -137,6 +137,11 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { const CXXRecordDecl *unadjustedClass, const ReturnAdjustment &ra) override; + bool shouldTypeidBeNullChecked(QualType srcTy) override; + mlir::Value emitTypeid(CIRGenFunction &cgf, QualType SrcRecordTy, + Address thisPtr, mlir::Type StdTypeInfoPtrTy) override; + void emitBadTypeidCall(CIRGenFunction &cgf, mlir::Location loc) override; + mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty) override; @@ -997,13 +1002,13 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) { case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: - cgm.errorNYI("VTableClassNameForType: __array_type_info"); - break; + // abi::__array_type_info. + return "_ZTVN10__cxxabiv117__array_type_infoE"; case Type::FunctionNoProto: case Type::FunctionProto: - cgm.errorNYI("VTableClassNameForType: __function_type_info"); - break; + // abi::__function_type_info. + return "_ZTVN10__cxxabiv120__function_type_infoE"; case Type::Enum: return "_ZTVN10__cxxabiv116__enum_type_infoE"; @@ -1033,12 +1038,12 @@ const char *vTableClassNameForType(const CIRGenModule &cgm, const Type *ty) { case Type::ObjCObjectPointer: case Type::Pointer: - cgm.errorNYI("VTableClassNameForType: __pointer_type_info"); - break; + // abi::__pointer_type_info. + return "_ZTVN10__cxxabiv119__pointer_type_infoE"; case Type::MemberPointer: - cgm.errorNYI("VTableClassNameForType: __pointer_to_member_type_info"); - break; + // abi::__pointer_to_member_type_info. + return "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE"; case Type::HLSLAttributedResource: case Type::HLSLInlineSpirv: @@ -1550,6 +1555,48 @@ mlir::Attribute CIRGenItaniumRTTIBuilder::buildTypeInfo( return builder.getGlobalViewAttr(builder.getUInt8PtrTy(), gv); } +bool CIRGenItaniumCXXABI::shouldTypeidBeNullChecked(QualType srcTy) { + return true; +} + +void CIRGenItaniumCXXABI::emitBadTypeidCall(CIRGenFunction &cgf, + mlir::Location loc) { + // void __cxa_bad_typeid(); + cir::FuncType fnTy = + cgf.getBuilder().getFuncType({}, cgf.getBuilder().getVoidTy()); + mlir::NamedAttrList attrs; + attrs.set(cir::CIRDialect::getNoReturnAttrName(), + mlir::UnitAttr::get(&cgf.cgm.getMLIRContext())); + + cgf.emitRuntimeCall( + loc, cgf.cgm.createRuntimeFunction(fnTy, "__cxa_bad_typeid", attrs), {}, + attrs); + cir::UnreachableOp::create(cgf.getBuilder(), loc); +} + +mlir::Value CIRGenItaniumCXXABI::emitTypeid(CIRGenFunction &cgf, QualType srcTy, + Address thisPtr, + mlir::Type typeInfoPtrTy) { + auto *classDecl = srcTy->castAsCXXRecordDecl(); + mlir::Location loc = cgm.getLoc(classDecl->getSourceRange()); + mlir::Value vptr = cgf.getVTablePtr(loc, thisPtr, classDecl); + mlir::Value vtbl; + + // TODO(cir): In classic codegen relative layouts cause us to do a + // 'load_relative' of -4 here. We probably don't want to reprensent this in + // CIR at all, but we should have the NYI here since this could be + // meaningful/notable for implementation of relative layout in the future. + if (cgm.getItaniumVTableContext().isRelativeLayout()) + cgm.errorNYI("buildVTablePointer: isRelativeLayout"); + else + vtbl = cir::VTableGetTypeInfoOp::create( + cgf.getBuilder(), loc, cgf.getBuilder().getPointerTo(typeInfoPtrTy), + vptr); + + return cgf.getBuilder().createAlignedLoad(loc, typeInfoPtrTy, vtbl, + cgf.getPointerAlign()); +} + mlir::Attribute CIRGenItaniumCXXABI::getAddrOfRTTIDescriptor(mlir::Location loc, QualType ty) { return CIRGenItaniumRTTIBuilder(*this, cgm).buildTypeInfo(loc, ty); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index c9df1499ea453..b5905e2db6de1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2425,7 +2425,7 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition( cir::FuncOp CIRGenModule::getOrCreateCIRFunction( StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable, bool dontDefer, bool isThunk, ForDefinition_t isForDefinition, - mlir::ArrayAttr extraAttrs) { + mlir::NamedAttrList extraAttrs) { const Decl *d = gd.getDecl(); if (const auto *fd = cast_or_null<FunctionDecl>(d)) { @@ -2518,6 +2518,10 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction( if (d) setFunctionAttributes(gd, funcOp, /*isIncompleteFunction=*/false, isThunk); + if (!extraAttrs.empty()) { + extraAttrs.append(funcOp->getAttrs()); + funcOp->setAttrs(extraAttrs); + } // 'dontDefer' actually means don't move this to the deferredDeclsToEmit list. if (dontDefer) { @@ -2702,14 +2706,15 @@ static void setWindowsItaniumDLLImport(CIRGenModule &cgm, bool isLocal, } cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty, - StringRef name, mlir::ArrayAttr, + StringRef name, + mlir::NamedAttrList extraAttrs, bool isLocal, bool assumeConvergent) { if (assumeConvergent) errorNYI("createRuntimeFunction: assumeConvergent"); cir::FuncOp entry = getOrCreateCIRFunction(name, ty, GlobalDecl(), - /*forVtable=*/false); + /*forVtable=*/false, extraAttrs); if (entry) { // TODO(cir): set the attributes of the function. diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 48bb1f2ae20d9..ac1699b3b8bfe 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -625,7 +625,16 @@ class CIRGenModule : public CIRGenTypeCache { clang::GlobalDecl gd, bool forVTable, bool dontDefer = false, bool isThunk = false, ForDefinition_t isForDefinition = NotForDefinition, - mlir::ArrayAttr extraAttrs = {}); + mlir::NamedAttrList extraAttrs = {}); + + cir::FuncOp getOrCreateCIRFunction(llvm::StringRef mangledName, + mlir::Type funcType, clang::GlobalDecl gd, + bool forVTable, + mlir::NamedAttrList extraAttrs) { + return getOrCreateCIRFunction(mangledName, funcType, gd, forVTable, + /*dontDefer=*/false, /*isThunk=*/false, + NotForDefinition, extraAttrs); + } cir::FuncOp createCIRFunction(mlir::Location loc, llvm::StringRef name, cir::FuncType funcType, @@ -641,7 +650,8 @@ class CIRGenModule : public CIRGenTypeCache { const clang::FunctionDecl *funcDecl); cir::FuncOp createRuntimeFunction(cir::FuncType ty, llvm::StringRef name, - mlir::ArrayAttr = {}, bool isLocal = false, + mlir::NamedAttrList extraAttrs = {}, + bool isLocal = false, bool assumeConvergent = false); static constexpr const char *builtinCoroId = "__builtin_coro_id"; diff --git a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp index cc6a6544a529a..b76dee98713cc 100644 --- a/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CXXABILowering.cpp @@ -368,6 +368,15 @@ mlir::LogicalResult CIRGetRuntimeMemberOpABILowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRVTableGetTypeInfoOpABILowering::matchAndRewrite( + cir::VTableGetTypeInfoOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value loweredResult = + lowerModule->getCXXABI().lowerVTableGetTypeInfo(op, rewriter); + rewriter.replaceOp(op, loweredResult); + return mlir::success(); +} + // Prepare the type converter for the CXXABI lowering pass. // Even though this is a CIR-to-CIR pass, we are eliminating some CIR types. static void prepareCXXABITypeConverter(mlir::TypeConverter &converter, @@ -446,6 +455,7 @@ populateCXXABIConversionTarget(mlir::ConversionTarget &target, return typeConverter.isLegal(op.getSymType()); }); target.addIllegalOp<cir::DynamicCastOp>(); + target.addIllegalOp<cir::VTableGetTypeInfoOp>(); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h index af5034db0a577..88c5265e57491 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CIRCXXABI.h @@ -122,6 +122,10 @@ class CIRCXXABI { virtual mlir::Value lowerDynamicCast(cir::DynamicCastOp op, mlir::OpBuilder &builder) const = 0; + + virtual mlir::Value + lowerVTableGetTypeInfo(cir::VTableGetTypeInfoOp op, + mlir::OpBuilder &builder) const = 0; }; /// Creates an Itanium-family ABI. diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp index e8853a27b2675..e972def4c416a 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerItaniumCXXABI.cpp @@ -106,6 +106,8 @@ class LowerItaniumCXXABI : public CIRCXXABI { mlir::Value lowerDynamicCast(cir::DynamicCastOp op, mlir::OpBuilder &builder) const override; + mlir::Value lowerVTableGetTypeInfo(cir::VTableGetTypeInfoOp op, + mlir::OpBuilder &builder) const override; }; } // namespace @@ -758,5 +760,20 @@ LowerItaniumCXXABI::lowerDynamicCast(cir::DynamicCastOp op, }) .getResult(); } +mlir::Value +LowerItaniumCXXABI::lowerVTableGetTypeInfo(cir::VTableGetTypeInfoOp op, + mlir::OpBuilder &builder) const { + mlir::Location loc = op->getLoc(); + auto offset = cir::ConstantOp::create( + builder, op->getLoc(), cir::IntAttr::get(getPtrDiffCIRTy(lm), -1)); + + // Cast the vptr to type_info-ptr, so that we can go backwards 1 pointer. + auto vptrCast = cir::CastOp::create(builder, loc, op.getType(), + cir::CastKind::bitcast, op.getVptr()); + + return cir::PtrStrideOp::create(builder, loc, vptrCast.getType(), vptrCast, + offset) + .getResult(); +} } // namespace cir diff --git a/clang/test/CIR/CodeGenCXX/Inputs/typeinfo b/clang/test/CIR/CodeGenCXX/Inputs/typeinfo new file mode 100644 index 0000000000000..a68b10302c6fe --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/Inputs/typeinfo @@ -0,0 +1,24 @@ +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; + }; +} diff --git a/clang/test/CIR/CodeGenCXX/typeid-cxx11.cpp b/clang/test/CIR/CodeGenCXX/typeid-cxx11.cpp new file mode 100644 index 0000000000000..1e29256f8cd2b --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/typeid-cxx11.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare -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 -I%S/Inputs %s -triple x86_64-apple-darwin10 -fclangir -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=LLVM +// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s --check-prefixes=LLVM + +#include <typeinfo> + +namespace Test1 { + +struct Item { + const std::type_info &ti; + const char *name; + void *(*make)(); +}; + +template<typename T> void *make_impl() { return new T; } +template<typename T> constexpr Item item(const char *name) { + return { typeid(T), name, make_impl<T> }; +} + +struct A { virtual ~A(); }; +struct B : virtual A {}; +struct C { int n; }; + +// CIR: cir.global constant external @_ZN5Test15itemsE = #cir.const_array<[ +// CIR-SAME: #cir.const_record<{#cir.global_view<@_ZTIN5Test11AE> : !cir.ptr<!rec_std3A3Atype_info>, #cir.global_view<@".str"> : !cir.ptr<!s8i>, #cir.global_view<@_ZN5Test19make_implINS_1AEEEPvv> : !cir.ptr<!cir.func<() -> !cir.ptr<!void>>>}> : !rec_Test13A3AItem +// CIR-SAME: #cir.const_record<{#cir.global_view<@_ZTIN5Test11BE> : !cir.ptr<!rec_std3A3Atype_info>, #cir.global_view<@".str.1"> : !cir.ptr<!s8i>, #cir.global_view<@_ZN5Test19make_implINS_1BEEEPvv> : !cir.ptr<!cir.func<() -> !cir.ptr<!void>>>}> : !rec_Test13A3AItem +// CIR-SAME: #cir.const_record<{#cir.global_view<@_ZTIN5Test11CE> : !cir.ptr<!rec_std3A3Atype_info>, #cir.global_view<@".str.2"> : !cir.ptr<!s8i>, #cir.global_view<@_ZN5Test19make_implINS_1CEEEPvv> : !cir.ptr<!cir.func<() -> !cir.ptr<!void>>>}> : !rec_Test13A3AItem +// CIR-SAME: #cir.const_record<{#cir.global_view<@_ZTIi> : !cir.ptr<!rec_std3A3Atype_info>, #cir.global_view<@".str.3"> : !cir.ptr<!s8i>, #cir.global_view<@_ZN5Test19make_implIiEEPvv> : !cir.ptr<!cir.func<() -> !cir.ptr<!void>>>}> : !rec_Test13A3AItem +// CIR-SAME: ]> : !cir.array<!rec_Test13A3AItem x 4> +// +// LLVM: @_ZN5Test15itemsE ={{.*}} constant [4 x {{.*}}] [{{.*}} @_ZTIN5Test11AE, {{.*}} @_ZN5Test19make_implINS_1AEEEPvv {{.*}} @_ZTIN5Test11BE, {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} @_ZTIN5Test11CE, {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} @_ZTIi, {{.*}} @_ZN5Test19make_implIiEEPvv }] +extern constexpr Item items[] = { + item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int") +}; + +// CIR: cir.global constant external @_ZN5Test11xE = #cir.global_view<@_ZTIN5Test11AE> +// LLVM: @_ZN5Test11xE ={{.*}} constant ptr @_ZTIN5Test11AE, align 8 +constexpr auto &x = items[0].ti; + +// CIR: cir.global constant external @_ZN5Test11yE = #cir.global_view<@_ZTIN5Test11BE> +// LLVM: @_ZN5Test11yE ={{.*}} constant ptr @_ZTIN5Test11BE, align 8 +constexpr auto &y = typeid(B{}); + +} diff --git a/clang/test/CIR/CodeGenCXX/typeid-should-throw.cpp b/clang/test/CIR/CodeGenCXX/typeid-should-throw.cpp new file mode 100644 index 0000000000000..9038d0010b753 --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/typeid-should-throw.cpp @@ -0,0 +1,172 @@ +// 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=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 +namespace std { +struct type_info; +} + +struct A { + virtual ~A(); + operator bool(); +}; +struct B : A {}; + +void f1(A *x) { typeid(false, *x); } +// CIR-LABEL: cir.func{{.*}}@_Z2f1P1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f1P1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f2(bool b, A *x, A *y) { typeid(b ? *x : *y); } +// CIR-LABEL: cir.func{{.*}}@_Z2f2bP1AS0_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f2bP1AS0_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f3(bool b, A *x, A &y) { typeid(b ? *x : y); } +// CIR-LABEL: cir.func{{.*}}@_Z2f3bP1ARS_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f3bP1ARS_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f4(bool b, A &x, A *y) { typeid(b ? x : *y); } +// CIR-LABEL: cir.func{{.*}}@_Z2f4bR1APS_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f4bR1APS_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f5(volatile A *x) { typeid(*x); } +// CIR-LABEL: cir.func{{.*}}@_Z2f5PV1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f5PV1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f6(A *x) { typeid((B &)*(B *)x); } +// CIR-LABEL: cir.func{{.*}}@_Z2f6P1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f6P1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f7(A *x) { typeid((*x)); } +// CIR-LABEL: cir.func{{.*}}@_Z2f7P1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f7P1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f8(A *x) { typeid(x[0]); } +// CIR-LABEL: cir.func{{.*}}@_Z2f8P1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f8P1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f9(A *x) { typeid(0[x]); } +// CIR-LABEL: cir.func{{.*}}@_Z2f9P1A +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z2f9P1A +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f10(A *x, A *y) { typeid(*y ?: *x); } +// CIR-LABEL: cir.func{{.*}}@_Z3f10P1AS0_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z3f10P1AS0_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f11(A *x, A &y) { typeid(*x ?: y); } +// CIR-LABEL: cir.func{{.*}}@_Z3f11P1ARS_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z3f11P1ARS_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f12(A &x, A *y) { typeid(x ?: *y); } +// CIR-LABEL: cir.func{{.*}}@_Z3f12R1APS_ +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %{{.*}}, %[[NULL]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z3f12R1APS_ +// LLVM: icmp eq {{.*}}, null +// LLVM-NEXT: br i1 + +void f13(A &x, A &y) { typeid(x ?: y); } +// CIR-LABEL: cir.func{{.*}}@_Z3f13R1AS0_ +// CIR-NOT: @__cxa_bad_typeid() +// LLVM-LABEL: define {{.*}}void @_Z3f13R1AS0_ +// LLVM-NOT: icmp eq {{.*}}, null + +void f14(A *x) { typeid((const A &)(A)*x); } +// CIR-LABEL: cir.func{{.*}}@_Z3f14P1A +// CIR-NOT: @__cxa_bad_typeid() +// LLVM-LABEL: define {{.*}}void @_Z3f14P1A +// LLVM-NOT: icmp eq {{.*}}, null + +void f15(A *x) { typeid((A &&)*(A *)nullptr); } +// CIR-LABEL: cir.func{{.*}}@_Z3f15P1A +// In this example, it only passes classic codegen because the icmp doesn't +// happen, it just does a branch on 'true' thanks to constant folding. So we're +// consistant with classic codegen. +// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[NULL2:.*]] = cir.const #cir.ptr<null> +// CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %[[NULL]], %[[NULL2]]) +// CIR-NEXT: cir.if %[[CMP]] +// CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () +// CIR-NEXT: cir.unreachable +// LLVM-LABEL: define {{.*}}void @_Z3f15P1A +// LLVM-NOT: icmp eq {{.*}}, null diff --git a/clang/test/CIR/CodeGenCXX/typeid.cpp b/clang/test/CIR/CodeGenCXX/typeid.cpp new file mode 100644 index 0000000000000..2a4d31ca9ef32 --- /dev/null +++ b/clang/test/CIR/CodeGenCXX/typeid.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-apple-darwin10 -fclangir -emit-cir -fcxx-exceptions -fexceptions -mmlir --mlir-print-ir-before=cir-cxxabi-lowering -o %t.cir 2> %t-before.cir +// RUN: FileCheck %s --input-file=%t-before.cir --check-prefixes=CIR,CIR-BEFORE +// RUN: FileCheck %s --input-file=%t.cir --check-prefixes=CIR,CIR-AFTER +// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-apple-darwin10 -fclangir -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s --check-prefixes=LLVM +// RUN: %clang_cc1 -I%S/Inputs %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s --check-prefixes=LLVM +#include <typeinfo> + +namespace Test1 { + +// PR7400 +struct A { virtual void f(); }; + +// CIR: cir.global constant external @_ZN5Test16int_tiE = #cir.global_view<@_ZTIi> : !cir.ptr<!rec_std3A3Atype_info> +// LLVM: @_ZN5Test16int_tiE ={{.*}} constant ptr @_ZTIi, align 8 +const std::type_info &int_ti = typeid(int); + +// CIR: cir.global constant external @_ZN5Test14A_tiE = #cir.global_view<@_ZTIN5Test11AE> : !cir.ptr<!rec_std3A3Atype_info> +// LLVM: @_ZN5Test14A_tiE ={{.*}} constant ptr @_ZTIN5Test11AE, align 8 +const std::type_info &A_ti = typeid(const volatile A &); + +volatile char c; + +// CIR: cir.global constant external @_ZN5Test14c_tiE = #cir.global_view<@_ZTIc> : !cir.ptr<!rec_std3A3Atype_info> +// LLVM: @_ZN5Test14c_tiE ={{.*}} constant ptr @_ZTIc, align 8 +const std::type_info &c_ti = typeid(c); + +extern const double &d; + +// CIR: cir.global constant external @_ZN5Test14d_tiE = #cir.global_view<@_ZTId> : !cir.ptr<!rec_std3A3Atype_info> +// LLVM: @_ZN5Test14d_tiE ={{.*}} constant ptr @_ZTId, align 8 +const std::type_info &d_ti = typeid(d); + +extern A &a; + +// CIR-AFTER: cir.global external @_ZN5Test14a_tiE = #cir.ptr<null> : !cir.ptr<!rec_std3A3Atype_info> + +// CIR-BEFORE: cir.global external @_ZN5Test14a_tiE = ctor : !cir.ptr<!rec_std3A3Atype_info> { +// CIR-AFTER: cir.func{{.*}}@__cxx_global_var_init() { +// +// CIR-NEXT: %[[GET_GLOB_ATI:.*]] = cir.get_global @_ZN5Test14a_tiE : !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> +// CIR-NEXT: %[[GET_GLOB_A:.*]] = cir.get_global @_ZN5Test11aE : !cir.ptr<!cir.ptr<!rec_Test13A3AA>> +// CIR-NEXT: %[[LOAD_GLOB_A:.*]] = cir.load %[[GET_GLOB_A]] : !cir.ptr<!cir.ptr<!rec_Test13A3AA>>, !cir.ptr<!rec_Test13A3AA> +// CIR-NEXT: %[[GET_VPTR:.*]] = cir.vtable.get_vptr %[[LOAD_GLOB_A]] : !cir.ptr<!rec_Test13A3AA> -> !cir.ptr<!cir.vptr> +// CIR-NEXT: %[[LOAD_VPTR:.*]] = cir.load align(8) %[[GET_VPTR]] : !cir.ptr<!cir.vptr>, !cir.vptr +// CIR-BEFORE: %[[GET_TYPEINFO:.*]] = cir.vtable.get_type_info %[[LOAD_VPTR]] : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> +// +// CIR-AFTER: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR-AFTER: %[[VPTR_CAST:.*]] = cir.cast bitcast %[[LOAD_VPTR]] : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> +// CIR-AFTER: %[[GET_TYPEINFO:.*]] = cir.ptr_stride %[[VPTR_CAST]], %[[NEG_ONE]] : (!cir.ptr<!cir.ptr<!rec_std3A3Atype_info>>, !s64i) -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> +// +// CIR-NEXT: %[[LOAD_TYPEINFO:.*]] = cir.load align(8) %[[GET_TYPEINFO]] : !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>>, !cir.ptr<!rec_std3A3Atype_info> +// CIR-NEXT: cir.store align(8) %[[LOAD_TYPEINFO]], %[[GET_GLOB_ATI]] : !cir.ptr<!rec_std3A3Atype_info>, !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> +// CIR-AFTER: cir.return +// CIR-NEXT:} +// CIR: cir.global "private" constant external @_ZN5Test11aE : !cir.ptr<!rec_Test13A3AA> +// LLVM: @_ZN5Test14a_tiE ={{.*}} global +const std::type_info &a_ti = typeid(a); + +// CIR: cir.global constant external @_ZN5Test18A10_c_tiE = #cir.global_view<@_ZTIA10_c> : !cir.ptr<!rec_std3A3Atype_info> +// LLVM: @_ZN5Test18A10_c_tiE ={{.*}} constant ptr @_ZTIA10_c, align 8 +const std::type_info &A10_c_ti = typeid(char const[10]); + +// CIR: cir.func private dso_local @__cxa_bad_typeid() attributes {noreturn} + +// CIR-LABEL: cir.func{{.*}} @_ZN5Test11fEPv +// CIR-SAME: personality(@__gxx_personality_v0) +// LLVM-LABEL: define{{.*}} ptr @_ZN5Test11fEPv +// LLVM-SAME: personality ptr @__gxx_personality_v0 +const char *f(void *arg) { + // CIR: %[[ARG:.*]] = cir.alloca !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>, ["arg", init] + try { + // CIR: %[[ARG_VALUE:.*]] = cir.load{{.*}}%[[ARG]] : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void> + // CIR-NEXT: %[[ARG_CAST:.*]] = cir.cast bitcast %[[ARG_VALUE]] : !cir.ptr<!void> -> !cir.ptr<!rec_Test13A3AA> + // CIR-NEXT: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!rec_Test13A3AA> + // CIR-NEXT: %[[CMP:.*]] = cir.cmp(eq, %[[ARG_CAST]], %[[NULL]]) + // CIR-NEXT: cir.if %[[CMP]] { + // CIR-NEXT: cir.call @__cxa_bad_typeid() {noreturn} : () -> () + // CIR-NEXT: cir.unreachable + // CIR-NEXT: } + // + // CIR: %[[GETVPTR:.*]] = cir.vtable.get_vptr %[[ARG_CAST]] + // CIR-NEXT: %[[LOAD_VPTR:.*]] = cir.load{{.*}} %[[GETVPTR]] : !cir.ptr<!cir.vptr>, !cir.vptr + // + // CIR-BEFORE: %[[GET_TYPEINFO:.*]] = cir.vtable.get_type_info %[[LOAD_VPTR]] : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> + // + // CIR-AFTER: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i + // CIR-AFTER: %[[VPTR_CAST:.*]] = cir.cast bitcast %[[LOAD_VPTR]] : !cir.vptr -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> + // CIR-AFTER: %[[GET_TYPEINFO:.*]] = cir.ptr_stride %[[VPTR_CAST]], %[[NEG_ONE]] : (!cir.ptr<!cir.ptr<!rec_std3A3Atype_info>>, !s64i) -> !cir.ptr<!cir.ptr<!rec_std3A3Atype_info>> + // + // CIR-NEXT: %[[LOAD_TYPEINFO:.*]] = cir.load{{.*}}%[[GET_TYPEINFO]] + // CIR-NEXT: cir.call @_ZNKSt9type_info4nameEv(%[[LOAD_TYPEINFO]]) + + // LLVM: br i1 + // LLVM: invoke void @__cxa_bad_typeid() + return typeid(*static_cast<A *>(arg)).name(); + } catch (...) { + // LLVM: landingpad { ptr, i32 } + // LLVM-NEXT: catch ptr null + } + + return 0; +} + +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
