Skip to content

Writing an LLVM backend for Bird

What is LLVM?

What is a Back-End?

Relevant Documentation

Basic reference for LLVM back-end writing is: http://jonathan2251.github.io/lbd/

This document is huge.. A short summary is given at https://llvm.org/docs/WritingAnLLVMBackend.html

TableGen is a program which is specifically written to help writing LLVM backends. A nice documentation about TableGen is provided by the Univ. of Aalto: https://wiki.aalto.fi/display/t1065450/LLVM+TableGen

A shortcut to writing backends is to examine already written backends. Here’s the backend for SPARC:

https://github.com/llvm-mirror/llvm/blob/master/lib/Target/Sparc/SparcTargetMachine.cpp

The following are also very useful

https://eli.thegreenplace.net/2013/02/25/a-deeper-look-into-the-llvm-code-generator-part-1

https://llvm.org/docs/CodeGenerator.html

Steps for writing the backend

  1. Write a subclass of TargetMachine class for our processor: Generate BirdTargetMachine.cpp and BirdTargetMachine.h files.
  2. Describe the register set.
  3. Describe the instruction set.

The BirdTargetMachine Class

namespace llvm {

class Module;

class BirdTargetMachine : public LLVMTargetMachine {
  const DataLayout DataLayout;       // Calculates type size & alignment
  BirdSubtarget Subtarget;
  BirdInstrInfo InstrInfo;
  TargetFrameInfo FrameInfo;

protected:
  virtual const TargetAsmInfo *createTargetAsmInfo() const;

public:
  BirdTargetMachine(const Module &M, const std::string &FS);

  virtual const BirdInstrInfo *getInstrInfo() const {return &InstrInfo; }
  virtual const TargetFrameInfo *getFrameInfo() const {return &FrameInfo; }
  virtual const TargetSubtarget *getSubtargetImpl() const{return &Subtarget; }
  virtual const TargetRegisterInfo *getRegisterInfo() const {
    return &InstrInfo.getRegisterInfo();
  }
  virtual const DataLayout *getDataLayout() const { return &DataLayout; }
  static unsigned getModuleMatchQuality(const Module &M);

  // Pass Pipeline Configuration
  virtual bool addInstSelector(PassManagerBase &PM, bool Fast);
  virtual bool addPreEmitPass(PassManagerBase &PM, bool Fast);
};

} // end namespace llvm

Defining Registers

The following Registerclass (specified in the file target.td) is used to define an object for each register.

class Register<string n> {        //register name
  string Namespace = "";
  string AsmName = n;
  string Name = n;
  int SpillSize = 0;
  int SpillAlignment = 0;
  list<Register> Aliases = [];
  list<Register> SubRegs = [];
  list<int> DwarfNumbers = [];
}

in theBirdRegisterInfo.tdfile, there are register definitions that utilize theRegisterclass, such as:

def AL : Register<"AL">, DwarfRegNum<[0, 0, 0]>;

This defines register AL. “DwarfRegNum” is not important for us..

From the register info file, TableGen generates a TargetRegisterDescobject for each register. TargetRegisterDesc

is defined in include/llvm/Target/TargetRegisterInfo.hwith the following fields:

struct TargetRegisterDesc {
  const char     *AsmName;      // Assembly language name for the register
  const char     *Name;         // Printable name for the reg (for debugging)
  const unsigned *AliasSet;     // Register Alias Set
  const unsigned *SubRegs;      // Sub-register set
  const unsigned *ImmSubRegs;   // Immediate sub-register set
  const unsigned *SuperRegs;    // Super-register set
};

Structure of tablegen files

Tablegen inputs .td files and generates .inc files.

TableGen files consist of two key parts: classes (marked with the classkeyword) and definitions (marked with the defkeyword). Definitions are instantiations of classes..

TableGen’s syntax includes some automation concepts that facilitate development and reduce amount of code, for exampleforeach, letand multiclass. letallows derived class or definition to override a value defined by a superclass. Multiclasses are used to describe groups of records that may be instantiated all at once.