diff options
| author | David Peixotto <dpeixott@codeaurora.org> | 2013-12-19 18:12:36 +0000 | 
|---|---|---|
| committer | David Peixotto <dpeixott@codeaurora.org> | 2013-12-19 18:12:36 +0000 | 
| commit | e407d093e82b654d214877fecdbf75975a97c635 (patch) | |
| tree | ce56821cb41b2ed8964323be9d23574f25f7e6aa /llvm/lib | |
| parent | e6153933565571e7e142facea5b5ea1a0e408d34 (diff) | |
| download | bcm5719-llvm-e407d093e82b654d214877fecdbf75975a97c635.tar.gz bcm5719-llvm-e407d093e82b654d214877fecdbf75975a97c635.zip | |
Implement the ldr-pseudo opcode for ARM assembly
The ldr-pseudo opcode is a convenience for loading 32-bit constants.
It is converted into a pc-relative load from a constant pool. For
example,
  ldr r0, =0x10001
  ldr r1, =bar
will generate this output in the final assembly
  ldr r0, .Ltmp0
  ldr r1, .Ltmp1
  ...
  .Ltmp0: .long 0x10001
  .Ltmp1: .long bar
Sketch of the LDR pseudo implementation:
  Keep a map from Section => ConstantPool
  When parsing ldr r0, =val
    parse val as an MCExpr
    get ConstantPool for current Section
    Label = CreateTempSymbol()
    remember val in ConstantPool at next free slot
    add operand to ldr that is MCSymbolRef of Label
  On finishParse() callback
    Write out all non-empty constant pools
    for each Entry in ConstantPool
      Emit Entry.Label
      Emit Entry.Value
Possible improvements to be added in a later patch:
  1. Does not convert load of small constants to mov
     (e.g. ldr r0, =0x1 => mov r0, 0x1)
  2. Does reuse constant pool entries for same constant
The implementation was tested for ARM, Thumb1, and Thumb2 targets on
linux and darwin.
llvm-svn: 197708
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 94 | 
1 files changed, 93 insertions, 1 deletions
| diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 6c9e445346b..8ebf1e41ebf 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -36,6 +36,7 @@  #include "llvm/MC/MCRegisterInfo.h"  #include "llvm/MC/MCStreamer.h"  #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h"  #include "llvm/Support/ELF.h"  #include "llvm/Support/MathExtras.h"  #include "llvm/Support/SourceMgr.h" @@ -50,11 +51,69 @@ class ARMOperand;  enum VectorLaneTy { NoLanes, AllLanes, IndexedLane }; +// A class to keep track of assembler-generated constant pools that are use to +// implement the ldr-pseudo. +class ConstantPool { +  typedef SmallVector<std::pair<MCSymbol *, const MCExpr *>, 4> EntryVecTy; +  EntryVecTy Entries; + +public: +  // Initialize a new empty constant pool +  ConstantPool() { } + +  // Add a new entry to the constant pool in the next slot. +  // \param Value is the new entry to put in the constant pool. +  // +  // \returns a MCExpr that references the newly inserted value +  const MCExpr *addEntry(const MCExpr *Value, MCContext &Context) { +    MCSymbol *CPEntryLabel = Context.CreateTempSymbol(); + +    Entries.push_back(std::make_pair(CPEntryLabel, Value)); +    return MCSymbolRefExpr::Create(CPEntryLabel, Context); +  } + +  // Emit the contents of the constant pool using the provided streamer. +  void emitEntries(MCStreamer &Streamer) const { +    Streamer.EmitCodeAlignment(4); // align to 4-byte address +    Streamer.EmitDataRegion(MCDR_DataRegion); +    for (EntryVecTy::const_iterator I = Entries.begin(), E = Entries.end(); +         I != E; ++I) { +      Streamer.EmitLabel(I->first); +      Streamer.EmitValue(I->second, 4); +    } +    Streamer.EmitDataRegion(MCDR_DataRegionEnd); +  } +}; + +// Map type used to keep track of per-Section constant pools used by the +// ldr-pseudo opcode. The map associates a section to its constant pool. The +// constant pool is a vector of (label, value) pairs. When the ldr +// pseudo is parsed we insert a new (label, value) pair into the constant pool +// for the current section and add MCSymbolRefExpr to the new label as +// an opcode to the ldr. After we have parsed all the user input we +// output the (label, value) pairs in each constant pool at the end of the +// section. +typedef std::map<const MCSection *, ConstantPool> ConstantPoolMapTy; +  class ARMAsmParser : public MCTargetAsmParser {    MCSubtargetInfo &STI;    MCAsmParser &Parser;    const MCInstrInfo &MII;    const MCRegisterInfo *MRI; +  ConstantPoolMapTy ConstantPools; + +  // Assembler created constant pools for ldr pseudo +  ConstantPool *getConstantPool(const MCSection *Section) { +    ConstantPoolMapTy::iterator CP = ConstantPools.find(Section); +    if (CP == ConstantPools.end()) +      return 0; + +    return &CP->second; +  } + +  ConstantPool &getOrCreateConstantPool(const MCSection *Section) { +    return ConstantPools[Section]; +  }    ARMTargetStreamer &getTargetStreamer() {      MCTargetStreamer &TS = getParser().getStreamer().getTargetStreamer(); @@ -296,7 +355,7 @@ public:                                 MCStreamer &Out, unsigned &ErrorInfo,                                 bool MatchingInlineAsm);    void onLabelParsed(MCSymbol *Symbol); - +  void finishParse();  };  } // end anonymous namespace @@ -4656,6 +4715,24 @@ bool ARMAsmParser::parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,      Operands.push_back(ARMOperand::CreateImm(ExprVal, S, E));      return false;    } +  case AsmToken::Equal: { +    if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val) +      return Error(Parser.getTok().getLoc(), "unexpected token in operand"); + +    const MCSection *Section = +        getParser().getStreamer().getCurrentSection().first; +    assert(Section); +    Parser.Lex(); // Eat '=' +    const MCExpr *SubExprVal; +    if (getParser().parseExpression(SubExprVal)) +      return true; +    E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + +    const MCExpr *CPLoc = +        getOrCreateConstantPool(Section).addEntry(SubExprVal, getContext()); +    Operands.push_back(ARMOperand::CreateImm(CPLoc, S, E)); +    return false; +  }    }  } @@ -8396,3 +8473,18 @@ unsigned ARMAsmParser::validateTargetOperandClass(MCParsedAsmOperand *AsmOp,    }    return Match_InvalidOperand;  } + +void ARMAsmParser::finishParse() { +  // Dump contents of assembler constant pools. +  MCStreamer &Streamer = getParser().getStreamer(); +  for (ConstantPoolMapTy::iterator CPI = ConstantPools.begin(), +                                   CPE = ConstantPools.end(); +       CPI != CPE; ++CPI) { +    const MCSection *Section = CPI->first; +    ConstantPool &CP = CPI->second; + +    // Dump assembler constant pools at the end of the section. +    Streamer.SwitchSection(Section); +    CP.emitEntries(Streamer); +  } +} | 

