mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 11:16:07 +00:00
[MC] Aligned bundling: remove special handling for RelaxAll
When both aligned bundling and RelaxAll are enabled, bundle padding is directly written into fragments (https://reviews.llvm.org/D8072). (The original motivation was memory usage, which has been achieved from different angles with recent assembler improvement). The code presents challenges with the work to replace fragment representation (e.g. #94950 #95077). This patch removes the special handling. RelaxAll still works but the behavior seems slightly different as revealed by 2 changed tests. However, most `-mc-relax-all` tests are unchanged. RelaxAll used to be the default for clang -O0. This mode has significant code size drawbacks and newer Clang doesn't use it (#90013). --- flushPendingLabels: The FOffset parameter can be removed: pending labels will be assigned to the incoming fragment at offset 0. Pull Request: https://github.com/llvm/llvm-project/pull/95188
This commit is contained in:
parent
72b841d016
commit
b1932b8483
@ -39,7 +39,6 @@ public:
|
|||||||
/// state management
|
/// state management
|
||||||
void reset() override {
|
void reset() override {
|
||||||
SeenIdent = false;
|
SeenIdent = false;
|
||||||
BundleGroups.clear();
|
|
||||||
MCObjectStreamer::reset();
|
MCObjectStreamer::reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,14 +141,7 @@ private:
|
|||||||
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S, uint64_t Offset);
|
void finalizeCGProfileEntry(const MCSymbolRefExpr *&S, uint64_t Offset);
|
||||||
void finalizeCGProfile();
|
void finalizeCGProfile();
|
||||||
|
|
||||||
/// Merge the content of the fragment \p EF into the fragment \p DF.
|
|
||||||
void mergeFragment(MCDataFragment *, MCDataFragment *);
|
|
||||||
|
|
||||||
bool SeenIdent = false;
|
bool SeenIdent = false;
|
||||||
|
|
||||||
/// BundleGroups - The stack of fragments holding the bundle-locked
|
|
||||||
/// instructions.
|
|
||||||
SmallVector<MCDataFragment *, 4> BundleGroups;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MCELFStreamer *createARMELFStreamer(MCContext &Context,
|
MCELFStreamer *createARMELFStreamer(MCContext &Context,
|
||||||
|
@ -227,8 +227,7 @@ public:
|
|||||||
void addPendingLabel(MCSymbol* label, unsigned Subsection = 0);
|
void addPendingLabel(MCSymbol* label, unsigned Subsection = 0);
|
||||||
|
|
||||||
/// Associate all pending labels in a subsection with a fragment.
|
/// Associate all pending labels in a subsection with a fragment.
|
||||||
void flushPendingLabels(MCFragment *F, uint64_t FOffset = 0,
|
void flushPendingLabels(MCFragment *F, unsigned Subsection);
|
||||||
unsigned Subsection = 0);
|
|
||||||
|
|
||||||
/// Associate all pending labels with empty data fragments. One fragment
|
/// Associate all pending labels with empty data fragments. One fragment
|
||||||
/// will be created for each subsection as necessary.
|
/// will be created for each subsection as necessary.
|
||||||
|
@ -73,9 +73,6 @@ private:
|
|||||||
|
|
||||||
void fixSymbolsInTLSFixups(const MCExpr *expr);
|
void fixSymbolsInTLSFixups(const MCExpr *expr);
|
||||||
|
|
||||||
/// Merge the content of the fragment \p EF into the fragment \p DF.
|
|
||||||
void mergeFragment(MCDataFragment *, MCDataFragment *);
|
|
||||||
|
|
||||||
bool SeenIdent;
|
bool SeenIdent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -420,12 +420,6 @@ void MCAsmLayout::layoutBundle(MCFragment *F) {
|
|||||||
// The fragment's offset will point to after the padding, and its computed
|
// The fragment's offset will point to after the padding, and its computed
|
||||||
// size won't include the padding.
|
// size won't include the padding.
|
||||||
//
|
//
|
||||||
// When the -mc-relax-all flag is used, we optimize bundling by writting the
|
|
||||||
// padding directly into fragments when the instructions are emitted inside
|
|
||||||
// the streamer. When the fragment is larger than the bundle size, we need to
|
|
||||||
// ensure that it's bundle aligned. This means that if we end up with
|
|
||||||
// multiple fragments, we must emit bundle padding between fragments.
|
|
||||||
//
|
|
||||||
// ".align N" is an example of a directive that introduces multiple
|
// ".align N" is an example of a directive that introduces multiple
|
||||||
// fragments. We could add a special case to handle ".align N" by emitting
|
// fragments. We could add a special case to handle ".align N" by emitting
|
||||||
// within-fragment padding (which would produce less padding when N is less
|
// within-fragment padding (which would produce less padding when N is less
|
||||||
@ -436,7 +430,7 @@ void MCAsmLayout::layoutBundle(MCFragment *F) {
|
|||||||
MCEncodedFragment *EF = cast<MCEncodedFragment>(F);
|
MCEncodedFragment *EF = cast<MCEncodedFragment>(F);
|
||||||
uint64_t FSize = Assembler.computeFragmentSize(*this, *EF);
|
uint64_t FSize = Assembler.computeFragmentSize(*this, *EF);
|
||||||
|
|
||||||
if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize())
|
if (FSize > Assembler.getBundleAlignSize())
|
||||||
report_fatal_error("Fragment can't be larger than a bundle size");
|
report_fatal_error("Fragment can't be larger than a bundle size");
|
||||||
|
|
||||||
uint64_t RequiredBundlePadding =
|
uint64_t RequiredBundlePadding =
|
||||||
|
@ -50,44 +50,6 @@ bool MCELFStreamer::isBundleLocked() const {
|
|||||||
return getCurrentSectionOnly()->isBundleLocked();
|
return getCurrentSectionOnly()->isBundleLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCELFStreamer::mergeFragment(MCDataFragment *DF,
|
|
||||||
MCDataFragment *EF) {
|
|
||||||
MCAssembler &Assembler = getAssembler();
|
|
||||||
|
|
||||||
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
|
|
||||||
uint64_t FSize = EF->getContents().size();
|
|
||||||
|
|
||||||
if (FSize > Assembler.getBundleAlignSize())
|
|
||||||
report_fatal_error("Fragment can't be larger than a bundle size");
|
|
||||||
|
|
||||||
uint64_t RequiredBundlePadding = computeBundlePadding(
|
|
||||||
Assembler, EF, DF->getContents().size(), FSize);
|
|
||||||
|
|
||||||
if (RequiredBundlePadding > UINT8_MAX)
|
|
||||||
report_fatal_error("Padding cannot exceed 255 bytes");
|
|
||||||
|
|
||||||
if (RequiredBundlePadding > 0) {
|
|
||||||
SmallString<256> Code;
|
|
||||||
raw_svector_ostream VecOS(Code);
|
|
||||||
EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
|
|
||||||
Assembler.writeFragmentPadding(VecOS, *EF, FSize);
|
|
||||||
|
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
flushPendingLabels(DF, DF->getContents().size());
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) {
|
|
||||||
EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() +
|
|
||||||
DF->getContents().size());
|
|
||||||
DF->getFixups().push_back(EF->getFixups()[i]);
|
|
||||||
}
|
|
||||||
if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo())
|
|
||||||
DF->setHasInstructions(*EF->getSubtargetInfo());
|
|
||||||
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) {
|
void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) {
|
||||||
MCContext &Ctx = getContext();
|
MCContext &Ctx = getContext();
|
||||||
switchSection(Ctx.getObjectFileInfo()->getTextSection());
|
switchSection(Ctx.getObjectFileInfo()->getTextSection());
|
||||||
@ -575,24 +537,12 @@ void MCELFStreamer::emitInstToData(const MCInst &Inst,
|
|||||||
|
|
||||||
if (Assembler.isBundlingEnabled()) {
|
if (Assembler.isBundlingEnabled()) {
|
||||||
MCSection &Sec = *getCurrentSectionOnly();
|
MCSection &Sec = *getCurrentSectionOnly();
|
||||||
if (Assembler.getRelaxAll() && isBundleLocked()) {
|
if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) {
|
||||||
// If the -mc-relax-all flag is used and we are bundle-locked, we re-use
|
|
||||||
// the current bundle group.
|
|
||||||
DF = BundleGroups.back();
|
|
||||||
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
|
|
||||||
}
|
|
||||||
else if (Assembler.getRelaxAll() && !isBundleLocked())
|
|
||||||
// When not in a bundle-locked group and the -mc-relax-all flag is used,
|
|
||||||
// we create a new temporary fragment which will be later merged into
|
|
||||||
// the current fragment.
|
|
||||||
DF = getContext().allocFragment<MCDataFragment>();
|
|
||||||
else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) {
|
|
||||||
// If we are bundle-locked, we re-use the current fragment.
|
// If we are bundle-locked, we re-use the current fragment.
|
||||||
// The bundle-locking directive ensures this is a new data fragment.
|
// The bundle-locking directive ensures this is a new data fragment.
|
||||||
DF = cast<MCDataFragment>(getCurrentFragment());
|
DF = cast<MCDataFragment>(getCurrentFragment());
|
||||||
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
|
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
|
||||||
}
|
} else if (!isBundleLocked() && Fixups.size() == 0) {
|
||||||
else if (!isBundleLocked() && Fixups.size() == 0) {
|
|
||||||
// Optimize memory usage by emitting the instruction to a
|
// Optimize memory usage by emitting the instruction to a
|
||||||
// MCCompactEncodedInstFragment when not in a bundle-locked group and
|
// MCCompactEncodedInstFragment when not in a bundle-locked group and
|
||||||
// there are no fixups registered.
|
// there are no fixups registered.
|
||||||
@ -632,13 +582,6 @@ void MCELFStreamer::emitInstToData(const MCInst &Inst,
|
|||||||
getAssembler().getBackend().RelaxFixupKind)
|
getAssembler().getBackend().RelaxFixupKind)
|
||||||
DF->setLinkerRelaxable();
|
DF->setLinkerRelaxable();
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
DF->getContents().append(Code.begin(), Code.end());
|
||||||
|
|
||||||
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
|
|
||||||
if (!isBundleLocked()) {
|
|
||||||
mergeFragment(getOrCreateDataFragment(&STI), DF);
|
|
||||||
delete DF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCELFStreamer::emitBundleAlignMode(Align Alignment) {
|
void MCELFStreamer::emitBundleAlignMode(Align Alignment) {
|
||||||
@ -660,12 +603,6 @@ void MCELFStreamer::emitBundleLock(bool AlignToEnd) {
|
|||||||
if (!isBundleLocked())
|
if (!isBundleLocked())
|
||||||
Sec.setBundleGroupBeforeFirstInst(true);
|
Sec.setBundleGroupBeforeFirstInst(true);
|
||||||
|
|
||||||
if (getAssembler().getRelaxAll() && !isBundleLocked()) {
|
|
||||||
// TODO: drop the lock state and set directly in the fragment
|
|
||||||
MCDataFragment *DF = getContext().allocFragment<MCDataFragment>();
|
|
||||||
BundleGroups.push_back(DF);
|
|
||||||
}
|
|
||||||
|
|
||||||
Sec.setBundleLockState(AlignToEnd ? MCSection::BundleLockedAlignToEnd
|
Sec.setBundleLockState(AlignToEnd ? MCSection::BundleLockedAlignToEnd
|
||||||
: MCSection::BundleLocked);
|
: MCSection::BundleLocked);
|
||||||
}
|
}
|
||||||
@ -680,27 +617,7 @@ void MCELFStreamer::emitBundleUnlock() {
|
|||||||
else if (Sec.isBundleGroupBeforeFirstInst())
|
else if (Sec.isBundleGroupBeforeFirstInst())
|
||||||
report_fatal_error("Empty bundle-locked group is forbidden");
|
report_fatal_error("Empty bundle-locked group is forbidden");
|
||||||
|
|
||||||
// When the -mc-relax-all flag is used, we emit instructions to fragments
|
Sec.setBundleLockState(MCSection::NotBundleLocked);
|
||||||
// stored on a stack. When the bundle unlock is emitted, we pop a fragment
|
|
||||||
// from the stack a merge it to the one below.
|
|
||||||
if (getAssembler().getRelaxAll()) {
|
|
||||||
assert(!BundleGroups.empty() && "There are no bundle groups");
|
|
||||||
MCDataFragment *DF = BundleGroups.back();
|
|
||||||
|
|
||||||
// FIXME: Use BundleGroups to track the lock state instead.
|
|
||||||
Sec.setBundleLockState(MCSection::NotBundleLocked);
|
|
||||||
|
|
||||||
// FIXME: Use more separate fragments for nested groups.
|
|
||||||
if (!isBundleLocked()) {
|
|
||||||
mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF);
|
|
||||||
BundleGroups.pop_back();
|
|
||||||
delete DF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Sec.getBundleLockState() != MCSection::BundleLockedAlignToEnd)
|
|
||||||
getOrCreateDataFragment()->setAlignToBundleEnd(false);
|
|
||||||
} else
|
|
||||||
Sec.setBundleLockState(MCSection::NotBundleLocked);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCELFStreamer::finishImpl() {
|
void MCELFStreamer::finishImpl() {
|
||||||
|
@ -81,7 +81,7 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Associate the labels with F.
|
// Associate the labels with F.
|
||||||
CurSection->flushPendingLabels(F, FOffset, CurSubsectionIdx);
|
CurSection->flushPendingLabels(F, CurSubsectionIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCObjectStreamer::flushPendingLabels() {
|
void MCObjectStreamer::flushPendingLabels() {
|
||||||
@ -215,7 +215,7 @@ static bool canReuseDataFragment(const MCDataFragment &F,
|
|||||||
// When bundling is enabled, we don't want to add data to a fragment that
|
// When bundling is enabled, we don't want to add data to a fragment that
|
||||||
// already has instructions (see MCELFStreamer::emitInstToData for details)
|
// already has instructions (see MCELFStreamer::emitInstToData for details)
|
||||||
if (Assembler.isBundlingEnabled())
|
if (Assembler.isBundlingEnabled())
|
||||||
return Assembler.getRelaxAll();
|
return false;
|
||||||
// If the subtarget is changed mid fragment we start a new fragment to record
|
// If the subtarget is changed mid fragment we start a new fragment to record
|
||||||
// the new STI.
|
// the new STI.
|
||||||
return !STI || F.getSubtargetInfo() == STI;
|
return !STI || F.getSubtargetInfo() == STI;
|
||||||
@ -292,8 +292,7 @@ void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
|
|||||||
// Otherwise queue the label and set its fragment pointer when we emit the
|
// Otherwise queue the label and set its fragment pointer when we emit the
|
||||||
// next fragment.
|
// next fragment.
|
||||||
auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
|
auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
|
||||||
if (F && !(getAssembler().isBundlingEnabled() &&
|
if (F) {
|
||||||
getAssembler().getRelaxAll())) {
|
|
||||||
Symbol->setFragment(F);
|
Symbol->setFragment(F);
|
||||||
Symbol->setOffset(F->getContents().size());
|
Symbol->setOffset(F->getContents().size());
|
||||||
} else {
|
} else {
|
||||||
@ -465,9 +464,6 @@ void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
|
|||||||
|
|
||||||
void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
|
void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
|
||||||
const MCSubtargetInfo &STI) {
|
const MCSubtargetInfo &STI) {
|
||||||
if (getAssembler().getRelaxAll() && getAssembler().isBundlingEnabled())
|
|
||||||
llvm_unreachable("All instructions should have already been relaxed");
|
|
||||||
|
|
||||||
// Always create a new, separate fragment here, because its size can change
|
// Always create a new, separate fragment here, because its size can change
|
||||||
// during relaxation.
|
// during relaxation.
|
||||||
MCRelaxableFragment *IF =
|
MCRelaxableFragment *IF =
|
||||||
|
@ -82,15 +82,14 @@ void MCSection::addPendingLabel(MCSymbol *label, unsigned Subsection) {
|
|||||||
PendingLabels.push_back(PendingLabel(label, Subsection));
|
PendingLabels.push_back(PendingLabel(label, Subsection));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MCSection::flushPendingLabels(MCFragment *F, uint64_t FOffset,
|
void MCSection::flushPendingLabels(MCFragment *F, unsigned Subsection) {
|
||||||
unsigned Subsection) {
|
|
||||||
// Set the fragment and fragment offset for all pending symbols in the
|
// Set the fragment and fragment offset for all pending symbols in the
|
||||||
// specified Subsection, and remove those symbols from the pending list.
|
// specified Subsection, and remove those symbols from the pending list.
|
||||||
for (auto It = PendingLabels.begin(); It != PendingLabels.end(); ++It) {
|
for (auto It = PendingLabels.begin(); It != PendingLabels.end(); ++It) {
|
||||||
PendingLabel& Label = *It;
|
PendingLabel& Label = *It;
|
||||||
if (Label.Subsection == Subsection) {
|
if (Label.Subsection == Subsection) {
|
||||||
Label.Sym->setFragment(F);
|
Label.Sym->setFragment(F);
|
||||||
Label.Sym->setOffset(FOffset);
|
assert(Label.Sym->getOffset() == 0);
|
||||||
PendingLabels.erase(It--);
|
PendingLabels.erase(It--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +104,7 @@ void MCSection::flushPendingLabels() {
|
|||||||
MCFragment *F = new MCDataFragment();
|
MCFragment *F = new MCDataFragment();
|
||||||
addFragment(*F);
|
addFragment(*F);
|
||||||
F->setParent(this);
|
F->setParent(this);
|
||||||
flushPendingLabels(F, 0, Label.Subsection);
|
flushPendingLabels(F, Label.Subsection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,19 +39,6 @@ using namespace llvm;
|
|||||||
|
|
||||||
MCWasmStreamer::~MCWasmStreamer() = default; // anchor.
|
MCWasmStreamer::~MCWasmStreamer() = default; // anchor.
|
||||||
|
|
||||||
void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) {
|
|
||||||
flushPendingLabels(DF, DF->getContents().size());
|
|
||||||
|
|
||||||
for (unsigned I = 0, E = EF->getFixups().size(); I != E; ++I) {
|
|
||||||
EF->getFixups()[I].setOffset(EF->getFixups()[I].getOffset() +
|
|
||||||
DF->getContents().size());
|
|
||||||
DF->getFixups().push_back(EF->getFixups()[I]);
|
|
||||||
}
|
|
||||||
if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo())
|
|
||||||
DF->setHasInstructions(*EF->getSubtargetInfo());
|
|
||||||
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
|
void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
|
||||||
auto *Symbol = cast<MCSymbolWasm>(S);
|
auto *Symbol = cast<MCSymbolWasm>(S);
|
||||||
MCObjectStreamer::emitLabel(Symbol, Loc);
|
MCObjectStreamer::emitLabel(Symbol, Loc);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-OPT %s
|
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-OPT %s
|
||||||
# RUN: llvm-mc -filetype=obj -triple i686-pc-linux-gnu -mcpu=pentiumpro -mc-relax-all %s -o - \
|
# RUN: llvm-mc -filetype=obj -triple i686-pc-linux-gnu -mcpu=pentiumpro -mc-relax-all %s -o - \
|
||||||
# RUN: | llvm-objdump -d --no-show-raw-insn - \
|
# RUN: | llvm-objdump -d --no-show-raw-insn - \
|
||||||
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-RELAX %s
|
# RUN: | FileCheck --check-prefixes=CHECK,CHECK-OPT %s
|
||||||
|
|
||||||
.text
|
.text
|
||||||
foo:
|
foo:
|
||||||
@ -13,11 +13,7 @@ foo:
|
|||||||
.bundle_lock align_to_end
|
.bundle_lock align_to_end
|
||||||
# CHECK: 1: nopw %cs:(%eax,%eax)
|
# CHECK: 1: nopw %cs:(%eax,%eax)
|
||||||
# CHECK: 10: nopw %cs:(%eax,%eax)
|
# CHECK: 10: nopw %cs:(%eax,%eax)
|
||||||
# CHECK-RELAX: 1a: nop
|
|
||||||
# CHECK-RELAX: 20: nopw %cs:(%eax,%eax)
|
|
||||||
# CHECK-RELAX: 2a: nopw %cs:(%eax,%eax)
|
|
||||||
# CHECK-OPT: 1b: calll 0x1c
|
# CHECK-OPT: 1b: calll 0x1c
|
||||||
# CHECK-RELAX: 3b: calll 0x3c
|
|
||||||
calll bar # 5 bytes
|
calll bar # 5 bytes
|
||||||
.bundle_unlock
|
.bundle_unlock
|
||||||
ret # 1 byte
|
ret # 1 byte
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-OPT %s
|
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-OPT %s
|
||||||
# RUN: llvm-mc -filetype=obj -triple i686-pc-linux-gnu -mcpu=pentiumpro -mc-relax-all %s -o - \
|
# RUN: llvm-mc -filetype=obj -triple i686-pc-linux-gnu -mcpu=pentiumpro -mc-relax-all %s -o - \
|
||||||
# RUN: | llvm-objdump --no-print-imm-hex -d --no-show-raw-insn - \
|
# RUN: | llvm-objdump --no-print-imm-hex -d --no-show-raw-insn - \
|
||||||
# RUN: | FileCheck -check-prefix=CHECK -check-prefix=CHECK-RELAX %s
|
# RUN: | FileCheck --check-prefixes=CHECK,CHECK-OPT %s
|
||||||
|
|
||||||
.text
|
.text
|
||||||
foo:
|
foo:
|
||||||
@ -11,17 +11,12 @@ foo:
|
|||||||
push %ebp # 1 byte
|
push %ebp # 1 byte
|
||||||
.align 16
|
.align 16
|
||||||
# CHECK: 1: nopw %cs:(%eax,%eax)
|
# CHECK: 1: nopw %cs:(%eax,%eax)
|
||||||
# CHECK-RELAX: 10: nopw %cs:(%eax,%eax)
|
|
||||||
# CHECK-RELAX: 1a: nop
|
|
||||||
# CHECK-OPT: 10: movl $1, (%esp)
|
# CHECK-OPT: 10: movl $1, (%esp)
|
||||||
# CHECK-RELAX: 20: movl $1, (%esp)
|
|
||||||
movl $0x1, (%esp) # 7 bytes
|
movl $0x1, (%esp) # 7 bytes
|
||||||
movl $0x1, (%esp) # 7 bytes
|
movl $0x1, (%esp) # 7 bytes
|
||||||
# CHECK-OPT: 1e: nop
|
# CHECK-OPT: 1e: nop
|
||||||
movl $0x2, 0x1(%esp) # 8 bytes
|
movl $0x2, 0x1(%esp) # 8 bytes
|
||||||
movl $0x2, 0x1(%esp) # 8 bytes
|
movl $0x2, 0x1(%esp) # 8 bytes
|
||||||
# CHECK-RELAX: 3e: nop
|
|
||||||
# CHECK-RELAX: 40: movl $2, 1(%esp)
|
|
||||||
movl $0x2, 0x1(%esp) # 8 bytes
|
movl $0x2, 0x1(%esp) # 8 bytes
|
||||||
movl $0x2, (%esp) # 7 bytes
|
movl $0x2, (%esp) # 7 bytes
|
||||||
# CHECK-OPT: 3f: nop
|
# CHECK-OPT: 3f: nop
|
||||||
|
Loading…
x
Reference in New Issue
Block a user