Ivan Kosarev 21c1ba16ed
[TableGen] Complete the support for artificial registers (#183371)
Artificial registers were added in
eb0c510ecde667cd911682cc1e855f73f341d134
as a means of giving super-registers heavier weights than that
of their subregisters, even when they only contain a single
physical subregister.

Artifical registers thus do exist in code and participate in
register unit weight calculations, but are not supposed to be
available for register allocation.

This patch completes the support for artificial registers to:

- Ignore artificial registers when joining register unit uber
  sets. Artificial registers may be members of classes that
  together include registers and their sub-registers, making it
  impossible to compute normalised weights for uber sets they
  belong to.

  We have a use case downstream relying on this being supported,
  which allows to avoid introducing a large number of additional
  register classes.

- Not generate purely artificial register class intersections.
  It is critical not to have such classes, as the common LLVM
  codegen infrastructure will try to use them to constrain
  classes of virtual registers instead of producing COPYs
  whenever both the source and target register classes contain
  the same artificial registers.

- Not generate sub-classes where classes with the same
  non-artificial members already exist. This is mostly for
  convenience. For example, the HI16-capable subset of AMDGPU's
  AV_32 is VGPR_32, except VGPR_32 also contains the artificial
  staging registers. If the staging registers are not ignored,
  we'll end up having an additional generated register class,
  AV_32_with_hi16_in_VGPR_16, -- harmless, but also useless.

Eliminates a few inferred AMDGPU register classes:
    - VS_32_with_hi16
    - VS_32_Lo256_with_hi16
    - VS_32_Lo128_with_hi16
    - VRegOrLds_32_and_VS_32_Lo256
    - VRegOrLds_32_and_VS_32_Lo128
    - SRegOrLds_32_and_VRegOrLds_32

Causes no register class changes for other targets.
2026-03-04 13:33:26 +00:00
..

LLVM TableGen

The purpose of TableGen is to generate complex output files based on information from source files that are significantly easier to code than the output files would be, and also easier to maintain and modify over time.

The information is coded in a declarative style involving classes and records, which are then processed by TableGen.

class Hello <string _msg> {
  string msg = !strconcat("Hello ", _msg);
}

def HelloWorld: Hello<"world!"> {}
------------- Classes -----------------
class Hello<string Hello:_msg = ?> {
  string msg = !strconcat("Hello ", Hello:_msg);
}
------------- Defs -----------------
def HelloWorld {        // Hello
  string msg = "Hello world!";
}

Try this example on Compiler Explorer.

The internalized records are passed on to various backends, which extract information from a subset of the records and generate one or more output files.

These output files are typically .inc files for C++, but may be any type of file that the backend developer needs.

Resources for learning the language:

Writing TableGen backends:

TableGen in MLIR:

Useful tools: