Skip to content

[TableGen] Extend direct lookup to instruction values in generic tables. #80486

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

Merged
merged 4 commits into from
Feb 7, 2024

Conversation

nvjle
Copy link
Contributor

@nvjle nvjle commented Feb 2, 2024

Currently, for some tables involving a single primary key field which is integral and densely numbered, a direct lookup is generated rather than a binary search. This patch extends the direct lookup function generation to instructions, where the integral value corresponds to the instruction's enum value.

While this isn't as common as for other tables, it does occur in at least one downstream backend and one in-tree backend.

Added a unit test and minimally updated the documentation.

Currently, for some tables involving a single primary key field which is
integral and densely numbered, a direct lookup is generated rather than
a binary search. This patch extends the direct lookup function generation
to instructions, where the integral value corresponds to the instruction's
enum value.

While this isn't as common as for other tables, it does occur in at least
one downstream backend and one in-tree backend.

Added a unit test and minimally updated the documentation.
@nvjle
Copy link
Contributor Author

nvjle commented Feb 2, 2024

If one of @wangpc-pp , @nhaehnle , @Paul-C-Anagnostopoulos , or @TNorthover could review this small patch, it would be appreciated (chosen based on recent or past commits in this area-- other suggestions welcome). Thank you.

Copy link
Contributor

@wangpc-pp wangpc-pp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a great idea generally!

