Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -17,6 +17,7 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/Support/DataTypes.h" +#include using namespace llvm; @@ -34,12 +35,26 @@ namespace { +// Struct used to store the register usage for a translation unit. +// In theory Operating Systems can inspect the .reginfo section or +// .Mips.Options to decide what registers need to be saved or which +// coprocessors the program uses. +struct MipsRegInfo { + uint32_t ri_gprmask; + uint32_t ri_cprmask[4]; + union { + int32_t ri_gp_value_32; // ELF32 (ARCH=Mips32 or ABI=n32) + int64_t ri_gp_value_64; // ELF64 (ARCH=Mips64 and ABI=n64) + }; +}; + class MipsMCCodeEmitter : public MCCodeEmitter { MipsMCCodeEmitter(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; void operator=(const MipsMCCodeEmitter &) LLVM_DELETED_FUNCTION; const MCInstrInfo &MCII; MCContext &Ctx; bool IsLittleEndian; + mutable MipsRegInfo RegInfo; bool isMicroMips(const MCSubtargetInfo &STI) const; @@ -124,6 +139,33 @@ getExprOpValue(const MCExpr *Expr,SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + // Returns mask of General Purpose Registers used by the TU (one bit for each + // register; register 31 being the most significant bit). This should only be + // called after all instructions are encoded otherwise this information will + // probably be incomplete. + uint32_t getRI_gprmask() { return RegInfo.ri_gprmask; }; + + // Returns mask of Coprocessor Registers used by the TU (one bit for each + // register; register 31 being the most significant bit). This should only be + // called after all instructions are encoded otherwise this information will + // probably be incomplete. + uint32_t getRI_cprmask(int CoPro) { + if (CoPro < 0 || CoPro > 3) { + assert (0 && "Invalid CoPro"); + return (uint32_t)-1; + } + + return RegInfo.ri_cprmask[CoPro]; + }; + + // Returns the value of $gp. It is set to 0 at this stage and the static + // linker is responsible to compute its final value. + int32_t getRI_gpValue32() { return RegInfo.ri_gp_value_32; }; + + // Returns the value of $gp. It is set to 0 at this stage and the static + // linker is responsible to compute its final value. + int64_t getRI_gpValue64() { return RegInfo.ri_gp_value_64; }; + }; // class MipsMCCodeEmitter } // namespace Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -26,6 +26,11 @@ #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/raw_ostream.h" +#include + +#define GET_REGINFO_ENUM +#include "MipsGenRegisterInfo.inc" +#undef GET_REGINFO_ENUM #define GET_INSTRMAP_INFO #define GET_INSTRINFO_ENUM @@ -203,6 +208,54 @@ if (!Size) llvm_unreachable("Desc.getSize() returns 0"); + const MCRegisterInfo *MCRegInfo = Ctx.getRegisterInfo(); + + // Capture the register usage for this instruction and update RegInfo. + for (unsigned NumOp = 0; NumOp < TmpInst.getNumOperands(); ++NumOp) { + MCOperand &Op = TmpInst.getOperand(NumOp); + + if (!Op.isReg()) + continue; + + int16_t RegClass = Desc.OpInfo[NumOp].RegClass; + unsigned RegClassID = Ctx.getRegisterInfo()->getRegClass(RegClass).getID(); + unsigned EncVal = MCRegInfo->getEncodingValue(Op.getReg()); + + 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): + RegInfo.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 registers clobber part of the FP registers. + case (Mips::FGR32RegClassID): + case (Mips::FGR64RegClassID): + case (Mips::MSA128BRegClassID): + case (Mips::MSA128HRegClassID): + case (Mips::MSA128WRegClassID): + case (Mips::MSA128DRegClassID): + RegInfo.ri_cprmask[1] |= (1 << EncVal); + break; + // 64-bit register on an FPU configured with mfp32. Two FP register + // affected (even + odd). + case (Mips::AFGR64RegClassID): + RegInfo.ri_cprmask[1] |= (1 << EncVal); + RegInfo.ri_cprmask[1] |= (1 << (EncVal + 1)); + break; + } + } + EmitInstruction(Binary, Size, STI, OS); } 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 "MipsMCCodeEmitter.h" #include "MipsMCTargetDesc.h" #include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" @@ -186,6 +187,8 @@ MCStreamer &OS = getStreamer(); Triple T(STI.getTargetTriple()); uint64_t Features = STI.getFeatureBits(); + MCCodeEmitter &Emitter = MCA.getEmitter(); + MipsMCCodeEmitter &MipsMCE = static_cast(Emitter); if (T.isArch64Bit() && (Features & Mips::FeatureN64)) { const MCSectionELF *Sec = Context.getELFSection( @@ -197,25 +200,25 @@ OS.EmitIntValue(40, 1); // size OS.EmitIntValue(0, 2); // section OS.EmitIntValue(0, 4); // info - OS.EmitIntValue(0, 4); // ri_gprmask + OS.EmitIntValue(MipsMCE.getRI_gprmask(), 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 + OS.EmitIntValue(MipsMCE.getRI_cprmask(0), 4); // ri_cpr[0]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(1), 4); // ri_cpr[1]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(2), 4); // ri_cpr[2]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(3), 4); // ri_cpr[3]mask + OS.EmitIntValue(MipsMCE.getRI_gpValue64(), 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 + OS.EmitIntValue(MipsMCE.getRI_gprmask(), 4); // ri_gprmask + OS.EmitIntValue(MipsMCE.getRI_cprmask(0), 4); // ri_cpr[0]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(1), 4); // ri_cpr[1]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(2), 4); // ri_cpr[2]mask + OS.EmitIntValue(MipsMCE.getRI_cprmask(3), 4); // ri_cpr[3]mask + OS.EmitIntValue(MipsMCE.getRI_gpValue32(), 4); // ri_gp_value } } 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