IRTranslator

This pass translates the input LLVM-IR Function to a Generic Machine IR MachineFunction. This is typically a direct translation but does occasionally get a bit more involved. For example:

%2 = add i32 %0, %1

becomes:

%2:_(s32) = G_ADD %0:_(s32), %1:_(s32)

whereas

call i32 @puts(i8* %cast210)

is translated according to the ABI rules of the target.

Note

The currently implemented portion of the LLVM Language Reference Manual is sufficient for many compilations but it is not 100% complete. Users seeking to compile LLVM-IR containing some of the rarer features may need to implement the translation.

Target Intrinsics

There has been some (off-list) debate about whether to add target hooks for translating target intrinsics. Among those who discussed it, it was generally agreed that the IRTranslator should be able to lower target intrinsics in a customizable way but no work has happened to implement this at the time of writing.

Translating Function Calls

The IRTranslator also implements the ABI’s calling convention by lowering calls, returns, and arguments to the appropriate physical register usage and instruction sequences. This is achieved using the CallLowering interface, which provides several hooks that targets should implement: lowerFormalArguments, lowerReturn, lowerCall etc.

In essence, all of these hooks need to find a way to move the argument/return values between the virtual registers used in the rest of the function and either physical registers or the stack, as dictated by the ABI. This may involve splitting large types into smaller ones, introducing sign/zero extensions etc. In order to share as much of this code as possible between the different backends, CallLowering makes available a few helpers and interfaces:

  • ArgInfo - used for formal arguments, but also return values, actual arguments and call results; contains info such as the IR type, the virtual registers etc; large values will likely have to be split into several ArgInfo objects (CallLowering::splitToValueTypes can help with that);

  • ValueAssigner - uses a CCAssignFn, usually generated by TableGen (see Calling Conventions), to decide where to put each ArgInfo (physical register or stack); backends can use the provided IncomingValueAssigner (for formal arguments and call results) and OutgoingValueAssigner (for actual arguments and function returns), but it’s also possible to subclass them;

  • ValueHandler - inserts the necessary instructions for putting each value where it belongs; it has pure virtual methods for assigning values to registers or to addresses, and a host of other helpers;

  • determineAndHandleAssignments (or for more fine grained control, determineAssignments and handleAssignments) - contains some boilerplate for invoking a given ValueAssigner and ValueHandler on a series of ArgInfo objects.

Aggregates

Caution

This has changed since it was written and is no longer accurate. It has not been refreshed in this pass of improving the documentation as I haven’t worked much in this part of the codebase and it should have attention from someone more knowledgeable about it.

Aggregates are lowered into multiple virtual registers, similar to SelectionDAG’s multiple vregs via GetValueVTs.

TODO: As some of the bits are undef (padding), we should consider augmenting the representation with additional metadata (in effect, caching computeKnownBits information on vregs). See PR26161: [GlobalISel] Value to vreg during IR to MachineInstr translation for aggregate type

Translation of Constants

Constant operands are translated as a use of a virtual register that is defined by a G_CONSTANT or G_FCONSTANT instruction. These instructions are placed in the entry block to allow them to be subject to the continuous CSE implementation (CSEMIRBuilder). Their debug location information is removed to prevent this from confusing debuggers.

This is beneficial as it allows us to fold constants into immediate operands during InstructionSelect, while still avoiding redundant materializations for expensive non-foldable constants. However, this can lead to unnecessary spills and reloads in an -O0 pipeline, as these virtual registers can have long live ranges. This can be mitigated by running a localizer after the translator.