This is an archive of the discontinued LLVM Phabricator instance.

Make CodeGen choose when to emit vtables.
Needs ReviewPublic

Authored by rsmith on Nov 27 2018, 7:51 PM.

Details

Summary

Previously, we expected Sema to make this ABI decision for us, resulting
in our emitting vtables in some cases where we didn't need them. With
this change, we emit vtables in precisely three cases:

  1. When we emit a reference to the vtable and it has suitable linkage.
  2. When we emit a key function definition.
  3. When we emit an explicit instantiation of a class.

This also removes the need to mark key functions as "must be emitted",
which means that an inline key function is no longer added to the list
of eagerly deserialized declarations in an AST file.

In exchange, we do now list explicit instantiation definitions of
dynamic classes as eagerly deserialized declarations. But they should
be much rarer in header files!

Diff Detail

Event Timeline

rsmith created this revision.Nov 27 2018, 7:51 PM
rsmith marked an inline comment as done.Nov 27 2018, 7:56 PM
rsmith added inline comments.
lib/CodeGen/CodeGenModule.cpp
3991–3992

@rjmccall Is there any reason we (from the CodeGen perspective) should treat an inline key function as emitting the vtable? I can't think of any reason to do so -- it's not in a comdat with the vtable or anything like that, so every translation unit that emits a reference to the vtable should emit its own copy anyway.

rjmccall added inline comments.Nov 27 2018, 8:46 PM
lib/CodeGen/CodeGenModule.cpp
3991–3992

The thinking was as follows: translation units that can't see a definition of the key function don't know that the definition is actually inline, so they'll emit a reference to an external v-table definition, which will lead to link failures if the translation units that do contain the inline definition don't eagerly emit the v-table. However, ARM pointed out years ago that the ODR requires inline definitions of virtual functions to be present in every translation unit which declares the virtual function at all, so there's no legal situation where a translation unit can't see the definition of an inline key function. Furthermore, I believe Clang has never made v-tables undiscardable in translation units with inline key function definitions, so there's no real guarantee that ODR-violating code will actually link, although you can certainly imagine ways in which an ODR-violating program might get by without such a guarantee.

Personally, I think the strongest argument for "deviating" here is that the language standard takes priority over the ABI, which means we're allowed to assume the program is overall well-formed, i.e. we're only required to interoperate with legal code. Now, that's a line of reasoning which leads us into some grey areas of implementation-definedness, but I feel fairly comfortable about deviating in this particular instance because I don't know why someone would really *want* to take advantage of v-tables being emitted eagerly; in general, eager emission of inline code is a bad thing that significantly slows down builds.

Now, ARM used this property of inline definitions to change the key function to the first non-inline function, and unfortunately we can't do that on existing targets without breaking interoperation. (We did do it on some newer Darwin targets, though, and we haven't had any problem with it.) But I do think we could use this property of inline definitions to just treat the class as no longer having a key function when we see an inline definition of it. That would rid us of this particular scourge of eager emission of inline code.

rsmith marked an inline comment as done.Nov 27 2018, 9:07 PM
rsmith added inline comments.
lib/CodeGen/CodeGenModule.cpp
3991–3992

My thinking is this: if a vtable has discardable linkage, then it can be discarded when optimizing if it's not referenced. So there's no point emitting it unless we also emit a reference to it. So we should only emit vtables with discardable linkage if they're actually referenced, just like we do for other symbols with discardable linkage. This is, I think, stronger than what you're suggesting, because it affects internal-linkage explicit instantiations too.

rjmccall added inline comments.Nov 27 2018, 9:33 PM
lib/CodeGen/CodeGenModule.cpp
3991–3992

Given only the ABI rule, using discardable linkage is a bug. If you take the "those translation units containing the definition must emit the v-table so that other translation units can use it" argument seriously, you obviously can't use discardable linkage, because the other translation units can't use it. That's why I bothered developing the whole argument above about why it's okay to ignore the ABI rule here.

Your argument about internal-linkage explicit instantiations abstractly makes a lot of sense but also sets off a bunch of klaxons in my mind about ignoring obvious programmer intent. Still, I think it's reasonable to try it out.

rsmith marked 2 inline comments as done.Nov 27 2018, 10:36 PM
rsmith added inline comments.
lib/CodeGen/CodeGenModule.cpp
3991–3992

OK, fair enough. I was only starting from the "these vtables have discardable linkage" position because that has been the status quo in Clang ~forever (godbolt.org only goes back to Clang 3). I'll give it a go and see what shakes out.

rjmccall added inline comments.Nov 28 2018, 8:20 AM
lib/CodeGen/CodeGenModule.cpp
3991–3992

Yeah, we've never actually taken that argument seriously, but we never took our current stance to its logical conclusion of emitting the v-table lazily, either.

rsmith updated this revision to Diff 175791.Nov 28 2018, 5:02 PM
  • Do not emit unused discardable vtables.

Will -fforce-emit-vtables still work?

rjmccall added inline comments.Nov 29 2018, 10:59 AM
lib/AST/ASTContext.cpp
9801

Does it matter if it's not this particular declaration that's the explicit instantiation?

lib/AST/RecordLayoutBuilder.cpp
3069

Why not just change computeKeyFunction to decide that the class doesn't have a key function if it would be an inline definition? We can do the same updating we do with the ARM rule except just bailing out instead of scanning for another candidate.

lib/CodeGen/CGVTables.cpp
889

I feel like "don't emit the v-table for this" should be handled in the caller.

rsmith marked an inline comment as done.Nov 29 2018, 1:33 PM

Will -fforce-emit-vtables still work?

Yes, it still works. (The tests for it still pass and I've manually tested it too.)

lib/AST/ASTContext.cpp
9801

The explicit instantiation definition decl itself is the only one that CodeGen needs to see. (Earlier declarations would have a different TSK, and the language rules generally don't permit any later decls.)

lib/AST/RecordLayoutBuilder.cpp
3069

It seems desirable to me for Clang's notion of what the "key function" is to exactly match the ABI specification. That way, the decision to not emit a vtable with an inline key function is purely a lowering concern, not part of the program model represented by the frontend, and non-compiler tools who query this data will get correct answers. Also, if we made the suggested change, I'd still want to perform the linkage check to avoid unnecessary emission of vtables for explicit instantiation definitions, so this wouldn't remove any complexity from CodeGen.

If we want to go down this path, I'd prefer that we also change the ABI document to say that an inline virtual function definition results in the class having no key function.

lib/CodeGen/CGVTables.cpp
889

OK, but that'd mean putting the same check into both callers of this function. As an alternative, what do you think about renaming this function to something more like "MarkVTableDemanded" that doesn't suggest that we'll necessarily emit it?

rjmccall added inline comments.Nov 29 2018, 1:46 PM
lib/AST/RecordLayoutBuilder.cpp
3069

That's fair. We could instead wrap all the calls to the function from IRGen to apply this rule retroactively; that should be easy.

@rsmith, what was the fate of this patch? I thought it landed but cannot find a trace of it in the master...

v.g.vassilev resigned from this revision.Jun 25 2022, 1:08 PM

I think this landed in a different form.

Herald added a project: Restricted Project. · View Herald TranscriptJun 25 2022, 1:08 PM