This is an archive of the discontinued LLVM Phabricator instance.

[CodeGen] Replace CCValAssign::Loc with std::variant (NFCI)
ClosedPublic

Authored by barannikov88 on Oct 16 2022, 11:18 AM.

Details

Summary

The motivation behind this change is as follows.
Targets with stack growing up (there are no such in-tree targets) pass
arguments at negative offsets relative to the stack pointer. This makes
it hard to use the generic value assigner because CCValAssign stores the
offset as an unsigned integer, which is then zero-extended when
converted to int64_t, e.g. when passing to CreateFixedObject. This
results in conversion of, for example, -4 into 4294967292, which is not
desired.

While it is possible to insert a cast to int before passing the result
of getLocMemOffset into CreateFixedObject in backend code, this is
error-prone, and some uses of getLocMemOffset are located in
places common to all backends (e.g. CallLowering::handleAssignments).

That said, I wanted to change the type of the memory offset from
unsigned to int64_t (this would be consistent with other places
where stack offsets are used). However, the Loc field which stores the
offset is shared between three different kinds of the location:
register, memory, and "pending". Storing a register number as int64_t
does not seem right (there are Register and MCRegister for this), so
I did the most straightforward change - replaced the Loc field with
std::variant.

The main change that changes the type of the memory offset from
unsigned to int64_t will be in a follow-up patch to simplify the
review.

Diff Detail

Unit TestsFailed

Event Timeline

barannikov88 created this revision.Oct 16 2022, 11:18 AM
barannikov88 requested review of this revision.Oct 16 2022, 11:18 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 16 2022, 11:18 AM
barannikov88 added inline comments.Oct 16 2022, 11:22 AM
llvm/include/llvm/CodeGen/CallingConvLower.h
91–100

This constructor was added because the default constructor used in get* methods has become implicitly-deleted (due to non-trivial constructor of Register in the union). This also reduces code duplication a bit.

Editorial suggestions are appreciated.

Revert unintended change

Looks okay to me, at least on the SPARC side.
For the CodeGen changes I'm not seeing anything obviously wrong, but it'd be better if someone else also review that part since I'm not very familiar with its workings.

llvm/lib/Target/Sparc/SparcISelLowering.cpp
1151–1152

Minor nit but it'd be better if this line is removed.

Remove empty line

barannikov88 marked an inline comment as done.Oct 22 2022, 8:27 AM

Ping
I don't know who to ask for review, this part of CodeGen is not changed frequently. The last non-refactoring changes were made two years ago.

tschuett added inline comments.
llvm/include/llvm/CodeGen/CallingConvLower.h
63

You cannot use std::variant<Register, unsigned, unsigned>?

barannikov88 added inline comments.Dec 17 2022, 11:57 AM
llvm/include/llvm/CodeGen/CallingConvLower.h
63

I crafted this patch before LLVM has moved to C++17. I'll try and see what it will look like, thanks for reminding.

63

I've tried.
std::variant allows to remove some assertions and the Kind discriminator, some methods become one-liners, and the total patch size is reduced by 20 lines.
However, due to and repeated unsigned type and registers passed in arguments as 'unsigned', I have to write weird looking stuff like:

void convertToReg(unsigned RegNo) { Data = Register(RegNo); }

void convertToMem(unsigned Offset) {
  Data = decltype(Data)(std::in_place_index<LK_Memory>, Offset);
}

which, in my opinion, is more difficult to read than

void convertToReg(unsigned RegNo) {
  Kind = LocKind::Register;
  this->RegNo = RegNo;
}

void convertToMem(unsigned Offset) {
  Kind = LocKind::Memory;
  this->Offset = Offset;
}

It would look much prettier if the 'Offset' was 'int64_t' (which I planned to fix next), so that all three types are different and in_place_index is unnecessary.
Another small inconvenience is that valuable comment inside the union. Any idea how to port it to`std::variant` variant?

That said, there does not seem to be a huge benefit of using std::variant here. But if more people support the idea of using it, I'll update the patch.

I cannot stop you, but I prefer variant over unions. Does it become easier, if you introduce the int64_t in this patch? You could put the documentation above the variant?

Does it become easier, if you introduce the int64_t in this patch?

Changing the type to int64_t is not a local change, it will bloat the patch considerably and make it harder to review.
I also don't want to change the type to int64_t before this patch, because unsigned Loc; is shared between Register and Memory and Pending variants, and changing it to int64_t does not look right.
What do you say if I ping you after the second patch lands so that you can exercise std::variant here?

Ah, I don't have to change the interfaces right away, I only need to change the storage type. Just a sec...

Use std::variant.

@tschuett
PTAL. This is the first time I ever used std::variant, so it might not be very canonical.
Any other comments are also welcome, including my poor English.

I am unsure about the value of LockKind.

llvm/include/llvm/CodeGen/CallingConvLower.h
144

Here you could also use std::holds_variant<unsigned>(Data).

152

Or std::get<int>(Data).

I am unsure about the value of LockKind.

Could you elaborate?

llvm/include/llvm/CodeGen/CallingConvLower.h
144

Yes, thanks.
I'd keep it with symbolic constant: it protects from bugs if the storage type changes and is arguably more readable.

Either you have to keep LockKind in-sync with the variants or you have to keep the variants in the functions in-sync. Either is fine by me.

Address review comments

barannikov88 marked 3 inline comments as done.Dec 17 2022, 2:01 PM

Either you have to keep LockKind in-sync with the variants or you have to keep the variants in the functions in-sync. Either is fine by me.

I see now, thanks. That is actually a good point that I didn't think of.
I removed the enum and updated methods to use types as you suggested in inline comments.

Remove unnecessarily introduced extra newlines.

barannikov88 retitled this revision from [CodeGen] Replace CCValAssign::Loc with a discriminated union (NFCI) to [CodeGen] Replace CCValAssign::Loc with std::variant (NFCI).Dec 21 2022, 12:14 PM
barannikov88 edited the summary of this revision. (Show Details)
barannikov88 edited reviewers, added: tschuett; removed: nikic.
nikic accepted this revision.Dec 21 2022, 1:42 PM
nikic added a subscriber: nikic.

LGTM

This revision is now accepted and ready to land.Dec 21 2022, 1:42 PM
MaskRay accepted this revision.Dec 22 2022, 7:59 PM