This is an archive of the discontinued LLVM Phabricator instance.

[TableGen] Add a backend to help with target enums
AcceptedPublic

Authored by frasercrmck on Mar 31 2022, 9:25 AM.

Details

Summary

This patch adds a TableGen backend which aims to help keep enums and
their values in sync between TableGen and C++. Previously enums would be
defined separately, usually with a comment to the effect of "must be
kept in sync with XXX".

Enumerators can be individually defined with or without values. Enums
can be given underling types and be optionally declared as enum classes.
Support is also present for automatically converting enums to/from
string values, using custom string values if desired.

The backend operates on two new basic classes: Enum and EnumMember,
which are fairly self-explanatory.

Although almost every (if not all) backends could likely stand to
benefit from this enum support to some extent, only a handful of RISC-V
enums have been converted to use this new support, both as a proof of
concept and to avoid bloating the patch.

Diff Detail

Event Timeline

frasercrmck created this revision.Mar 31 2022, 9:25 AM
frasercrmck requested review of this revision.Mar 31 2022, 9:25 AM

create enums based on derived definitions of Enum (not classes)

add copyright header & docs; fix Target.td comment

Sorry, I'm just quickly passing through for now. How does this new feature relate to the existing GenericEnum class?

https://llvm.org/docs/TableGen/BackEnds.html#generic-enumerated-types

Sorry, I'm just quickly passing through for now. How does this new feature relate to the existing GenericEnum class?

https://llvm.org/docs/TableGen/BackEnds.html#generic-enumerated-types

Good question! If I'm honest, I originally wrote this patch back in 2017 before that class was added and didn't fully grok GenericEnum when rebasing the patch. I thought it was purely internal to the searchable-table backend for some reason.

The way I see it, these two enum classes overlap more than is ideal. Personally I feel that GenericEnum's implicit use of alphabetical enumerator order isn't as flexible for use in C++ as using an ordered list is. When explicitly instantiating values that's less of a problem, though. Having to/from string support is quite useful, too.

Now whether or not those features can/should go into GenericEnum is a question I don't really have the answer to. If there's no appetite to really use TableGen enums in backends then it's probably not worth the hassle.

So one possibility is to deprecate GenericEnum, replace all uses of it with your Enum, and document Enum as the standard solution.

What do others think? @RKSimon @craig.topper

So one possibility is to deprecate GenericEnum, replace all uses of it with your Enum, and document Enum as the standard solution.

What do others think? @RKSimon @craig.topper

Obviously we shouldn't be duplicating functionality, but other than this code is very unfamiliar to me.

Why don't you take an inventory of the number of uses of GenericEnum? Then we can see if it's practical to replace those uses.

Also, please review your Enum against GenericEnum to be sure you've covered all the features.

I don't think we can eliminate GenericEnum, because there may be users outside of the LLVM project. But we could deprecate it in favor of Enum.

And, of course, you will have to write documentation similar to that for GenericEnum.

craig.topper added inline comments.Apr 9 2022, 8:36 PM
llvm/include/llvm/Target/Target.td
1776

This set unset but you're using empty string instead of '?'

1803

MuEnum -> MyEnum?

1823

Would StringRef be better?

llvm/utils/TableGen/EnumEmitter.cpp
26

MuEnum -> MyEnum?

64

EnumClass is unused in release builds

68

Doesn't getAllDerivedDefinitions return a std::vector? Can we just assign it to Enums instead of copying every value.

78

Why getValueAsOptionalString and not getValueAsString? Are you intending to allow Unset as well as empty?

109

command after "names" I think.

121

Maybe just a regular if statement for UnderlyingType being set instead of the conditional operator and an empty string.

156

Why do we need a Twine in the middle here?

180

Same question about the Twine here

myhsu added inline comments.Apr 10 2022, 11:45 AM
llvm/utils/TableGen/EnumEmitter.cpp
118

I wonder if it will be better to use Twine here?

142

can we simplify this using Record::getValueAsOptionalString?

166

ditto

frasercrmck marked 14 inline comments as done.

address feedback

llvm/include/llvm/Target/Target.td
1776

As in a comment below I think <string name = NAME> and field string Name = name is what I want here.

1823

