[RFC] Conditional RegClass membership

Hello,

About a month ago, I submitted a set of patches for review on llvm-commit. The most controversial of the patches, http://lists.cs.uiuc.edu/pipermail/llvm-commits/attachments/20150622/d104ea71/attachment-0009.obj deals with the fact that before ARMv8, the rGPR RegClass in Thumb encodings didn’t include SP; but from ARMv8 onwards, it does include it.

RegClass membership is currently implemented as entirely static, driven by read-only TableGen’d tables and switch blocks encoding the various classes, subclasses, and their relationships. The approach I had taken in my patch was to include ARMGenInstrInfo.inc for a second time, after re-defining rGPRRegClassID to use a different RegClass in the same instructions. Then, Thumb2InstrInfo constructor overrides the MCInstrInfo that it inherited from ARMBaseInstrInfo with the “patched” one. (This “patching”, still, happens at compile-time.)

As John rightly noted, this approach looks rather hacky and confusing:

This isn’t “rGPR includes SP” it’s “rGPR is #defined to GPRnopc”, which makes things really confusing if you’re just looking at the .td files to figure out what’s what you see instructions that use rGPR, and you see a definition of the rGPR register class, but those instructions may

actually be redefined to use GPRnopc due to something happening elsewhere that you haven’t noticed.

James added, “Given these instructions are no longer unpredictable the rest of the compiler should know about them too, not just the MC layer, so this is even more of a hack,” – and he suggested instead converting every instruction that takes an rGPR operand into a multiclass of two instructions, one predicated on HasV8Ops, and the other on its inverse. This isn’t practical, however: ARMInstrThumb2.td specifies several hundred individual encodings, InstAliases and match patterns that use rGPR, and all these would need to be manually duplicated.

Right now, we’re trying to come up with a more sensible approach, and perhaps one that could be useful for other targets as well.

Any suggestions? And are there any other cases where the definition of a register class depends on target attributes?

The MIPS back end also includes a lot of hacks along this and basically follows James’ suggestion: almost every instruction is defined twice, once for 32-bit and once for 64-bit operations.

Having some mechanism in TableGen that would allow a register class used by instructions to be parameterised would simplify this a lot. It would also simplify the C code if we could just ask for the definition of Mips::ADD (for example) for the current target, where currently we have a load of things like ABI.IsN64() ? Mips::AND64 : Mips::AND scattered about the place.

David

And are there any other cases where the definition of a register class depends on target attributes?

As David mentioned, a few instructions (bitwise operations, and comparisons) are register-width operations and we therefore have definitions that differ only by register class. Being able to specify one class that is 32-bit or 64-bit registers as appropriate for the subtarget would be useful. We'd also need a special type in SelectionDAG patterns for register-width integers (similar to iPTR) to be able to reduce the definitions but that's a separate topic.

Another case that comes up in the Mips backend is that subregisters depend on target attributes. Our FPU implementation consists of 3 classes:
* FGR32 - 32-bit FPU registers
* AFGR64 - 64-bit FPU registers on a 32-bit FPU. They are composed of odd/even pairs of 32-bit subregisters.
* FGR64 - 64-bit FPU registers on a 64-bit FPU. They are composed of 32-bit subregisters and a 32-bit subregister representing the additional bits.

The double-precision FPU instructions are defined for both AFGR64 and FGR64. However, the only difference between them is the subregister that is used for bits 32-63 is either an additional 32-bits subregister or the 32-bits from the neighbouring odd-numbered FPU register.

> And are there any other cases where the definition of a register class depends on target attributes?

As David mentioned, a few instructions (bitwise operations, and comparisons) are register-width operations and we therefore have definitions that differ only by register class. Being able to specify one class that is 32-bit or 64-bit registers as appropriate for the subtarget would be useful. We'd also need a special type in SelectionDAG patterns for register-width integers (similar to iPTR) to be able to reduce the definitions but that's a separate topic.

Another case that comes up in the Mips backend is that subregisters depend on target attributes. Our FPU implementation consists of 3 classes:
* FGR32 - 32-bit FPU registers
* AFGR64 - 64-bit FPU registers on a 32-bit FPU. They are composed of odd/even pairs of 32-bit subregisters.
* FGR64 - 64-bit FPU registers on a 64-bit FPU. They are composed of 32-bit subregisters and a 32-bit subregister representing the additional bits.

The double-precision FPU instructions are defined for both AFGR64 and FGR64. However, the only difference between them is the subregister that is used for bits 32-63 is either an additional 32-bits subregister or the 32-bits from the neighbouring odd-numbered FPU register.

Hi,

You may want to take a look at the AMDGPU backend. We have a somewhat
similar situation where instructions differ only by their operands types
(_e32 and _e64 encoding variants).

We also have instructions which are identical, except that their opcode
encoding is dependent on the subtarget. The solution we're using
is to create multiclasses for each instruction. The multiclass
contains a pseudo instruction, which is what is used in all
the MachineFunction passes, plus one def per instruction variant.

The pseudo instructions are lowered to the correct variant during
MachineInstr -> MCInst lowering. The lowering is handled
automatically by tables generated by the InstrMapping classes
in TableGen.

Take a look at lib/Target/AMDGPU/SIInstrInfo.td for examples.

-Tom