Index: include/llvm/MC/MCExpr.h =================================================================== --- include/llvm/MC/MCExpr.h +++ include/llvm/MC/MCExpr.h @@ -257,6 +257,7 @@ VK_Mips_GOT, VK_Mips_ABS_HI, VK_Mips_ABS_LO, + VK_Mips_LITERAL, VK_Mips_TLSGD, VK_Mips_TLSLDM, VK_Mips_DTPREL_HI, Index: lib/MC/MCExpr.cpp =================================================================== --- lib/MC/MCExpr.cpp +++ lib/MC/MCExpr.cpp @@ -269,6 +269,7 @@ case VK_Mips_GOT: return "GOT"; case VK_Mips_ABS_HI: return "ABS_HI"; case VK_Mips_ABS_LO: return "ABS_LO"; + case VK_Mips_LITERAL: return "LITERAL"; case VK_Mips_TLSGD: return "TLSGD"; case VK_Mips_TLSLDM: return "TLSLDM"; case VK_Mips_DTPREL_HI: return "DTPREL_HI"; Index: lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/MipsABIInfo.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" @@ -22,6 +23,7 @@ #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" @@ -156,6 +158,9 @@ SMLoc S); OperandMatchResultTy parseAnyRegister(OperandVector &Operands); OperandMatchResultTy parseImm(OperandVector &Operands); + OperandMatchResultTy parseFPImm(OperandVector &Operands, bool isDouble); + OperandMatchResultTy parseFPImmSingle(OperandVector &Operands); + OperandMatchResultTy parseFPImmDouble(OperandVector &Operands); OperandMatchResultTy parseJumpTarget(OperandVector &Operands); OperandMatchResultTy parseInvNum(OperandVector &Operands); OperandMatchResultTy parseLSAImm(OperandVector &Operands); @@ -225,6 +230,15 @@ bool expandUlw(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions); + bool expandLoadImmSingleGPR(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + bool expandLoadImmSingleFGR(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + bool expandLoadImmDoubleGPR(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + bool expandLoadImmDoubleFGR(MCInst &Inst, SMLoc IDLoc, + SmallVectorImpl &Instructions); + void createNop(bool hasShortDelaySlot, SMLoc IDLoc, SmallVectorImpl &Instructions); @@ -541,7 +555,7 @@ RegKind_COP3 = 512, /// COP3 RegKind_COP0 = 1024, /// COP0 /// Potentially any (e.g. $1) - RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | + RegKind_Numeric = RegKind_GPR | RegKind_FCC | RegKind_MSA128 | RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | RegKind_CCR | RegKind_HWRegs | RegKind_COP3 | RegKind_COP0 }; @@ -549,6 +563,8 @@ private: enum KindTy { k_Immediate, /// An immediate (possibly involving symbol references) + k_FPImmSingle, + k_FPImmDouble, k_Memory, /// Base + Offset Memory Address k_PhysRegister, /// A physical register from the Mips namespace k_RegisterIndex, /// A register index in one or more RegKind. @@ -584,6 +600,10 @@ const MCExpr *Val; }; + struct FPImmOp { + int64_t Val; + }; + struct MemOp { MipsOperand *Base; const MCExpr *Off; @@ -598,6 +618,7 @@ struct PhysRegOp PhysReg; struct RegIdxOp RegIdx; struct ImmOp Imm; + struct FPImmOp FPImm; struct MemOp Mem; struct RegListOp RegList; }; @@ -900,6 +921,16 @@ addExpr(Inst, Expr); } + void addFPImmSingleOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getFPImmSingle())); + } + + void addFPImmDoubleOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(getFPImmDouble())); + } + void addMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); @@ -950,6 +981,8 @@ } bool isRegIdx() const { return Kind == k_RegisterIndex; } bool isImm() const override { return Kind == k_Immediate; } + bool isFPImmSingle() const { return Kind == k_FPImmSingle; } + bool isFPImmDouble() const { return Kind == k_FPImmDouble; } bool isConstantImm() const { return isImm() && dyn_cast(getImm()); } @@ -1057,6 +1090,16 @@ return Imm.Val; } + int64_t getFPImmSingle() const { + assert((Kind == k_FPImmSingle) && "Invalid access!"); + return FPImm.Val; + } + + int64_t getFPImmDouble() const { + assert((Kind == k_FPImmDouble) && "Invalid access!"); + return FPImm.Val; + } + int64_t getConstantImm() const { const MCExpr *Val = getImm(); return static_cast(Val)->getValue(); @@ -1171,6 +1214,24 @@ } static std::unique_ptr + CreateFPImmSingle(int64_t Val, SMLoc S, MipsAsmParser &Parser) { + auto Op = make_unique(k_FPImmSingle, Parser); + Op->FPImm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr + CreateFPImmDouble(int64_t Val, SMLoc S, MipsAsmParser &Parser) { + auto Op = make_unique(k_FPImmDouble, Parser); + Op->FPImm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr CreateMem(std::unique_ptr Base, const MCExpr *Off, SMLoc S, SMLoc E, MipsAsmParser &Parser) { auto Op = make_unique(k_Memory, Parser); @@ -1269,6 +1330,10 @@ switch (Kind) { case k_Immediate: break; + case k_FPImmSingle: + break; + case k_FPImmDouble: + break; case k_Memory: delete Mem.Base; break; @@ -1289,6 +1354,14 @@ OS << *Imm.Val; OS << ">"; break; + case k_FPImmSingle: + OS << ""; + break; + case k_FPImmDouble: + OS << ""; + break; case k_Memory: OS << "Mem<"; Mem.Base->print(OS); @@ -1952,6 +2025,18 @@ Instructions) ? MER_Fail : MER_Success; + case Mips::LoadImmSingleGPR: + return expandLoadImmSingleGPR(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::LoadImmSingleFGR: + return expandLoadImmSingleFGR(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::LoadImmDoubleGPR: + return expandLoadImmDoubleGPR(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; + case Mips::LoadImmDoubleFGR: + return expandLoadImmDoubleFGR(Inst, IDLoc, Instructions) ? MER_Fail + : MER_Success; case Mips::B_MM_Pseudo: case Mips::B_MMR6_Pseudo: return expandUncondBranchMMPseudo(Inst, IDLoc, Instructions) ? MER_Fail @@ -3189,6 +3274,193 @@ return true; } +bool MipsAsmParser::expandLoadImmSingleGPR( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { + assert(Inst.getNumOperands() == 2 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isImm() && + "Invalid instruction operand."); + + unsigned FirstReg = Inst.getOperand(0).getReg(); + int64_t ImmValue = Inst.getOperand(1).getImm(); + + if (loadImmediate(ImmValue, FirstReg, Mips::NoRegister, true, false, IDLoc, + Instructions)) + return true; + + return false; +} + +bool MipsAsmParser::expandLoadImmSingleFGR( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { + assert(Inst.getNumOperands() == 2 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isImm() && + "Invalid instruction operand."); + + unsigned FirstReg = Inst.getOperand(0).getReg(); + int64_t ImmValue = Inst.getOperand(1).getImm(); + + MCInst tmpInst; + tmpInst.setLoc(IDLoc); + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + MCSection *Lit4Section = getContext().getELFSection( + ".lit4", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_MIPS_GPREL); + getStreamer().SwitchSection(Lit4Section); + getStreamer().EmitIntValue(ImmValue, 4); + getStreamer().SwitchSection(CS); + + MCSymbolELF *Sym = getContext().getOrCreateSectionSymbol( + *(dyn_cast(Lit4Section))); + + const MCSymbolRefExpr *LitExpr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_Mips_LITERAL, getContext()); + + int32_t size_data_fragment = 0; + MCSection::FragmentListType &FragList = Lit4Section->getFragmentList(); + if (!FragList.empty()) { + MCDataFragment *DF = + &cast(Lit4Section->getFragmentList().back()); + size_data_fragment = DF->getContents().size(); + } + + const MCExpr *FixupAddr = MCBinaryExpr::createAdd( + LitExpr, MCConstantExpr::create(size_data_fragment - 4, getContext()), + getContext()); + + tmpInst.setOpcode(Mips::LWC1); + tmpInst.addOperand(MCOperand::createReg(FirstReg)); + tmpInst.addOperand(MCOperand::createReg(Mips::GP)); + tmpInst.addOperand(MCOperand::createExpr(FixupAddr)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + + return false; +} + +bool MipsAsmParser::expandLoadImmDoubleGPR( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { + assert(Inst.getNumOperands() == 2 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isImm() && + "Invalid instruction operand."); + + unsigned FirstOp = Inst.getOperand(0).getReg(); + int64_t ImmOp = Inst.getOperand(1).getImm(); + + int64_t LoOffset = ImmOp & 0xffffffff; + int64_t HiOffset = (ImmOp & 0xffffffff00000000) >> 32; + + unsigned ATReg = getATReg(IDLoc); + if (!ATReg) + return true; + + MCInst tmpInst; + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + MCSection *ReadOnlySection = + getContext().getELFSection(".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + getStreamer().SwitchSection(ReadOnlySection); + getStreamer().EmitIntValue(HiOffset, 4); + getStreamer().EmitIntValue(LoOffset, 4); + getStreamer().SwitchSection(CS); + + int32_t size_data_fragment = 0; + MCSection::FragmentListType &FragList = ReadOnlySection->getFragmentList(); + if (!FragList.empty()) { + MCDataFragment *DF = + &cast(ReadOnlySection->getFragmentList().back()); + size_data_fragment = DF->getContents().size(); + } + + MCSymbolELF *Sym = getContext().getOrCreateSectionSymbol( + *(dyn_cast(ReadOnlySection))); + + const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_Mips_ABS_HI, getContext()); + const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_Mips_ABS_LO, getContext()); + + tmpInst.setOpcode(Mips::LUi); + tmpInst.addOperand(MCOperand::createReg(ATReg)); + tmpInst.addOperand(MCOperand::createExpr(HiExpr)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + + const MCExpr *FixupAddr = MCBinaryExpr::createAdd( + LoExpr, MCConstantExpr::create(size_data_fragment - 8, getContext()), + getContext()); + + tmpInst.setOpcode(Mips::LW); + tmpInst.addOperand(MCOperand::createReg(FirstOp)); + tmpInst.addOperand(MCOperand::createReg(ATReg)); + tmpInst.addOperand(MCOperand::createExpr(FixupAddr)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + + FixupAddr = MCBinaryExpr::createAdd( + LoExpr, MCConstantExpr::create(size_data_fragment - 4, getContext()), + getContext()); + + tmpInst.setOpcode(Mips::LW); + tmpInst.addOperand(MCOperand::createReg(FirstOp + 1)); + tmpInst.addOperand(MCOperand::createReg(ATReg)); + tmpInst.addOperand(MCOperand::createExpr(FixupAddr)); + Instructions.push_back(tmpInst); + tmpInst.clear(); + + return false; +} + +bool MipsAsmParser::expandLoadImmDoubleFGR( + MCInst &Inst, SMLoc IDLoc, SmallVectorImpl &Instructions) { + assert(Inst.getNumOperands() == 2 && "Invalid operand count"); + assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isImm() && + "Invalid instruction operand."); + + const MCOperand FirstRegOp = Inst.getOperand(0); + int64_t ImmOp = Inst.getOperand(1).getImm(); + + int64_t LoOffset = ImmOp & 0xffffffff; + int64_t HiOffset = (ImmOp & 0xffffffff00000000) >> 32; + + MCSection *CS = getStreamer().getCurrentSectionOnly(); + MCSection *Lit8Section = getContext().getELFSection( + ".lit8", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_MIPS_GPREL); + + getStreamer().SwitchSection(Lit8Section); + getStreamer().EmitIntValue(HiOffset, 4); + getStreamer().EmitIntValue(LoOffset, 4); + getStreamer().SwitchSection(CS); + + int32_t size_data_fragment = 0; + MCSection::FragmentListType &FragList = Lit8Section->getFragmentList(); + if (!FragList.empty()) { + MCDataFragment *DF = + &cast(Lit8Section->getFragmentList().back()); + size_data_fragment = DF->getContents().size(); + } + + MCSymbolELF *Sym = getContext().getOrCreateSectionSymbol( + *(dyn_cast(Lit8Section))); + + const MCSymbolRefExpr *LitExpr = MCSymbolRefExpr::create( + Sym, MCSymbolRefExpr::VK_Mips_LITERAL, getContext()); + const MCExpr *FixupAddr = MCBinaryExpr::createAdd( + LitExpr, MCConstantExpr::create(size_data_fragment - 8, getContext()), + getContext()); + + MCInst tmpInst; + tmpInst.setLoc(IDLoc); + tmpInst.setOpcode(Mips::LDC1); + tmpInst.addOperand(FirstRegOp); + tmpInst.addOperand(MCOperand::createReg(Mips::GP)); + tmpInst.addOperand(MCOperand::createExpr(FixupAddr)); + Instructions.push_back(tmpInst); + + return false; +} + void MipsAsmParser::createNop(bool hasShortDelaySlot, SMLoc IDLoc, SmallVectorImpl &Instructions) { if (hasShortDelaySlot) @@ -3998,6 +4270,49 @@ } MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFPImm(OperandVector &Operands, bool isDouble) { + MCAsmParser &Parser = getParser(); + bool isNegative = false; + if (Parser.getTok().is(AsmToken::Minus)) { + isNegative = true; + Parser.Lex(); // Eat the token. + } + + if (Parser.getTok().is(AsmToken::Real)) { + if (isDouble) { + APFloat RealVal(APFloat::IEEEdouble, Parser.getTok().getString()); + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); + IntVal ^= (uint64_t)isNegative << 63; + Parser.Lex(); // Eat the token. + Operands.push_back(MipsOperand::CreateFPImmDouble( + IntVal, Parser.getTok().getLoc(), *this)); + } else { + APFloat RealVal(APFloat::IEEEsingle, Parser.getTok().getString()); + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); + IntVal ^= (uint64_t)isNegative << 31; + Parser.Lex(); // Eat the token. + Operands.push_back(MipsOperand::CreateFPImmSingle( + IntVal, Parser.getTok().getLoc(), *this)); + } + + return MatchOperand_Success; + } + Error(Parser.getTok().getLoc(), "invalid floating point immediate"); + return MatchOperand_ParseFail; +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFPImmDouble(OperandVector &Operands) { + return parseFPImm(Operands, true); +} + +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseFPImmSingle(OperandVector &Operands) { + return parseFPImm(Operands, false); +} + + +MipsAsmParser::OperandMatchResultTy MipsAsmParser::parseJumpTarget(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseJumpTarget\n"); @@ -4243,6 +4558,7 @@ .Case("highest", MCSymbolRefExpr::VK_Mips_HIGHEST) .Case("pcrel_hi", MCSymbolRefExpr::VK_Mips_PCREL_HI16) .Case("pcrel_lo", MCSymbolRefExpr::VK_Mips_PCREL_LO16) + .Case("literal", MCSymbolRefExpr::VK_Mips_LITERAL) .Default(MCSymbolRefExpr::VK_None); assert(VK != MCSymbolRefExpr::VK_None); Index: lib/Target/Mips/InstPrinter/MipsInstPrinter.h =================================================================== --- lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -97,6 +97,7 @@ void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printUnsignedImm(const MCInst *MI, int opNum, raw_ostream &O); void printUnsignedImm8(const MCInst *MI, int opNum, raw_ostream &O); + void printFPImmOperand(const MCInst *MI, int opNum, raw_ostream &O); void printMemOperand(const MCInst *MI, int opNum, raw_ostream &O); void printMemOperandEA(const MCInst *MI, int opNum, raw_ostream &O); void printFCCOperand(const MCInst *MI, int opNum, raw_ostream &O); Index: lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp =================================================================== --- lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsMCExpr.h" #include "MipsInstrInfo.h" #include "llvm/ADT/StringExtras.h" @@ -169,6 +170,7 @@ case MCSymbolRefExpr::VK_Mips_CALL_LO16: OS << "%call_lo("; break; case MCSymbolRefExpr::VK_Mips_PCREL_HI16: OS << "%pcrel_hi("; break; case MCSymbolRefExpr::VK_Mips_PCREL_LO16: OS << "%pcrel_lo("; break; + case MCSymbolRefExpr::VK_Mips_LITERAL: OS << "%literal("; break; } SRE->getSymbol().print(OS, MAI); @@ -221,6 +223,13 @@ printOperand(MI, opNum, O); } +void MipsInstPrinter::printFPImmOperand(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + O << markup(""); +} + void MipsInstPrinter:: printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) { // Load/Store memory operands -- imm($reg) Index: lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h +++ lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -14,6 +14,7 @@ #ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H #define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H +#include "llvm/ADT/APFloat.h" #include "MipsFixupKinds.h" #include "MipsMCTargetDesc.h" #include "llvm/MC/MCExpr.h" @@ -53,6 +54,8 @@ MO_ABS_HI, MO_ABS_LO, + MO_LITERAL, + /// MO_TLSGD - Represents the offset into the global offset table at which // the module ID and TSL block offset reside during execution (General // Dynamic TLS). @@ -122,4 +125,93 @@ } } +namespace llvm { + +namespace MIPS_FP { +//===--------------------------------------------------------------------===// +// Floating-point Immediates +// +static inline float getFPImmFloat(unsigned Imm) { + // We expect an 8-bit binary encoding of a floating-point number here. + union { + uint32_t I; + float F; + } FPUnion; + + uint8_t Sign = (Imm >> 7) & 0x1; + uint8_t Exp = (Imm >> 4) & 0x7; + uint8_t Mantissa = Imm & 0xf; + + // 8-bit FP iEEEE Float Encoding + // abcd efgh aBbbbbbc defgh000 00000000 00000000 + // + // where B = NOT(b); + + FPUnion.I = 0; + FPUnion.I |= Sign << 31; + FPUnion.I |= ((Exp & 0x4) != 0 ? 0 : 1) << 30; + FPUnion.I |= ((Exp & 0x4) != 0 ? 0x1f : 0) << 25; + FPUnion.I |= (Exp & 0x3) << 23; + FPUnion.I |= Mantissa << 19; + return FPUnion.F; +} + +/// getFP32Imm - Return an 8-bit floating-point version of the 32-bit +/// floating-point value. If the value cannot be represented as an 8-bit +/// floating-point value, then return -1. +static inline int getFP32Imm(const APInt &Imm) { + uint32_t Sign = Imm.lshr(31).getZExtValue() & 1; + int32_t Exp = (Imm.lshr(23).getSExtValue() & 0xff) - 127; // -126 to 127 + int64_t Mantissa = Imm.getZExtValue() & 0x7fffff; // 23 bits + + // We can handle 4 bits of mantissa. + // mantissa = (16+UInt(e:f:g:h))/16. + if (Mantissa & 0x7ffff) + return -1; + Mantissa >>= 19; + if ((Mantissa & 0xf) != Mantissa) + return -1; + + // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 + if (Exp < -3 || Exp > 4) + return -1; + Exp = ((Exp + 3) & 0x7) ^ 4; + + return ((int)Sign << 7) | (Exp << 4) | Mantissa; +} + +static inline int getFP32Imm(const APFloat &FPImm) { + return getFP32Imm(FPImm.bitcastToAPInt()); +} + +/// getFP64Imm - Return an 8-bit floating-point version of the 64-bit +/// floating-point value. If the value cannot be represented as an 8-bit +/// floating-point value, then return -1. +static inline int getFP64Imm(const APInt &Imm) { + uint64_t Sign = Imm.lshr(63).getZExtValue() & 1; + int64_t Exp = (Imm.lshr(52).getSExtValue() & 0x7ff) - 1023; // -1022 to 1023 + uint64_t Mantissa = Imm.getZExtValue() & 0xfffffffffffffULL; + + // We can handle 4 bits of mantissa. + // mantissa = (16+UInt(e:f:g:h))/16. + if (Mantissa & 0xffffffffffffULL) + return -1; + Mantissa >>= 48; + if ((Mantissa & 0xf) != Mantissa) + return -1; + + // We can handle 3 bits of exponent: exp == UInt(NOT(b):c:d)-3 + if (Exp < -3 || Exp > 4) + return -1; + Exp = ((Exp + 3) & 0x7) ^ 4; + + return ((int)Sign << 7) | (Exp << 4) | Mantissa; +} + +static inline int getFP64Imm(const APFloat &FPImm) { + return getFP64Imm(FPImm.bitcastToAPInt()); +} +} // end namespace MIPS_FP +} // end namespace llvm + #endif Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp @@ -123,6 +123,8 @@ return ELF::R_MIPS_26; case Mips::fixup_Mips_CALL16: return ELF::R_MIPS_CALL16; + case Mips::fixup_Mips_LITERAL: + return ELF::R_MIPS_LITERAL; case Mips::fixup_Mips_GOT_Global: case Mips::fixup_Mips_GOT_Local: return ELF::R_MIPS_GOT16; Index: lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -563,6 +563,9 @@ FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_LO16 : Mips::fixup_Mips_LO16; break; + case MCSymbolRefExpr::VK_Mips_LITERAL: + FixupKind = Mips::fixup_Mips_LITERAL; + break; case MCSymbolRefExpr::VK_Mips_TLSGD: FixupKind = isMicroMips(STI) ? Mips::fixup_MICROMIPS_TLS_GD : Mips::fixup_Mips_TLSGD; Index: lib/Target/Mips/MipsInstrFPU.td =================================================================== --- lib/Target/Mips/MipsInstrFPU.td +++ lib/Target/Mips/MipsInstrFPU.td @@ -88,6 +88,30 @@ return N->isExactlyValue(-0.0); }]>; +// 8-bit floating-point immediate encodings. +def FPImmSingleOperand : AsmOperandClass { + let Name = "FPImmSingle"; + let ParserMethod = "parseFPImmSingle"; +} + +def FPImmDoubleOperand : AsmOperandClass { + let Name = "FPImmDouble"; + let ParserMethod = "parseFPImmDouble"; +} + +def fp_f32imm : Operand, PatLeaf<(f32 fpimm), [{ + return llvm::MIPS_FP::getFPImm(N->getValueAPF()) != -1; + }]> { + let PrintMethod = "printFPImmOperand"; + let ParserMatchClass = FPImmSingleOperand; +} + +def fp_f64imm : Operand, PatLeaf<(f64 fpimm), [{ + return llvm::MIPS_FP::getFP64Imm(N->getValueAPF()) != -1; + }]> { + let PrintMethod = "printFPImmOperand"; + let ParserMatchClass = FPImmDoubleOperand; +} //===----------------------------------------------------------------------===// // Instruction Class Templates // @@ -533,6 +557,27 @@ // Floating Point Pseudo-Instructions //===----------------------------------------------------------------------===// +def LoadImmSingleGPR : MipsAsmPseudoInst<(outs GPR32Opnd + : $rd), + (ins fp_f32imm + : $fpimm), + "li.s\t$rd, $fpimm">; +def LoadImmSingleFGR : MipsAsmPseudoInst<(outs FGR32Opnd + : $rd), + (ins fp_f32imm + : $fpimm), + "li.s\t$rd, $fpimm">; +def LoadImmDoubleGPR : MipsAsmPseudoInst<(outs GPR32Opnd + : $rd), + (ins fp_f64imm + : $fpimm), + "li.d\t$rd, $fpimm">; +def LoadImmDoubleFGR : MipsAsmPseudoInst<(outs FGR32Opnd + : $rd), + (ins fp_f64imm + : $fpimm), + "li.d\t$rd, $fpimm">; + // This pseudo instr gets expanded into 2 mtc1 instrs after register // allocation. class BuildPairF64Base : Index: lib/Target/Mips/MipsMCInstLower.cpp =================================================================== --- lib/Target/Mips/MipsMCInstLower.cpp +++ lib/Target/Mips/MipsMCInstLower.cpp @@ -66,6 +66,7 @@ case MipsII::MO_GOT_LO16: Kind = MCSymbolRefExpr::VK_Mips_GOT_LO16; break; case MipsII::MO_CALL_HI16: Kind = MCSymbolRefExpr::VK_Mips_CALL_HI16; break; case MipsII::MO_CALL_LO16: Kind = MCSymbolRefExpr::VK_Mips_CALL_LO16; break; + case MipsII::MO_LITERAL: Kind = MCSymbolRefExpr::VK_Mips_LITERAL; break; } switch (MOTy) { Index: test/MC/Mips/li.d.s =================================================================== --- test/MC/Mips/li.d.s +++ test/MC/Mips/li.d.s @@ -0,0 +1,83 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32 -show-encoding | FileCheck %s +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips64 -show-encoding | FileCheck %s + +foo: +li.d $4, 1.12345 +# CHECK: .section .rodata,"a",@progbits +# CHECK: .4byte 1072822694 +# CHECK: .4byte 3037400872 +# CHECK: .text +# CHECK: lui $1, %hi(.rodata) # encoding: [A,A,0x01,0x3c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: lw $4, %lo(.rodata-8)($1) # encoding: [0xf8'A',0xff'A',0x24,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: lw $5, %lo(.rodata-4)($1) # encoding: [0xfc'A',0xff'A',0x25,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 + +li.d $4, -1.12345 +# CHECK: .section .rodata,"a",@progbits +# CHECK: .4byte 3220306342 +# CHECK: .4byte 3037400872 +# CHECK: .text +# CHECK: lui $1, %hi(.rodata) # encoding: [A,A,0x01,0x3c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: lw $4, %lo(.rodata-8)($1) # encoding: [0xf8'A',0xff'A',0x24,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: lw $5, %lo(.rodata-4)($1) # encoding: [0xfc'A',0xff'A',0x25,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 + +li.d $4, 12345678910.12345678910 +# CHECK: .section .rodata,"a",@progbits +# CHECK: .4byte 1107754720 +# CHECK: .4byte 3790666967 +# CHECK: .text +# CHECK: lui $1, %hi(.rodata) # encoding: [A,A,0x01,0x3c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: lw $4, %lo(.rodata-8)($1) # encoding: [0xf8'A',0xff'A',0x24,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: lw $5, %lo(.rodata-4)($1) # encoding: [0xfc'A',0xff'A',0x25,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 + +li.d $4, -12345678910.12345678910 +# CHECK: .section .rodata,"a",@progbits +# CHECK: .4byte 3255238368 +# CHECK: .4byte 3790666967 +# CHECK: .text +# CHECK: lui $1, %hi(.rodata) # encoding: [A,A,0x01,0x3c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_HI, kind: fixup_Mips_HI16 +# CHECK: lw $4, %lo(.rodata-8)($1) # encoding: [0xf8'A',0xff'A',0x24,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 +# CHECK: lw $5, %lo(.rodata-4)($1) # encoding: [0xfc'A',0xff'A',0x25,0x8c] +# CHECK: # fixup A - offset: 0, value: .rodata@ABS_LO, kind: fixup_Mips_LO16 + +li.d $f4, 1.12345 +# CHECK: .section .lit8,"aw",@progbits +# CHECK: .4byte 1072822694 +# CHECK: .4byte 3037400872 +# CHECK: .text +# CHECK: ldc1 $f4, %literal(.lit8-8)($gp) # encoding: [0xf8'A',0xff'A',0x84,0xd7] +# CHECK: # fixup A - offset: 0, value: .lit8@LITERAL, kind: fixup_Mips_LITERAL + +li.d $f4, -1.12345 +# CHECK: .section .lit8,"aw",@progbits +# CHECK: .4byte 3220306342 +# CHECK: .4byte 3037400872 +# CHECK: .text +# CHECK: ldc1 $f4, %literal(.lit8-8)($gp) # encoding: [0xf8'A',0xff'A',0x84,0xd7] +# CHECK: # fixup A - offset: 0, value: .lit8@LITERAL, kind: fixup_Mips_LITERAL + +li.d $f4, 12345678910.12345678910 +# CHECK: .section .lit8,"aw",@progbits +# CHECK: .4byte 1107754720 +# CHECK: .4byte 3790666967 +# CHECK: .text +# CHECK: ldc1 $f4, %literal(.lit8-8)($gp) # encoding: [0xf8'A',0xff'A',0x84,0xd7] +# CHECK: # fixup A - offset: 0, value: .lit8@LITERAL, kind: fixup_Mips_LITERAL + +li.d $f4, -12345678910.12345678910 +# CHECK: .section .lit8,"aw",@progbits +# CHECK: .4byte 3255238368 +# CHECK: .4byte 3790666967 +# CHECK: .text +# CHECK: ldc1 $f4, %literal(.lit8-8)($gp) # encoding: [0xf8'A',0xff'A',0x84,0xd7] +# CHECK: # fixup A - offset: 0, value: .lit8@LITERAL, kind: fixup_Mips_LITERAL Index: test/MC/Mips/li.s.s =================================================================== --- test/MC/Mips/li.s.s +++ test/MC/Mips/li.s.s @@ -0,0 +1,47 @@ +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips32 -show-encoding | FileCheck %s +# RUN: llvm-mc %s -triple=mipsel-unknown-linux -mcpu=mips64 -show-encoding | FileCheck %s + +foo: +li.s $4, 1.12345 +# CHECK: lui $4, 16271 # encoding: [0x8f,0x3f,0x04,0x3c] +# CHECK: ori $4, $4, 52534 # encoding: [0x36,0xcd,0x84,0x34] + +li.s $4, -1.12345 +# CHECK: lui $4, 49039 # encoding: [0x8f,0xbf,0x04,0x3c] +# CHECK: ori $4, $4, 52534 # encoding: [0x36,0xcd,0x84,0x34] + +li.s $4, 12345678910.12345678910 +# CHECK: lui $4, 20535 # encoding: [0x37,0x50,0x04,0x3c] +# CHECK: ori $4, $4, 63239 # encoding: [0x07,0xf7,0x84,0x34] + +li.s $4, -12345678910.12345678910 +# CHECK: lui $4, 53303 # encoding: [0x37,0xd0,0x04,0x3c] +# CHECK: ori $4, $4, 63239 # encoding: [0x07,0xf7,0x84,0x34] + +li.s $f4, 1.12345 +# CHECK: .section .lit4,"aw",@progbits +# CHECK: .4byte 1066388790 +# CHECK: .text +# CHECK: lwc1 $f4, %literal(.lit4-4)($gp) # encoding: [0xfc'A',0xff'A',0x84,0xc7] +# CHECK: # fixup A - offset: 0, value: .lit4@LITERAL, kind: fixup_Mips_LITERAL + +li.s $f4, -1.12345 +# CHECK: .section .lit4,"aw",@progbits +# CHECK: .4byte 3213872438 +# CHECK: .text +# CHECK: lwc1 $f4, %literal(.lit4-4)($gp) # encoding: [0xfc'A',0xff'A',0x84,0xc7] +# CHECK: # fixup A - offset: 0, value: .lit4@LITERAL, kind: fixup_Mips_LITERAL + +li.s $f4, 12345678910.12345678910 +# CHECK: .section .lit4,"aw",@progbits +# CHECK: .4byte 1345844999 +# CHECK: .text +# CHECK: lwc1 $f4, %literal(.lit4-4)($gp) # encoding: [0xfc'A',0xff'A',0x84,0xc7] +# CHECK: # fixup A - offset: 0, value: .lit4@LITERAL, kind: fixup_Mips_LITERAL + +li.s $f4, -12345678910.12345678910 +# CHECK: .section .lit4,"aw",@progbits +# CHECK: .4byte 3493328647 +# CHECK: .text +# CHECK: lwc1 $f4, %literal(.lit4-4)($gp) # encoding: [0xfc'A',0xff'A',0x84,0xc7] +# CHECK: # fixup A - offset: 0, value: .lit4@LITERAL, kind: fixup_Mips_LITERAL