Yeah, I'll do that. Ta

llvm/utils/TableGen/EnumEmitter.cpp
64

Ah yes, thanks! I'll just assert(Records.getClass("Enum")) then

68

Yep, thanks.

78

I was kind of hoping EnumMember could have both a default of NAME and a template parameter for a common situation where it might need renaming, without relying on an extra derived class. I think class EnumMember<string name = NAME> is the right way to do that? In which case, no, this should never be unset - or empty, really? Should I assert that it isn't empty, then?

118

Done

121

Yeah, that's better. Ta

142

Much better, thank you!

156

We don't! Not sure what was happening there.

oh, also, renamed PrintMethod to ToStringMethod (as "print" is an overloaded term) and MatchMethod to FromStringMethod (to better serve as the compliment to ToString)

  • remove stale comments

finish print/match renaming effort

Thanks for the input! Since it's not a clear "no" I've ploughed on.

One thing that probably needs a bit of feedback is whether this should continue to be a separate backend as I've got it in this patch. The searchable tables backend currently gathers GenericEnums for use in tables and emits the decls, which I see as cross-purposes, but obviously another backend is adding extra compile time to targets. My inclination is to support Enum in the searchable tables backend but not emit them as enum decls anywhere but the enum backend. Then it's (arguably) cleaner that targets can choose the enum backend if they just want enums.

Also, if the searchable tables backend now uses Enum then Enum should live somewhere that include/llvm/TableGen/SearchableTable.td can include. So, include/llvm/TableGen/Enum.td?

Lastly, what's the deprecation/removal path for GenericEnum if this does go ahead? We only have one example of it in tree which is AMDGPU. I'm currently experimenting whether I can move everything there to Enum. I presume that this sort of TableGen infrastructure isn't part of a stable API, but I don't want to bother downstream targets if it can be helped. Apart from straight-up removal, one thought would be to drop GenericEnum enum generation but keep it for tables, and encourage people to move to Enum. Then remove it later?

Looking again, the way AMDGPU use GenericEnum (in particular the FilterClass) is different to how I'd envisaged enums. For example,MIMGDim : GenericEnum { let FilterClass = "AMDGPUDimProps"; } allows the creation of an enum from a completely different complex class without having to manually enumerate them, since it just pulls in all defs of the AMDGPUDimProps class. I'd originally done something similar but found that relying on alphabetical order can be restrictive in its own sense, so I used list<EnumMember> Members. I feel there's a valid use case for both behaviours.

Is there a way we can support both in the same class? A toggling of behaviour between FilterClass or Members? Or something like if FilterClass is a subclass of EnumMembers it could pull in members in a different way. Might be a little convoluted.

Sorry, I'm pretty busy now and don't have time right away to work on this. Would it make sense to document it now? Then we can determine whether the two schemes can be merged in a reasonable way.

Again, sorry for being scarce.

craig.topper added inline comments.Apr 12 2022, 9:32 AM
llvm/utils/TableGen/EnumEmitter.cpp
65

Is this assert important? It looks like the code will just work even if there are no enums. If you're really concerned, it might be better to check !Enums.empty after the getAllDerivedDefinitions?

77

Should these asserts be fatal errors since they are under the control of the input file?

107

Only duplicate names would be caught by the compiler right? It's not an error to have duplicate values.

151

Looking at other uses of OS.ident, I don't think we typically use it for small constant indentations. The spaces are just included in the strings. That would make the formatting more obvious from the tablegen source.

frasercrmck marked 3 inline comments as done.Apr 22 2022, 8:27 AM
frasercrmck added inline comments.
llvm/utils/TableGen/EnumEmitter.cpp
65

I don't think it's important, no. From what I can tell, getAllDerivedDefinitions reports a fatal error if the class isn't defined. That's better than an assert.

77

Done.

107

It's only a error when requesting a ToString method, due to the way we use a switch over the enum. So it's an "opt-in" error, in that sense. Maybe the comment isn't making that clear?

151

Ah yeah, you're right. Thanks!

frasercrmck marked 3 inline comments as done.

address feedback

This revision is now accepted and ready to land.Apr 23 2022, 3:43 PM

Sorry I've been scarce for this patch. Doesn't it need documentation?