Index: clang/tools/driver/cc1as_main.cpp =================================================================== --- clang/tools/driver/cc1as_main.cpp +++ clang/tools/driver/cc1as_main.cpp @@ -398,17 +398,19 @@ if (Opts.OutputType == AssemblerInvocation::FT_Asm) { MCInstPrinter *IP = TheTarget->createMCInstPrinter( llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI); - MCCodeEmitter *CE = nullptr; - MCAsmBackend *MAB = nullptr; - if (Opts.ShowEncoding) { - CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); - MCTargetOptions Options; - MAB = TheTarget->createMCAsmBackend(*STI, *MRI, Options); - } + + std::unique_ptr CE; + if (Opts.ShowEncoding) + CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); + MCTargetOptions MCOptions; + std::unique_ptr MAB( + TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); + auto FOut = llvm::make_unique(*Out); Str.reset(TheTarget->createAsmStreamer( Ctx, std::move(FOut), /*asmverbose*/ true, - /*useDwarfDirectory*/ true, IP, CE, MAB, Opts.ShowInst)); + /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB), + Opts.ShowInst)); } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { Str.reset(createNullStreamer(Ctx)); } else { @@ -419,17 +421,23 @@ Out = BOS.get(); } - MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); - MCTargetOptions Options; - MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*STI, *MRI, Options); + std::unique_ptr CE( + TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); + MCTargetOptions MCOptions; + std::unique_ptr MAB( + TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); + Triple T(Opts.Triple); Str.reset(TheTarget->createMCObjectStreamer( - T, Ctx, std::unique_ptr(MAB), *Out, std::unique_ptr(CE), *STI, - Opts.RelaxAll, Opts.IncrementalLinkerCompatible, + T, Ctx, std::move(MAB), *Out, std::move(CE), *STI, Opts.RelaxAll, + Opts.IncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ true)); Str.get()->InitSections(Opts.NoExecStack); } + // Use Assembler information for parsing. + Str->setUseAssemblerInfoForParsing(true); + bool Failed = false; std::unique_ptr Parser( Index: llvm/include/llvm/MC/MCAssembler.h =================================================================== --- llvm/include/llvm/MC/MCAssembler.h +++ llvm/include/llvm/MC/MCAssembler.h @@ -99,11 +99,11 @@ private: MCContext &Context; - MCAsmBackend &Backend; + std::unique_ptr Backend; - MCCodeEmitter &Emitter; + std::unique_ptr Emitter; - MCObjectWriter &Writer; + std::unique_ptr Writer; SectionListType Sections; @@ -214,8 +214,9 @@ // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. - MCAssembler(MCContext &Context, MCAsmBackend &Backend, - MCCodeEmitter &Emitter, MCObjectWriter &Writer); + MCAssembler(MCContext &Context, std::unique_ptr Backend, + std::unique_ptr Emitter, + std::unique_ptr Writer); MCAssembler(const MCAssembler &) = delete; MCAssembler &operator=(const MCAssembler &) = delete; ~MCAssembler(); @@ -274,11 +275,17 @@ MCContext &getContext() const { return Context; } - MCAsmBackend &getBackend() const { return Backend; } + MCAsmBackend *getBackendPtr() const { return Backend.get(); } - MCCodeEmitter &getEmitter() const { return Emitter; } + MCCodeEmitter *getEmitterPtr() const { return Emitter.get(); } - MCObjectWriter &getWriter() const { return Writer; } + MCObjectWriter *getWriterPtr() const { return Writer.get(); } + + MCAsmBackend &getBackend() const { return *Backend; } + + MCCodeEmitter &getEmitter() const { return *Emitter; } + + MCObjectWriter &getWriter() const { return *Writer; } MCDwarfLineTableParams getDWARFLinetableParams() const { return LTParams; } void setDWARFLinetableParams(MCDwarfLineTableParams P) { LTParams = P; } Index: llvm/include/llvm/MC/MCExpr.h =================================================================== --- llvm/include/llvm/MC/MCExpr.h +++ llvm/include/llvm/MC/MCExpr.h @@ -96,6 +96,7 @@ const SectionAddrMap &Addrs) const; bool evaluateAsAbsolute(int64_t &Res) const; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const; + bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const; bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const; bool evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const; Index: llvm/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/include/llvm/MC/MCObjectStreamer.h +++ llvm/include/llvm/MC/MCObjectStreamer.h @@ -34,9 +34,6 @@ /// to that file format or custom semantics expected by the object writer /// implementation. class MCObjectStreamer : public MCStreamer { - std::unique_ptr ObjectWriter; - std::unique_ptr TAB; - std::unique_ptr Emitter; std::unique_ptr Assembler; MCSection::iterator CurInsertionPoint; bool EmitEHFrame; @@ -92,7 +89,7 @@ void visitUsedSymbol(const MCSymbol &Sym) override; MCAssembler &getAssembler() { return *Assembler; } - + MCAssembler *getAssemblerPtr() override; /// \name MCStreamer Interface /// @{ Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -211,6 +211,8 @@ /// requires. unsigned NextWinCFIID = 0; + bool UseAssemblerInfoForParsing; + protected: MCStreamer(MCContext &Ctx); @@ -247,6 +249,11 @@ MCContext &getContext() const { return Context; } + virtual MCAssembler *getAssemblerPtr() { return nullptr; } + + void setUseAssemblerInfoForParsing(bool v) { UseAssemblerInfoForParsing = v; } + bool getUseAssemblerInfoForParsing() { return UseAssemblerInfoForParsing; } + MCTargetStreamer *getTargetStreamer() { return TargetStreamer.get(); } Index: llvm/include/llvm/MC/MCSymbol.h =================================================================== --- llvm/include/llvm/MC/MCSymbol.h +++ llvm/include/llvm/MC/MCSymbol.h @@ -316,6 +316,8 @@ Index = Value; } + bool isUnset() const { return SymbolContents == SymContentsUnset; } + uint64_t getOffset() const { assert((SymbolContents == SymContentsUnset || SymbolContents == SymContentsOffset) && Index: llvm/include/llvm/Support/TargetRegistry.h =================================================================== --- llvm/include/llvm/Support/TargetRegistry.h +++ llvm/include/llvm/Support/TargetRegistry.h @@ -60,13 +60,30 @@ class TargetOptions; MCStreamer *createNullStreamer(MCContext &Ctx); -MCStreamer *createAsmStreamer(MCContext &Ctx, - std::unique_ptr OS, - bool isVerboseAsm, bool useDwarfDirectory, - MCInstPrinter *InstPrint, MCCodeEmitter *CE, - MCAsmBackend *TAB, bool ShowInst); +// Takes ownership of \p TAB and \p CE. + +/// Create a machine code streamer which will print out assembly for the native +/// target, suitable for compiling with a native assembler. +/// +/// \param InstPrint - If given, the instruction printer to use. If not given +/// the MCInst representation will be printed. This method takes ownership of +/// InstPrint. +/// +/// \param CE - If given, a code emitter to use to show the instruction +/// encoding inline with the assembly. This method takes ownership of \p CE. +/// +/// \param TAB - If given, a target asm backend to use to show the fixup +/// information in conjunction with encoding information. This method takes +/// ownership of \p TAB. +/// +/// \param ShowInst - Whether to show the MCInst representation inline with +/// the assembly. +MCStreamer * +createAsmStreamer(MCContext &Ctx, std::unique_ptr OS, + bool isVerboseAsm, bool useDwarfDirectory, + MCInstPrinter *InstPrint, std::unique_ptr &&CE, + std::unique_ptr &&TAB, bool ShowInst); -/// Takes ownership of \p TAB and \p CE. MCStreamer *createELFStreamer(MCContext &Ctx, std::unique_ptr &&TAB, raw_pwrite_stream &OS, @@ -493,12 +510,14 @@ MCStreamer *createAsmStreamer(MCContext &Ctx, std::unique_ptr OS, bool IsVerboseAsm, bool UseDwarfDirectory, - MCInstPrinter *InstPrint, MCCodeEmitter *CE, - MCAsmBackend *TAB, bool ShowInst) const { + MCInstPrinter *InstPrint, + std::unique_ptr &&CE, + std::unique_ptr &&TAB, + bool ShowInst) const { formatted_raw_ostream &OSRef = *OS; - MCStreamer *S = llvm::createAsmStreamer(Ctx, std::move(OS), IsVerboseAsm, - UseDwarfDirectory, InstPrint, CE, - TAB, ShowInst); + MCStreamer *S = llvm::createAsmStreamer( + Ctx, std::move(OS), IsVerboseAsm, UseDwarfDirectory, InstPrint, + std::move(CE), std::move(TAB), ShowInst); createAsmTargetStreamer(*S, OSRef, InstPrint, IsVerboseAsm); return S; } Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -132,6 +132,9 @@ std::unique_ptr Parser( createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum)); + // Do not use assembler-level information for parsing inline assembly. + OutStreamer->setUseAssemblerInfoForParsing(false); + // We create a new MCInstrInfo here since we might be at the module level // and not have a MachineFunction to initialize the TargetInstrInfo from and // we only need MCInstrInfo for asm parsing. We create one unconditionally Index: llvm/lib/CodeGen/LLVMTargetMachine.cpp =================================================================== --- llvm/lib/CodeGen/LLVMTargetMachine.cpp +++ llvm/lib/CodeGen/LLVMTargetMachine.cpp @@ -138,17 +138,17 @@ getTargetTriple(), MAI.getAssemblerDialect(), MAI, MII, MRI); // Create a code emitter if asked to show the encoding. - MCCodeEmitter *MCE = nullptr; + std::unique_ptr MCE; if (Options.MCOptions.ShowMCEncoding) - MCE = getTarget().createMCCodeEmitter(MII, MRI, Context); + MCE.reset(getTarget().createMCCodeEmitter(MII, MRI, Context)); - MCAsmBackend *MAB = - getTarget().createMCAsmBackend(STI, MRI, Options.MCOptions); + std::unique_ptr MAB( + getTarget().createMCAsmBackend(STI, MRI, Options.MCOptions)); auto FOut = llvm::make_unique(Out); MCStreamer *S = getTarget().createAsmStreamer( Context, std::move(FOut), Options.MCOptions.AsmVerbose, - Options.MCOptions.MCUseDwarfDirectory, InstPrinter, MCE, MAB, - Options.MCOptions.ShowMCInst); + Options.MCOptions.MCUseDwarfDirectory, InstPrinter, std::move(MCE), + std::move(MAB), Options.MCOptions.ShowMCInst); AsmStreamer.reset(S); break; } Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" @@ -22,6 +23,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" @@ -31,6 +33,7 @@ #include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" #include using namespace llvm; @@ -42,12 +45,12 @@ formatted_raw_ostream &OS; const MCAsmInfo *MAI; std::unique_ptr InstPrinter; - std::unique_ptr Emitter; - std::unique_ptr AsmBackend; + std::unique_ptr Assembler; SmallString<128> ExplicitCommentToEmit; SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; + raw_null_ostream NullStream; unsigned IsVerboseAsm : 1; unsigned ShowInst : 1; @@ -60,18 +63,24 @@ public: MCAsmStreamer(MCContext &Context, std::unique_ptr os, bool isVerboseAsm, bool useDwarfDirectory, - MCInstPrinter *printer, MCCodeEmitter *emitter, - MCAsmBackend *asmbackend, bool showInst) + MCInstPrinter *printer, std::unique_ptr emitter, + std::unique_ptr asmbackend, bool showInst) : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner), - MAI(Context.getAsmInfo()), InstPrinter(printer), Emitter(emitter), - AsmBackend(asmbackend), CommentStream(CommentToEmit), - IsVerboseAsm(isVerboseAsm), ShowInst(showInst), - UseDwarfDirectory(useDwarfDirectory) { + MAI(Context.getAsmInfo()), InstPrinter(printer), + Assembler(llvm::make_unique( + Context, std::move(asmbackend), std::move(emitter), + (asmbackend) ? asmbackend->createObjectWriter(NullStream) + : nullptr)), + CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), + ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) { assert(InstPrinter); if (IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); } + MCAssembler &getAssembler() { return *Assembler; } + MCAssembler *getAssemblerPtr() override { return Assembler.get(); } + inline void EmitEOL() { // Dump Explicit Comments here. emitExplicitComments(); @@ -1612,7 +1621,12 @@ SmallString<256> Code; SmallVector Fixups; raw_svector_ostream VecOS(Code); - Emitter->encodeInstruction(Inst, VecOS, Fixups, STI); + + // If we have no code emitter, don't emit code. + if (!getAssembler().getEmitterPtr()) + return; + + getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); // If we are showing fixups, create symbolic markers in the encoded // representation. We do this by making a per-bit map to the fixup item index, @@ -1624,7 +1638,8 @@ for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = + getAssembler().getBackend().getFixupKindInfo(F.getKind()); for (unsigned j = 0; j != Info.TargetSize; ++j) { unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); @@ -1688,7 +1703,8 @@ for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = + getAssembler().getBackend().getFixupKindInfo(F.getKind()); OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; } @@ -1701,8 +1717,7 @@ "Cannot emit contents before setting section!"); // Show the encoding in a comment if we have a code emitter. - if (Emitter) - AddEncodingComment(Inst, STI, PrintSchedInfo); + AddEncodingComment(Inst, STI, PrintSchedInfo); // Show the MCInst if enabled. if (ShowInst) { @@ -1791,8 +1806,11 @@ MCStreamer *llvm::createAsmStreamer(MCContext &Context, std::unique_ptr OS, bool isVerboseAsm, bool useDwarfDirectory, - MCInstPrinter *IP, MCCodeEmitter *CE, - MCAsmBackend *MAB, bool ShowInst) { + MCInstPrinter *IP, + std::unique_ptr &&CE, + std::unique_ptr &&MAB, + bool ShowInst) { return new MCAsmStreamer(Context, std::move(OS), isVerboseAsm, - useDwarfDirectory, IP, CE, MAB, ShowInst); + useDwarfDirectory, IP, std::move(CE), std::move(MAB), + ShowInst); } Index: llvm/lib/MC/MCAssembler.cpp =================================================================== --- llvm/lib/MC/MCAssembler.cpp +++ llvm/lib/MC/MCAssembler.cpp @@ -83,9 +83,12 @@ /* *** */ -MCAssembler::MCAssembler(MCContext &Context, MCAsmBackend &Backend, - MCCodeEmitter &Emitter, MCObjectWriter &Writer) - : Context(Context), Backend(Backend), Emitter(Emitter), Writer(Writer), +MCAssembler::MCAssembler(MCContext &Context, + std::unique_ptr Backend, + std::unique_ptr Emitter, + std::unique_ptr Writer) + : Context(Context), Backend(std::move(Backend)), + Emitter(std::move(Emitter)), Writer(std::move(Writer)), BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false), IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) { VersionInfo.Major = 0; // Major version == 0 for "none specified" @@ -110,9 +113,12 @@ VersionInfo.Major = 0; // reset objects owned by us - getBackend().reset(); - getEmitter().reset(); - getWriter().reset(); + if (getBackendPtr()) + getBackendPtr()->reset(); + if (getEmitterPtr()) + getEmitterPtr()->reset(); + if (getWriterPtr()) + getWriterPtr()->reset(); getLOHContainer().reset(); } @@ -215,8 +221,9 @@ } } - bool IsPCRel = Backend.getFixupKindInfo( - Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + assert(getBackendPtr() && "Expected assembler backend"); + bool IsPCRel = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; bool IsResolved; if (IsPCRel) { @@ -229,8 +236,8 @@ const MCSymbol &SA = A->getSymbol(); if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) { IsResolved = false; - } else { - IsResolved = getWriter().isSymbolRefDifferenceFullyResolvedImpl( + } else if (auto *Writer = getWriterPtr()) { + IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl( *this, SA, *DF, false, true); } } @@ -251,8 +258,8 @@ Value -= Layout.getSymbolOffset(Sym); } - bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & - MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; + bool ShouldAlignPC = getBackend().getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; assert((ShouldAlignPC ? IsPCRel : true) && "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); @@ -266,7 +273,7 @@ } // Let the backend force a relocation if needed. - if (IsResolved && Backend.shouldForceRelocation(*this, Fixup, Target)) + if (IsResolved && getBackend().shouldForceRelocation(*this, Fixup, Target)) IsResolved = false; return IsResolved; @@ -274,6 +281,7 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const { + assert(getBackendPtr() && "Requires assembler backend"); switch (F.getKind()) { case MCFragment::FT_Data: return cast(F).getContents().size(); @@ -437,6 +445,7 @@ void MCAssembler::writeFragmentPadding(const MCFragment &F, uint64_t FSize, MCObjectWriter *OW) const { + assert(getBackendPtr() && "Expected assembler backend"); // Should NOP padding be written out before this fragment? unsigned BundlePadding = F.getBundlePadding(); if (BundlePadding > 0) { @@ -470,7 +479,8 @@ /// \brief Write the fragment \p F to the output file. static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment &F) { - MCObjectWriter *OW = &Asm.getWriter(); + MCObjectWriter *OW = Asm.getWriterPtr(); + assert(OW && "Need ObjectWriter to write fragment"); // FIXME: Embed in fragments instead? uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); @@ -619,6 +629,8 @@ void MCAssembler::writeSectionData(const MCSection *Sec, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); + // Ignore virtual sections. if (Sec->isVirtualSection()) { assert(Layout.getSectionFileSize(Sec) == 0 && "Invalid size for section!"); @@ -688,6 +700,7 @@ } void MCAssembler::layout(MCAsmLayout &Layout) { + assert(getBackendPtr() && "Expected assembler backend"); DEBUG_WITH_TYPE("mc-dump", { errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -788,6 +801,7 @@ bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); MCValue Target; uint64_t Value; bool Resolved = evaluateFixup(Layout, Fixup, DF, Target, Value); @@ -801,6 +815,7 @@ bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F, const MCAsmLayout &Layout) const { + assert(getBackendPtr() && "Expected assembler backend"); // If this inst doesn't ever need relaxation, ignore it. This occurs when we // are intentionally pushing out inst fragments, or because we relaxed a // previous instruction to one that doesn't need relaxation. @@ -816,6 +831,8 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, MCRelaxableFragment &F) { + assert(getEmitterPtr() && + "Expected CodeEmitter defined for relaxInstruction"); if (!fragmentNeedsRelaxation(&F, Layout)) return false; @@ -848,6 +865,7 @@ bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout, MCPaddingFragment &PF) { + assert(getBackendPtr() && "Expected assembler backend"); uint64_t OldSize = PF.getSize(); if (!getBackend().relaxFragment(&PF, Layout)) return false; @@ -992,6 +1010,7 @@ } void MCAssembler::finishLayout(MCAsmLayout &Layout) { + assert(getBackendPtr() && "Expected assembler backend"); // The layout is done. Mark every fragment as valid. for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { MCSection &Section = *Layout.getSectionOrder()[i]; Index: llvm/lib/MC/MCExpr.cpp =================================================================== --- llvm/lib/MC/MCExpr.cpp +++ llvm/lib/MC/MCExpr.cpp @@ -440,6 +440,10 @@ return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr); } +bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { + return evaluateAsAbsolute(Res, Asm, nullptr, nullptr); +} + bool MCExpr::evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const { return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, @@ -493,7 +497,7 @@ return; if (SA.getFragment() == SB.getFragment() && !SA.isVariable() && - !SB.isVariable()) { + !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) { Addend += (SA.getOffset() - SB.getOffset()); // Pointers to Thumb symbols need to have their low-bit set to allow Index: llvm/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/lib/MC/MCObjectStreamer.cpp +++ llvm/lib/MC/MCObjectStreamer.cpp @@ -27,14 +27,23 @@ std::unique_ptr TAB, raw_pwrite_stream &OS, std::unique_ptr Emitter) - : MCStreamer(Context), ObjectWriter(TAB->createObjectWriter(OS)), - TAB(std::move(TAB)), Emitter(std::move(Emitter)), - Assembler(llvm::make_unique(Context, *this->TAB, - *this->Emitter, *ObjectWriter)), + : MCStreamer(Context), + Assembler(llvm::make_unique(Context, std::move(TAB), + std::move(Emitter), + TAB->createObjectWriter(OS))), EmitEHFrame(true), EmitDebugFrame(false) {} MCObjectStreamer::~MCObjectStreamer() {} +// AssemblerPtr is used for evaluation of expressions and causes +// difference between asm and object outputs. Return nullptr to in +// inline asm mode to limit divergence to assembly inputs. +MCAssembler *MCObjectStreamer::getAssemblerPtr() { + if (getUseAssemblerInfoForParsing()) + return Assembler.get(); + return nullptr; +} + void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) { if (PendingLabels.empty()) return; @@ -155,7 +164,7 @@ // Avoid fixups when possible. int64_t AbsValue; - if (Value->evaluateAsAbsolute(AbsValue, getAssembler())) { + if (Value->evaluateAsAbsolute(AbsValue, getAssemblerPtr())) { if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) { getContext().reportError( Loc, "value evaluated as " + Twine(AbsValue) + " is out of range."); @@ -217,7 +226,7 @@ void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { int64_t IntValue; - if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { + if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) { EmitULEB128IntValue(IntValue); return; } @@ -226,7 +235,7 @@ void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) { int64_t IntValue; - if (Value->evaluateAsAbsolute(IntValue, getAssembler())) { + if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) { EmitSLEB128IntValue(IntValue); return; } @@ -253,7 +262,7 @@ int64_t IntSubsection = 0; if (Subsection && - !Subsection->evaluateAsAbsolute(IntSubsection, getAssembler())) + !Subsection->evaluateAsAbsolute(IntSubsection, getAssemblerPtr())) report_fatal_error("Cannot evaluate subsection number"); if (IntSubsection < 0 || IntSubsection > 8192) report_fatal_error("Subsection number out of range"); @@ -399,7 +408,7 @@ } const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; - if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { + if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) { MCDwarfLineAddr::Emit(this, Assembler->getDWARFLinetableParams(), LineDelta, Res); return; @@ -411,7 +420,7 @@ const MCSymbol *Label) { const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel); int64_t Res; - if (AddrDelta->evaluateAsAbsolute(Res, getAssembler())) { + if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) { MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); return; } @@ -607,7 +616,7 @@ void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr, SMLoc Loc) { int64_t IntNumValues; - if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssembler())) { + if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssemblerPtr())) { getContext().reportError(Loc, "expected absolute expression"); return; } Index: llvm/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/AsmParser.cpp +++ llvm/lib/MC/MCParser/AsmParser.cpp @@ -779,7 +779,7 @@ Bytes = Bytes.drop_front(Skip); if (Count) { int64_t Res; - if (!Count->evaluateAsAbsolute(Res)) + if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(Loc, "expected absolute expression"); if (Res < 0) return Warning(Loc, "negative count has no effect"); @@ -1382,7 +1382,8 @@ Lex(); } - // Try to constant fold it up front, if possible. + // Try to constant fold it up front, if possible. Do not exploit + // assembler here. int64_t Value; if (Res->evaluateAsAbsolute(Value)) Res = MCConstantExpr::create(Value, getContext()); @@ -1423,7 +1424,7 @@ if (parseExpression(Expr)) return true; - if (!Expr->evaluateAsAbsolute(Res)) + if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(StartLoc, "expected absolute expression"); return false; @@ -2632,7 +2633,8 @@ Lex(); if (parseExpression(AbsoluteExp, EndLoc)) return false; - if (!AbsoluteExp->evaluateAsAbsolute(Value)) + if (!AbsoluteExp->evaluateAsAbsolute(Value, + getStreamer().getAssemblerPtr())) return Error(StrLoc, "expected absolute expression"); const char *StrChar = StrLoc.getPointer(); const char *EndChar = EndLoc.getPointer(); @@ -2932,8 +2934,9 @@ if (parseExpression(Offset)) return true; - if (check(!Offset->evaluateAsAbsolute(OffsetValue), OffsetLoc, - "expression is not a constant value") || + if (check(!Offset->evaluateAsAbsolute(OffsetValue, + getStreamer().getAssemblerPtr()), + OffsetLoc, "expression is not a constant value") || check(OffsetValue < 0, OffsetLoc, "expression is negative") || parseToken(AsmToken::Comma, "expected comma") || check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) @@ -5350,7 +5353,7 @@ return true; int64_t Count; - if (!CountExpr->evaluateAsAbsolute(Count)) { + if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) { return Error(CountLoc, "unexpected token in '" + Dir + "' directive"); } Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -75,7 +75,8 @@ void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} MCStreamer::MCStreamer(MCContext &Ctx) - : Context(Ctx), CurrentWinFrameInfo(nullptr) { + : Context(Ctx), CurrentWinFrameInfo(nullptr), + UseAssemblerInfoForParsing(false) { SectionStack.push_back(std::pair()); } Index: llvm/test/MC/AsmParser/assembler-expressions-fail.s =================================================================== --- /dev/null +++ llvm/test/MC/AsmParser/assembler-expressions-fail.s @@ -0,0 +1,18 @@ +# RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ERR +# RUN: not llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ERR + +.text + +test2: + jmp baz +# ERR: [[@LINE+1]]:5: error: expected absolute expression +.if . - text2 == 1 + nop +.else + ret +.endif + push fs + +# No additional errors. +# +# ERR-NOT: {{[0-9]+}}:{{[0-9]+}}: error: Index: llvm/test/MC/AsmParser/assembler-expressions-inlineasm.ll =================================================================== --- /dev/null +++ llvm/test/MC/AsmParser/assembler-expressions-inlineasm.ll @@ -0,0 +1,14 @@ +; RUN: not llc -mtriple x86_64-unknown-linux-gnu -o %t.s -filetype=asm %s 2>&1 | FileCheck %s +; RUN: not llc -mtriple x86_64-unknown-linux-gnu -o %t.o -filetype=obj %s 2>&1 | FileCheck %s + +; Assembler-aware expression evaluation should be disabled in inline +; assembly to prevent differences in behavior between object and +; assembly output. + + +; CHECK: :1:17: error: expected absolute expression + +define i32 @main() local_unnamed_addr { + tail call void asm sideeffect "foo: nop; .if . - foo==1; nop;.endif", "~{dirflag},~{fpsr},~{flags}"() + ret i32 0 +} Index: llvm/test/MC/AsmParser/assembler-expressions.s =================================================================== --- /dev/null +++ llvm/test/MC/AsmParser/assembler-expressions.s @@ -0,0 +1,47 @@ +# RUN: not llvm-mc -triple x86_64-unknown-unknown %s 2>&1 | FileCheck %s --check-prefix=ASM-ERR +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s | llvm-objdump -j .data -s - | FileCheck %s --check-prefix=OBJDATA +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s | llvm-objdump -j .text -s - | FileCheck %s --check-prefix=OBJTEXT +.data + +# OBJDATA: Contents of section .data +# OBJDATA-NEXT: 0000 aa0506ff + +foo2: +# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression +.if . - foo2 == 0 + .byte 0xaa +.else + .byte 0x00 +.endif + +foo3: + .byte 5 +# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression +.if . - foo3 == 1 + .byte 6 +.else + .byte 7 +.endif + +.byte 0xff + +# nop is a fixed size instruction so this should pass. + +# OBJTEXT: Contents of section .text +# OBJTEXT-NEXT: 0000 9090ff34 25 + +.text + +text1: + nop +# ASM-ERR: [[@LINE+1]]:5: error: expected absolute expression +.if . - text1 == 1 + nop +.else + ret +.endif + push gs + +# No additional errors. +# +# ASM-ERR-NOT: {{[0-9]+}}:{{[0-9]+}}: error: Index: llvm/test/MC/AsmParser/directive_fill.s =================================================================== --- llvm/test/MC/AsmParser/directive_fill.s +++ llvm/test/MC/AsmParser/directive_fill.s @@ -1,7 +1,7 @@ # RUN: llvm-mc -triple i386-unknown-unknown %s 2> %t.err | FileCheck %s # RUN: FileCheck --check-prefix=CHECK-WARNINGS %s < %t.err -# RUN: llvm-mc -triple i386-unknown-unknown -filetype=obj -o %t.o %s 2> %t.err -# RUN: FileCheck --check-prefix=OBJ-WARNINGS %s < %t.err +# RUN: llvm-mc -triple i386-unknown-unknown -filetype=obj -o %t.o %s 2> %t.err2 +# RUN: FileCheck --check-prefix=OBJ-WARNINGS %s < %t.err2 # CHECK: TEST0: # CHECK: .fill 1, 1, 0xa Index: llvm/tools/llvm-mc/llvm-mc.cpp =================================================================== --- llvm/tools/llvm-mc/llvm-mc.cpp +++ llvm/tools/llvm-mc/llvm-mc.cpp @@ -429,16 +429,17 @@ IP->setPrintImmHex(PrintImmHex); // Set up the AsmStreamer. - MCCodeEmitter *CE = nullptr; - MCAsmBackend *MAB = nullptr; - if (ShowEncoding) { - CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); - MAB = TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions); - } + std::unique_ptr CE; + if (ShowEncoding) + CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx)); + + std::unique_ptr MAB( + TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); auto FOut = llvm::make_unique(*OS); - Str.reset(TheTarget->createAsmStreamer( - Ctx, std::move(FOut), /*asmverbose*/ true, - /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); + Str.reset( + TheTarget->createAsmStreamer(Ctx, std::move(FOut), /*asmverbose*/ true, + /*useDwarfDirectory*/ true, IP, + std::move(CE), std::move(MAB), ShowInst)); } else if (FileType == OFT_Null) { Str.reset(TheTarget->createNullStreamer(Ctx)); @@ -464,6 +465,9 @@ Str->InitSections(true); } + // Use Assembler information for parsing. + Str->setUseAssemblerInfoForParsing(true); + int Res = 1; bool disassemble = false; switch (Action) {