diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 031820d5286..b665cdff83e 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -25,9 +25,6 @@ #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmBackend.h" -// FIXME: Gross. -#include "../Target/X86/X86FixupKinds.h" - #include using namespace llvm; @@ -551,10 +548,6 @@ void MCAssembler::Finish() { bool MCAssembler::FixupNeedsRelaxation(const MCAsmFixup &Fixup, const MCFragment *DF, const MCAsmLayout &Layout) const { - // Currently we only need to relax X86::reloc_pcrel_1byte. - if (unsigned(Fixup.Kind) != X86::reloc_pcrel_1byte) - return false; - // If we cannot resolve the fixup value, it requires relaxation. MCValue Target; uint64_t Value; @@ -565,6 +558,22 @@ bool MCAssembler::FixupNeedsRelaxation(const MCAsmFixup &Fixup, return int64_t(Value) != int64_t(int8_t(Value)); } +bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF, + const MCAsmLayout &Layout) const { + // 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. + if (!getBackend().MayNeedRelaxation(IF->getInst(), IF->getFixups())) + return false; + + for (MCInstFragment::const_fixup_iterator it = IF->fixup_begin(), + ie = IF->fixup_end(); it != ie; ++it) + if (FixupNeedsRelaxation(*it, IF, Layout)) + return true; + + return false; +} + bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { // Layout the concrete sections and fragments. uint64_t Address = 0; @@ -609,87 +618,50 @@ bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { Address += SD.getSize(); } - // Scan the fixups in order and relax any that don't fit. + // Scan for fragments that need relaxation. for (iterator it = begin(), ie = end(); it != ie; ++it) { MCSectionData &SD = *it; for (MCSectionData::iterator it2 = SD.begin(), ie2 = SD.end(); it2 != ie2; ++it2) { - MCDataFragment *DF = dyn_cast(it2); - if (!DF) + // Check if this is an instruction fragment that needs relaxation. + MCInstFragment *IF = dyn_cast(it2); + if (!IF || !FragmentNeedsRelaxation(IF, Layout)) continue; - for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), - ie3 = DF->fixup_end(); it3 != ie3; ++it3) { - MCAsmFixup &Fixup = *it3; + // FIXME-PERF: We could immediately lower out instructions if we can tell + // they are fully resolved, to avoid retesting on later passes. - // Check whether we need to relax this fixup. - if (!FixupNeedsRelaxation(Fixup, DF, Layout)) - continue; + // Relax the fragment. - // Relax the instruction. - // - // FIXME: This is a huge temporary hack which just looks for x86 - // branches; the only thing we need to relax on x86 is - // 'X86::reloc_pcrel_1byte'. Once we have MCInst fragments, this will be - // replaced by a TargetAsmBackend hook (most likely tblgen'd) to relax - // an individual MCInst. - SmallVectorImpl &C = DF->getContents(); - uint64_t PrevOffset = Fixup.Offset; - unsigned Amt = 0; + MCInst Relaxed; + getBackend().RelaxInstruction(IF, Relaxed); - // jcc instructions - if (unsigned(C[Fixup.Offset-1]) >= 0x70 && - unsigned(C[Fixup.Offset-1]) <= 0x7f) { - C[Fixup.Offset] = C[Fixup.Offset-1] + 0x10; - C[Fixup.Offset-1] = char(0x0f); - ++Fixup.Offset; - Amt = 4; + // Encode the new instruction. + // + // FIXME-PERF: If it matters, we could let the target do this. It can + // probably do so more efficiently in many cases. + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups); + VecOS.flush(); - // jmp rel8 - } else if (C[Fixup.Offset-1] == char(0xeb)) { - C[Fixup.Offset-1] = char(0xe9); - Amt = 3; - - } else - llvm_unreachable("unknown 1 byte pcrel instruction!"); - - Fixup.Value = MCBinaryExpr::Create( - MCBinaryExpr::Sub, Fixup.Value, - MCConstantExpr::Create(3, getContext()), - getContext()); - C.insert(C.begin() + Fixup.Offset, Amt, char(0)); - Fixup.Kind = MCFixupKind(X86::reloc_pcrel_4byte); - - // Update the remaining fixups, which have slid. - // - // FIXME: This is bad for performance, but will be eliminated by the - // move to MCInst specific fragments. - ++it3; - for (; it3 != ie3; ++it3) - it3->Offset += Amt; - - // Update all the symbols for this fragment, which may have slid. - // - // FIXME: This is really really bad for performance, but will be - // eliminated by the move to MCInst specific fragments. - for (MCAssembler::symbol_iterator it = symbol_begin(), - ie = symbol_end(); it != ie; ++it) { - MCSymbolData &SD = *it; - - if (it->getFragment() != DF) - continue; - - if (SD.getOffset() > PrevOffset) - SD.setOffset(SD.getOffset() + Amt); - } - - // Restart layout. - // - // FIXME-PERF: This is O(N^2), but will be eliminated once we have a - // smart MCAsmLayout object. - return true; + // Update the instruction fragment. + IF->setInst(Relaxed); + IF->getCode() = Code; + IF->getFixups().clear(); + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + MCFixup &F = Fixups[i]; + IF->getFixups().push_back(MCAsmFixup(F.getOffset(), *F.getValue(), + F.getKind())); } + + // Restart layout. + // + // FIXME-PERF: This is O(N^2), but will be eliminated once we have a + // smart MCAsmLayout object. + return true; } } diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 2a1aa273014..9141a903dd9 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -18,6 +18,8 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" + using namespace llvm; namespace { @@ -391,6 +393,32 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { F.getKind())); } + // See if we might need to relax this instruction, if so it needs its own + // fragment. + // + // FIXME-PERF: Support target hook to do a fast path that avoids the encoder, + // when we can immediately tell that we will get something which might need + // relaxation (and compute its size). + // + // FIXME-PERF: We should also be smart about immediately relaxing instructions + // which we can already show will never possibly fit (we can also do a very + // good job of this before we do the first relaxation pass, because we have + // total knowledge about undefined symbols at that point). Even now, though, + // we can do a decent job, especially on Darwin where scattering means that we + // are going to often know that we can never fully resolve a fixup. + if (Assembler.getBackend().MayNeedRelaxation(Inst, AsmFixups)) { + MCInstFragment *IF = new MCInstFragment(Inst, CurSectionData); + + // Add the fixups and data. + // + // FIXME: Revisit this design decision when relaxation is done, we may be + // able to get away with not storing any extra data in the MCInst. + IF->getCode() = Code; + IF->getFixups() = AsmFixups; + + return; + } + // Add the fixups and data. MCDataFragment *DF = getOrCreateDataFragment(); for (unsigned i = 0, e = AsmFixups.size(); i != e; ++i) {