IRTranslator

Reference

Overview

This pass can be disabled according to LLVM selector type. There are three selector types: FastISel, GlobalISel, and SelectionDAG. Both FastISel and SelectionDAG do not use IRTranslator pass for ISel, but instead uses target dependent passes, such as MipsModuleDAGToDAGISel, Mips16DAGToDAGISel, MipsSEDAGToDAGISel, etc. see MipsPassConfig::addInstSelector() in llvm/lib/Target/Mips/MipsTargetMachine.cpp. Users can provide options to help LLVM determine the right selector type. The logic is programmed at TargetPassConfig::addCoreISelPasses() in llvm/lib/CodeGen/TargetPassConfig.cpp. GlobalISel is a framework aiming to be used to replace FastISel and SelectionDAG. More on GlobalISel.

IRTranslator pass is responsible for translating LLVM IR Function into a Generic MIR 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)

and

call i32 @puts(i8* %cast210)

is translated according to the ABI rules of the target.

Translating Function Calls

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 implementation.

Translating 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 (Machine Common Subexpression Elimination Pass)

Tracking the pass code

Pass Creation/Registration

TargetPassConfig::addCoreISelPasses()
-> addIRTranslator()
   -> MipsPassConfig::addIRTranslator()
      -> TargetPassConfig::addPass(new IRTranslator());

IRTranslator::runOnMachineFunction

Steps:

  1. get the IR function for this MachineFunction. ??? already has a MachineFunction for this IR function?
  2. // Algo:
    //   CallLowering = MF.subtarget.getCallLowering()
    //   F = MF.getParent()
    //   MIRBuilder.reset(MF)
    //   getMBB(F.getEntryBB())
    //   CallLowering->translateArguments(MIRBuilder, F, ValToVReg)
    //   for each bb in F
    //     getMBB(bb)
    //     for each inst in bb
    //       if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence))
    //         report_fatal_error("Don't know how to translate input");
    //   finalize()
IRTranslator::runOnMachineFunction()
  • A DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB; store all BB->MBB.
    • A one to one mapping.
  • MachineBasicBlock * MachineFunction::CreateMachineBasicBlock(const BasicBlock *bb)
  • Translate Instructions:IRTranslator::translateXXX()
    • IRTranslator::translate()
    • IRTranslator::translateLoad()
    • IRTranslator::translateStore()
    • IRTranslator::translateGetElementPtr()
    • IRTranslator::translateMemFunc()
    • IRTranslator::translateCall()
    • IRTranslator::translateInvoke()
    • IRTranslator::translateCallBr()
    • IRTranslator::translateLandingPad()
    • IRTranslator::translateInlineAsm()
    • IRTranslator::translateAlloc()
    • IRTranslator::translatePHI()
    • IRTranslator::translateSimpleIntrinsic()
    • ~ 37 funcs.

IRTranslator::translate()

The general algorithm:

  1. Look for a virtual register for each operand or create one.
  2. Update the VMap accordingly.
    • Alternative: For constant arguments, if they are compile time constants, produce an immediate in the right operand and do not touch ValToVReg.
    • In implementation: Actually we will go with a virtual register for each constants because it may be expensive to actually materialize the constant. Moreover, if the constant spans on several instructions, CSE may not catch them.
    • Update ValToVReg and remember that we saw a constant in Constants. We will materialize all the constant in finalize.
  3. Create the generic instruction.

Reference:

  • llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
  • ``

    // 
    

IRTranslator::translateLoad()

Call path

IRTranslator::runOnMachineFunction() -> IRTranslator::translate(Inst) -> IRTranslator::translateLoad(), via HANDLE_INST macro, and instruction definitions in llvm/IR/Instructions.def:

// IRTranslator::translate(const Instruction &Inst)

  switch (Inst.getOpcode()) {
#define HANDLE_INST(NUM, OPCODE, CLASS)                                        \
  case Instruction::OPCODE:                                                    \
    return translate##OPCODE(Inst, *CurBuilder.get());
#include "llvm/IR/Instruction.def"
  default:
    return false;
  }
code IRTranslator::translateLoad()
Created Jul 19, 2020 // Last Updated Jul 22, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?