Instantiating Target-Specifc ASM Parser

Hello,

I am working on backend development and would like to utilize my target’s MCAsmParser inside of an MCInst-level class implementation. I noticed that the AsmParser is registered with the target registry however I am having no luck grepping for a “template” of how to instantiate it and have yet to find specific documentation on how it is done. Any ideas or help is greatly appreciated!

Cheers,
Kyle Dunn

Hi,

We are using the AsmParser to analyse inline asm instructions in our backend, i.e. to get the actual size in bytes of an instruction or to find all calls,.. I assume this might be similar to what you want to do.
I let AsmPrinter do all the hard work of parsing inline asm and instantiating everything. This might be a bit of an overkill though if you do not need inline-asm parsing (it replaces placeholders with proper register names, ...). For your case it might be sufficient to have a look at the code in AsmParser::EmitInlineAsm(StringRef Str, ..). You will need to have a proper context and MCStreamer object though..

Here is what I did to make this happen:

1) Extract a header for the MCNullStreamer class to include/llvm/MC to be able to make subclasses. I will attach the modified files for your convenience.

2) Make the EmitInlineAsm functions in AsmPrinter public. Move construction and deletion of the Mangler in AsmPrinter.cpp into the constructor/destructor of AsmPrinter. In AsmPrinter::EmitInlineAsm (AsmPrinterInlineAsm.cpp:93), add an 'if (MMI) { .. }' to skip the DiagnosticHandler stuff if MMI is not set.

3) Create a subclass of MCNullStreamer to visit all parsed instructions in the inline asm code, like so:

class InstrAnalyzer : public MCNullStreamer {
   const MCInstrInfo &MII;
   unsigned size;
public:
   InstrAnalyzer(MCContext &ctx)
     : MCNullStreamer(ctx), MII(ctx.getInstrInfo()), size(0)
     { }
   virtual void EmitInstruction(const MCInst &Inst) {
     const MCInstrDesc &MID = MII.get(Inst.getOpcode());
     size += MID.getSize();
   }
};

4) Create a new AsmPrinter and use it to parse and emit asm, e.g. like so (our backend is called Patmos, so do not wonder about this..):

unsigned int PatmosInstrInfo::getInstrSize(const MachineInstr *MI) const {
   if (MI->isInlineAsm()) {
     // PTM is the TargetMachine
     // TODO is there a way to get the current context?
     MCContext Ctx(*PTM.getMCAsmInfo(),
                   *PTM.getRegisterInfo(), *PTM.getInstrInfo(), 0);

     // PIA is deleted by AsmPrinter
     PatmosInstrAnalyzer *PIA = new InstrAnalyzer(Ctx);

     // PTM.getTargetLowering()->getObjFileLowering() might not yet be
     // initialized, so we create a new section object for this temp context
     const MCSection* TS = Ctx.getELFSection(".text",
                                             ELF::SHT_PROGBITS, 0,
                                             SectionKind::getText());
     PIA->SwitchSection(TS);

     PatmosAsmPrinter PAP(PTM, *PIA);
     PAP.EmitInlineAsm(MI);

     return PIA->getSize();
   }
   else if (MI->isBundle()) {
     // handle bundles..
     unsigned size = ...;
     return size;
   }
   else {
     // trust the desc..
     return MI->getDesc().getSize();
   }
}

I tested this with LLVM 3.2, and it should work with LLVM 3.3 (though I am not finished testing it..).

Cheers,
  Stefan Hepp

MCNullStreamer.h (4.47 KB)

MCNullStreamer.cpp (877 Bytes)