Printing an instruction

Printing an assembly instruction is an important step in generating target code. Various classes are defined that work as a gateway to the streamers.

First, we initialize the class for instruction, assigning the operands, the assembly string, pattern, the output variable, and so on in the TOYInstrFormats.td file:

class InstTOY<dag outs, dag ins, string asmstr, list<dag> pattern>
    : Instruction {
  field bits<32> Inst;
  let Namespace = "TOY";
  dag OutOperandList = outs;
  dag InOperandList = ins;
  let AsmString = asmstr;
  let Pattern = pattern;
  let Size = 4;
}

Then, we define functions to print operands in TOYInstPrinter.cpp.

void TOYInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
                                  raw_ostream &O) {
  const MCOperand &Op = MI->getOperand(OpNo);
  if (Op.isReg()) {
    printRegName(O, Op.getReg());
    return;
  }
  if (Op.isImm()) {
    O << "#" << Op.getImm();
    return;
  }
  assert(Op.isExpr() && "unknown operand kind in printOperand");
  printExpr(Op.getExpr(), O);
}

This function simply prints operands, registers, or immediate values, as the case may be.

We also define a function to print the register names in the same file:

void TOYInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
  OS << StringRef(getRegisterName(RegNo)).lower();
}

Next, we define a function to print the instruction:

void TOYInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
                               StringRef Annot) {
  printInstruction(MI, O);
  printAnnotation(O, Annot);
}

Next, we declare and define assembly info as follows:

We create a TOYMCAsmInfo.h and declare an ASMInfo class:

#ifndef TOYTARGETASMINFO_H
#define TOYTARGETASMINFO_H
#include "llvm/MC/MCAsmInfoELF.h"
namespace llvm {
class StringRef;
class Target;
class TOYMCAsmInfo : public MCAsmInfoELF {
  virtual void anchor();

public:
  explicit TOYMCAsmInfo(StringRef TT);
};
} // namespace llvm
#endif

The constructor can be defined in TOYMCAsmInfo.cpp as follows:

#include "TOYMCAsmInfo.h"
#include "llvm/ADT/StringRef.h"
using namespace llvm;
void TOYMCAsmInfo::anchor() {}
TOYMCAsmInfo::TOYMCAsmInfo(StringRef TT) {
  SupportsDebugInformation = true;
  Data16bitsDirective = "	.short	";
  Data32bitsDirective = "	.long	";
  Data64bitsDirective = 0;
  ZeroDirective = "	.space	";
  CommentString = "#";
  AscizDirective = ".asciiz";
  HiddenVisibilityAttr = MCSA_Invalid;
  HiddenDeclarationVisibilityAttr = MCSA_Invalid;
  ProtectedVisibilityAttr = MCSA_Invalid;
}

For compilation, we define LLVMBuild.txt as follows:

[component_0]
type = Library
name = TOYAsmPrinter
parent = TOY
required_libraries = MC Support
add_to_library_groups = TOY

Furthermore, we define the CMakeLists.txt file as follows:

add_llvm_library(LLVMTOYAsmPrinter
TOYInstPrinter.cpp
)

When the final compilation takes place, the llc tool—a static compiler—will generate the assembly of the TOY architecture (after registering the TOY architecture with the llc tool).

