MC: Switch to using MCInst fragments to do relaxation.

Also, both MCMachOStreamer and MCAssembler are now target independent!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@99256 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2010-03-23 05:09:03 +00:00
parent 337055e62f
commit d8036fb0de
2 changed files with 76 additions and 76 deletions

View File

@ -25,9 +25,6 @@
#include "llvm/Target/TargetRegistry.h"
#include "llvm/Target/TargetAsmBackend.h"
// FIXME: Gross.
#include "../Target/X86/X86FixupKinds.h"
#include <vector>
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<MCDataFragment>(it2);
if (!DF)
// Check if this is an instruction fragment that needs relaxation.
MCInstFragment *IF = dyn_cast<MCInstFragment>(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<char> &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<MCFixup, 4> 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;
}
}

View File

@ -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) {