diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d023f1f82a1b..cb7206e1638e 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2595,7 +2595,7 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [ // VTableAddrPointOp //===----------------------------------------------------------------------===// -def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point",[ +def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [ Pure, DeclareOpInterfaceMethods ]> { let summary = "Get the vtable (global variable) address point"; @@ -2604,39 +2604,116 @@ def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point",[ (address point) of a C++ virtual table. An object internal `__vptr` gets initializated on top of the value returned by this operation. - `address_point.index` (vtable index) provides the appropriate vtable within the vtable group - (as specified by Itanium ABI), and `address_point.offset` (address point index) the actual address - point within that vtable. + `address_point.index` (vtable index) provides the appropriate vtable within + the vtable group (as specified by Itanium ABI), and `address_point.offset` + (address point index) the actual address point within that vtable. - The return type is always a `!cir.ptr i32>>`. + The return type is always `!cir.vptr`. Example: ```mlir cir.global linkonce_odr @_ZTV1B = ... ... - %3 = cir.vtable.address_point(@_ZTV1B, address_point = ) : !cir.ptr i32>> + %3 = cir.vtable.address_point(@_ZTV1B, + address_point = ) : !cir.vptr ``` }]; let arguments = (ins - OptionalAttr:$name, - Optional:$sym_addr, + FlatSymbolRefAttr:$name, CIR_AddressPointAttr:$address_point ); - let results = (outs Res:$addr); + let results = (outs Res:$addr); let assemblyFormat = [{ `(` - ($name^)? - ($sym_addr^ `:` type($sym_addr))? - `,` - `address_point` `=` $address_point + $name `,` `address_point` `=` $address_point `)` `:` qualified(type($addr)) attr-dict }]; +} - let hasVerifier = 1; +//===----------------------------------------------------------------------===// +// VTableGetVPtr +//===----------------------------------------------------------------------===// + +def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> { + let summary = "Get a the address of the vtable pointer for an object"; + let description = [{ + The `vtable.get_vptr` operation retrieves the address of the vptr for a + C++ object. This operation requires that the object pointer points to + the start of a complete object. (TODO: Describe how we get that). + The vptr will always be at offset zero in the object, but this operation + is more explicit about what is being retrieved than a direct bitcast. + + The return type is always `!cir.ptr`. + + Example: + ```mlir + %2 = cir.load %0 : !cir.ptr>, !cir.ptr + %3 = cir.vtable.get_vptr %2 : !cir.ptr -> !cir.ptr + ``` + }]; + + let arguments = (ins + Arg:$src + ); + + let results = (outs CIR_PtrToVPtr:$result); + + let assemblyFormat = [{ + $src `:` qualified(type($src)) `->` qualified(type($result)) attr-dict + }]; + +} + +//===----------------------------------------------------------------------===// +// VTableGetVirtualFnAddrOp +//===----------------------------------------------------------------------===// + +def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ + Pure +]> { + let summary = "Get a the address of a virtual function pointer"; + let description = [{ + The `vtable.get_virtual_fn_addr` operation retrieves the address of a + virtual function pointer from an object's vtable (__vptr). + This is an abstraction to perform the basic pointer arithmetic to get + the address of the virtual function pointer, which can then be loaded and + called. + + The `vptr` operand must be a `!cir.ptr` value, which would + have been returned by a previous call to `cir.vatble.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. + + Example: + ```mlir + %2 = cir.load %0 : !cir.ptr>, !cir.ptr + %3 = cir.vtable.get_vptr %2 : !cir.ptr -> !cir.ptr + %4 = cir.load %3 : !cir.ptr, !cir.vptr + %5 = cir.vtable.get_virtual_fn_addr %4[2] : !cir.vptr + -> !cir.ptr) -> !s32i>>> + %6 = cir.load align(8) %5 : !cir.ptr) + -> !s32i>>>, + !cir.ptr) -> !s32i>> + %7 = cir.call %6(%2) : (!cir.ptr) -> !s32i>>, + !cir.ptr) -> !s32i + ``` + }]; + + let arguments = (ins + Arg:$vptr, + I64Attr:$index); + + let results = (outs CIR_PointerType:$result); + + let assemblyFormat = [{ + $vptr `[` $index `]` attr-dict + `:` qualified(type($vptr)) `->` qualified(type($result)) + }]; } //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 19057ae80c9b..2b448a2675da 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -263,13 +263,21 @@ def CIR_PtrToExceptionInfoType def CIR_AnyDataMemberType : CIR_TypeBase<"::cir::DataMemberType", "data member type">; +//===----------------------------------------------------------------------===// +// VPtr type predicates +//===----------------------------------------------------------------------===// + +def CIR_AnyVPtrType : CIR_TypeBase<"::cir::VPtrType", "vptr type">; + +def CIR_PtrToVPtr : CIR_PtrToType; + //===----------------------------------------------------------------------===// // Scalar Type predicates //===----------------------------------------------------------------------===// defvar CIR_ScalarTypes = [ CIR_AnyBoolType, CIR_AnyIntType, CIR_AnyFloatType, CIR_AnyPtrType, - CIR_AnyDataMemberType + CIR_AnyDataMemberType, CIR_AnyVPtrType ]; def CIR_AnyScalarType : AnyTypeOf { diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 47cb8a302465..830c8f9b82fc 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -343,6 +343,37 @@ def CIR_DataMemberType : CIR_Type<"DataMember", "data_member", }]; } +//===----------------------------------------------------------------------===// +// CIR_VPtrType +//===----------------------------------------------------------------------===// + +def CIR_VPtrType : CIR_Type<"VPtr", "vptr", [ + DeclareTypeInterfaceMethods +]> { + + let summary = "CIR type that is used for the vptr member of C++ objects"; + let description = [{ + `cir.vptr` is a special type used as the type for the vptr member of a C++ + object. This avoids using arbitrary pointer types to declare vptr values + and allows stronger type-based checking for operations that use or provide + access to the vptr. + + This type will be the element type of the 'vptr' member of structures that + require a vtable pointer. A pointer to this type is returned by the + `cir.vtable.address_point` and `cir.vtable.get_vptr` operations, and this + pointer may be passed to the `cir.vtable.get_virtual_fn_addr` operation to + get the address of a virtual function pointer. + + The pointer may also be cast to other pointer types in order to perform + pointer arithmetic based on information encoded in the AST layout to get + the offset from a pointer to a dynamic object to the base object pointer, + the base object offset value from the vtable, or the type information + entry for an object. + TODO: We should have special operations to do that too. + }]; +} + + //===----------------------------------------------------------------------===// // BoolType //===----------------------------------------------------------------------===// @@ -751,7 +782,8 @@ def CIRRecordType : Type< def CIR_AnyType : AnyTypeOf<[ CIR_IntType, CIR_PointerType, CIR_DataMemberType, CIR_MethodType, CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_FuncType, CIR_VoidType, - CIR_RecordType, CIR_ExceptionType, CIR_AnyFloatType, CIR_ComplexType + CIR_RecordType, CIR_ExceptionType, CIR_AnyFloatType, CIR_ComplexType, + CIR_VPtrType ]>; #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index add04c39bad1..d8d3d15e7864 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -425,12 +425,8 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { llvm_unreachable("unsupported long double format"); } - mlir::Type getVirtualFnPtrType(bool isVarArg = false) { - // FIXME: replay LLVM codegen for now, perhaps add a vtable ptr special - // type so it's a bit more clear and C++ idiomatic. - auto fnTy = cir::FuncType::get({}, getUInt32Ty(), isVarArg); - assert(!cir::MissingFeatures::isVarArg()); - return getPointerTo(getPointerTo(fnTy)); + mlir::Type getPtrToVPtrType() { + return getPointerTo(cir::VPtrType::get(getContext())); } cir::FuncType getFuncType(llvm::ArrayRef params, mlir::Type retTy, diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index d98e903d5905..d08dbfda443f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -806,6 +806,10 @@ void CIRGenFunction::initializeVTablePointer(mlir::Location loc, // // vtable field is derived from `this` pointer, therefore they should be in // the same addr space. + // TODO(cir): We should be using cir.get_vptr rather than a bitcast to get + // the vptr field, but the call to ApplyNonVirtualAndVirtualOffset + // will also need to be adjusted. That should probably be using + // cir.base_class_addr. assert(!cir::MissingFeatures::addressSpace()); VTableField = builder.createElementBitCast(loc, VTableField, VTableAddressPoint.getType()); @@ -1704,10 +1708,12 @@ void CIRGenFunction::emitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, } mlir::Value CIRGenFunction::getVTablePtr(mlir::Location Loc, Address This, - mlir::Type VTableTy, const CXXRecordDecl *RD) { - Address VTablePtrSrc = builder.createElementBitCast(Loc, This, VTableTy); - auto VTable = builder.createLoad(Loc, VTablePtrSrc); + auto VTablePtr = builder.create( + Loc, builder.getPtrToVPtrType(), This.getPointer()); + Address VTablePtrAddr = Address(VTablePtr, This.getAlignment()); + + auto VTable = builder.createLoad(Loc, VTablePtrAddr); assert(!cir::MissingFeatures::tbaa()); if (CGM.getCodeGenOpts().OptimizationLevel > 0 && diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index d49cf2eeeba3..5a84d0ff083a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -957,7 +957,6 @@ class CIRGenFunction : public CIRGenTypeCache { VisitedVirtualBasesSetTy &VBases, VPtrsVector &vptrs); /// Return the Value of the vtable pointer member pointed to by This. mlir::Value getVTablePtr(mlir::Location Loc, Address This, - mlir::Type VTableTy, const CXXRecordDecl *VTableClass); /// Returns whether we should perform a type checked load when loading a diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 019790f2c54a..b39cee89224f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -935,11 +935,11 @@ cir::GlobalOp CIRGenItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer( CIRGenFunction &CGF, GlobalDecl GD, Address This, mlir::Type Ty, SourceLocation Loc) { + auto &builder = CGM.getBuilder(); auto loc = CGF.getLoc(Loc); - auto TyPtr = CGF.getBuilder().getPointerTo(Ty); + auto TyPtr = builder.getPointerTo(Ty); auto *MethodDecl = cast(GD.getDecl()); - auto VTable = CGF.getVTablePtr( - loc, This, CGF.getBuilder().getPointerTo(TyPtr), MethodDecl->getParent()); + auto VTable = CGF.getVTablePtr(loc, This, MethodDecl->getParent()); uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); mlir::Value VFunc{}; @@ -952,15 +952,10 @@ CIRGenCallee CIRGenItaniumCXXABI::getVirtualFunctionPointer( if (CGM.getItaniumVTableContext().isRelativeLayout()) { llvm_unreachable("NYI"); } else { - VTable = CGF.getBuilder().createBitcast( - loc, VTable, CGF.getBuilder().getPointerTo(TyPtr)); - auto VTableSlotPtr = CGF.getBuilder().create( - loc, CGF.getBuilder().getPointerTo(TyPtr), - ::mlir::FlatSymbolRefAttr{}, VTable, - cir::AddressPointAttr::get(CGF.getBuilder().getContext(), 0, - VTableIndex)); - VFuncLoad = CGF.getBuilder().createAlignedLoad(loc, TyPtr, VTableSlotPtr, - CGF.getPointerAlign()); + auto VTableSlotPtr = builder.create( + loc, builder.getPointerTo(TyPtr), VTable, VTableIndex); + VFuncLoad = builder.createAlignedLoad(loc, TyPtr, VTableSlotPtr, + CGF.getPointerAlign()); } // Add !invariant.load md to virtual function load to indicate that @@ -1014,11 +1009,11 @@ CIRGenItaniumCXXABI::getVTableAddressPoint(BaseSubobject Base, .getAddressPoint(Base); auto &builder = CGM.getBuilder(); - auto vtablePtrTy = builder.getVirtualFnPtrType(/*isVarArg=*/false); + auto vtablePtrTy = cir::VPtrType::get(builder.getContext()); return builder.create( CGM.getLoc(VTableClass->getSourceRange()), vtablePtrTy, - mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()), mlir::Value{}, + mlir::FlatSymbolRefAttr::get(vtable.getSymNameAttr()), cir::AddressPointAttr::get(CGM.getBuilder().getContext(), AddressPoint.VTableIndex, AddressPoint.AddressPointIndex)); @@ -2410,14 +2405,16 @@ void CIRGenItaniumCXXABI::emitThrow(CIRGenFunction &CGF, mlir::Value CIRGenItaniumCXXABI::getVirtualBaseClassOffset( mlir::Location loc, CIRGenFunction &CGF, Address This, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { - auto VTablePtr = CGF.getVTablePtr(loc, This, CGM.UInt8PtrTy, ClassDecl); + auto VTablePtr = CGF.getVTablePtr(loc, This, ClassDecl); + auto VTableBytePtr = + CGF.getBuilder().createBitcast(VTablePtr, CGM.UInt8PtrTy); CharUnits VBaseOffsetOffset = CGM.getItaniumVTableContext().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); mlir::Value OffsetVal = CGF.getBuilder().getSInt64(VBaseOffsetOffset.getQuantity(), loc); auto VBaseOffsetPtr = CGF.getBuilder().create( - loc, VTablePtr.getType(), VTablePtr, + loc, CGM.UInt8PtrTy, VTableBytePtr, OffsetVal); // vbase.offset.ptr mlir::Value VBaseOffset; diff --git a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp index c4edbee33dea..7854c1f4629b 100644 --- a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp @@ -488,9 +488,7 @@ void CIRRecordLowering::accumulateVPtrs() { } mlir::Type CIRRecordLowering::getVFPtrType() { - // FIXME: replay LLVM codegen for now, perhaps add a vtable ptr special - // type so it's a bit more clear and C++ idiomatic. - return builder.getVirtualFnPtrType(); + return cir::VPtrType::get(builder.getContext()); } void CIRRecordLowering::fillOutputFields() { diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index ce4ff5dbb1d3..194d047386f6 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -561,6 +561,12 @@ LogicalResult cir::CastOp::verify() { return success(); } + // Allow casting cir.vptr to pointer types. + // TODO: Add operations to get object offset and type info and remove this. + if (mlir::isa(srcType) && + mlir::dyn_cast(resType)) + return success(); + // Handle the data member pointer types. if (mlir::isa(srcType) && mlir::isa(resType)) @@ -2390,10 +2396,7 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { LogicalResult cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) { - // vtable ptr is not coming from a symbol. - if (!getName()) - return success(); - auto name = *getName(); + StringRef name = getName(); // Verify that the result type underlying pointer type matches the type of // the referenced cir.global or cir.func op. @@ -2411,27 +2414,6 @@ cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) { return success(); } -LogicalResult cir::VTableAddrPointOp::verify() { - // The operation uses either a symbol or a value to operate, but not both - if (getName() && getSymAddr()) - return emitOpError("should use either a symbol or value, but not both"); - - // If not a symbol, stick with the concrete type used for getSymAddr. - if (getSymAddr()) - return success(); - - auto resultType = getAddr().getType(); - auto intTy = cir::IntType::get(getContext(), 32, /*isSigned=*/false); - auto fnTy = cir::FuncType::get({}, intTy); - - auto resTy = cir::PointerType::get(cir::PointerType::get(fnTy)); - - if (resultType != resTy) - return emitOpError("result type must be '") - << resTy << "', but provided result type is '" << resultType << "'"; - return success(); -} - //===----------------------------------------------------------------------===// // VTTAddrPointOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp index 09ad0f3b9f51..519b4dbff807 100644 --- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp @@ -407,6 +407,20 @@ DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout, return 8; } +llvm::TypeSize +VPtrType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: consider size differences under different ABIs + return llvm::TypeSize::getFixed(64); +} + +uint64_t +VPtrType::getABIAlignment(const ::mlir::DataLayout &dataLayout, + ::mlir::DataLayoutEntryListRef params) const { + // FIXME: consider alignment differences under different ABIs + return 8; +} + llvm::TypeSize ArrayType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params) const { diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp index abd3bcd00d98..e2d058401b27 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/LoweringPrepareItaniumCXXABI.cpp @@ -114,13 +114,17 @@ buildDynamicCastToVoidAfterNullCheck(CIRBaseBuilderTy &builder, // Access vtable to get the offset from the given object to its containing // complete object. - auto vtablePtrTy = builder.getPointerTo(vtableElemTy); - auto vtablePtrPtr = - builder.createBitcast(op.getSrc(), builder.getPointerTo(vtablePtrTy)); - auto vtablePtr = builder.createLoad(loc, vtablePtrPtr); - auto offsetToTopSlotPtr = builder.create( - loc, vtablePtrTy, mlir::FlatSymbolRefAttr{}, vtablePtr, - cir::AddressPointAttr::get(builder.getContext(), 0, -2)); + // TODO: Add a specialized operation to get the object offset? + auto vptrTy = cir::VPtrType::get(builder.getContext()); + auto vptrPtrTy = builder.getPointerTo(vptrTy); + auto vptrPtr = + builder.create(loc, vptrPtrTy, op.getSrc()); + auto vptr = builder.createLoad(loc, vptrPtr); + auto elementPtr = + builder.createBitcast(vptr, builder.getPointerTo(vtableElemTy)); + auto minusTwo = builder.getSignedInt(loc, -2, 64); + auto offsetToTopSlotPtr = builder.create( + loc, builder.getPointerTo(vtableElemTy), elementPtr, minusTwo); auto offsetToTop = builder.createAlignedLoad(loc, offsetToTopSlotPtr, vtableElemAlign); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 27df9718efb3..54b2cc23d416 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3208,6 +3208,12 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite( /* isSigned=*/false); rewriter.replaceOpWithNewOp( cmpOp, kind, adaptor.getLhs(), adaptor.getRhs()); + } else if (auto ptrTy = mlir::dyn_cast(type)) { + // !cir.vptr is a special case, but it's just a pointer to LLVM. + auto kind = convertCmpKindToICmpPredicate(cmpOp.getKind(), + /* isSigned=*/false); + rewriter.replaceOpWithNewOp( + cmpOp, kind, adaptor.getLhs(), adaptor.getRhs()); } else if (mlir::isa(type)) { auto kind = convertCmpKindToFCmpPredicate(cmpOp.getKind()); rewriter.replaceOpWithNewOp( @@ -3866,22 +3872,13 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( mlir::ConversionPatternRewriter &rewriter) const { const auto *converter = getTypeConverter(); auto targetType = converter->convertType(op.getType()); - mlir::Value symAddr = op.getSymAddr(); llvm::SmallVector offsets; mlir::Type eltType; - if (!symAddr) { - symAddr = getValueForVTableSymbol(op, rewriter, getTypeConverter(), - op.getNameAttr(), eltType); - offsets = llvm::SmallVector{ - 0, op.getAddressPointAttr().getIndex(), - op.getAddressPointAttr().getOffset()}; - } else { - // Get indirect vtable address point retrieval - symAddr = adaptor.getSymAddr(); - eltType = converter->convertType(symAddr.getType()); - offsets = llvm::SmallVector{ - op.getAddressPointAttr().getOffset()}; - } + mlir::Value symAddr = getValueForVTableSymbol( + op, rewriter, getTypeConverter(), op.getNameAttr(), eltType); + offsets = llvm::SmallVector{ + 0, op.getAddressPointAttr().getIndex(), + op.getAddressPointAttr().getOffset()}; assert(eltType && "Shouldn't ever be missing an eltType here"); rewriter.replaceOpWithNewOp(op, targetType, eltType, @@ -3890,6 +3887,31 @@ mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMVTableGetVPtrOpLowering::matchAndRewrite( + cir::VTableGetVPtrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + // cir.vtable.get_vptr is equivalent to a bitcast from the source object + // pointer to the vptr type. Since the LLVM dialect uses opaque pointers + // we can just replace uses of this operation with the original pointer. + mlir::Value srcVal = op.getSrc(); + rewriter.replaceAllUsesWith(op, srcVal); + rewriter.eraseOp(op); + return mlir::success(); +} + +mlir::LogicalResult CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite( + cir::VTableGetVirtualFnAddrOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + const auto *converter = getTypeConverter(); + auto targetType = converter->convertType(op.getType()); + mlir::Type eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext()); + llvm::SmallVector offsets = + llvm::SmallVector{op.getIndex()}; + rewriter.replaceOpWithNewOp( + op, targetType, eltType, adaptor.getVptr(), offsets, true); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite( cir::StackSaveOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -4540,6 +4562,8 @@ void populateCIRToLLVMConversionPatterns( CIRToLLVMVecSplatOpLowering, CIRToLLVMVecTernaryOpLowering, CIRToLLVMVTableAddrPointOpLowering, + CIRToLLVMVTableGetVPtrOpLowering, + CIRToLLVMVTableGetVirtualFnAddrOpLowering, CIRToLLVMVTTAddrPointOpLowering #define GET_BUILTIN_LOWERING_LIST #include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc" @@ -4584,6 +4608,10 @@ void prepareTypeConverter(mlir::LLVMTypeConverter &converter, getTargetAddrSpaceFromCIRAddrSpace(type.getAddrSpace(), lowerModule); return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace); }); + converter.addConversion([&](cir::VPtrType type) -> mlir::Type { + assert(!cir::MissingFeatures::addressSpace()); + return mlir::LLVM::LLVMPointerType::get(type.getContext()); + }); converter.addConversion( [&, lowerModule](cir::DataMemberType type) -> mlir::Type { assert(lowerModule && "CXXABI is not available"); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index da5e598bc4bf..01bc7c12be6e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -1034,6 +1034,27 @@ class CIRToLLVMVTableAddrPointOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMVTableGetVPtrOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VTableGetVPtrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + +class CIRToLLVMVTableGetVirtualFnAddrOpLowering + : public mlir::OpConversionPattern { +public: + using mlir::OpConversionPattern< + cir::VTableGetVirtualFnAddrOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::VTableGetVirtualFnAddrOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + class CIRToLLVMStackSaveOpLowering : public mlir::OpConversionPattern { public: diff --git a/clang/test/CIR/CodeGen/delete.cpp b/clang/test/CIR/CodeGen/delete.cpp index 9e7647a8eb80..11afa5fe7cdb 100644 --- a/clang/test/CIR/CodeGen/delete.cpp +++ b/clang/test/CIR/CodeGen/delete.cpp @@ -38,9 +38,9 @@ namespace test3 { // CHECK-LABEL: cir.func dso_local @_ZN5test37destroyEPNS_1XE // CHECK: %[[ARG_VAR:.*]] = cir.alloca !cir.ptr // CHECK: %[[ARG:.*]] = cir.load{{.*}} %[[ARG_VAR]] : !cir.ptr>, !cir.ptr -// CHECK: %[[ARG_PTR:.*]] = cir.cast(bitcast, %[[ARG]] -// CHECK: %[[VTABLE:.*]] = cir.load{{.*}} %[[ARG_PTR]] -// CHECK: %[[DTOR_PTR:.*]] = cir.vtable.address_point( %[[VTABLE]] : !cir.ptr)>>>, address_point = ) +// CHECK: %[[VPTR_PTR:.*]] = cir.vtable.get_vptr %[[ARG]] : !cir.ptr -> !cir.ptr +// CHECK: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_PTR]] : !cir.ptr, !cir.vptr +// CHECK: %[[DTOR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][1] : !cir.vptr -> !cir.ptr)>>> // CHECK: %[[DTOR_FUN:.*]] = cir.load{{.*}} %[[DTOR_PTR]] // CHECK: cir.call %[[DTOR_FUN]](%[[ARG]]) // CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/derived-to-base.cpp b/clang/test/CIR/CodeGen/derived-to-base.cpp index fb51c5fb69c2..ab96c7f754eb 100644 --- a/clang/test/CIR/CodeGen/derived-to-base.cpp +++ b/clang/test/CIR/CodeGen/derived-to-base.cpp @@ -118,9 +118,9 @@ void vcall(C1 &c1) { // CHECK: %5 = cir.load{{.*}} %2 : !cir.ptr, !s32i // CHECK: cir.copy %1 to %3 : !cir.ptr // CHECK: %6 = cir.load{{.*}} %3 : !cir.ptr, !rec_buffy -// CHECK: %7 = cir.cast(bitcast, %4 : !cir.ptr), !cir.ptr, !s32i, !rec_buffy) -> !s32i>>>> -// CHECK: %8 = cir.load{{.*}} %7 : !cir.ptr, !s32i, !rec_buffy) -> !s32i>>>>, !cir.ptr, !s32i, !rec_buffy) -> !s32i>>> -// CHECK: %9 = cir.vtable.address_point( %8 : !cir.ptr, !s32i, !rec_buffy) -> !s32i>>>, address_point = ) : !cir.ptr, !s32i, !rec_buffy) -> !s32i>>> +// CHECK: %7 = cir.vtable.get_vptr %4 : !cir.ptr -> !cir.ptr +// CHECK: %8 = cir.load{{.*}} %7 : !cir.ptr, !cir.vptr +// CHECK: %9 = cir.vtable.get_virtual_fn_addr %8[2] : !cir.vptr -> !cir.ptr, !s32i, !rec_buffy) -> !s32i>>> // CHECK: %10 = cir.load align(8) %9 : !cir.ptr, !s32i, !rec_buffy) -> !s32i>>>, !cir.ptr, !s32i, !rec_buffy) -> !s32i>> // CHECK: %11 = cir.call %10(%4, %5, %6) : (!cir.ptr, !s32i, !rec_buffy) -> !s32i>>, !cir.ptr, !s32i, !rec_buffy) -> !s32i // CHECK: cir.return diff --git a/clang/test/CIR/CodeGen/dtors.cpp b/clang/test/CIR/CodeGen/dtors.cpp index 6a913dca9afb..ffc68a8e79a8 100644 --- a/clang/test/CIR/CodeGen/dtors.cpp +++ b/clang/test/CIR/CodeGen/dtors.cpp @@ -36,7 +36,7 @@ class B : public A }; // Class A -// CHECK: ![[ClassA:rec_.*]] = !cir.record !u32i>>>} #cir.record.decl.ast> +// CHECK: ![[ClassA:rec_.*]] = !cir.record // Class B // CHECK: ![[ClassB:rec_.*]] = !cir.record diff --git a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp index ba2b56ebf2ea..6d8dc86c932f 100644 --- a/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp +++ b/clang/test/CIR/CodeGen/dynamic-cast-exact.cpp @@ -16,10 +16,10 @@ struct Derived final : Base1 {}; Derived *ptr_cast(Base1 *ptr) { return dynamic_cast(ptr); // CHECK: %[[#SRC:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>, !cir.ptr - // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.ptr !u32i>>> - // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr !u32i>>>> - // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load{{.*}} %[[#SRC_VPTR_PTR]] : !cir.ptr !u32i>>>>, !cir.ptr !u32i>>> - // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.ptr !u32i>>>, !cir.bool + // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.vptr + // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr + // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load{{.*}} %[[#SRC_VPTR_PTR]] : !cir.ptr, !cir.vptr + // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.vptr, !cir.bool // CHECK-NEXT: %{{.+}} = cir.ternary(%[[#SUCCESS]], true { // CHECK-NEXT: %[[#RES:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr // CHECK-NEXT: cir.yield %[[#RES]] : !cir.ptr @@ -39,10 +39,10 @@ Derived *ptr_cast(Base1 *ptr) { Derived &ref_cast(Base1 &ref) { return dynamic_cast(ref); // CHECK: %[[#SRC:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>, !cir.ptr - // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.ptr !u32i>>> - // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr !u32i>>>> - // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load{{.*}} %[[#SRC_VPTR_PTR]] : !cir.ptr !u32i>>>>, !cir.ptr !u32i>>> - // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.ptr !u32i>>>, !cir.bool + // CHECK-NEXT: %[[#EXPECTED_VPTR:]] = cir.vtable.address_point(@_ZTV7Derived, address_point = ) : !cir.vptr + // CHECK-NEXT: %[[#SRC_VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr + // CHECK-NEXT: %[[#SRC_VPTR:]] = cir.load{{.*}} %[[#SRC_VPTR_PTR]] : !cir.ptr, !cir.vptr + // CHECK-NEXT: %[[#SUCCESS:]] = cir.cmp(eq, %[[#SRC_VPTR]], %[[#EXPECTED_VPTR]]) : !cir.vptr, !cir.bool // CHECK-NEXT: %[[#FAILED:]] = cir.unary(not, %[[#SUCCESS]]) : !cir.bool, !cir.bool // CHECK-NEXT: cir.if %[[#FAILED]] { // CHECK-NEXT: cir.call @__cxa_bad_cast() : () -> () diff --git a/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp b/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp index cbe5b3a41c20..ee6bbe5bea2e 100644 --- a/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp +++ b/clang/test/CIR/CodeGen/dynamic-cast-relative-layout.cpp @@ -19,9 +19,11 @@ void *ptr_cast_to_complete(Base *ptr) { // AFTER: %[[#SRC:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>, !cir.ptr // AFTER-NEXT: %[[#SRC_IS_NOT_NULL:]] = cir.cast(ptr_to_bool, %[[#SRC]] : !cir.ptr), !cir.bool // AFTER-NEXT: %{{.+}} = cir.ternary(%[[#SRC_IS_NOT_NULL]], true { -// AFTER-NEXT: %[[#VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr> -// AFTER-NEXT: %[[#VPTR:]] = cir.load{{.*}} %[[#VPTR_PTR]] : !cir.ptr>, !cir.ptr -// AFTER-NEXT: %[[#OFFSET_TO_TOP_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr, address_point = ) : !cir.ptr +// AFTER-NEXT: %[[#VPTR_PTR:]] = cir.vtable.get_vptr %[[#SRC:]] : !cir.ptr -> !cir.ptr +// AFTER-NEXT: %[[#VPTR:]] = cir.load %[[#VPTR_PTR]] : !cir.ptr, !cir.vptr +// AFTER-NEXT: %[[#ELEM_PTR:]] = cir.cast(bitcast, %[[#VPTR:]] : !cir.vptr), !cir.ptr +// AFTER-NEXT: %[[#MINUS_TWO:]] = cir.const #cir.int<-2> : !s64i +// AFTER-NEXT: %[[#OFFSET_TO_TOP_PTR:]] = cir.ptr_stride(%[[#ELEM_PTR]] : !cir.ptr, %[[#MINUS_TWO:]] : !s64i), !cir.ptr // AFTER-NEXT: %[[#OFFSET_TO_TOP:]] = cir.load align(4) %[[#OFFSET_TO_TOP_PTR]] : !cir.ptr, !s32i // AFTER-NEXT: %[[#SRC_BYTES_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr // AFTER-NEXT: %[[#DST_BYTES_PTR:]] = cir.ptr_stride(%[[#SRC_BYTES_PTR]] : !cir.ptr, %[[#OFFSET_TO_TOP]] : !s32i), !cir.ptr diff --git a/clang/test/CIR/CodeGen/dynamic-cast.cpp b/clang/test/CIR/CodeGen/dynamic-cast.cpp index 715a129d31df..633fc218fb54 100644 --- a/clang/test/CIR/CodeGen/dynamic-cast.cpp +++ b/clang/test/CIR/CodeGen/dynamic-cast.cpp @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=BEFORE -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2>&1 | FileCheck %s -check-prefix=AFTER +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t.before.log +// RUN: FileCheck %s --input-file=%t.before.log -check-prefix=BEFORE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -fclangir -emit-cir -mmlir --mlir-print-ir-after=cir-lowering-prepare %s -o %t.cir 2> %t.after.log +// RUN: FileCheck %s --input-file=%t.after.log -check-prefix=AFTER struct Base { virtual ~Base(); @@ -7,9 +9,9 @@ struct Base { struct Derived : Base {}; -// BEFORE: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> -// BEFORE: !rec_Base = !cir.record -// BEFORE: !rec_Derived = !cir.record +// BEFORE-DAG: #dyn_cast_info__ZTI4Base__ZTI7Derived = #cir.dyn_cast_info<#cir.global_view<@_ZTI4Base> : !cir.ptr, #cir.global_view<@_ZTI7Derived> : !cir.ptr, @__dynamic_cast, @__cxa_bad_cast, #cir.int<0> : !s64i> +// BEFORE-DAG: !rec_Base = !cir.record +// BEFORE-DAG: !rec_Derived = !cir.record Derived *ptr_cast(Base *b) { return dynamic_cast(b); @@ -71,9 +73,11 @@ void *ptr_cast_to_complete(Base *ptr) { // AFTER: %[[#SRC:]] = cir.load{{.*}} %{{.+}} : !cir.ptr>, !cir.ptr // AFTER-NEXT: %[[#SRC_IS_NOT_NULL:]] = cir.cast(ptr_to_bool, %[[#SRC]] : !cir.ptr), !cir.bool // AFTER-NEXT: %{{.+}} = cir.ternary(%[[#SRC_IS_NOT_NULL]], true { -// AFTER-NEXT: %[[#VPTR_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr> -// AFTER-NEXT: %[[#VPTR:]] = cir.load{{.*}} %[[#VPTR_PTR]] : !cir.ptr>, !cir.ptr -// AFTER-NEXT: %[[#BASE_OFFSET_PTR:]] = cir.vtable.address_point( %[[#VPTR]] : !cir.ptr, address_point = ) : !cir.ptr +// AFTER-NEXT: %[[#VPTR_PTR:]] = cir.vtable.get_vptr %[[#SRC]] : !cir.ptr -> !cir.ptr +// AFTER-NEXT: %[[#VPTR:]] = cir.load %[[#VPTR_PTR]] : !cir.ptr, !cir.vptr +// AFTER-NEXT: %[[#ELEM_PTR:]] = cir.cast(bitcast, %[[#VPTR]] : !cir.vptr), !cir.ptr +// AFTER-NEXT: %[[#MINUS_TWO:]] = cir.const #cir.int<-2> : !s64i +// AFTER-NEXT: %[[#BASE_OFFSET_PTR:]] = cir.ptr_stride(%[[#ELEM_PTR]] : !cir.ptr, %[[#MINUS_TWO:]] : !s64i), !cir.ptr // AFTER-NEXT: %[[#BASE_OFFSET:]] = cir.load align(8) %[[#BASE_OFFSET_PTR]] : !cir.ptr, !s64i // AFTER-NEXT: %[[#SRC_BYTES_PTR:]] = cir.cast(bitcast, %[[#SRC]] : !cir.ptr), !cir.ptr // AFTER-NEXT: %[[#DST_BYTES_PTR:]] = cir.ptr_stride(%[[#SRC_BYTES_PTR]] : !cir.ptr, %[[#BASE_OFFSET]] : !s64i), !cir.ptr diff --git a/clang/test/CIR/CodeGen/multi-vtable.cpp b/clang/test/CIR/CodeGen/multi-vtable.cpp index 4f49d43814e6..0545075b7f34 100644 --- a/clang/test/CIR/CodeGen/multi-vtable.cpp +++ b/clang/test/CIR/CodeGen/multi-vtable.cpp @@ -29,19 +29,19 @@ int main() { return 0; } -// CIR: ![[VTypeInfoA:rec_.*]] = !cir.record, !cir.ptr}> -// CIR: ![[VTypeInfoB:rec_.*]] = !cir.record, !cir.ptr, !u32i, !u32i, !cir.ptr, !s64i, !cir.ptr, !s64i}> -// CIR: ![[VTableTypeMother:rec_.*]] = !cir.record x 4>}> -// CIR: ![[VTableTypeFather:rec_.*]] = !cir.record x 3>}> -// CIR: ![[VTableTypeChild:rec_.*]] = !cir.record x 4>, !cir.array x 3>}> -// CIR: !rec_Father = !cir.record !u32i>>>} #cir.record.decl.ast> -// CIR: !rec_Mother = !cir.record !u32i>>>} #cir.record.decl.ast> -// CIR: !rec_Child = !cir.record +// CIR-DAG: ![[VTypeInfoA:rec_.*]] = !cir.record, !cir.ptr}> +// CIR-DAG: ![[VTypeInfoB:rec_.*]] = !cir.record, !cir.ptr, !u32i, !u32i, !cir.ptr, !s64i, !cir.ptr, !s64i}> +// CIR-DAG: ![[VPtrTypeMother:rec_.*]] = !cir.record x 4>}> +// CIR-DAG: ![[VPtrTypeFather:rec_.*]] = !cir.record x 3>}> +// CIR-DAG: ![[VPtrTypeChild:rec_.*]] = !cir.record x 4>, !cir.array x 3>}> +// CIR-DAG: !rec_Father = !cir.record +// CIR-DAG: !rec_Mother = !cir.record +// CIR-DAG: !rec_Child = !cir.record // CIR: cir.func linkonce_odr @_ZN6MotherC2Ev(%arg0: !cir.ptr -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV6Mother, address_point = ) : !cir.ptr !u32i>>> -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %2, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV6Mother, address_point = ) : !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %2, %{{[0-9]+}} : !cir.vptr, !cir.ptr // CIR: cir.return // CIR: } @@ -52,13 +52,13 @@ int main() { // LLVM-DAG: } // CIR: cir.func linkonce_odr @_ZN5ChildC2Ev(%arg0: !cir.ptr -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV5Child, address_point = ) : !cir.ptr !u32i>>> -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV5Child, address_point = ) : !cir.ptr !u32i>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV5Child, address_point = ) : !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV5Child, address_point = ) : !cir.vptr // CIR: %7 = cir.base_class_addr %1 : !cir.ptr nonnull [8] -> !cir.ptr -// CIR: %8 = cir.cast(bitcast, %7 : !cir.ptr), !cir.ptr !u32i>>>> loc(#loc8) -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CIR: %8 = cir.cast(bitcast, %7 : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr // CIR: cir.return // CIR: } @@ -76,14 +76,14 @@ int main() { // CIR: cir.func dso_local @main() -> !s32i extra(#fn_attr) { -// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, address_point = ) : !cir.ptr)>>> +// CIR: %{{[0-9]+}} = cir.vtable.get_virtual_fn_addr %{{[0-9]+}}[0] : !cir.vptr -> !cir.ptr)>>> -// CIR: %{{[0-9]+}} = cir.vtable.address_point( %{{[0-9]+}} : !cir.ptr)>>>, address_point = ) : !cir.ptr)>>> +// CIR: %{{[0-9]+}} = cir.vtable.get_virtual_fn_addr %{{[0-9]+}}[0] : !cir.vptr -> !cir.ptr)>>> // CIR: } // vtable for Mother -// CIR: cir.global linkonce_odr @_ZTV6Mother = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI6Mother> : !cir.ptr, #cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr, #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr]> : !cir.array x 4>}> : ![[VTableTypeMother]] {alignment = 8 : i64} +// CIR: cir.global linkonce_odr @_ZTV6Mother = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI6Mother> : !cir.ptr, #cir.global_view<@_ZN6Mother9MotherFooEv> : !cir.ptr, #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr]> : !cir.array x 4>}> : ![[VPtrTypeMother]] {alignment = 8 : i64} // LLVM-DAG: @_ZTV6Mother = linkonce_odr global { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI6Mother, ptr @_ZN6Mother9MotherFooEv, ptr @_ZN6Mother10MotherFoo2Ev] } // vtable for __cxxabiv1::__class_type_info @@ -100,11 +100,11 @@ int main() { // LLVM-DAG: @_ZTI6Mother = constant { ptr, ptr } { ptr getelementptr inbounds nuw (i8, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 16), ptr @_ZTS6Mother } // vtable for Father -// CIR: cir.global linkonce_odr @_ZTV6Father = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI6Father> : !cir.ptr, #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr]> : !cir.array x 3>}> : ![[VTableTypeFather]] {alignment = 8 : i64} +// CIR: cir.global linkonce_odr @_ZTV6Father = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI6Father> : !cir.ptr, #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr]> : !cir.array x 3>}> : ![[VPtrTypeFather]] {alignment = 8 : i64} // LLVM-DAG: @_ZTV6Father = linkonce_odr global { [3 x ptr] } { [3 x ptr] [ptr null, ptr @_ZTI6Father, ptr @_ZN6Father9FatherFooEv] } // vtable for Child -// CIR: cir.global linkonce_odr @_ZTV5Child = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI5Child> : !cir.ptr, #cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr, #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr]> : !cir.array x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr, #cir.global_view<@_ZTI5Child> : !cir.ptr, #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr]> : !cir.array x 3>}> : ![[VTableTypeChild]] {alignment = 8 : i64} +// CIR: cir.global linkonce_odr @_ZTV5Child = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI5Child> : !cir.ptr, #cir.global_view<@_ZN5Child9MotherFooEv> : !cir.ptr, #cir.global_view<@_ZN6Mother10MotherFoo2Ev> : !cir.ptr]> : !cir.array x 4>, #cir.const_array<[#cir.ptr<-8 : i64> : !cir.ptr, #cir.global_view<@_ZTI5Child> : !cir.ptr, #cir.global_view<@_ZN6Father9FatherFooEv> : !cir.ptr]> : !cir.array x 3>}> : ![[VPtrTypeChild]] {alignment = 8 : i64} // LLVM-DAG: @_ZTV5Child = linkonce_odr global { [4 x ptr], [3 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI5Child, ptr @_ZN5Child9MotherFooEv, ptr @_ZN6Mother10MotherFoo2Ev], [3 x ptr] [ptr inttoptr (i64 -8 to ptr), ptr @_ZTI5Child, ptr @_ZN6Father9FatherFooEv] } // vtable for __cxxabiv1::__vmi_class_type_info diff --git a/clang/test/CIR/CodeGen/tbaa-vptr.cpp b/clang/test/CIR/CodeGen/tbaa-vptr.cpp index 4a460b9760ca..01602bc4d8d8 100644 --- a/clang/test/CIR/CodeGen/tbaa-vptr.cpp +++ b/clang/test/CIR/CodeGen/tbaa-vptr.cpp @@ -9,7 +9,7 @@ // NO-TBAA-NOT: !tbaa -// CIR: #tbaa[[VPTR:.*]] = #cir.tbaa_vptr !u32i>>>> +// CIR: #tbaa[[VPTR:.*]] = #cir.tbaa_vptr struct Member { ~Member(); @@ -26,7 +26,7 @@ struct B : A { B::~B() { } // CIR-LABEL: _ZN1BD2Ev -// CIR: cir.store{{.*}} %{{.*}}, %{{.*}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> tbaa(#tbaa[[VPTR]]) +// CIR: cir.store{{.*}} %{{.*}}, %{{.*}} : !cir.vptr, !cir.ptr tbaa(#tbaa[[VPTR]]) // LLVM-LABEL: _ZN1BD2Ev // LLVM: store ptr getelementptr inbounds nuw (i8, ptr @_ZTV1B, i64 16), ptr %{{.*}}, align 8, !tbaa ![[TBAA_VPTR:.*]] diff --git a/clang/test/CIR/CodeGen/virtual-base-cast.cpp b/clang/test/CIR/CodeGen/virtual-base-cast.cpp index 56c0ffc34d4d..f1b885e27908 100644 --- a/clang/test/CIR/CodeGen/virtual-base-cast.cpp +++ b/clang/test/CIR/CodeGen/virtual-base-cast.cpp @@ -16,8 +16,16 @@ D* x; A* a() { return x; } // CIR-LABEL: @_Z1av() + +// This uses the vtable to get the offset to the base object. The offset from +// the vptr to the base object offset in the vtable is a compile-time constant. +// CIR: %[[X_ADDR:.*]] = cir.get_global @x : !cir.ptr> +// CIR: %[[X:.*]] = cir.load{{.*}} %[[X_ADDR]] +// CIR: %[[X_VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[X]] : !cir.ptr -> !cir.ptr +// CIR: %[[X_VPTR_BASE:.*]] = cir.load{{.*}} %[[X_VPTR_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[X_BASE_I8PTR:.*]] = cir.cast(bitcast, %[[X_VPTR_BASE]] : !cir.vptr), !cir.ptr // CIR: %[[OFFSET_OFFSET:.*]] = cir.const #cir.int<-32> : !s64i -// CIR: %[[OFFSET_PTR:.*]] = cir.ptr_stride(%4 : !cir.ptr, %[[OFFSET_OFFSET]] : !s64i), !cir.ptr +// CIR: %[[OFFSET_PTR:.*]] = cir.ptr_stride(%[[X_BASE_I8PTR]] : !cir.ptr, %[[OFFSET_OFFSET]] : !s64i), !cir.ptr // CIR: %[[OFFSET_PTR_CAST:.*]] = cir.cast(bitcast, %[[OFFSET_PTR]] : !cir.ptr), !cir.ptr // CIR: %[[OFFSET:.*]] = cir.load{{.*}} %[[OFFSET_PTR_CAST]] : !cir.ptr, !s64i // CIR: %[[VBASE_ADDR:.*]] = cir.ptr_stride({{.*}} : !cir.ptr, %[[OFFSET]] : !s64i), !cir.ptr diff --git a/clang/test/CIR/CodeGen/virtual-function-calls.cpp b/clang/test/CIR/CodeGen/virtual-function-calls.cpp new file mode 100644 index 000000000000..09f48f7c16d2 --- /dev/null +++ b/clang/test/CIR/CodeGen/virtual-function-calls.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +struct A { + virtual void f(char); +}; + +void f1(A *a) { + a->f('c'); +} + +// CIR: cir.func{{.*}} @_Z2f1P1A(%arg0: !cir.ptr {{.*}}) +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr +// CIR: cir.store %arg0, %[[A_ADDR]] +// CIR: %[[A:.*]] = cir.load{{.*}} %[[A_ADDR]] +// CIR: %[[C_LITERAL:.*]] = cir.const #cir.int<99> : !s8i +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[A]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[FN_PTR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][0] : !cir.vptr -> !cir.ptr, !s8i)>>> +// CIR: %[[FN_PTR:.*]] = cir.load{{.*}} %[[FN_PTR_PTR:.*]] : !cir.ptr, !s8i)>>>, !cir.ptr, !s8i)>> +// CIR: cir.call %[[FN_PTR]](%[[A]], %[[C_LITERAL]]) : (!cir.ptr, !s8i)>>, !cir.ptr, !s8i) -> () + +// LLVM: define{{.*}} void @_Z2f1P1A(ptr %[[ARG0:.*]]) +// LLVM: %[[A_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[A_ADDR]] +// LLVM: %[[A:.*]] = load ptr, ptr %[[A_ADDR]] +// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[A]] +// LLVM: %[[FN_PTR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 0 +// LLVM: %[[FN_PTR:.*]] = load ptr, ptr %5 +// LLVM: call void %[[FN_PTR]](ptr %[[A]], i8 99) + +struct B : virtual A { + virtual void f(); +}; + +void f2(B * b) { + b->f(); +} + +// CIR: cir.func{{.*}} @_Z2f2P1B(%arg0: !cir.ptr {{.*}}) +// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.ptr +// CIR: cir.store %arg0, %[[B_ADDR]] +// CIR: %[[B:.*]] = cir.load{{.*}} %[[B_ADDR]] +// CIR: %[[VPTR_ADDR:.*]] = cir.vtable.get_vptr %[[B]] : !cir.ptr -> !cir.ptr +// CIR: %[[VPTR:.*]] = cir.load{{.*}} %[[VPTR_ADDR]] : !cir.ptr, !cir.vptr +// CIR: %[[FN_PTR_PTR:.*]] = cir.vtable.get_virtual_fn_addr %[[VPTR]][1] : !cir.vptr -> !cir.ptr)>>> +// CIR: %[[FN_PTR:.*]] = cir.load{{.*}} %[[FN_PTR_PTR:.*]] : !cir.ptr)>>>, !cir.ptr)>> +// CIR: cir.call %[[FN_PTR]](%[[B]]) : (!cir.ptr)>>, !cir.ptr) -> () + +// LLVM: define{{.*}} void @_Z2f2P1B(ptr %[[ARG0:.*]]) +// LLVM: %[[B_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[ARG0]], ptr %[[B_ADDR]] +// LLVM: %[[B:.*]] = load ptr, ptr %[[B_ADDR]] +// LLVM: %[[VPTR:.*]] = load ptr, ptr %[[B]] +// LLVM: %[[FN_PTR_PTR:.*]] = getelementptr inbounds ptr, ptr %[[VPTR]], i32 1 +// LLVM: %[[FN_PTR:.*]] = load ptr, ptr %5 +// LLVM: call void %[[FN_PTR]](ptr %[[B]]) diff --git a/clang/test/CIR/CodeGen/vtable-rtti.cpp b/clang/test/CIR/CodeGen/vtable-rtti.cpp index 80716ae0ad81..711312a11911 100644 --- a/clang/test/CIR/CodeGen/vtable-rtti.cpp +++ b/clang/test/CIR/CodeGen/vtable-rtti.cpp @@ -20,19 +20,19 @@ class B : public A }; // Type info B. -// CHECK: ![[TypeInfoB:rec_.*]] = !cir.record, !cir.ptr, !cir.ptr}> +// CHECK-DAG: ![[TypeInfoB:rec_.*]] = !cir.record, !cir.ptr, !cir.ptr}> // vtable for A type -// CHECK: ![[VTableTypeA:rec_.*]] = !cir.record x 5>}> -// RTTI_DISABLED: ![[VTableTypeA:rec_.*]] = !cir.record x 5>}> +// CHECK-DAG: ![[VPtrTypeA:rec_.*]] = !cir.record x 5>}> +// RTTI_DISABLED-DAG: ![[VPtrTypeA:rec_.*]] = !cir.record x 5>}> // Class A -// CHECK: ![[ClassA:rec_.*]] = !cir.record !u32i>>>} #cir.record.decl.ast> -// RTTI_DISABLED: ![[ClassA:rec_.*]] = !cir.record !u32i>>>} #cir.record.decl.ast> +// CHECK-DAG: ![[ClassA:rec_.*]] = !cir.record +// RTTI_DISABLED-DAG: ![[ClassA:rec_.*]] = !cir.record // Class B -// CHECK: ![[ClassB:rec_.*]] = !cir.record -// RTTI_DISABLED: ![[ClassB:rec_.*]] = !cir.record +// CHECK-DAG: ![[ClassB:rec_.*]] = !cir.record +// RTTI_DISABLED-DAG: ![[ClassB:rec_.*]] = !cir.record // B ctor => @B::B() // Calls @A::A() and initialize __vptr with address of B's vtable. @@ -45,9 +45,9 @@ class B : public A // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: %2 = cir.base_class_addr %1 : !cir.ptr nonnull [0] -> !cir.ptr // CHECK: cir.call @_ZN1AC2Ev(%2) : (!cir.ptr) -> () -// CHECK: %3 = cir.vtable.address_point(@_ZTV1B, address_point = ) : !cir.ptr !u32i>>> -// CHECK: %4 = cir.cast(bitcast, %1 : !cir.ptr), !cir.ptr !u32i>>>> -// CHECK: cir.store{{.*}} %3, %4 : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CHECK: %3 = cir.vtable.address_point(@_ZTV1B, address_point = ) : !cir.vptr +// CHECK: %4 = cir.cast(bitcast, %1 : !cir.ptr), !cir.ptr +// CHECK: cir.store{{.*}} %3, %4 : !cir.vptr, !cir.ptr // CHECK: cir.return // CHECK: } @@ -64,7 +64,7 @@ class B : public A // CHECK: } // Vtable definition for A -// CHECK: cir.global "private" external @_ZTV1A : ![[VTableTypeA]] {alignment = 8 : i64} +// CHECK: cir.global "private" external @_ZTV1A : ![[VPtrTypeA]] {alignment = 8 : i64} // A ctor => @A::A() // Calls @A::A() and initialize __vptr with address of A's vtable @@ -73,15 +73,15 @@ class B : public A // CHECK: %0 = cir.alloca !cir.ptr, !cir.ptr>, ["this", init] {alignment = 8 : i64} // CHECK: cir.store{{.*}} %arg0, %0 : !cir.ptr, !cir.ptr> // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr -// CHECK: %2 = cir.vtable.address_point(@_ZTV1A, address_point = ) : !cir.ptr !u32i>>> -// CHECK: %3 = cir.cast(bitcast, %1 : !cir.ptr), !cir.ptr !u32i>>>> -// CHECK: cir.store{{.*}} %2, %3 : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CHECK: %2 = cir.vtable.address_point(@_ZTV1A, address_point = ) : !cir.vptr +// CHECK: %3 = cir.cast(bitcast, %1 : !cir.ptr), !cir.ptr +// CHECK: cir.store{{.*}} %2, %3 : !cir.vptr, !cir.ptr // CHECK: cir.return // CHECK: } // vtable for B -// CHECK: cir.global linkonce_odr @_ZTV1B = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI1B> : !cir.ptr, #cir.global_view<@_ZN1BD2Ev> : !cir.ptr, #cir.global_view<@_ZN1BD0Ev> : !cir.ptr, #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr]> : !cir.array x 5>}> : ![[VTableTypeA]] -// RTTI_DISABLED: cir.global linkonce_odr @_ZTV1B = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.ptr : !cir.ptr, #cir.global_view<@_ZN1BD2Ev> : !cir.ptr, #cir.global_view<@_ZN1BD0Ev> : !cir.ptr, #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr]> : !cir.array x 5>}> : ![[VTableTypeA]] +// CHECK: cir.global linkonce_odr @_ZTV1B = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.global_view<@_ZTI1B> : !cir.ptr, #cir.global_view<@_ZN1BD2Ev> : !cir.ptr, #cir.global_view<@_ZN1BD0Ev> : !cir.ptr, #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr]> : !cir.array x 5>}> : ![[VPtrTypeA]] +// RTTI_DISABLED: cir.global linkonce_odr @_ZTV1B = #cir.vtable<{#cir.const_array<[#cir.ptr : !cir.ptr, #cir.ptr : !cir.ptr, #cir.global_view<@_ZN1BD2Ev> : !cir.ptr, #cir.global_view<@_ZN1BD0Ev> : !cir.ptr, #cir.global_view<@_ZNK1A5quackEv> : !cir.ptr]> : !cir.array x 5>}> : ![[VPtrTypeA]] // vtable for __cxxabiv1::__si_class_type_info // CHECK: cir.global "private" external @_ZTVN10__cxxabiv120__si_class_type_infoE : !cir.ptr> diff --git a/clang/test/CIR/CodeGen/vtt.cpp b/clang/test/CIR/CodeGen/vtt.cpp index ac24873d96a9..4df9d9b95002 100644 --- a/clang/test/CIR/CodeGen/vtt.cpp +++ b/clang/test/CIR/CodeGen/vtt.cpp @@ -38,9 +38,9 @@ int f() { // Class A constructor // CIR: cir.func linkonce_odr @_ZN1AC2Ev(%arg0: !cir.ptr -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1A, address_point = ) : !cir.ptr !u32i>>> -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1A, address_point = ) : !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr // CIR: } // Vtable of Class D @@ -57,8 +57,9 @@ int f() { // CIR: %{{[0-9]+}} = cir.vtt.address_point %{{[0-9]+}} : !cir.ptr>, offset = 1 -> !cir.ptr> // CIR: %{{[0-9]+}} = cir.load align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr> -// CIR: %{{[0-9]+}} = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr>, !cir.ptr +// CIR: %{{[0-9]+}} = cir.vtable.get_vptr %{{.*}} : !cir.ptr -> !cir.ptr +// CIR: %{{[0-9]+}} = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr, !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.vptr), !cir.ptr // CIR: %{{[0-9]+}} = cir.const #cir.int<-24> : !s64i // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr, %{{[0-9]+}} : !s64i), !cir.ptr // CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr @@ -88,8 +89,9 @@ int f() { // CIR: %{{[0-9]+}} = cir.vtt.address_point %{{[0-9]+}} : !cir.ptr>, offset = 1 -> !cir.ptr> // CIR: %{{[0-9]+}} = cir.load align(8) %{{[0-9]+}} : !cir.ptr>, !cir.ptr -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr> -// CIR: %{{[0-9]+}} = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr>, !cir.ptr +// CIR: %{{[0-9]+}} = cir.vtable.get_vptr %{{[0-9]+}} : !cir.ptr -> !cir.ptr +// CIR: %{{[0-9]+}} = cir.load{{.*}} %{{[0-9]+}} : !cir.ptr, !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.vptr), !cir.ptr // CIR: %{{[0-9]+}} = cir.const #cir.int<-24> : !s64i // CIR: %{{[0-9]+}} = cir.ptr_stride(%{{[0-9]+}} : !cir.ptr, %{{[0-9]+}} : !s64i), !cir.ptr // CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr @@ -115,19 +117,19 @@ int f() { // CIR: %[[VTT_D_TO_C:.*]] = cir.vtt.address_point @_ZTT1D, offset = 3 -> !cir.ptr> // CIR: cir.call @_ZN1CC2Ev(%[[C_PTR]], %[[VTT_D_TO_C]]) : (!cir.ptr, !cir.ptr>) -> () -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.ptr !u32i>>> -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.ptr !u32i>>> +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.vptr +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.vptr // CIR: %{{[0-9]+}} = cir.base_class_addr %{{[0-9]+}} : !cir.ptr nonnull [40] -> !cir.ptr -// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> -// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.ptr !u32i>>> +// CIR: %{{[0-9]+}} = cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr +// CIR: %{{[0-9]+}} = cir.vtable.address_point(@_ZTV1D, address_point = ) : !cir.vptr // CIR: cir.base_class_addr %{{[0-9]+}} : !cir.ptr nonnull [16] -> !cir.ptr -// CIR: cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr !u32i>>>> -// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.ptr !u32i>>>, !cir.ptr !u32i>>>> +// CIR: cir.cast(bitcast, %{{[0-9]+}} : !cir.ptr), !cir.ptr +// CIR: cir.store{{.*}} %{{[0-9]+}}, %{{[0-9]+}} : !cir.vptr, !cir.ptr // CIR: cir.return // CIR: }