Index: lib/Target/Mips/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -8,5 +8,6 @@ MipsMCExpr.cpp MipsMCTargetDesc.cpp MipsNaClELFStreamer.cpp + MipsOptionRecord.cpp MipsTargetStreamer.cpp ) Index: lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h +++ lib/Target/Mips/MCTargetDesc/MipsELFStreamer.h @@ -15,8 +15,10 @@ #ifndef MIPSELFSTREAMER_H #define MIPSELFSTREAMER_H +#include "MipsOptionRecord.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCELFStreamer.h" -#include "llvm/Support/raw_ostream.h" +#include namespace llvm { class MCAsmBackend; @@ -25,13 +27,26 @@ class MCSubtargetInfo; class MipsELFStreamer : public MCELFStreamer { + SmallVector, 8> MipsOptionRecords; + MipsRegInfoRecord* RegInfoRecord; public: MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) - : MCELFStreamer(Context, MAB, OS, Emitter) {} + : MCELFStreamer(Context, MAB, OS, Emitter) { - virtual ~MipsELFStreamer() {} + RegInfoRecord = new MipsRegInfoRecord(this, Context, STI); + MipsOptionRecords.push_back(std::unique_ptr(RegInfoRecord)); + } + + /// Overriding this function allows us to add arbitrary behaviour before the + /// \p Inst is actually emitted. For example, we can inspect the operands and + /// gather sufficient information that allows us to reason about the register + /// usage for the translation unit. + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + + /// Emits all the option records stored up until the point it's called. + void EmitMipsOptionRecords(); }; MCELFStreamer *createMipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, Index: lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -8,6 +8,30 @@ //===----------------------------------------------------------------------===// #include "MipsELFStreamer.h" +#include "llvm/MC/MCInst.h" + +void MipsELFStreamer::EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCELFStreamer::EmitInstruction(Inst, STI); + + MCContext &Context = getContext(); + const MCRegisterInfo *MCRegInfo = Context.getRegisterInfo(); + + for (unsigned OpIndex = 0; OpIndex < Inst.getNumOperands(); ++OpIndex) { + const MCOperand &Op = Inst.getOperand(OpIndex); + + if (!Op.isReg()) + continue; + + unsigned Reg = Op.getReg(); + RegInfoRecord->SetPhysRegUsed(Reg, MCRegInfo); + } +} + +void MipsELFStreamer::EmitMipsOptionRecords() { + for (const auto &I : MipsOptionRecords) + I->EmitMipsOptionRecord(); +} namespace llvm { MCELFStreamer *createMipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, Index: lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp =================================================================== --- /dev/null +++ lib/Target/Mips/MCTargetDesc/MipsOptionRecord.cpp @@ -0,0 +1,92 @@ +//===-- MipsOptionRecord.cpp - Abstraction for storing information --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MipsOptionRecord.h" +#include "MipsELFStreamer.h" +#include "llvm/MC/MCSectionELF.h" + +using namespace llvm; + +void MipsRegInfoRecord::EmitMipsOptionRecord() { + MCAssembler &MCA = Streamer->getAssembler(); + Triple T(STI.getTargetTriple()); + uint64_t Features = STI.getFeatureBits(); + + Streamer->PushSection(); + + // We need to distinguish between N64 and the rest because at the moment + // we don't emit .Mips.options for other ELFs other than N64. + // Since .reginfo has the same information as .Mips.options (ODK_REGINFO), + // we can use the same abstraction (MipsRegInfoRecord class) to handle both. + if (Features & Mips::FeatureN64) { + // The EntrySize value of 1 seems strange since the records are neither + // 1-byte long nor fixed length but it matches the value GAS emits. + const MCSectionELF *Sec = + Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, + SectionKind::getMetadata(), 1, ""); + MCA.getOrCreateSectionData(*Sec).setAlignment(8); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(1, 1); // kind + Streamer->EmitIntValue(40, 1); // size + Streamer->EmitIntValue(0, 2); // section + Streamer->EmitIntValue(0, 4); // info + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(0, 4); // pad + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + Streamer->EmitIntValue(ri_gp_value, 8); + } else { + const MCSectionELF *Sec = + Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, + SectionKind::getMetadata(), 24, ""); + MCA.getOrCreateSectionData(*Sec) + .setAlignment(Features & Mips::FeatureN32 ? 8 : 4); + Streamer->SwitchSection(Sec); + + Streamer->EmitIntValue(ri_gprmask, 4); + Streamer->EmitIntValue(ri_cprmask[0], 4); + Streamer->EmitIntValue(ri_cprmask[1], 4); + Streamer->EmitIntValue(ri_cprmask[2], 4); + Streamer->EmitIntValue(ri_cprmask[3], 4); + assert((ri_gp_value & 0xffffffff) == ri_gp_value); + Streamer->EmitIntValue(ri_gp_value, 4); + } + + Streamer->PopSection(); +} + +void MipsRegInfoRecord::SetPhysRegUsed(unsigned Reg, + const MCRegisterInfo *MCRegInfo) { + unsigned Value = 0; + + for (MCSubRegIterator SubRegIt(Reg, MCRegInfo, true); SubRegIt.isValid(); + ++SubRegIt) { + unsigned CurrentSubReg = *SubRegIt; + + unsigned EncVal = MCRegInfo->getEncodingValue(CurrentSubReg); + Value |= 1 << EncVal; + + if (GPR32RegClass->contains(CurrentSubReg) || + GPR64RegClass->contains(CurrentSubReg)) + ri_gprmask |= Value; + else if (FGR32RegClass->contains(CurrentSubReg) || + FGR64RegClass->contains(CurrentSubReg) || + AFGR64RegClass->contains(CurrentSubReg) || + MSA128BRegClass->contains(CurrentSubReg)) + ri_cprmask[1] |= Value; + else if (COP2RegClass->contains(CurrentSubReg)) + ri_cprmask[2] |= Value; + else if (COP3RegClass->contains(CurrentSubReg)) + ri_cprmask[3] |= Value; + } +} Index: lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "InstPrinter/MipsInstPrinter.h" +#include "MipsELFStreamer.h" #include "MipsMCTargetDesc.h" #include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" @@ -323,11 +324,7 @@ void MipsTargetELFStreamer::finish() { MCAssembler &MCA = getStreamer().getAssembler(); - MCContext &Context = MCA.getContext(); - MCStreamer &OS = getStreamer(); - const MCObjectFileInfo &OFI = *Context.getObjectFileInfo(); - Triple T(STI.getTargetTriple()); - uint64_t Features = STI.getFeatureBits(); + const MCObjectFileInfo &OFI = *MCA.getContext().getObjectFileInfo(); // .bss, .text and .data are always at least 16-byte aligned. MCSectionData &TextSectionData = @@ -341,42 +338,12 @@ DataSectionData.setAlignment(std::max(16u, DataSectionData.getAlignment())); BSSSectionData.setAlignment(std::max(16u, BSSSectionData.getAlignment())); - if (T.isArch64Bit() && (Features & Mips::FeatureN64)) { - // The EntrySize value of 1 seems strange since the records are neither - // 1-byte long nor fixed length but it matches the value GAS emits. - const MCSectionELF *Sec = - Context.getELFSection(".MIPS.options", ELF::SHT_MIPS_OPTIONS, - ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, - SectionKind::getMetadata(), 1, ""); - MCA.getOrCreateSectionData(*Sec).setAlignment(8); - OS.SwitchSection(Sec); - - OS.EmitIntValue(1, 1); // kind - OS.EmitIntValue(40, 1); // size - OS.EmitIntValue(0, 2); // section - OS.EmitIntValue(0, 4); // info - OS.EmitIntValue(0, 4); // ri_gprmask - OS.EmitIntValue(0, 4); // pad - OS.EmitIntValue(0, 4); // ri_cpr[0]mask - OS.EmitIntValue(0, 4); // ri_cpr[1]mask - OS.EmitIntValue(0, 4); // ri_cpr[2]mask - OS.EmitIntValue(0, 4); // ri_cpr[3]mask - OS.EmitIntValue(0, 8); // ri_gp_value - } else { - const MCSectionELF *Sec = - Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, - SectionKind::getMetadata(), 24, ""); - MCA.getOrCreateSectionData(*Sec) - .setAlignment(Features & Mips::FeatureN32 ? 8 : 4); - OS.SwitchSection(Sec); - - OS.EmitIntValue(0, 4); // ri_gprmask - OS.EmitIntValue(0, 4); // ri_cpr[0]mask - OS.EmitIntValue(0, 4); // ri_cpr[1]mask - OS.EmitIntValue(0, 4); // ri_cpr[2]mask - OS.EmitIntValue(0, 4); // ri_cpr[3]mask - OS.EmitIntValue(0, 4); // ri_gp_value - } + // Emit all the option records. + // At the moment we are only emitting .Mips.options (ODK_REGINFO) and + // .reginfo. + MipsELFStreamer &MEF = static_cast(Streamer); + MEF.EmitMipsOptionRecords(); + emitMipsAbiFlags(); } Index: lib/Target/Mips/MipsOptionRecord.h =================================================================== --- /dev/null +++ lib/Target/Mips/MipsOptionRecord.h @@ -0,0 +1,80 @@ +//===-- MipsOptionRecord.h - Abstraction for storing information ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// MipsOptionRecord - Abstraction for storing arbitrary information in +// ELF files. Arbitrary information (e.g. register usage) can be stored in Mips +// specific ELF sections like .Mips.options. Specific records should subclass +// MipsOptionRecord and provide an implementation to EmitMipsOptionRecord which +// basically just dumps the information into an ELF section. More information +// about .Mips.option can be found in the SysV ABI and the 64-bit ELF Object +// specification. +// +//===----------------------------------------------------------------------===// + +#ifndef MIPSOPTIONRECORD_H +#define MIPSOPTIONRECORD_H + +#include "MipsMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCRegisterInfo.h" + +using namespace llvm; + +namespace llvm { +class MipsELFStreamer; +class MCSubtargetInfo; +} + +class MipsOptionRecord { +public: + virtual ~MipsOptionRecord() {}; + virtual void EmitMipsOptionRecord() = 0; +}; + +class MipsRegInfoRecord : public MipsOptionRecord { +public: + MipsRegInfoRecord(MipsELFStreamer *S, MCContext &Context, + const MCSubtargetInfo &STI) + : Streamer(S), Context(Context), STI(STI) { + ri_gprmask = 0; + ri_cprmask[0] = ri_cprmask[1] = ri_cprmask[2] = ri_cprmask[3] = 0; + ri_gp_value = 0; + + const MCRegisterInfo *TRI = Context.getRegisterInfo(); + GPR32RegClass = &(TRI->getRegClass(Mips::GPR32RegClassID)); + GPR64RegClass = &(TRI->getRegClass(Mips::GPR64RegClassID)); + FGR32RegClass = &(TRI->getRegClass(Mips::FGR32RegClassID)); + FGR64RegClass = &(TRI->getRegClass(Mips::FGR64RegClassID)); + AFGR64RegClass = &(TRI->getRegClass(Mips::AFGR64RegClassID)); + MSA128BRegClass = &(TRI->getRegClass(Mips::MSA128BRegClassID)); + COP2RegClass = &(TRI->getRegClass(Mips::COP2RegClassID)); + COP3RegClass = &(TRI->getRegClass(Mips::COP3RegClassID)); + } + ~MipsRegInfoRecord() {} + + void EmitMipsOptionRecord(); + void SetPhysRegUsed(unsigned Reg, const MCRegisterInfo *MCRegInfo); + +private: + MipsELFStreamer *Streamer; + MCContext &Context; + const MCSubtargetInfo &STI; + const MCRegisterClass *GPR32RegClass; + const MCRegisterClass *GPR64RegClass; + const MCRegisterClass *FGR32RegClass; + const MCRegisterClass *FGR64RegClass; + const MCRegisterClass *AFGR64RegClass; + const MCRegisterClass *MSA128BRegClass; + const MCRegisterClass *COP2RegClass; + const MCRegisterClass *COP3RegClass; + uint32_t ri_gprmask; + uint32_t ri_cprmask[4]; + int64_t ri_gp_value; +}; +#endif Index: test/MC/Mips/mips-reginfo-fp32.s =================================================================== --- /dev/null +++ test/MC/Mips/mips-reginfo-fp32.s @@ -0,0 +1,34 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -filetype=obj -o - | \ +# RUN: llvm-readobj -s -section-data | \ +# RUN: FileCheck %s + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .reginfo +# CHECK: Type: SHT_MIPS_REGINFO (0x70000006) +# CHECK: Flags [ (0x2) +# CHECK: SHF_ALLOC (0x2) +# CHECK: ] +# CHECK: Size: 24 +# CHECK: SectionData ( +# CHECK: 0000: 01010101 00000000 C0007535 00000000 +# CHECK: 0010: 00000000 00000000 +# CHECK: ) +# CHECK: } + +.text + add $0,$0,$0 + add $8,$0,$0 + add $16,$0,$0 + add $24,$0,$0 + +# abs.s - Reads and writes from/to $f0. + abs.s $f0,$f0 +# round.w.d - Reads $f4 and $f5 and writes to $f2. + round.w.d $f2,$f4 +# ceil.w.s - Reads $f8 and writes to $f10. + ceil.w.s $f10, $f8 +# cvt.s.d - Reads from $f12 and $f13 and writes to $f14 + cvt.s.d $f14, $f12 +# abs.d - Reads from $f30 and $f31 and writes to $f30 and $f31. + abs.d $f30,$f30 Index: test/MC/Mips/mips-reginfo-fp64.s =================================================================== --- /dev/null +++ test/MC/Mips/mips-reginfo-fp64.s @@ -0,0 +1,60 @@ +# RUN: llvm-mc %s -arch=mips -mcpu=mips32r2 -mattr=+msa,+fp64 -filetype=obj -o - | \ +# RUN: llvm-readobj -s -section-data | \ +# RUN: FileCheck %s -check-prefix=ELF32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64r2 -mattr=+msa,+fp64,-n64,+n32 -filetype=obj -o - | \ +# RUN: llvm-readobj -s -section-data | \ +# RUN: FileCheck %s -check-prefix=ELF32 + +# RUN: llvm-mc %s -arch=mips64 -mcpu=mips64r2 -mattr=+msa,+fp64,+n64 -filetype=obj -o - | \ +# RUN: llvm-readobj -s -section-data | \ +# RUN: FileCheck %s -check-prefix=ELF64 + +# ELF32: Section { +# ELF32: Name: .reginfo +# ELF32: Type: SHT_MIPS_REGINFO (0x70000006) +# ELF32: Flags [ (0x2) +# ELF32: SHF_ALLOC (0x2) +# ELF32: ] +# ELF32: Size: 24 +# ELF32: SectionData ( +# ELF32: 0000: 01010101 00000000 4C005515 00000000 +# ELF32: 0010: 00000000 00000000 +# ELF32: ) +# ELF32: } + +# ELF64: Section { +# ELF64: Name: .MIPS.options +# ELF64: Type: SHT_MIPS_OPTIONS (0x7000000D) +# ELF64: Flags [ (0x8000002) +# ELF64: SHF_ALLOC (0x2) +# ELF64: SHF_MIPS_NOSTRIP (0x8000000) +# ELF64: ] +# ELF64: Size: 40 +# ELF64: SectionData ( +# ELF64: 0000: 01280000 00000000 01010101 00000000 +# ELF64: 0010: 00000000 4C005515 00000000 00000000 +# ELF64: 0020: 00000000 00000000 +# ELF64: ) +# ELF64: } + +.text + add $0,$0,$0 + add $8,$0,$0 + add $16,$0,$0 + add $24,$0,$0 + +# abs.s - Reads and writes from/to $f0. + abs.s $f0,$f0 +# round.w.d - Reads $f4 and writes to $f2. + round.w.d $f2,$f4 +# ceil.w.s - Reads $f8 and writes to $f10. + ceil.w.s $f10, $f8 +# cvt.s.d - Reads from $f12 and writes to $f14. + cvt.s.d $f14, $f12 +# abs.d - Reads from $f30 and writes to $f30. + abs.d $f30,$f30 + +# Read and write from/to $f26 and $f27 + add_a.b $w26,$w26,$w26 + add_a.b $w27,$w27,$w27 Index: test/MC/Mips/mips64/abiflags.s =================================================================== --- test/MC/Mips/mips64/abiflags.s +++ test/MC/Mips/mips64/abiflags.s @@ -10,7 +10,7 @@ # Checking if the Mips.abiflags were correctly emitted. # CHECK-OBJ: Section { # CHECK-OBJ: Index: 5 -# CHECK-OBJ-LABEL: Name: .MIPS.abiflags (12) +# CHECK-OBJ-LABEL: Name: .MIPS.abiflags # CHECK-OBJ: Type: SHT_MIPS_ABIFLAGS (0x7000002A) # CHECK-OBJ: Flags [ (0x2) # CHECK-OBJ: SHF_ALLOC (0x2) Index: test/MC/Mips/mips64r2/abiflags.s =================================================================== --- test/MC/Mips/mips64r2/abiflags.s +++ test/MC/Mips/mips64r2/abiflags.s @@ -10,7 +10,7 @@ # Checking if the Mips.abiflags were correctly emitted. # CHECK-OBJ: Section { # CHECK-OBJ: Index: 5 -# CHECK-OBJ-LABEL: Name: .MIPS.abiflags (12) +# CHECK-OBJ-LABEL: Name: .MIPS.abiflags # CHECK-OBJ: Type: SHT_MIPS_ABIFLAGS (0x7000002A) # CHECK-OBJ: Flags [ (0x2) # CHECK-OBJ: SHF_ALLOC (0x2)