Index: lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- lib/Target/AArch64/AArch64SystemOperands.td +++ lib/Target/AArch64/AArch64SystemOperands.td @@ -235,6 +235,23 @@ def : SVEPREDPAT<"all", 0x1f>; //===----------------------------------------------------------------------===// +// Named FP Immediates +//===----------------------------------------------------------------------===// +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: lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -133,6 +133,8 @@ OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands); OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands); OperandMatchResultTy tryParseFPImm(OperandVector &Operands); + LLVM_ATTRIBUTE_UNUSED + OperandMatchResultTy tryParseExactFPImm(OperandVector &Operands); OperandMatchResultTy tryParseImmWithOptionalShift(OperandVector &Operands); OperandMatchResultTy tryParseGPR64sp0Operand(OperandVector &Operands); bool tryParseNeonVectorRegister(OperandVector &Operands); @@ -206,6 +208,7 @@ k_Prefetch, k_ShiftExtend, k_FPImm, + k_ExactFPImm, k_Barrier, k_PSBHint, } Kind; @@ -276,6 +279,11 @@ unsigned Val; // Encoded 8-bit representation. }; + struct ExactFPImmOp { + uint64_t Val; // APFloat value bitcasted to uint64_t. + bool IsExact; // describes whether parsed value was exact. + }; + struct BarrierOp { const char *Data; unsigned Length; @@ -319,6 +327,7 @@ struct ShiftedImmOp ShiftedImm; struct CondCodeOp CondCode; struct FPImmOp FPImm; + struct ExactFPImmOp ExactFPImm; struct BarrierOp Barrier; struct SysRegOp SysReg; struct SysCRImmOp SysCRImm; @@ -354,6 +363,9 @@ case k_FPImm: FPImm = o.FPImm; break; + case k_ExactFPImm: + ExactFPImm = o.ExactFPImm; + break; case k_Barrier: Barrier = o.Barrier; break; @@ -424,6 +436,16 @@ return FPImm.Val; } + uint64_t getExactFPImm() const { + assert (Kind == k_ExactFPImm && "Invalid access!"); + return ExactFPImm.Val; + } + + bool getExactFPImmIsExact() const { + assert (Kind == k_ExactFPImm && "Invalid access!"); + return ExactFPImm.IsExact; + } + unsigned getBarrier() const { assert(Kind == k_Barrier && "Invalid access!"); return Barrier.Val; @@ -1080,6 +1102,39 @@ ST == AArch64_AM::ASR || ST == AArch64_AM::ROR || ST == AArch64_AM::MSL); } + + template DiagnosticPredicate isExactFPImm() const { + if (Kind != k_ExactFPImm) + return DiagnosticPredicateTy::NoMatch; + + if (getExactFPImmIsExact()) { + // 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()); + auto Status = + RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero); + assert(Status == APFloat::opOK && "FP immediate is not exact"); + + if (getExactFPImm() == RealVal.bitcastToAPInt().getZExtValue()) + 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 +1397,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 @@ -1709,6 +1771,16 @@ return Op; } + static std::unique_ptr + CreateExactFPImm(uint64_t Val, bool IsExact, SMLoc S, MCContext &Ctx) { + auto Op = make_unique(k_ExactFPImm, Ctx); + Op->ExactFPImm.Val = Val; + Op->ExactFPImm.IsExact = IsExact; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + static std::unique_ptr CreateBarrier(unsigned Val, StringRef Str, SMLoc S, @@ -1794,6 +1866,12 @@ OS << ""; break; + case k_ExactFPImm: + OS << ""; + break; case k_Barrier: { StringRef Name = getBarrierName(); if (!Name.empty()) @@ -2337,6 +2415,32 @@ return MatchOperand_ParseFail; } +/// tryParseFPImm - A floating point immediate expression operand. +OperandMatchResultTy +AArch64AsmParser::tryParseExactFPImm(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + + if (!Parser.getTok().is(AsmToken::Hash)) + return MatchOperand_NoMatch; + + Parser.Lex(); // Eat '#' + + const AsmToken &Tok = Parser.getTok(); + if (!Tok.is(AsmToken::Real)) + return MatchOperand_NoMatch; + + APFloat RealVal(APFloat::IEEEdouble()); + auto Status = + RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero); + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); + Operands.push_back(AArch64Operand::CreateExactFPImm( + IntVal, Status == APFloat::opOK, getLoc(), getContext())); + + Parser.Lex(); // Eat the token. + + return MatchOperand_Success; +} + /// tryParseImmWithOptionalShift - Parse immediate operand, optionally with /// a shift suffix, for example '#1, lsl #12'. OperandMatchResultTy Index: lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h =================================================================== --- lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ 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: lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp =================================================================== --- lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ 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: lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- lib/Target/AArch64/SVEInstrFormats.td +++ 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 = "tryParseExactFPImm"; + 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: lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ 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: lib/Target/AArch64/Utils/AArch64BaseInfo.cpp =================================================================== --- lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ 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"