Index: llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td +++ llvm/trunk/lib/Target/AArch64/AArch64InstrFormats.td @@ -167,7 +167,7 @@ // 8-bit floating-point immediate encodings. def FPImmOperand : AsmOperandClass { let Name = "FPImm"; - let ParserMethod = "tryParseFPImm"; + let ParserMethod = "tryParseFPImm"; let DiagnosticType = "InvalidFPImm"; } Index: llvm/trunk/lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64SystemOperands.td +++ llvm/trunk/lib/Target/AArch64/AArch64SystemOperands.td @@ -235,6 +235,27 @@ def : SVEPREDPAT<"all", 0x1f>; //===----------------------------------------------------------------------===// +// Exact FP Immediates. +// +// These definitions are used to create a lookup table with FP Immediates that +// is used for a few instructions that only accept a limited set of exact FP +// immediates values. +//===----------------------------------------------------------------------===// +class ExactFPImm enum > : SearchableTable { + let SearchableFields = ["Enum", "Repr"]; + let EnumValueField = "Enum"; + + string Name = name; + bits<4> Enum = enum; + string Repr = repr; +} + +def : ExactFPImm<"zero", "0.0", 0x0>; +def : ExactFPImm<"half", "0.5", 0x1>; +def : ExactFPImm<"one", "1.0", 0x2>; +def : ExactFPImm<"two", "2.0", 0x3>; + +//===----------------------------------------------------------------------===// // PState instruction options. //===----------------------------------------------------------------------===// Index: llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -132,6 +132,7 @@ OperandMatchResultTy tryParsePSBHint(OperandVector &Operands); OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); + template OperandMatchResultTy tryParseFPImm(OperandVector &Operands); OperandMatchResultTy tryParseImmWithOptionalShift(OperandVector &Operands); OperandMatchResultTy tryParseGPR64sp0Operand(OperandVector &Operands); @@ -273,7 +274,8 @@ }; struct FPImmOp { - unsigned Val; // Encoded 8-bit representation. + uint64_t Val; // APFloat value bitcasted to uint64_t. + bool IsExact; // describes whether parsed value was exact. }; struct BarrierOp { @@ -419,9 +421,14 @@ return CondCode.Code; } - unsigned getFPImm() const { - assert(Kind == k_FPImm && "Invalid access!"); - return FPImm.Val; + APFloat getFPImm() const { + assert (Kind == k_FPImm && "Invalid access!"); + return APFloat(APFloat::IEEEdouble(), APInt(64, FPImm.Val, true)); + } + + bool getFPImmIsExact() const { + assert (Kind == k_FPImm && "Invalid access!"); + return FPImm.IsExact; } unsigned getBarrier() const { @@ -872,7 +879,11 @@ return AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth); } - bool isFPImm() const { return Kind == k_FPImm; } + bool isFPImm() const { + return Kind == k_FPImm && + AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()) != -1; + } + bool isBarrier() const { return Kind == k_Barrier; } bool isSysReg() const { return Kind == k_SysReg; } @@ -1080,6 +1091,39 @@ ST == AArch64_AM::ASR || ST == AArch64_AM::ROR || ST == AArch64_AM::MSL); } + + template DiagnosticPredicate isExactFPImm() const { + if (Kind != k_FPImm) + return DiagnosticPredicateTy::NoMatch; + + if (getFPImmIsExact()) { + // Lookup the immediate from table of supported immediates. + auto *Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmEnum); + assert(Desc && "Unknown enum value"); + + // Calculate its FP value. + APFloat RealVal(APFloat::IEEEdouble()); + if (RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero) != + APFloat::opOK) + llvm_unreachable("FP immediate is not exact"); + + if (getFPImm().bitwiseIsEqual(RealVal)) + return DiagnosticPredicateTy::Match; + } + + return DiagnosticPredicateTy::NearMatch; + } + + template + DiagnosticPredicate isExactFPImm() const { + DiagnosticPredicate Res = DiagnosticPredicateTy::NoMatch; + if ((Res = isExactFPImm())) + return DiagnosticPredicateTy::Match; + if ((Res = isExactFPImm())) + return DiagnosticPredicateTy::Match; + return Res; + } + bool isExtend() const { if (!isShiftExtend()) return false; @@ -1342,6 +1386,13 @@ Inst.addOperand(MCOperand::createImm(getVectorIndex())); } + template + void addExactFPImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + assert(bool(isExactFPImm()) && "Invalid operand"); + Inst.addOperand(MCOperand::createImm(bool(isExactFPImm()))); + } + void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // If this is a pageoff symrefexpr with an addend, adjust the addend @@ -1481,7 +1532,8 @@ void addFPImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); - Inst.addOperand(MCOperand::createImm(getFPImm())); + Inst.addOperand(MCOperand::createImm( + AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()))); } void addBarrierOperands(MCInst &Inst, unsigned N) const { @@ -1700,10 +1752,11 @@ return Op; } - static std::unique_ptr CreateFPImm(unsigned Val, SMLoc S, - MCContext &Ctx) { + static std::unique_ptr + CreateFPImm(APFloat Val, bool IsExact, SMLoc S, MCContext &Ctx) { auto Op = make_unique(k_FPImm, Ctx); - Op->FPImm.Val = Val; + Op->FPImm.Val = Val.bitcastToAPInt().getSExtValue(); + Op->FPImm.IsExact = IsExact; Op->StartLoc = S; Op->EndLoc = S; return Op; @@ -1791,8 +1844,10 @@ void AArch64Operand::print(raw_ostream &OS) const { switch (Kind) { case k_FPImm: - OS << ""; + OS << ""; break; case k_Barrier: { StringRef Name = getBarrierName(); @@ -2285,6 +2340,7 @@ } /// tryParseFPImm - A floating point immediate expression operand. +template OperandMatchResultTy AArch64AsmParser::tryParseFPImm(OperandVector &Operands) { MCAsmParser &Parser = getParser(); @@ -2296,45 +2352,44 @@ bool isNegative = parseOptionalToken(AsmToken::Minus); const AsmToken &Tok = Parser.getTok(); - if (Tok.is(AsmToken::Real) || Tok.is(AsmToken::Integer)) { - int64_t Val; - if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) { - Val = Tok.getIntVal(); - if (Val > 255 || isNegative) { - TokError("encoded floating point value out of range"); - return MatchOperand_ParseFail; - } - } else { - APFloat RealVal(APFloat::IEEEdouble(), Tok.getString()); - if (isNegative) - RealVal.changeSign(); - - uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); - Val = AArch64_AM::getFP64Imm(APInt(64, IntVal)); + if (!Tok.is(AsmToken::Real) && !Tok.is(AsmToken::Integer)) { + if (!Hash) + return MatchOperand_NoMatch; + TokError("invalid floating point immediate"); + return MatchOperand_ParseFail; + } - // Check for out of range values. As an exception we let Zero through, - // but as tokens instead of an FPImm so that it can be matched by the - // appropriate alias if one exists. - if (RealVal.isPosZero()) { - Parser.Lex(); // Eat the token. - Operands.push_back(AArch64Operand::CreateToken("#0", false, S, getContext())); - Operands.push_back(AArch64Operand::CreateToken(".0", false, S, getContext())); - return MatchOperand_Success; - } else if (Val == -1) { - TokError("expected compatible register or floating-point constant"); - return MatchOperand_ParseFail; - } + // Parse hexadecimal representation. + if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) { + if (Tok.getIntVal() > 255 || isNegative) { + TokError("encoded floating point value out of range"); + return MatchOperand_ParseFail; } - Parser.Lex(); // Eat the token. - Operands.push_back(AArch64Operand::CreateFPImm(Val, S, getContext())); - return MatchOperand_Success; + + APFloat F((double)AArch64_AM::getFPImmFloat(Tok.getIntVal())); + Operands.push_back( + AArch64Operand::CreateFPImm(F, true, S, getContext())); + } else { + // Parse FP representation. + APFloat RealVal(APFloat::IEEEdouble()); + auto Status = + RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero); + if (isNegative) + RealVal.changeSign(); + + if (AddFPZeroAsLiteral && RealVal.isPosZero()) { + Operands.push_back( + AArch64Operand::CreateToken("#0", false, S, getContext())); + Operands.push_back( + AArch64Operand::CreateToken(".0", false, S, getContext())); + } else + Operands.push_back(AArch64Operand::CreateFPImm( + RealVal, Status == APFloat::opOK, S, getContext())); } - if (!Hash) - return MatchOperand_NoMatch; + Parser.Lex(); // Eat the token. - TokError("invalid floating point immediate"); - return MatchOperand_ParseFail; + return MatchOperand_Success; } /// tryParseImmWithOptionalShift - Parse immediate operand, optionally with Index: llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h =================================================================== --- llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h @@ -183,6 +183,9 @@ template void printZPRasFPR(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + template + void printExactFPImm(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, raw_ostream &O); }; class AArch64AppleInstPrinter : public AArch64InstPrinter { Index: llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -1517,3 +1517,13 @@ unsigned Reg = MI->getOperand(OpNum).getReg(); O << getRegisterName(Reg - AArch64::Z0 + Base); } + +template +void AArch64InstPrinter::printExactFPImm(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + auto *Imm0Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs0); + auto *Imm1Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs1); + unsigned Val = MI->getOperand(OpNum).getImm(); + O << "#" << (Val ? Imm1Desc->Repr : Imm0Desc->Repr); +} Index: llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td +++ llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td @@ -203,6 +203,18 @@ return AArch64_AM::isSVEAddSubImm(Imm); }]>; +class SVEExactFPImm : AsmOperandClass { + let Name = "SVEExactFPImmOperand" # Suffix; + let DiagnosticType = "Invalid" # Name; + let ParserMethod = "tryParseFPImm"; + let PredicateMethod = "isExactFPImm<" # ValA # ", " # ValB # ">"; + let RenderMethod = "addExactFPImmOperands<" # ValA # ", " # ValB # ">"; +} + +class SVEExactFPImmOperand : Operand { + let PrintMethod = "printExactFPImm<" # ValA # ", " # ValB # ">"; + let ParserMatchClass = SVEExactFPImm; +} //===----------------------------------------------------------------------===// // SVE PTrue - These are used extensively throughout the pattern matching so Index: llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -352,6 +352,16 @@ #include "AArch64GenSystemOperands.inc" } +namespace AArch64ExactFPImm { + struct ExactFPImm { + const char *Name; + int Enum; + const char *Repr; + }; +#define GET_EXACTFPIMM_DECL +#include "AArch64GenSystemOperands.inc" +} + namespace AArch64PState { struct PState : SysAlias{ using SysAlias::SysAlias; Index: llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ llvm/trunk/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -75,6 +75,13 @@ } namespace llvm { + namespace AArch64ExactFPImm { +#define GET_EXACTFPIMM_IMPL +#include "AArch64GenSystemOperands.inc" + } +} + +namespace llvm { namespace AArch64PState { #define GET_PSTATE_IMPL #include "AArch64GenSystemOperands.inc"