This is an archive of the discontinued LLVM Phabricator instance.

TableGen: Streamline the semantics of NAME
ClosedPublic

Authored by nhaehnle on May 27 2018, 1:46 PM.

Details

Summary

The new rules are straightforward. The main rules to keep in mind
are:

  1. NAME is an implicit template argument of class and multiclass, and will be substituted by the name of the instantiating def/defm.
  1. The name of a def/defm in a multiclass must contain a reference to NAME. If such a reference is not present, it is automatically prepended.

And for some additional subtleties, consider these:

  1. defm with no name generates a unique name but has no special behavior otherwise.
  1. def with no name generates an anonymous record, whose name is unique but undefined. In particular, the name won't contain a reference to NAME.

Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.

The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers in the edge cases, as the old version of the
name-resolution-consistency.td test case shows.

Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.

Some existing .td files have to be adjusted because they ended up
depending on the undocumented quirks of the old implementation.

Change-Id: I694095231565b30f563e6fd0417b41ee01a12589

Diff Detail

Repository
rL LLVM

Event Timeline

nhaehnle created this revision.May 27 2018, 1:46 PM
simon_tatham added inline comments.May 29 2018, 9:41 AM
docs/TableGen/LangRef.rst
151 ↗(On Diff #148766)

I haven't fully got my head round all of this, but this new description of NAME doesn't quite seem to match the text in index.rst:

Each def record has a special entry called "NAME". This is the name of the record ("ADD32rr" above). In the general case def names can be formed from various kinds of string processing expressions and NAME resolves to the final value obtained after resolving all of those expressions. The user may refer to NAME anywhere she desires to use the ultimate name of the def.

The general intention seems to be the same (if you refer to NAME in some expression in a class declaration, then each def that inherits that expression gets it evaluated in terms of that def's own name). But the old text says that NAME is also a property of the final def, whereas the new text seems to suggest that it's a more transient entity that never _really_ exists in the def but is just something classes can refer to while everything's being set up.

In my JSON backend (D46054) I manually filled in the NAME field in the JSON dict for every output def, because that text in index.rst said it should be there. But if that's not a reflection of reality any more, perhaps I should rename that field to !name to mark it as one of the extra pieces of JSON-level metadata?

tra added a comment.May 29 2018, 2:01 PM

Perhaps unrelated documentation cleanup can be extracted into a separate patch.

docs/TableGen/LangRef.rst
247–251 ↗(On Diff #148766)

[doc cleanup candidate] I don't think multiclass supports local variables.

foo.td:2:3: error: expected 'let', 'def', 'defm' or 'foreach' in multiclass body
  int Baz = Bar;
  ^
387–389 ↗(On Diff #148766)

I'd add an example similar to def here as well.

include/llvm/TableGen/Record.h
1907 ↗(On Diff #148766)

However fun puns are, I'd rather use a boring descriptive name. VarNameToTrack would make the purpose somewhat more obvious than Needle.

lib/TableGen/TGParser.cpp
249–250 ↗(On Diff #148766)

Can this be folded into getNameInit() ?

286–292 ↗(On Diff #148766)

This could use some comments explaining that this deals with expanding default template arguments.

294 ↗(On Diff #148766)

Do I understand it correctly that this error will be produced if we can't get complete value for the default argument? If so, then we should probably change the message a bit. Saying "value not specified" for an implicit argument which may intentionally be left unspecified is somewhat confusing. Perhaps something along the lines of "default argument X has unspecified value" would work better?

lib/Target/AArch64/AArch64InstrFormats.td
8648 ↗(On Diff #148766)

Given that it's an implicit argument of class/multiclass, it should be available here, so there must be another reason for the change.

IIUIC, this is needed because previously NAME would often be resolved to be the name of the top-level def/defm and this is what this code was relying on. Now that NAME is resolved to complete chain of templates from the top level to this multiclass, this no longer works. Is that so?

If this is indeed the case, I'd rename Name->BaseName to make it a tiny bit easier to understand.
I'd also add more details to the patch description as it would help explaining what specifically is wrong with using NAME this way.

nhaehnle edited the summary of this revision. (Show Details)May 30 2018, 4:21 AM
nhaehnle updated this revision to Diff 149084.May 30 2018, 4:21 AM
nhaehnle marked 6 inline comments as done.

Address review comments.

Thank you for the review!

docs/TableGen/LangRef.rst
151 ↗(On Diff #148766)

Right. I don't have a very strong opinion on whether NAME should really occur in the final defs, but they currently don't occur consistently and nobody actually uses it, so I lean slightly against having it (which is reflected in the patch). Note that you can always get the name of a record in TableGen by using !cast<string>(...), which is a nice mirror construct of the more common !cast<ClassName>(some_string).

I'm updating the docs accordingly. I think your suggestion for the JSON dict makes sense as well.

247–251 ↗(On Diff #148766)

Done as a separate patch.

387–389 ↗(On Diff #148766)

Done.

include/llvm/TableGen/Record.h
1907 ↗(On Diff #148766)

Done.

lib/TableGen/TGParser.cpp
249–250 ↗(On Diff #148766)

Maybe I misunderstand you, but CurRec->getNameInit() returns the name of the class here, while what we want is "NAME" but with a scoping prefix because we treat it like a template arg. So if the class name is "Foo", the string we're looking for is "Foo:NAME".

I personally find the whole scoping thing is a bit awkward, but it works fine from what I can tell.

286–292 ↗(On Diff #148766)

Done?

294 ↗(On Diff #148766)

I'm not sure how I feel about this. The common case in which you'd run into this error is if you forgot a template argument, and for that case, the error message as it currently stands seems more likely to put you on the right track.

The deeper issue here is that we allow ? as an explicit template argument (and I've actually used that, although I could have worked around it), but we don't distinguish between a default template argument that was set to ? (which won't work) and a template argument that simply has no default.

It makes sense to clean that up at some point, but the same issue also exists for class template arguments, and it doesn't really fit into this change.

lib/Target/AArch64/AArch64InstrFormats.td
8648 ↗(On Diff #148766)

You understand correctly. I'm making the change for the AArch64 .td file.

I'm sticking with Name in X86InstrAVX512.td, because that file already has precedent for using "Name" for the same purpose (in multiclass avx512_int_broadcastbw_reg).

tra accepted this revision.May 30 2018, 11:38 AM
tra added inline comments.
lib/TableGen/TGParser.cpp
249–250 ↗(On Diff #148766)

My thinking was that all the information necessary to derive the name is contained in CurRec and so could be done in a CurRec's method (though maybe getNameInit() may not be the right one). Given that there's only one place where we do this, I'm OK to keep it as is.

294 ↗(On Diff #148766)

Ah, we're actually dealing with two separate error conditions here. One would be "not enough template arguments" and the other is "we have to provide some default arguments, but can't get the values." OK. I've missed the former.

If there's no easy way to separate those the current error message should be OK to cover both cases.

lib/Target/AArch64/AArch64InstrFormats.td
9418 ↗(On Diff #149084)

defm "" pattern is something we should probably highlight in the docs (as examples for def/defm in a multiclass?) because it's somewhat unintuitive. We need to point that defm w/o a name will produce a unique name, while "" is effectively a synonym for NAME (IIUIC, due to rule 2).

8648 ↗(On Diff #148766)

OK.

This revision is now accepted and ready to land.May 30 2018, 11:38 AM
nhaehnle added inline comments.Jun 4 2018, 7:30 AM
lib/Target/AArch64/AArch64InstrFormats.td
9418 ↗(On Diff #149084)

I had already added a mention of this in the LangRef, but I've made it more explicit with an example.

This revision was automatically updated to reflect the committed changes.