Index: lib/Target/Mips/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/Mips/MCTargetDesc/CMakeLists.txt +++ lib/Target/Mips/MCTargetDesc/CMakeLists.txt @@ -7,5 +7,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,7 +15,9 @@ #ifndef MIPSELFSTREAMER_H #define MIPSELFSTREAMER_H +#include "MipsOptionRecord.h" #include "llvm/MC/MCELFStreamer.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -28,14 +30,34 @@ } class MipsELFStreamer : public MCELFStreamer { + SmallVector MipsOptionRecords; + MipsRegInfo *RegInfo; const MCSubtargetInfo &STI; public: MipsELFStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, MCCodeEmitter *Emitter, const MCSubtargetInfo &STI) - : MCELFStreamer(Context, MAB, OS, Emitter), STI(STI) {} + : MCELFStreamer(Context, MAB, OS, Emitter), STI(STI) { + RegInfo = new MipsRegInfo(this, Context, STI); + MipsOptionRecords.push_back(RegInfo); + } - virtual ~MipsELFStreamer() {} + virtual ~MipsELFStreamer() { + for (SmallVector::iterator I = + MipsOptionRecords.begin(); + I != MipsOptionRecords.end(); ++I) + delete *I; + } + + /// EmitInstruction - 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; + + /// EmitOptionRecords - Emits all the option records stored up until the + /// point it's called. + void EmitOptionRecords(); }; namespace llvm { Index: lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFStreamer.cpp @@ -8,6 +8,55 @@ //===----------------------------------------------------------------------===// #include "MipsELFStreamer.h" +#include "MipsMCTargetDesc.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/ELF.h" + +namespace llvm { +extern const MCInstrDesc MipsInsts[]; +} + +namespace { +const MCInstrDesc &getInstDesc(unsigned Opcode) { + return MipsInsts[Opcode]; +} +} + +void MipsELFStreamer::EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCELFStreamer::EmitInstruction(Inst, STI); + + MCContext &Context = getContext(); + const MCRegisterInfo *MCRegInfo = Context.getRegisterInfo(); + const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); + + // Capture the register usage for this instruction. + for (unsigned NumOp = 0; NumOp < Inst.getNumOperands(); ++NumOp) { + const MCOperand &Op = Inst.getOperand(NumOp); + + if (!Op.isReg()) + continue; + + int16_t RegClass = Desc.OpInfo[NumOp].RegClass; + unsigned RegClassID = + Context.getRegisterInfo()->getRegClass(RegClass).getID(); + unsigned EncVal = MCRegInfo->getEncodingValue(Op.getReg()); + + RegInfo->SetPhysRegUsed(RegClassID, EncVal); + } +} + +void MipsELFStreamer::EmitOptionRecords() { + for (SmallVector::iterator I = + MipsOptionRecords.begin(); + I != MipsOptionRecords.end(); ++I) + (*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,102 @@ +//===-- 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 "MipsMCTargetDesc.h" +#include "MipsELFStreamer.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +void MipsRegInfo::EmitMipsOptionRecord() { + 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 (MipsRegInfo class) to handle both. + if (Features & Mips::FeatureN64) { + const MCSectionELF *Sec = Context.getELFSection( + ".MIPS.options", ELF::SHT_MIPS_OPTIONS, + ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata()); + 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_value64, 8); + } else { + const MCSectionELF *Sec = + Context.getELFSection(".reginfo", ELF::SHT_MIPS_REGINFO, ELF::SHF_ALLOC, + SectionKind::getMetadata()); + 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); + Streamer->EmitIntValue(ri_gp_value32, 4); + } + + Streamer->PopSection(); +} + +// FIXME: It should be possible to improve this code by using an unallocatable +// register class that contains only the relevant registers. This way we don't +// need to list every register class. +// We can also use MCSubRegIterator so that we don't need to distinguish FR=0 +// from FR=1 mode. +void MipsRegInfo::SetPhysRegUsed(unsigned RegClassID, unsigned EncVal) { + switch (RegClassID) { + default: + // At the moment we don't support other coprocessors other than copro1. + // If we ever support others, we should update this switch statement with + // the new register classes. + break; + case(Mips::GPR32RegClassID) : + case(Mips::GPR64RegClassID) : + ri_gprmask |= (1 << EncVal); + break; + // FPU can be configured in several distinct ways. We have to distinguish + // between operands that represent only one FP register from operands that + // are implicitly two FP registers (one even + one odd). + + // FGR32 - Operand representing a single-precision FP register. + // FGR64 - Operand representing a 64-bit register on an FPU with 64-bit + // wide registers. + // MSA clobbers part of the FP registers. + case(Mips::FGR32RegClassID) : + case(Mips::FGR64RegClassID) : + case(Mips::MSA128BRegClassID) : + case(Mips::MSA128HRegClassID) : + case(Mips::MSA128WRegClassID) : + case(Mips::MSA128DRegClassID) : + ri_cprmask[1] |= (1 << EncVal); + break; + // 64-bit register on an FPU configured with mfp32. Two FP registers + // affected (even + odd). + case(Mips::AFGR64RegClassID) : + ri_cprmask[1] |= (1 << EncVal); + ri_cprmask[1] |= (1 << (EncVal + 1)); + break; + } +} 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" @@ -181,42 +182,12 @@ } void MipsTargetELFStreamer::finish() { - MCAssembler &MCA = getStreamer().getAssembler(); - MCContext &Context = MCA.getContext(); - MCStreamer &OS = getStreamer(); - Triple T(STI.getTargetTriple()); - uint64_t Features = STI.getFeatureBits(); + MipsELFStreamer &MEF = static_cast(Streamer); - if (T.isArch64Bit() && (Features & Mips::FeatureN64)) { - const MCSectionELF *Sec = Context.getELFSection( - ".MIPS.options", ELF::SHT_MIPS_OPTIONS, - ELF::SHF_ALLOC | ELF::SHF_MIPS_NOSTRIP, SectionKind::getMetadata()); - 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()); - 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. + MEF.EmitOptionRecords(); } void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, Index: lib/Target/Mips/MipsOptionRecord.h =================================================================== --- /dev/null +++ lib/Target/Mips/MipsOptionRecord.h @@ -0,0 +1,68 @@ +//===-- 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 "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/DataTypes.h" + +class MipsELFStreamer; + +using namespace llvm; + +namespace llvm { +class MCContext; +class MCELFStreamer; +class MCStreamer; +class MCSubtargetInfo; +} + +class MipsOptionRecord { +public: + virtual ~MipsOptionRecord() {}; + virtual void EmitMipsOptionRecord() = 0; +}; + +class MipsRegInfo : public MipsOptionRecord { +public: + MipsRegInfo(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_value32 = 0; + ri_gp_value64 = 0; + } + ~MipsRegInfo() {} + + void EmitMipsOptionRecord(); + void SetPhysRegUsed(unsigned RegClassID, unsigned EncVal); + +private: + MipsELFStreamer *Streamer; + MCContext &Context; + const MCSubtargetInfo &STI; + uint32_t ri_gprmask; + uint32_t ri_cprmask[4]; + int32_t ri_gp_value32; + int64_t ri_gp_value64; +}; +#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 (12) +# 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 (12) +# 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 (12) +# 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