diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index d7f1acea35e..d14122bf74c 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -679,6 +679,10 @@ private: bool FixupNeedsRelaxation(const MCAsmFixup &Fixup, const MCFragment *DF, const MCAsmLayout &Layout) const; + /// Check whether the given fragment needs relaxation. + bool FragmentNeedsRelaxation(const MCInstFragment *IF, + const MCAsmLayout &Layout) const; + /// LayoutSection - Assign offsets and sizes to the fragments in the section /// \arg SD, and update the section size. The section file offset should /// already have been computed. diff --git a/include/llvm/Target/TargetAsmBackend.h b/include/llvm/Target/TargetAsmBackend.h index 16f33c32f48..f350ecc410a 100644 --- a/include/llvm/Target/TargetAsmBackend.h +++ b/include/llvm/Target/TargetAsmBackend.h @@ -19,6 +19,8 @@ class MCInst; class MCInstFragment; class MCObjectWriter; class MCSection; +template +class SmallVectorImpl; class Target; class raw_ostream; @@ -98,6 +100,15 @@ public: virtual void ApplyFixup(const MCAsmFixup &Fixup, MCDataFragment &Fragment, uint64_t Value) const = 0; + /// MayNeedRelaxation - Check whether the given instruction may need + /// relaxation. + /// + /// \arg Inst - The instruction to test. + /// \arg Fixups - The actual fixups this instruction encoded to, for potential + /// use by the target backend. + virtual bool MayNeedRelaxation(const MCInst &Inst, + const SmallVectorImpl &Fixups) const = 0; + /// RelaxInstruction - Relax the instruction in the given fragment to the next /// wider instruction. virtual void RelaxInstruction(const MCInstFragment *IF, diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 7672528524b..031820d5286 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -715,7 +715,7 @@ void MCAssembler::FinishLayout(MCAsmLayout &Layout) { // Create a new data fragment for the instruction. // - // FIXME: Reuse previous data fragment if possible. + // FIXME-PERF: Reuse previous data fragment if possible. MCDataFragment *DF = new MCDataFragment(); SD.getFragmentList().insert(it2, DF); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index a52d962c9a4..2a1aa273014 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -383,12 +383,19 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); - // Add the fixups and data. - MCDataFragment *DF = getOrCreateDataFragment(); + // FIXME: Eliminate this copy. + SmallVector AsmFixups; for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - DF->addFixup(MCAsmFixup(DF->getContents().size()+F.getOffset(), - *F.getValue(), F.getKind())); + AsmFixups.push_back(MCAsmFixup(F.getOffset(), *F.getValue(), + F.getKind())); + } + + // Add the fixups and data. + MCDataFragment *DF = getOrCreateDataFragment(); + for (unsigned i = 0, e = AsmFixups.size(); i != e; ++i) { + AsmFixups[i].Offset += DF->getContents().size(); + DF->addFixup(AsmFixups[i]); } DF->getContents().append(Code.begin(), Code.end()); } diff --git a/lib/Target/X86/X86AsmBackend.cpp b/lib/Target/X86/X86AsmBackend.cpp index 3e4e2b5ae2f..8e2928c3b71 100644 --- a/lib/Target/X86/X86AsmBackend.cpp +++ b/lib/Target/X86/X86AsmBackend.cpp @@ -12,6 +12,7 @@ #include "X86FixupKinds.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MachObjectWriter.h" @@ -52,6 +53,9 @@ public: DF.getContents()[Fixup.Offset + i] = uint8_t(Value >> (i * 8)); } + bool MayNeedRelaxation(const MCInst &Inst, + const SmallVectorImpl &Fixups) const; + void RelaxInstruction(const MCInstFragment *IF, MCInst &Res) const; bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const; @@ -82,6 +86,20 @@ static unsigned getRelaxedOpcode(unsigned Op) { } } +bool X86AsmBackend::MayNeedRelaxation(const MCInst &Inst, + const SmallVectorImpl &Fixups) const { + // Check for a 1byte pcrel fixup, and enforce that we would know how to relax + // this instruction. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + if (unsigned(Fixups[i].Kind) == X86::reloc_pcrel_1byte) { + assert(getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode()); + return true; + } + } + + return false; +} + // FIXME: Can tblgen help at all here to verify there aren't other instructions // we can relax? void X86AsmBackend::RelaxInstruction(const MCInstFragment *IF,