diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index 3228aa7bb90895ca7cfd1ac53038bdaf48c6f830..2a677c56787fc75cba52fe07f60ad4b33f5e15a7 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -39,6 +39,7 @@ class StringRef; class Twine; class raw_ostream; class formatted_raw_ostream; +class AssemblerConstantPools; typedef std::pair MCSectionSubPair; @@ -83,37 +84,51 @@ public: // FIXME: declared here because it is used from // lib/CodeGen/AsmPrinter/ARMException.cpp. class ARMTargetStreamer : public MCTargetStreamer { - virtual void anchor(); public: ARMTargetStreamer(MCStreamer &S); - - virtual void emitFnStart() = 0; - virtual void emitFnEnd() = 0; - virtual void emitCantUnwind() = 0; - virtual void emitPersonality(const MCSymbol *Personality) = 0; - virtual void emitPersonalityIndex(unsigned Index) = 0; - virtual void emitHandlerData() = 0; + ~ARMTargetStreamer(); + + virtual void emitFnStart(); + virtual void emitFnEnd(); + virtual void emitCantUnwind(); + virtual void emitPersonality(const MCSymbol *Personality); + virtual void emitPersonalityIndex(unsigned Index); + virtual void emitHandlerData(); virtual void emitSetFP(unsigned FpReg, unsigned SpReg, - int64_t Offset = 0) = 0; - virtual void emitMovSP(unsigned Reg, int64_t Offset = 0) = 0; - virtual void emitPad(int64_t Offset) = 0; + int64_t Offset = 0); + virtual void emitMovSP(unsigned Reg, int64_t Offset = 0); + virtual void emitPad(int64_t Offset); virtual void emitRegSave(const SmallVectorImpl &RegList, - bool isVector) = 0; + bool isVector); virtual void emitUnwindRaw(int64_t StackOffset, - const SmallVectorImpl &Opcodes) = 0; + const SmallVectorImpl &Opcodes); - virtual void switchVendor(StringRef Vendor) = 0; - virtual void emitAttribute(unsigned Attribute, unsigned Value) = 0; - virtual void emitTextAttribute(unsigned Attribute, StringRef String) = 0; + virtual void switchVendor(StringRef Vendor); + virtual void emitAttribute(unsigned Attribute, unsigned Value); + virtual void emitTextAttribute(unsigned Attribute, StringRef String); virtual void emitIntTextAttribute(unsigned Attribute, unsigned IntValue, - StringRef StringValue = "") = 0; - virtual void emitFPU(unsigned FPU) = 0; - virtual void emitArch(unsigned Arch) = 0; - virtual void emitObjectArch(unsigned Arch) = 0; - virtual void finishAttributeSection() = 0; - virtual void emitInst(uint32_t Inst, char Suffix = '\0') = 0; - - virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE) = 0; + StringRef StringValue = ""); + virtual void emitFPU(unsigned FPU); + virtual void emitArch(unsigned Arch); + virtual void emitObjectArch(unsigned Arch); + virtual void finishAttributeSection(); + virtual void emitInst(uint32_t Inst, char Suffix = '\0'); + + virtual void AnnotateTLSDescriptorSequence(const MCSymbolRefExpr *SRE); + + virtual void finish(); + + /// Callback used to implement the ldr= pseudo. + /// Add a new entry to the constant pool for the current section and return an + /// MCExpr that can be used to refer to the constant pool location. + const MCExpr *addConstantPoolEntry(const MCExpr *); + + /// Callback used to implemnt the .ltorg directive. + /// Emit contents of constant pool for the current section. + void emitCurrentConstantPool(); + +private: + OwningPtr ConstantPools; }; /// MCStreamer - Streaming machine code generation interface. This interface diff --git a/llvm/include/llvm/MC/MCTargetAsmParser.h b/llvm/include/llvm/MC/MCTargetAsmParser.h index c5fb30ef99905a1cfb89e94f239f3f159b9e58c7..0073136015ced4d1406416dc9f3a79d016fdaf3e 100644 --- a/llvm/include/llvm/MC/MCTargetAsmParser.h +++ b/llvm/include/llvm/MC/MCTargetAsmParser.h @@ -182,11 +182,6 @@ public: return 0; } - /// Allow a target to perform any actions after the parse completes - /// successfully. For example, to write out constant pools for ldr pseudo on - /// ARM. - virtual void finishParse() {}; - virtual void onLabelParsed(MCSymbol *Symbol) { }; }; diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index 63a00fedfa7f8a036818ee48224a8c4df3ba22ca..459e126793876ddcb7dc373d75d99edcc0ee8f57 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -681,10 +681,6 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { } } - // Callback to the target parser in case it needs to do anything. - if (!HadError) - getTargetParser().finishParse(); - // Finalize the output stream if there are no errors and if the client wants // us to. if (!HadError && !NoFinalize) diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 74e4e66c6e704ebdd64fccfb8bfbc44037d23155..288d9b96da2ca2930079999b3af8527c2d629961 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -56,64 +56,6 @@ 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) { - if (Entries.empty()) - return; - 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); - Entries.clear(); - } - - // Return true if the constant pool is empty - bool empty() { - return Entries.empty(); - } -}; - -// 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. -// -// We use the MapVector for the map type to ensure stable iteration of -// the sections at the end of the parse. We need to iterate over the -// sections in a stable order to ensure that we have print the -// constant pools in a deterministic order when printing an assembly -// file. -typedef MapVector ConstantPoolMapTy; - class UnwindContext { MCAsmParser &Parser; @@ -191,22 +133,8 @@ class ARMAsmParser : public MCTargetAsmParser { MCAsmParser &Parser; const MCInstrInfo &MII; const MCRegisterInfo *MRI; - ConstantPoolMapTy ConstantPools; UnwindContext UC; - // 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(); return static_cast(TS); @@ -443,7 +371,6 @@ public: MCStreamer &Out, unsigned &ErrorInfo, bool MatchingInlineAsm); void onLabelParsed(MCSymbol *Symbol); - void finishParse(); }; } // end anonymous namespace @@ -4812,17 +4739,13 @@ bool ARMAsmParser::parseOperand(SmallVectorImpl &Operands, 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()); + const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal); Operands.push_back(ARMOperand::CreateImm(CPLoc, S, E)); return false; } @@ -8843,13 +8766,7 @@ bool ARMAsmParser::parseDirectiveInst(SMLoc Loc, char Suffix) { /// parseDirectiveLtorg /// ::= .ltorg | .pool bool ARMAsmParser::parseDirectiveLtorg(SMLoc L) { - MCStreamer &Streamer = getParser().getStreamer(); - const MCSection *Section = Streamer.getCurrentSection().first; - - if (ConstantPool *CP = getConstantPool(Section)) { - if (!CP->empty()) - CP->emitEntries(Streamer); - } + getTargetStreamer().emitCurrentConstantPool(); return false; } @@ -9181,20 +9098,3 @@ 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 non-empty assembler constant pools at the end of the section. - if (!CP.empty()) { - Streamer.SwitchSection(Section); - CP.emitEntries(Streamer); - } - } -} diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp index 44b56fbe199f56ada28ae01e8051c09ce6d4d140..710f19a8632ed0e890675ff8a75707ebc4c60b46 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -104,9 +104,6 @@ static unsigned GetArchDefaultCPUArch(unsigned ID) { return 0; } -void ARMTargetStreamer::anchor() {} -ARMTargetStreamer::ARMTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} - namespace { class ARMELFStreamer; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp index 4581f4113043779ae9b25992e3be249fb525d4c0..434f27f46fc312655c18f0f68a1510d408fa76da 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -247,8 +247,11 @@ static MCStreamer *createMCStreamer(const Target &T, StringRef TT, bool NoExecStack) { Triple TheTriple(TT); - if (TheTriple.isOSBinFormatMachO()) - return createMachOStreamer(Ctx, MAB, OS, Emitter, false); + if (TheTriple.isOSBinFormatMachO()) { + MCStreamer *S = createMachOStreamer(Ctx, MAB, OS, Emitter, false); + new ARMTargetStreamer(*S); + return S; + } if (TheTriple.isOSWindows()) { llvm_unreachable("ARM does not support Windows COFF format"); diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce8b67f1eec28ed17e235bc9a9ab44894cf3b57d --- /dev/null +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMTargetStreamer.cpp @@ -0,0 +1,248 @@ +//===- ARMTargetStreamer.cpp - ARMTargetStreamer class --*- C++ -*---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ARMTargetStreamer class. +// +//===----------------------------------------------------------------------===// +#include "llvm/ADT/MapVector.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCContext.h" + +using namespace llvm; + +namespace { +// 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); + + // Emit the contents of the constant pool using the provided streamer. + void emitEntries(MCStreamer &Streamer); + + // Return true if the constant pool is empty + bool empty(); +}; +} + +namespace llvm { +class AssemblerConstantPools { + // 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. + // + // We use the MapVector for the map type to ensure stable iteration of + // the sections at the end of the parse. We need to iterate over the + // sections in a stable order to ensure that we have print the + // constant pools in a deterministic order when printing an assembly + // file. + typedef MapVector ConstantPoolMapTy; + ConstantPoolMapTy ConstantPools; + +public: + AssemblerConstantPools() {} + ~AssemblerConstantPools() {} + + void emitAll(MCStreamer &Streamer); + void emitForCurrentSection(MCStreamer &Streamer); + const MCExpr *addEntry(MCStreamer &Streamer, const MCExpr *Expr); + +private: + ConstantPool *getConstantPool(const MCSection *Section); + ConstantPool &getOrCreateConstantPool(const MCSection *Section); +}; +} + +// +// ConstantPool implementation +// +// Emit the contents of the constant pool using the provided streamer. +void ConstantPool::emitEntries(MCStreamer &Streamer) { + if (Entries.empty()) + return; + 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); + Entries.clear(); +} + +const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context) { + MCSymbol *CPEntryLabel = Context.CreateTempSymbol(); + + Entries.push_back(std::make_pair(CPEntryLabel, Value)); + return MCSymbolRefExpr::Create(CPEntryLabel, Context); +} + +bool ConstantPool::empty() { return Entries.empty(); } + +// +// AssemblerConstantPools implementation +// +ConstantPool * +AssemblerConstantPools::getConstantPool(const MCSection *Section) { + ConstantPoolMapTy::iterator CP = ConstantPools.find(Section); + if (CP == ConstantPools.end()) + return 0; + + return &CP->second; +} + +ConstantPool & +AssemblerConstantPools::getOrCreateConstantPool(const MCSection *Section) { + return ConstantPools[Section]; +} + +static void emitConstantPool(MCStreamer &Streamer, const MCSection *Section, + ConstantPool &CP) { + if (!CP.empty()) { + Streamer.SwitchSection(Section); + CP.emitEntries(Streamer); + } +} + +void AssemblerConstantPools::emitAll(MCStreamer &Streamer) { + // Dump contents of assembler constant pools. + for (ConstantPoolMapTy::iterator CPI = ConstantPools.begin(), + CPE = ConstantPools.end(); + CPI != CPE; ++CPI) { + const MCSection *Section = CPI->first; + ConstantPool &CP = CPI->second; + + emitConstantPool(Streamer, Section, CP); + } +} + +void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) { + const MCSection *Section = Streamer.getCurrentSection().first; + if (ConstantPool *CP = getConstantPool(Section)) { + emitConstantPool(Streamer, Section, *CP); + } +} + +const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer, + const MCExpr *Expr) { + const MCSection *Section = Streamer.getCurrentSection().first; + return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext()); +} + +// +// ARMTargetStreamer Implemenation +// +ARMTargetStreamer::ARMTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {} + +ARMTargetStreamer::~ARMTargetStreamer() {} + +// The constant pool handling is shared by all ARMTargetStreamer +// implementations. +const MCExpr *ARMTargetStreamer::addConstantPoolEntry(const MCExpr *Expr) { + return ConstantPools->addEntry(Streamer, Expr); +} + +void ARMTargetStreamer::emitCurrentConstantPool() { + ConstantPools->emitForCurrentSection(Streamer); +} + +// finish() - write out any non-empty assembler constant pools. +void ARMTargetStreamer::finish() { ConstantPools->emitAll(Streamer); } + +// The remaining callbacks should be handled separately by each +// streamer. +void ARMTargetStreamer::emitFnStart() { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitFnEnd() { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitCantUnwind() { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitPersonality(const MCSymbol *Personality) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitPersonalityIndex(unsigned Index) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitHandlerData() { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitSetFP(unsigned FpReg, unsigned SpReg, + int64_t Offset) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitMovSP(unsigned Reg, int64_t Offset) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitPad(int64_t Offset) { + llvm_unreachable("unimplemented"); +} +void +ARMTargetStreamer::emitRegSave(const SmallVectorImpl &RegList, + bool isVector) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitUnwindRaw( + int64_t StackOffset, const SmallVectorImpl &Opcodes) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::switchVendor(StringRef Vendor) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitTextAttribute(unsigned Attribute, + StringRef String) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitIntTextAttribute(unsigned Attribute, + unsigned IntValue, + StringRef StringValue) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitArch(unsigned Arch) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitObjectArch(unsigned Arch) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitFPU(unsigned FPU) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::finishAttributeSection() { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::emitInst(uint32_t Inst, char Suffix) { + llvm_unreachable("unimplemented"); +} +void ARMTargetStreamer::AnnotateTLSDescriptorSequence( + const MCSymbolRefExpr *SRE) { + llvm_unreachable("unimplemented"); +} diff --git a/llvm/lib/Target/ARM/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/ARM/MCTargetDesc/CMakeLists.txt index 162de7d21e2137127371af02f31d39a692a74321..06812d4503af913de15ff24b760cd45c5827e64d 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/CMakeLists.txt +++ b/llvm/lib/Target/ARM/MCTargetDesc/CMakeLists.txt @@ -8,6 +8,7 @@ add_llvm_library(LLVMARMDesc ARMMCTargetDesc.cpp ARMMachObjectWriter.cpp ARMELFObjectWriter.cpp + ARMTargetStreamer.cpp ARMUnwindOpAsm.cpp ARMMachORelocationInfo.cpp ) diff --git a/llvm/test/CodeGen/ARM/inlineasm-ldr-pseudo.ll b/llvm/test/CodeGen/ARM/inlineasm-ldr-pseudo.ll new file mode 100644 index 0000000000000000000000000000000000000000..f63e4b0b3a17e694b8d1d7b103a678127e9e9e30 --- /dev/null +++ b/llvm/test/CodeGen/ARM/inlineasm-ldr-pseudo.ll @@ -0,0 +1,17 @@ +; PR18354 +; We actually need to use -filetype=obj in this test because if we output +; assembly, the current code path will bypass the parser and just write the +; raw text out to the Streamer. We need to actually parse the inlineasm to +; demonstrate the bug. Going the asm->obj route does not show the issue. +; RUN: llc -mtriple=arm-none-linux < %s -filetype=obj | llvm-objdump -d - | FileCheck %s +; RUN: llc -mtriple=arm-apple-darwin < %s -filetype=obj | llvm-objdump -d - | FileCheck %s +; CHECK-LABEL: foo: +; CHECK: 0: 00 00 9f e5 ldr r0, [pc] +; CHECK: 4: 0e f0 a0 e1 mov pc, lr +; Make sure the constant pool entry comes after the return +; CHECK: 8: 01 00 00 00 +define i32 @foo() nounwind { +entry: + %0 = tail call i32 asm sideeffect "ldr $0,=1", "=r"() nounwind + ret i32 %0 +}