summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Peixotto <dpeixott@codeaurora.org>2013-12-19 18:12:36 +0000
committerDavid Peixotto <dpeixott@codeaurora.org>2013-12-19 18:12:36 +0000
commit0fa193b08627927ccaa0804a34d80480894614b8 (patch)
treee78debe0830293b2d1833e63b92eba04254726bd /lib
parent6075fa1e0eba255e217095bd2573339e64de8c8d (diff)
downloadllvm-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')
-rw-r--r--lib/Target/ARM/AsmParser/ARMAsmParser.cpp94
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);
+ }
+}