From 0fa193b08627927ccaa0804a34d80480894614b8 Mon Sep 17 00:00:00 2001 From: David Peixotto Date: Thu, 19 Dec 2013 18:12:36 +0000 Subject: 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 --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 94 ++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) (limited to 'lib') 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, 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 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 &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); + } +} -- cgit v1.2.3