if (SawInstructionField && InstrEnumValueMap.empty()) {
CodeGenTarget Target(Records);
unsigned Num = 0;
for (const CodeGenInstruction *Inst : Target.getInstructionsByEnumValue())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a CodeGenTarget::getInstrToIntMap (or other names?) to get this instr->int mapping, so that we can reuse these logics and sync with other emittters (like you said, InstrInfoEmitter::emitEnums).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you suggested, I have moved this map into CodeGenTarget::InstrToIntMap and added a lookup method CodeGenTarget::getInstrIntValue. The map is now populated in CodeGenTarget::computeInstrsByEnum right after the sort that creates the order in the first place.

Overall this is cleaner and simplified the patch as well. Thanks again for the suggestions.

In a follow-up patch, as you alluded to, I could use the new query in InstrInfoEmitter::emitEnums (and elsewhere if applicable) to reuse/sync the logic.

@@ -638,6 +662,7 @@ void SearchableTableEmitter::collectTableEntries(

Record *IntrinsicClass = Records.getClass("Intrinsic");
Record *InstructionClass = Records.getClass("Instruction");
bool SawInstructionField = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SawInstructionField->HasInstructionField?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed this variable since it is no longer necessary due to having moved the map population logic.

@@ -207,12 +213,17 @@ class SearchableTableEmitter {

// For search indices that consists of a single field whose numeric value is
// known, return that numeric value.
static int64_t getNumericKey(const SearchIndex &Index, Record *Rec) {
static int64_t getNumericKey(const SearchIndex &Index, Record *Rec,
InstrEnumMapT &InstrEnumMap) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A style nit(just mine). What about making getNumericKey a class function like getIntrinsic, so that we don't need to pass InstrEnumMap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Although I removed the InstrEnumMap parameter, it is still useful to do this since we need to invoke the new query function Target->getInstrIntValue.

Move the instruction-to-int map into CodeGenTarget::InstrToIntMap and
add CodeGenTarget::getInstrIntValue query method.

Populate the map in CodeGenTarget::ComputeInstrsByEnum just below
where the order is created in the first place.
@nvjle
Copy link
Contributor Author

nvjle commented Feb 4, 2024

I think this is a great idea generally!

Thank you for the review comments, it is appreciated. I've made changes according to your suggestions below.

Copy link
Contributor

@wangpc-pp wangpc-pp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with nits.

@@ -663,6 +682,8 @@ void SearchableTableEmitter::run(raw_ostream &OS) {
// Emit tables in a deterministic order to avoid needless rebuilds.
SmallVector<std::unique_ptr<GenericTable>, 4> Tables;
DenseMap<Record *, GenericTable *> TableMap;
if (Records.getClass("Instruction"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (Records.getClass("Instruction"))
if (!Records.getAllDerivedDefinitions("Instruction").empty())

Do this only if there are Instruction definitions instead of Instruction class definition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.
I've added the derived definitions guard as suggested. I needed to leave in the original guard since the derived definitions lookup will fail with "The class 'Instruction' is not defined" for clients that do not happen to have a Instruction class at all.

If I could also trouble you (or anyone else) to merge on my behalf, I'd appreciate that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry, I forgot it, we can use getAllDerivedDefinitionsIfDefined here.

If I could also trouble you (or anyone else) to merge on my behalf, I'd appreciate that.

Yeah, no problem!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (used getAllDerivedDefinitionsIfDefined).

nvjle added 2 commits February 5, 2024 07:38
Add derived definitions guard.
Use getAllDerivedDefinitionsIfDefined.
// InstrInfoEmitter::emitEnums.
assert(InstrToIntMap.empty());
unsigned Num = 0;
for (const CodeGenInstruction *Inst : InstrsByEnum)
Copy link
Collaborator

@topperc topperc Feb 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm late to this, but why not make this a field of CodeGenInstruction? We already have a map from Record* to CodeGenInstruction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm late to this, but why not make this a field of CodeGenInstruction? We already have a map from Record to CodeGenInstruction.

Thanks for your comments @topperc, much appreciated. I'll make your suggested change in a new PR shortly, with you as reviewer/committer if you wouldn't mind.

@piotrAMD
Copy link
Collaborator

Looks the code assumes that Index.Fields[0].Enum and Index.Fields[0].IsInstruction are exclusive.

This is not universally true. For example WMMAOpcode2AddrMappingTable in AMDGPU target has both of them set.

This can cause problems, because SearchableTableEmitter::compareBy() or primaryRepresentation() check IsInstruction first and Enum next, but SearchableTableEmitter::getNumericKey() checks Enum first and IsInstruction next.

An immediate fix for that issue would be to switch the conditions around in getNumericKey so it checks Instruction before checking Enum maintainig consistency. Not sure how future-proof that would be, though.

@piotrAMD
Copy link
Collaborator

CC @nvjle (not sure if notifications are sent without explicit mention)

@nvjle
Copy link
Contributor Author

nvjle commented Feb 27, 2024

CC @nvjle (not sure if notifications are sent without explicit mention)

Thanks @piotrAMD, I'll look into this in detail sometime this week. At first glance it does seem there may be a potential problem, but there is no actual failure that I can see. All testing is good thus far, including for AMDGPU. But we surely want this to be bullet proof.

@piotrAMD
Copy link
Collaborator

CC @nvjle (not sure if notifications are sent without explicit mention)

Thanks @piotrAMD, I'll look into this in detail sometime this week. At first glance it does seem there may be a potential problem, but there is no actual failure that I can see. All testing is good thus far, including for AMDGPU. But we surely want this to be bullet proof.

Thanks, I'll try to come up with a reproducer.

@nvjle
Copy link
Contributor Author

nvjle commented Feb 28, 2024

CC @nvjle (not sure if notifications are sent without explicit mention)

Thanks @piotrAMD, I'll look into this in detail sometime this week. At first glance it does seem there may be a potential problem, but there is no actual failure that I can see. All testing is good thus far, including for AMDGPU. But we surely want this to be bullet proof.

Thanks, I'll try to come up with a reproducer.

Hi @piotrAMD, I've revisited this and agree with your reasoning and posted this tiny patch accordingly: #83284. All tests (including the backend I'm working on which is at least as SearchableTable-heavy as AMDGPU) are good and WMMAOpcode2AddrMappingTable isn't actually affected one way or the other.

@piotrAMD
Copy link
Collaborator

Thanks! I tried, but wasn't able to come up with a reproducer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants