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 | 0fa193b08627927ccaa0804a34d80480894614b8 (patch) | |
tree | e78debe0830293b2d1833e63b92eba04254726bd /lib/Target/ARM/AsmParser | |
parent | 6075fa1e0eba255e217095bd2573339e64de8c8d (diff) | |
download | llvm-0fa193b08627927ccaa0804a34d80480894614b8.tar.gz llvm-0fa193b08627927ccaa0804a34d80480894614b8.tar.bz2 llvm-0fa193b08627927ccaa0804a34d80480894614b8.tar.xz |
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197708 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/ARM/AsmParser')
-rw-r--r-- | lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 94 |
1 files changed, 93 insertions, 1 deletions
diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 6c9e445346..8ebf1e41eb 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/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); + } +} |