[GlobalISel] Are register banks allowed to overlap?

I have two sets of registers, Address Registers (AR) and General Purpose Registers (GR). They cannot be used interchangeably. AR registers cannot be used in ALU operations; GR registers can only be used in ALU operations and as an “index” in some addressing modes.

Naturally (?), I define two register banks, ARB and GRB. Some operations (e.g. add with immediate) can be computed in either AR or GR registers, so I provide alternative mappings in the hope that cross-class copies can be avoided. (Copies are not expensive, but they are still cross-class copies, that is, they can’t be coalesced == not free.)

The problem is some instructions don’t care about register classes / banks. Examples are “move register”, “move immediate” and load / store. They can read / write either AR or GR registers. It looks like I need a third register bank that includes both AR and GR registers so that I don’t overconstrain the result of a load, for example.

How do I deal with the issue? Should I define another regbank that includes both AR and GR banks or this is nonsense and there is other, “intended”, way?

Some operations (e.g. add with immediate) can be computed in either AR or GR registers, so I provide alternative mappings in the hope that cross-class copies can be avoided.

The problem is some instructions don’t care about register classes / banks. Examples are “move register”, “move immediate” and load / store. They can read / write either AR or GR registers.

I think you’re supposed to provide alternative mappings for G_CONSTANT / G_LOAD / G_STORE just like you did for G_ADD, so that the core regbankselect machinery can try to choose the best set of banks to minimize cross-bank copies.

The issue is not with regbankselect, it is with instruction-select, which doesn’t inflate the chosen register classes.

Suppose I have 10 loads into temporaries followed by 10 stores of these temporaries, but only have 8 registers on each bank.

Whichever bank regankselect chooses, there will be no cross-class copies.

instruction-select will try to infer register classes for register banks. It appears that the chosen register class must be “covered by” the register bank. So it can choose AR for ARB or GR for GRB, but it cannot choose the combined AR+GR register class for either of the banks. The inability to select the combined regclass results in 2 of 10 temporaries being spilled later on.

I can override getLargestLegalSuperClass, but it look like it only inflates register classes if the register would otherwise be spilled. I’d like to do the inflation as early as possible (to relieve register pressure).

So far I haven’t found a way to do that other than to introduce the combined regbank that covers the combined AR+GR regclass, but I’m not sure this is the best solution.

That means it did its job correctly. It’s not supposed to be the responsibility of instruction select to second guess the decision made by regbankselect. If there’s a register pressure reason to introduce a cross bank copy, that’s a decision for somewhere later in register allocation to make

This is a post-selection question. Somewhere during or prior to RA

Would it be correct to add the combined register bank so that intruction-select doesn’t have to second guess? Currently, it can select a load to
%tmp:AR = load %ptr or
%tmp:GR = load %ptr
because I only have ARB and GRB banks that cover AR and GR register classes, respectively.

I’d like it to select to
%tmp:R = load %ptr, where R is a superclass of both AR and GR,
and for that to happen I seem to need a register bank (RB?) that covers both AR and GR register classes. Is it valid for register banks to be hierarchical like register classes?

You could technically do it, but I don’t think it makes sense. Conceptually you still have 2 distinct banks.

I’m not sure what you mean by this, but I don’t see why you couldn’t choose AR+GR for one of either bank

What I mean here is that constrainGenericRegister() refuses to set a register’s class if the class is not covered by the selected regbank, which is the case:

I can call MRI.setRegClass() directly, but that would mean I wouldn’t be able to use imported SelectionDAG patterns, which was my initial intention.

In order to use imported SelectionDAG patterns, I’ll also have to implement getRegBankFromRegClass() to return some regbank for AR+GR class, but there isn’t a register bank that covers that class:

I guess I’ll have to implement selection in C++ code and insert copies myself as necessary. That’s unfortunate =\