To register our TOY target with static compiler llc, follow the steps mentioned below:

  1. First, add the entry of the TOY backend to llvm_root_dir/CMakeLists.txt:
    set(LLVM_ALL_TARGETS
    AArch64
    ARM
    …
    …
    TOY
    )
  2. Then, add the toy entry to llvm_root_dir/include/llvm/ADT/Triple.h:
    class Triple {
    public:
    enum ArchType {
    UnknownArch,
    arm, // ARM (little endian): arm, armv.*, xscale
    armeb, // ARM (big endian): armeb
    aarch64, // AArch64 (little endian): aarch64
    …
    …
    toy // TOY: toy
    };
  3. Add the toy entry to llvm_root_dir/include/llvm/ MC/MCExpr.h:
    class MCSymbolRefExpr : public MCExpr {
    public:
    enum VariantKind {
    ...
    VK_TOY_LO,
    VK_TOY_HI,
    };
  4. Add the toy entry to llvm_root_dir/include/llvm/ Support/ELF.h:
    enum {
    EM_NONE = 0, // No machine
    EM_M32 = 1, // AT&T WE 32100
    …
    …
    EM_TOY = 220 // whatever is the next number
    };
  5. Then, add the toy entry to lib/MC/MCExpr.cpp:
    StringRef MCSymbolRefExpr::getVariantKindName(VariantKind
    Kind) {
    switch (Kind) {
    …
    …
    case VK_TOY_LO: return "TOY_LO";
    case VK_TOY_HI: return "TOY_HI";
    }
    …
    }
  6. Next, add the toy entry to lib/Support/Triple.cpp:
    const char *Triple::getArchTypeName(ArchType Kind) {
    switch (Kind) {
    …
    …
    case toy: return "toy";
    }
    const char *Triple::getArchTypePrefix(ArchType Kind) {
    switch (Kind) {
    …
    …
    case toy: return "toy";
    }
    }
    Triple::ArchType Triple::getArchTypeForLLVMName(StringRef
    Name) {
    …
    …
    .Case("toy", toy)
    …
    }
    static Triple::ArchType parseArch(StringRef ArchName) {
    …
    …
    .Case("toy", Triple::toy)
    …
    }
    static unsigned
    getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
    …
    …
    case llvm::Triple::toy:
    return 32;
    …
    …
    }
    Triple Triple::get32BitArchVariant() const {
    …
    …
    case Triple::toy:
    // Already 32-bit.
    break;
    …
    }
    Triple Triple::get64BitArchVariant() const {
    …
    …
    case Triple::toy:
    T.setArch(UnknownArch);
    break;
    …
    …
    }
  7. Add the toy directory entry to lib/Target/LLVMBuild.txt:
    [common]
    subdirectories = ARM AArch64 CppBackend Hexagon MSP430 … …
    TOY
  8. Create a new file called TOY.h in the lib/Target/TOY folder:
    #ifndef TARGET_TOY_H
    #define TARGET_TOY_H
    #include "MCTargetDesc/TOYMCTargetDesc.h"
    #include "llvm/Target/TargetMachine.h"
    namespace llvm {
    class TargetMachine;
    class TOYTargetMachine;
    FunctionPass *createTOYISelDag(TOYTargetMachine &TM,
                                   CodeGenOpt::Level OptLevel);
    } // end namespace llvm;
    #endif
  9. Create a new folder called TargetInfo in the lib/Target/TOY folder. Inside that folder, create a new file called TOYTargetInfo.cpp, as follows:
    #include "TOY.h"
    #include "llvm/IR/Module.h"
    #include "llvm/Support/TargetRegistry.h"
    using namespace llvm;
    Target llvm::TheTOYTarget;
    extern "C" void LLVMInitializeTOYTargetInfo() {
      RegisterTarget<Triple::toy> X(TheTOYTarget, "toy", "TOY");
    }
  10. In the same folder, create the CMakeLists.txt file:
    add_llvm_library(LLVMTOYInfo TOYTargetInfo.cpp)
  11. Create an LLVMBuild.txt file:
    [component_0]
    type = Library
    name = TOYInfo
    parent = TOY
    required_libraries = Support
    add_to_library_groups = TOY
  12. In the lib/Target/TOY folder, create a file called TOYTargetMachine.cpp:
    #include "TOYTargetMachine.h"
    #include "TOY.h"
    #include "TOYFrameLowering.h"
    #include "TOYInstrInfo.h"
    #include "TOYISelLowering.h "
    #include "TOYSelectionDAGInfo.h"
    #include "llvm/CodeGen/Passes.h"
    #include "llvm/IR/Module.h"
    #include "llvm/PassManager.h"
    #include "llvm/Support/TargetRegistry.h"
    using namespace llvm;
    
    TOYTargetMachine::TOYTargetMachine(const Target &T, StringRef TT, StringRef CPU, StringRef FS, const 
    TargetOptions &Options, Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL)
        : LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
          Subtarget(TT, CPU, FS, *this) {
      initAsmInfo();
    }
    
    namespace {
    class TOYPassConfig : public TargetPassConfig {
    public:
      TOYPassConfig(TOYTargetMachine *TM, PassManagerBase &PM)
          : TargetPassConfig(TM, PM) {}
      TOYTargetMachine &getTOYTargetMachine() const {
        return getTM<TOYTargetMachine>();
      }
      virtual bool addPreISel();
      virtual bool addInstSelector();
      virtual bool addPreEmitPass();
    };
    } // namespace
    
    TargetPassConfig *TOYTargetMachine::createPassConfig
    (PassManagerBase &PM) {
      return new TOYPassConfig(this, PM);
    }
    
    bool TOYPassConfig::addPreISel() { return false; }
    
    bool TOYPassConfig::addInstSelector() {
      addPass(createTOYISelDag(getTOYTargetMachine(), 
    getOptLevel()));
      return false;
    }
    
    bool TOYPassConfig::addPreEmitPass() { return false; }
    
    // Force static initialization.
    extern "C" void LLVMInitializeTOYTarget() {
      RegisterTargetMachine<TOYTargetMachine> X(TheTOYTarget);
    }
    void TOYTargetMachine::addAnalysisPasses(PassManagerBase &PM) {}
  13. Create a new folder called MCTargetDesc and a new file called TOYMCTargetDesc.h:
    #ifndef TOYMCTARGETDESC_H
    #define TOYMCTARGETDESC_H
    #include "llvm/Support/DataTypes.h"
    namespace llvm {
    class Target;
    class MCInstrInfo;
    class MCRegisterInfo;
    class MCSubtargetInfo;
    class MCContext;
    class MCCodeEmitter;
    class MCAsmInfo;
    class MCCodeGenInfo;
    class MCInstPrinter;
    class MCObjectWriter;
    class MCAsmBackend;
    class StringRef;
    class raw_ostream;
    extern Target TheTOYTarget;
    
    MCCodeEmitter *createTOYMCCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI, MCContext &Ctx);
    
    MCAsmBackend *createTOYAsmBackend(const Target &T, const MCRegisterInfo &MRI, StringRef TT, StringRef CPU);
    
    MCObjectWriter *createTOYELFObjectWriter(raw_ostream &OS, uint8_t OSABI);
    } // End llvm namespace
    #define GET_REGINFO_ENUM
    #include "TOYGenRegisterInfo.inc"
    #define GET_INSTRINFO_ENUM
    #include "TOYGenInstrInfo.inc"
    #define GET_SUBTARGETINFO_ENUM
    #include "TOYGenSubtargetInfo.inc"
    #endif
  14. Create one more file, called TOYMCTargetDesc.cpp, in the same folder:
    #include "TOYMCTargetDesc.h"
    #include "InstPrinter/TOYInstPrinter.h"
    #include "TOYMCAsmInfo.h"
    #include "llvm/MC/MCCodeGenInfo.h"
    #include "llvm/MC/MCInstrInfo.h"
    #include "llvm/MC/MCRegisterInfo.h"
    #include "llvm/MC/MCSubtargetInfo.h"
    #include "llvm/MC/MCStreamer.h"
    #include "llvm/Support/ErrorHandling.h"
    #include "llvm/Support/FormattedStream.h"
    #include "llvm/Support/TargetRegistry.h"
    #define GET_INSTRINFO_MC_DESC
    #include "TOYGenInstrInfo.inc"
    #define GET_SUBTARGETINFO_MC_DESC
    #include "TOYGenSubtargetInfo.inc"
    #define GET_REGINFO_MC_DESC
    #include "TOYGenRegisterInfo.inc"
    using namespace llvm;
    
    static MCInstrInfo *createTOYMCInstrInfo() {
      MCInstrInfo *X = new MCInstrInfo();
      InitTOYMCInstrInfo(X);
      return X;
    }
    
    static MCRegisterInfo *createTOYMCRegisterInfo(StringRef TT) {
      MCRegisterInfo *X = new MCRegisterInfo();
      InitTOYMCRegisterInfo(X, TOY::LR);
      return X;
    }
    
    static MCSubtargetInfo *createTOYMCSubtargetInfo(StringRef TT, StringRef CPU, StringRef FS) {
      MCSubtargetInfo *X = new MCSubtargetInfo();
      InitTOYMCSubtargetInfo(X, TT, CPU, FS);
      return X;
    }
    
    static MCAsmInfo *createTOYMCAsmInfo(const MCRegisterInfo &MRI, StringRef TT) {
      MCAsmInfo *MAI = new TOYMCAsmInfo(TT);
      return MAI;
    }
    static MCCodeGenInfo *createTOYMCCodeGenInfo(StringRef TT, Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL)
     {
      MCCodeGenInfo *X = new MCCodeGenInfo();
      if (RM == Reloc::Default) {
        RM = Reloc::Static;
      }
      if (CM == CodeModel::Default) {
        CM = CodeModel::Small;
      }
      if (CM != CodeModel::Small && CM != CodeModel::Large) {
        report_fatal_error("Target only supports CodeModel Small or Large");
      }
      X->InitMCCodeGenInfo(RM, CM, OL);
      return X;
    }
    
    static MCInstPrinter *
    createTOYMCInstPrinter(const Target &T, unsigned SyntaxVariant,
                           const MCAsmInfo &MAI, const MCInstrInfo & MII, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI) {
      return new TOYInstPrinter(MAI, MII, MRI);
    }
    
    static MCStreamer *
    createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
                        bool isVerboseAsm, bool useDwarfDirectory,
                        MCInstPrinter *InstPrint, MCCodeEmitter *CE,
                        MCAsmBackend *TAB, bool ShowInst) {
      return createAsmStreamer(Ctx, OS, isVerboseAsm, useD - warfDirectory, InstPrint, CE, TAB, ShowInst);
    }
    
    static MCStreamer *createMCStreamer(const Target &T, StringRef TT,
    MCContext &Ctx, MCAsmBackend &MAB, raw_ostream &OS,
    MCCodeEmitter *Emitter, const MCSubtargetInfo &STI,
    bool RelaxAll, bool NoExecStack) {
      return createELFStreamer(Ctx, MAB, OS, Emitter, false, NoExecStack);
    }
    
    // Force static initialization.
    extern "C" void LLVMInitializeTOYTargetMC() {
      // Register the MC asm info.
      RegisterMCAsmInfoFn X(TheTOYTarget, createTOYMCAsmInfo);
      // Register the MC codegen info.
      TargetRegistry::RegisterMCCodeGenInfo(TheTOYTarget, createTOYMCCodeGenInfo);
      // Register the MC instruction info.
      TargetRegistry::RegisterMCInstrInfo(TheTOYTarget, createTOYMCInstrInfo);
      // Register the MC register info.
      TargetRegistry::RegisterMCRegInfo(TheTOYTarget, createTOYMCRegisterInfo);
      // Register the MC subtarget info.
      TargetRegistry::RegisterMCSubtargetInfo(TheTOYTarget,
                                              createTOYMCSub targetInfo);
      // Register the MCInstPrinter
      TargetRegistry::RegisterMCInstPrinter(TheTOYTarget, createTOYMCInstPrinter);
      // Register the ASM Backend.
      TargetRegistry::RegisterMCAsmBackend(TheTOYTarget, createTOYAsmBackend);
      // Register the assembly streamer.
      TargetRegistry::RegisterAsmStreamer(TheTOYTarget, createMCAsmStreamer);
      // Register the object streamer.
      TargetRegistry::RegisterMCObjectStreamer(TheTOYTarget, createMCStreamer);
      // Register the MCCodeEmitter
      TargetRegistry::RegisterMCCodeEmitter(TheTOYTarget, createTOYMCCodeEmitter);
    }
  15. In the same folder, create an LLVMBuild.txt file:
    [component_0]
    type = Library
    name = TOYDesc
    parent = TOY
    required_libraries = MC Support TOYAsmPrinter TOYInfo
    add_to_library_groups = TOY
  16. Create a CMakeLists.txt file:
    add_llvm_library(LLVMTOYDesc
    TOYMCTargetDesc.cpp)

    Build the enitre LLVM project, as follows:

    $ cmake llvm_src_dir –DCMAKE_BUILD_TYPE=Release –
    DLLVM_TARGETS_TO_BUILD="TOY"
    $ make
    
    Here, we have specified that we are building the LLVM compiler for the toy target. After the build completes, check whether the TOY target appears with the llc command:
    $ llc –version
    …
    …
    Registered Targets :
    toy – TOY

The following IR, when given to the llc tool, will generate an assembly as shown:

target datalayout = "e-m:e-p:32:32-i1:8:32-i8:8:32- i16:16:32-i64:32-f64:32-a:0:32-n32"
target triple = "toy"
define i32 @foo(i32 %a, i32 %b){
  %c = add nsw i32 %a, %b
  ret i32 %c
}

$ llc foo.ll

.text
.file "foo.ll"
.globl foo
.type foo,@function
foo: # @foo
# BB#0: # %entry
add r0, r0, r1
b lr
.Ltmp0:
.size foo, .Ltmp0-foo

To see the details of how to register a target with llc, you can visit http://llvm.org/docs/WritingAnLLVMBackend.html#target-registration and http://jonathan2251.github.io/lbd/llvmstructure.html#target-registration by Chen Chung-Shu and Anoushe Jamshidi.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.233.153