summaryrefslogtreecommitdiff
path: root/lib/MC/MCObjectStreamer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MC/MCObjectStreamer.cpp')
-rw-r--r--lib/MC/MCObjectStreamer.cpp150
1 files changed, 99 insertions, 51 deletions
diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index 15cc0faf5407..4b6dad5ce8f3 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/lib/MC/MCObjectStreamer.cpp
@@ -25,16 +25,24 @@ using namespace llvm;
MCObjectStreamer::MCObjectStreamer(MCContext &Context,
std::unique_ptr<MCAsmBackend> TAB,
- raw_pwrite_stream &OS,
+ std::unique_ptr<MCObjectWriter> OW,
std::unique_ptr<MCCodeEmitter> Emitter)
- : MCStreamer(Context), ObjectWriter(TAB->createObjectWriter(OS)),
- TAB(std::move(TAB)), Emitter(std::move(Emitter)),
- Assembler(llvm::make_unique<MCAssembler>(Context, *this->TAB,
- *this->Emitter, *ObjectWriter)),
+ : MCStreamer(Context),
+ Assembler(llvm::make_unique<MCAssembler>(
+ Context, std::move(TAB), std::move(Emitter), std::move(OW))),
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;
@@ -51,17 +59,35 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
PendingLabels.clear();
}
+// As a compile-time optimization, avoid allocating and evaluating an MCExpr
+// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment.
+static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ assert(Hi && Lo);
+ if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
+ Hi->isVariable() || Lo->isVariable())
+ return None;
+
+ return Hi->getOffset() - Lo->getOffset();
+}
+
void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
const MCSymbol *Lo,
unsigned Size) {
- // If not assigned to the same (valid) fragment, fallback.
- if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
- Hi->isVariable() || Lo->isVariable()) {
- MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) {
+ EmitIntValue(*Diff, Size);
return;
}
+ MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
+}
- EmitIntValue(Hi->getOffset() - Lo->getOffset(), Size);
+void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) {
+ EmitULEB128IntValue(*Diff);
+ return;
+ }
+ MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
}
void MCObjectStreamer::reset() {
@@ -94,12 +120,24 @@ MCFragment *MCObjectStreamer::getCurrentFragment() const {
return nullptr;
}
-MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() {
- MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+static bool CanReuseDataFragment(const MCDataFragment &F,
+ const MCAssembler &Assembler,
+ const MCSubtargetInfo *STI) {
+ if (!F.hasInstructions())
+ return true;
// When bundling is enabled, we don't want to add data to a fragment that
// already has instructions (see MCELFStreamer::EmitInstToData for details)
- if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() &&
- F->hasInstructions())) {
+ if (Assembler.isBundlingEnabled())
+ return Assembler.getRelaxAll();
+ // If the subtarget is changed mid fragment we start a new fragment to record
+ // the new STI.
+ return !STI || F.getSubtargetInfo() == STI;
+}
+
+MCDataFragment *
+MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) {
+ MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+ if (!F || !CanReuseDataFragment(*F, *Assembler, STI)) {
F = new MCDataFragment();
insert(F);
}
@@ -137,7 +175,7 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
// 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.");
@@ -199,7 +237,7 @@ void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) {
void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) {
int64_t IntValue;
- if (Value->evaluateAsAbsolute(IntValue, getAssembler())) {
+ if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
EmitULEB128IntValue(IntValue);
return;
}
@@ -208,7 +246,7 @@ void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) {
void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) {
int64_t IntValue;
- if (Value->evaluateAsAbsolute(IntValue, getAssembler())) {
+ if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
EmitSLEB128IntValue(IntValue);
return;
}
@@ -229,13 +267,14 @@ bool MCObjectStreamer::changeSectionImpl(MCSection *Section,
const MCExpr *Subsection) {
assert(Section && "Cannot switch to a null section!");
flushPendingLabels(nullptr);
+ getContext().clearCVLocSeen();
getContext().clearDwarfLocSeen();
bool Created = getAssembler().registerSection(*Section);
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");
@@ -274,7 +313,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst,
// If this instruction doesn't need relaxation, just emit it as data.
MCAssembler &Assembler = getAssembler();
- if (!Assembler.getBackend().mayNeedRelaxation(Inst)) {
+ if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
EmitInstToData(Inst, STI);
return;
}
@@ -288,7 +327,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst,
(Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
MCInst Relaxed;
getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
- while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
+ while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI))
getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
EmitInstToData(Relaxed, STI);
return;
@@ -381,7 +420,7 @@ void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
}
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;
@@ -393,7 +432,7 @@ void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
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;
}
@@ -553,7 +592,8 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) {
}
bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
- const MCExpr *Expr, SMLoc Loc) {
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) {
int64_t OffsetValue;
if (!Offset.evaluateAsAbsolute(OffsetValue))
llvm_unreachable("Offset is not absolute");
@@ -561,7 +601,7 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
if (OffsetValue < 0)
llvm_unreachable("Offset is negative");
- MCDataFragment *DF = getOrCreateDataFragment();
+ MCDataFragment *DF = getOrCreateDataFragment(&STI);
flushPendingLabels(DF, DF->getContents().size());
Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
@@ -577,53 +617,61 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
return false;
}
-void MCObjectStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) {
- assert(getCurrentSectionOnly() && "need a section");
- insert(new MCFillFragment(FillValue, NumBytes));
-}
-
void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc) {
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
- int64_t IntNumBytes;
- if (!NumBytes.evaluateAsAbsolute(IntNumBytes, getAssembler())) {
- getContext().reportError(Loc, "expected absolute expression");
- return;
- }
-
- if (IntNumBytes <= 0) {
- getContext().reportError(Loc, "invalid number of bytes");
- return;
- }
-
- emitFill(IntNumBytes, FillValue);
+ assert(getCurrentSectionOnly() && "need a section");
+ insert(new MCFillFragment(FillValue, 1, NumBytes, Loc));
}
void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
int64_t Expr, SMLoc Loc) {
int64_t IntNumValues;
- if (!NumValues.evaluateAsAbsolute(IntNumValues, getAssembler())) {
- getContext().reportError(Loc, "expected absolute expression");
+ // Do additional checking now if we can resolve the value.
+ if (NumValues.evaluateAsAbsolute(IntNumValues, getAssemblerPtr())) {
+ if (IntNumValues < 0) {
+ getContext().getSourceManager()->PrintMessage(
+ Loc, SourceMgr::DK_Warning,
+ "'.fill' directive with negative repeat count has no effect");
+ return;
+ }
+ // Emit now if we can for better errors.
+ int64_t NonZeroSize = Size > 4 ? 4 : Size;
+ Expr &= ~0ULL >> (64 - NonZeroSize * 8);
+ for (uint64_t i = 0, e = IntNumValues; i != e; ++i) {
+ EmitIntValue(Expr, NonZeroSize);
+ if (NonZeroSize < Size)
+ EmitIntValue(0, Size - NonZeroSize);
+ }
return;
}
- if (IntNumValues < 0) {
- getContext().getSourceManager()->PrintMessage(
- Loc, SourceMgr::DK_Warning,
- "'.fill' directive with negative repeat count has no effect");
- return;
- }
+ // Otherwise emit as fragment.
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
- MCStreamer::emitFill(IntNumValues, Size, Expr);
+ assert(getCurrentSectionOnly() && "need a section");
+ insert(new MCFillFragment(Expr, Size, NumValues, Loc));
}
void MCObjectStreamer::EmitFileDirective(StringRef Filename) {
getAssembler().addFileName(Filename);
}
+void MCObjectStreamer::EmitAddrsig() {
+ getAssembler().getWriter().emitAddrsigSection();
+}
+
+void MCObjectStreamer::EmitAddrsigSym(const MCSymbol *Sym) {
+ getAssembler().registerSymbol(*Sym);
+ getAssembler().getWriter().addAddrsigSymbol(Sym);
+}
+
void MCObjectStreamer::FinishImpl() {
+ getContext().RemapDebugPaths();
+
// If we are generating dwarf for assembly source files dump out the sections.
if (getContext().getGenDwarfForAssembly())
MCGenDwarfInfo::Emit(this);
@@ -631,6 +679,6 @@ void MCObjectStreamer::FinishImpl() {
// Dump out the dwarf file & directory tables and line tables.
MCDwarfLineTable::Emit(this, getAssembler().getDWARFLinetableParams());
- flushPendingLabels(nullptr);
+ flushPendingLabels();
getAssembler().Finish();
}