diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 5cded5cfff9..df896a6c683 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -346,8 +346,8 @@ public: /// @p Section. This is required to update CurSection. /// /// This corresponds to assembler directives like .section, .text, etc. - void SwitchSection(const MCSection *Section, - const MCExpr *Subsection = nullptr) { + virtual void SwitchSection(const MCSection *Section, + const MCExpr *Subsection = nullptr) { assert(Section && "Cannot switch to a null section!"); MCSectionSubPair curSection = SectionStack.back().first; SectionStack.back().second = curSection; diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp index 31c69455898..18c4a206059 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -8,7 +8,11 @@ //===----------------------------------------------------------------------===// #include "MipsELFStreamer.h" +#include "MipsTargetStreamer.h" +#include "llvm/MC/MCELF.h" #include "llvm/MC/MCInst.h" +#include "llvm/Support/ELF.h" + using namespace llvm; void MipsELFStreamer::EmitInstruction(const MCInst &Inst, @@ -17,6 +21,8 @@ void MipsELFStreamer::EmitInstruction(const MCInst &Inst, MCContext &Context = getContext(); const MCRegisterInfo *MCRegInfo = Context.getRegisterInfo(); + MipsTargetELFStreamer *ELFTargetStreamer = + static_cast(getTargetStreamer()); for (unsigned OpIndex = 0; OpIndex < Inst.getNumOperands(); ++OpIndex) { const MCOperand &Op = Inst.getOperand(OpIndex); @@ -27,6 +33,35 @@ void MipsELFStreamer::EmitInstruction(const MCInst &Inst, unsigned Reg = Op.getReg(); RegInfoRecord->SetPhysRegUsed(Reg, MCRegInfo); } + + if (ELFTargetStreamer->isMicroMipsEnabled()) { + for (auto Label : Labels) { + MCSymbolData &Data = getOrCreateSymbolData(Label); + // The "other" values are stored in the last 6 bits of the second byte. + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + MCELF::setOther(Data, ELF::STO_MIPS_MICROMIPS >> 2); + } + } + + Labels.clear(); +} + +void MipsELFStreamer::EmitLabel(MCSymbol *Symbol) { + MCELFStreamer::EmitLabel(Symbol); + Labels.push_back(Symbol); +} + +void MipsELFStreamer::SwitchSection(const MCSection * Section, + const MCExpr *Subsection) { + MCELFStreamer::SwitchSection(Section, Subsection); + Labels.clear(); +} + +void MipsELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + const SMLoc &Loc) { + MCELFStreamer::EmitValueImpl(Value, Size, Loc); + Labels.clear(); } void MipsELFStreamer::EmitMipsOptionRecords() { diff --git a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h index 0bc59eae32e..136146b9474 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h +++ b/lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h @@ -29,6 +29,8 @@ class MCSubtargetInfo; class MipsELFStreamer : public MCELFStreamer { SmallVector, 8> MipsOptionRecords; MipsRegInfoRecord *RegInfoRecord; + SmallVector Labels; + public: MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, @@ -46,6 +48,21 @@ public: /// usage for the translation unit. void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + /// Overriding this function allows us to record all labels that should be + /// marked as microMIPS. Based on this data marking is done in + /// EmitInstruction. + void EmitLabel(MCSymbol *Symbol) override; + + /// Overriding this function allows us to dismiss all labels that are + /// candidates for marking as microMIPS when .section directive is processed. + void SwitchSection(const MCSection *Section, + const MCExpr *Subsection = nullptr) override; + + /// Overriding this function allows us to dismiss all labels that are + /// candidates for marking as microMIPS when .word directive is emitted. + void EmitValueImpl(const MCExpr *Value, unsigned Size, + const SMLoc &Loc) override; + /// Emits all the option records stored up until the point it's called. void EmitMipsOptionRecords(); }; diff --git a/test/MC/Mips/micromips-label-test-sections.s b/test/MC/Mips/micromips-label-test-sections.s new file mode 100644 index 00000000000..569b64c6f98 --- /dev/null +++ b/test/MC/Mips/micromips-label-test-sections.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 \ +# RUN: -mattr=+micromips -filetype=obj -o - | llvm-readobj -t | FileCheck %s + .text + .set micromips +f: + nop +g: + .section .text +h: + nop + +# CHECK: Symbols [ +# CHECK: Symbol { +# CHECK: Name: f +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 128 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: g +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 0 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: h +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 128 +# CHECK: Section: .text +# CHECK: } +# CHECK: ] + diff --git a/test/MC/Mips/micromips-label-test.s b/test/MC/Mips/micromips-label-test.s new file mode 100644 index 00000000000..cc1566b9e67 --- /dev/null +++ b/test/MC/Mips/micromips-label-test.s @@ -0,0 +1,54 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32r2 \ +# RUN: -mattr=+micromips -filetype=obj -o - | llvm-readobj -t | FileCheck %s + .text + .set nomicromips +f: + nop +g: + .set micromips + nop +h: + .word 0 +i: + nop +j: + .set nomicromips + nop +# CHECK: Symbols [ +# CHECK: Symbol { +# CHECK: Name: f +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 0 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: g +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 128 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: h +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 0 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: i +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 128 +# CHECK: Section: .text +# CHECK: } +# CHECK: Symbol { +# CHECK: Name: j +# CHECK: Binding: Local +# CHECK: Type: None +# CHECK: Other: 0 +# CHECK: Section: .text +# CHECK: } +# CHECK: ] +