-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[CIR] Add initial support for virtual base classes #155534
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -222,13 +222,7 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd, | |
|
|
||
| const CXXRecordDecl *classDecl = cd->getParent(); | ||
|
|
||
| // This code doesn't use range-based iteration because we may need to emit | ||
| // code between the virtual base initializers and the non-virtual base or | ||
| // between the non-virtual base initializers and the member initializers. | ||
| CXXConstructorDecl::init_const_iterator b = cd->init_begin(), | ||
| e = cd->init_end(); | ||
|
|
||
| // Virtual base initializers first, if any. They aren't needed if: | ||
| // Virtual base initializers aren't needed if: | ||
| // - This is a base ctor variant | ||
| // - There are no vbases | ||
| // - The class is abstract, so a complete object of it cannot be constructed | ||
|
|
@@ -238,31 +232,60 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd, | |
| bool constructVBases = ctorType != Ctor_Base && | ||
| classDecl->getNumVBases() != 0 && | ||
| !classDecl->isAbstract(); | ||
| if (constructVBases) { | ||
| cgm.errorNYI(cd->getSourceRange(), "emitCtorPrologue: virtual base"); | ||
| return; | ||
| } | ||
|
|
||
| const mlir::Value oldThisValue = cxxThisValue; | ||
| if (!constructVBases && b != e && (*b)->isBaseInitializer() && | ||
| (*b)->isBaseVirtual()) { | ||
| if (constructVBases && | ||
| !cgm.getTarget().getCXXABI().hasConstructorVariants()) { | ||
| cgm.errorNYI(cd->getSourceRange(), | ||
| "emitCtorPrologue: virtual base initializer"); | ||
| "emitCtorPrologue: virtual base without variants"); | ||
| return; | ||
| } | ||
|
|
||
| // Handle non-virtual base initializers. | ||
| for (; b != e && (*b)->isBaseInitializer(); b++) { | ||
| assert(!(*b)->isBaseVirtual()); | ||
| // Create three separate ranges for the different types of initializers. | ||
| auto allInits = cd->inits(); | ||
|
|
||
| // Find the boundaries between the three groups. | ||
| auto virtualBaseEnd = std::find_if( | ||
| allInits.begin(), allInits.end(), [](const CXXCtorInitializer *Init) { | ||
| return !(Init->isBaseInitializer() && Init->isBaseVirtual()); | ||
| }); | ||
|
|
||
| auto nonVirtualBaseEnd = std::find_if(virtualBaseEnd, allInits.end(), | ||
| [](const CXXCtorInitializer *Init) { | ||
| return !Init->isBaseInitializer(); | ||
| }); | ||
|
|
||
| // Create the three ranges. | ||
| auto virtualBaseInits = llvm::make_range(allInits.begin(), virtualBaseEnd); | ||
| auto nonVirtualBaseInits = | ||
| llvm::make_range(virtualBaseEnd, nonVirtualBaseEnd); | ||
| auto memberInits = llvm::make_range(nonVirtualBaseEnd, allInits.end()); | ||
|
|
||
| const mlir::Value oldThisValue = cxxThisValue; | ||
|
|
||
| auto emitInitializer = [&](CXXCtorInitializer *baseInit) { | ||
| if (cgm.getCodeGenOpts().StrictVTablePointers && | ||
| cgm.getCodeGenOpts().OptimizationLevel > 0 && | ||
| isInitializerOfDynamicClass(*b)) { | ||
| isInitializerOfDynamicClass(baseInit)) { | ||
| // It's OK to continue after emitting the error here. The missing code | ||
| // just "launders" the 'this' pointer. | ||
| cgm.errorNYI(cd->getSourceRange(), | ||
| "emitCtorPrologue: strict vtable pointers"); | ||
| return; | ||
| "emitCtorPrologue: strict vtable pointers for vbase"); | ||
| } | ||
| emitBaseInitializer(getLoc(cd->getBeginLoc()), classDecl, *b); | ||
| emitBaseInitializer(getLoc(cd->getBeginLoc()), classDecl, baseInit); | ||
| }; | ||
|
|
||
| // Process virtual base initializers. | ||
| for (CXXCtorInitializer *virtualBaseInit : virtualBaseInits) { | ||
| if (!constructVBases) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this inside the loop rather than preventing this loop from happening at all? Also, is there any sort of range loop we can use here? Thisis awful ugly...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is inside the loop because if we are not constructing vbases we need to update the iterator to move past them. The initializers are ordered such that all virtual bases occur before the first non-virtual base. This loop is necessary to position the iterator for the loop below. The MS CXXABI throws a bit of a wrench into the possibility of a range loop, because we need to insert a branch to a continue block between the virtual initializers and the non-virtual initializers, but we can probably use a flag to check for the conditions to do that. I'll play around with this loop in OGCG and see if I can simplify it without breaking anything.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right! I missed the same iterators. Anything you can do to make this less awful would be appreciated :)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm proceeding with the implementation change modeled after the classic codegen change proposed in #155668. If that ends up being rejected, I'll update this accordingly. |
||
| continue; | ||
| emitInitializer(virtualBaseInit); | ||
| } | ||
|
|
||
| assert(!cir::MissingFeatures::msabi()); | ||
|
|
||
| // Then, non-virtual base initializers. | ||
| for (CXXCtorInitializer *nonVirtualBaseInit : nonVirtualBaseInits) { | ||
| assert(!nonVirtualBaseInit->isBaseVirtual()); | ||
| emitInitializer(nonVirtualBaseInit); | ||
| } | ||
|
|
||
| cxxThisValue = oldThisValue; | ||
|
|
@@ -276,8 +299,7 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd, | |
| // lowering or optimization phases to keep the memory accesses more | ||
| // explicit. For now, we don't insert memcpy at all. | ||
| assert(!cir::MissingFeatures::ctorMemcpyizer()); | ||
| for (; b != e; b++) { | ||
| CXXCtorInitializer *member = (*b); | ||
| for (CXXCtorInitializer *member : memberInits) { | ||
| assert(!member->isBaseInitializer()); | ||
| assert(member->isAnyMemberInitializer() && | ||
| "Delegating initializer on non-delegating constructor"); | ||
|
|
@@ -370,7 +392,7 @@ void CIRGenFunction::initializeVTablePointers(mlir::Location loc, | |
| initializeVTablePointer(loc, vptr); | ||
|
|
||
| if (rd->getNumVBases()) | ||
| cgm.errorNYI(loc, "initializeVTablePointers: virtual base"); | ||
| cgm.getCXXABI().initializeHiddenVirtualInheritanceMembers(*this, rd); | ||
| } | ||
|
|
||
| CIRGenFunction::VPtrsVector | ||
|
|
@@ -418,8 +440,17 @@ void CIRGenFunction::getVTablePointers(BaseSubobject base, | |
| const CXXRecordDecl *nextBaseDecl; | ||
|
|
||
| if (nextBase.isVirtual()) { | ||
| cgm.errorNYI(rd->getSourceRange(), "getVTablePointers: virtual base"); | ||
| return; | ||
| // Check if we've visited this virtual base before. | ||
| if (!vbases.insert(baseDecl).second) | ||
| continue; | ||
|
|
||
| const ASTRecordLayout &layout = | ||
| getContext().getASTRecordLayout(vtableClass); | ||
|
|
||
| nextBaseDecl = nearestVBase; | ||
| baseOffset = layout.getVBaseClassOffset(baseDecl); | ||
| baseOffsetFromNearestVBase = CharUnits::Zero(); | ||
| baseDeclIsNonVirtualPrimaryBase = false; | ||
| } else { | ||
| const ASTRecordLayout &layout = getContext().getASTRecordLayout(rd); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.