Skip to content

Commit dde50dc

Browse files
committed
[AArch64][SVE] Asm: Add parsing/printing support for exact FP immediates.
Some instructions require of a limited set of FP immediates as operands, for example '#0.5 or brson#1.0' for SVE's FADD instruction. This patch adds support for parsing and printing such FP immediates as exact values (e.g. #0.499999 is not accepted for #0.5). Reviewers: rengolin, fhahn, SjoerdMeijer, samparker, javed.absar Reviewed By: SjoerdMeijer Differential Revision: https://reviews.llvm.org/D47711 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@334826 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f58bfff commit dde50dc

File tree

8 files changed

+164
-46
lines changed

8 files changed

+164
-46
lines changed

lib/Target/AArch64/AArch64InstrFormats.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def ExtendOperandLSL64 : AsmOperandClass {
167167
// 8-bit floating-point immediate encodings.
168168
def FPImmOperand : AsmOperandClass {
169169
let Name = "FPImm";
170-
let ParserMethod = "tryParseFPImm";
170+
let ParserMethod = "tryParseFPImm<true>";
171171
let DiagnosticType = "InvalidFPImm";
172172
}
173173

lib/Target/AArch64/AArch64SystemOperands.td

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,27 @@ def : SVEPREDPAT<"mul4", 0x1d>;
234234
def : SVEPREDPAT<"mul3", 0x1e>;
235235
def : SVEPREDPAT<"all", 0x1f>;
236236

237+
//===----------------------------------------------------------------------===//
238+
// Exact FP Immediates.
239+
//
240+
// These definitions are used to create a lookup table with FP Immediates that
241+
// is used for a few instructions that only accept a limited set of exact FP
242+
// immediates values.
243+
//===----------------------------------------------------------------------===//
244+
class ExactFPImm<string name, string repr, bits<4> enum > : SearchableTable {
245+
let SearchableFields = ["Enum", "Repr"];
246+
let EnumValueField = "Enum";
247+
248+
string Name = name;
249+
bits<4> Enum = enum;
250+
string Repr = repr;
251+
}
252+
253+
def : ExactFPImm<"zero", "0.0", 0x0>;
254+
def : ExactFPImm<"half", "0.5", 0x1>;
255+
def : ExactFPImm<"one", "1.0", 0x2>;
256+
def : ExactFPImm<"two", "2.0", 0x3>;
257+
237258
//===----------------------------------------------------------------------===//
238259
// PState instruction options.
239260
//===----------------------------------------------------------------------===//

lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp

Lines changed: 100 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
132132
OperandMatchResultTy tryParsePSBHint(OperandVector &Operands);
133133
OperandMatchResultTy tryParseAdrpLabel(OperandVector &Operands);
134134
OperandMatchResultTy tryParseAdrLabel(OperandVector &Operands);
135+
template<bool AddFPZeroAsLiteral>
135136
OperandMatchResultTy tryParseFPImm(OperandVector &Operands);
136137
OperandMatchResultTy tryParseImmWithOptionalShift(OperandVector &Operands);
137138
OperandMatchResultTy tryParseGPR64sp0Operand(OperandVector &Operands);
@@ -273,7 +274,8 @@ class AArch64Operand : public MCParsedAsmOperand {
273274
};
274275

275276
struct FPImmOp {
276-
unsigned Val; // Encoded 8-bit representation.
277+
uint64_t Val; // APFloat value bitcasted to uint64_t.
278+
bool IsExact; // describes whether parsed value was exact.
277279
};
278280

279281
struct BarrierOp {
@@ -419,9 +421,14 @@ class AArch64Operand : public MCParsedAsmOperand {
419421
return CondCode.Code;
420422
}
421423

422-
unsigned getFPImm() const {
423-
assert(Kind == k_FPImm && "Invalid access!");
424-
return FPImm.Val;
424+
APFloat getFPImm() const {
425+
assert (Kind == k_FPImm && "Invalid access!");
426+
return APFloat(APFloat::IEEEdouble(), APInt(64, FPImm.Val, true));
427+
}
428+
429+
bool getFPImmIsExact() const {
430+
assert (Kind == k_FPImm && "Invalid access!");
431+
return FPImm.IsExact;
425432
}
426433

427434
unsigned getBarrier() const {
@@ -872,7 +879,11 @@ class AArch64Operand : public MCParsedAsmOperand {
872879
return AArch64_AM::isMOVNMovAlias(Value, Shift, RegWidth);
873880
}
874881

875-
bool isFPImm() const { return Kind == k_FPImm; }
882+
bool isFPImm() const {
883+
return Kind == k_FPImm &&
884+
AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt()) != -1;
885+
}
886+
876887
bool isBarrier() const { return Kind == k_Barrier; }
877888
bool isSysReg() const { return Kind == k_SysReg; }
878889

@@ -1080,6 +1091,39 @@ class AArch64Operand : public MCParsedAsmOperand {
10801091
ST == AArch64_AM::ASR || ST == AArch64_AM::ROR ||
10811092
ST == AArch64_AM::MSL);
10821093
}
1094+
1095+
template <unsigned ImmEnum> DiagnosticPredicate isExactFPImm() const {
1096+
if (Kind != k_FPImm)
1097+
return DiagnosticPredicateTy::NoMatch;
1098+
1099+
if (getFPImmIsExact()) {
1100+
// Lookup the immediate from table of supported immediates.
1101+
auto *Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmEnum);
1102+
assert(Desc && "Unknown enum value");
1103+
1104+
// Calculate its FP value.
1105+
APFloat RealVal(APFloat::IEEEdouble());
1106+
if (RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero) !=
1107+
APFloat::opOK)
1108+
llvm_unreachable("FP immediate is not exact");
1109+
1110+
if (getFPImm().bitwiseIsEqual(RealVal))
1111+
return DiagnosticPredicateTy::Match;
1112+
}
1113+
1114+
return DiagnosticPredicateTy::NearMatch;
1115+
}
1116+
1117+
template <unsigned ImmA, unsigned ImmB>
1118+
DiagnosticPredicate isExactFPImm() const {
1119+
DiagnosticPredicate Res = DiagnosticPredicateTy::NoMatch;
1120+
if ((Res = isExactFPImm<ImmA>()))
1121+
return DiagnosticPredicateTy::Match;
1122+
if ((Res = isExactFPImm<ImmB>()))
1123+
return DiagnosticPredicateTy::Match;
1124+
return Res;
1125+
}
1126+
10831127
bool isExtend() const {
10841128
if (!isShiftExtend())
10851129
return false;
@@ -1342,6 +1386,13 @@ class AArch64Operand : public MCParsedAsmOperand {
13421386
Inst.addOperand(MCOperand::createImm(getVectorIndex()));
13431387
}
13441388

1389+
template <unsigned ImmIs0, unsigned ImmIs1>
1390+
void addExactFPImmOperands(MCInst &Inst, unsigned N) const {
1391+
assert(N == 1 && "Invalid number of operands!");
1392+
assert(bool(isExactFPImm<ImmIs0, ImmIs1>()) && "Invalid operand");
1393+
Inst.addOperand(MCOperand::createImm(bool(isExactFPImm<ImmIs1>())));
1394+
}
1395+
13451396
void addImmOperands(MCInst &Inst, unsigned N) const {
13461397
assert(N == 1 && "Invalid number of operands!");
13471398
// If this is a pageoff symrefexpr with an addend, adjust the addend
@@ -1481,7 +1532,8 @@ class AArch64Operand : public MCParsedAsmOperand {
14811532

14821533
void addFPImmOperands(MCInst &Inst, unsigned N) const {
14831534
assert(N == 1 && "Invalid number of operands!");
1484-
Inst.addOperand(MCOperand::createImm(getFPImm()));
1535+
Inst.addOperand(MCOperand::createImm(
1536+
AArch64_AM::getFP64Imm(getFPImm().bitcastToAPInt())));
14851537
}
14861538

14871539
void addBarrierOperands(MCInst &Inst, unsigned N) const {
@@ -1700,10 +1752,11 @@ class AArch64Operand : public MCParsedAsmOperand {
17001752
return Op;
17011753
}
17021754

1703-
static std::unique_ptr<AArch64Operand> CreateFPImm(unsigned Val, SMLoc S,
1704-
MCContext &Ctx) {
1755+
static std::unique_ptr<AArch64Operand>
1756+
CreateFPImm(APFloat Val, bool IsExact, SMLoc S, MCContext &Ctx) {
17051757
auto Op = make_unique<AArch64Operand>(k_FPImm, Ctx);
1706-
Op->FPImm.Val = Val;
1758+
Op->FPImm.Val = Val.bitcastToAPInt().getSExtValue();
1759+
Op->FPImm.IsExact = IsExact;
17071760
Op->StartLoc = S;
17081761
Op->EndLoc = S;
17091762
return Op;
@@ -1791,8 +1844,10 @@ class AArch64Operand : public MCParsedAsmOperand {
17911844
void AArch64Operand::print(raw_ostream &OS) const {
17921845
switch (Kind) {
17931846
case k_FPImm:
1794-
OS << "<fpimm " << getFPImm() << "("
1795-
<< AArch64_AM::getFPImmFloat(getFPImm()) << ") >";
1847+
OS << "<fpimm " << getFPImm().bitcastToAPInt().getZExtValue();
1848+
if (!getFPImmIsExact())
1849+
OS << " (inexact)";
1850+
OS << ">";
17961851
break;
17971852
case k_Barrier: {
17981853
StringRef Name = getBarrierName();
@@ -2285,6 +2340,7 @@ AArch64AsmParser::tryParseAdrLabel(OperandVector &Operands) {
22852340
}
22862341

22872342
/// tryParseFPImm - A floating point immediate expression operand.
2343+
template<bool AddFPZeroAsLiteral>
22882344
OperandMatchResultTy
22892345
AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
22902346
MCAsmParser &Parser = getParser();
@@ -2296,45 +2352,44 @@ AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
22962352
bool isNegative = parseOptionalToken(AsmToken::Minus);
22972353

22982354
const AsmToken &Tok = Parser.getTok();
2299-
if (Tok.is(AsmToken::Real) || Tok.is(AsmToken::Integer)) {
2300-
int64_t Val;
2301-
if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) {
2302-
Val = Tok.getIntVal();
2303-
if (Val > 255 || isNegative) {
2304-
TokError("encoded floating point value out of range");
2305-
return MatchOperand_ParseFail;
2306-
}
2307-
} else {
2308-
APFloat RealVal(APFloat::IEEEdouble(), Tok.getString());
2309-
if (isNegative)
2310-
RealVal.changeSign();
2355+
if (!Tok.is(AsmToken::Real) && !Tok.is(AsmToken::Integer)) {
2356+
if (!Hash)
2357+
return MatchOperand_NoMatch;
2358+
TokError("invalid floating point immediate");
2359+
return MatchOperand_ParseFail;
2360+
}
23112361

2312-
uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
2313-
Val = AArch64_AM::getFP64Imm(APInt(64, IntVal));
2314-
2315-
// Check for out of range values. As an exception we let Zero through,
2316-
// but as tokens instead of an FPImm so that it can be matched by the
2317-
// appropriate alias if one exists.
2318-
if (RealVal.isPosZero()) {
2319-
Parser.Lex(); // Eat the token.
2320-
Operands.push_back(AArch64Operand::CreateToken("#0", false, S, getContext()));
2321-
Operands.push_back(AArch64Operand::CreateToken(".0", false, S, getContext()));
2322-
return MatchOperand_Success;
2323-
} else if (Val == -1) {
2324-
TokError("expected compatible register or floating-point constant");
2325-
return MatchOperand_ParseFail;
2326-
}
2362+
// Parse hexadecimal representation.
2363+
if (Tok.is(AsmToken::Integer) && Tok.getString().startswith("0x")) {
2364+
if (Tok.getIntVal() > 255 || isNegative) {
2365+
TokError("encoded floating point value out of range");
2366+
return MatchOperand_ParseFail;
23272367
}
2328-
Parser.Lex(); // Eat the token.
2329-
Operands.push_back(AArch64Operand::CreateFPImm(Val, S, getContext()));
2330-
return MatchOperand_Success;
2368+
2369+
APFloat F((double)AArch64_AM::getFPImmFloat(Tok.getIntVal()));
2370+
Operands.push_back(
2371+
AArch64Operand::CreateFPImm(F, true, S, getContext()));
2372+
} else {
2373+
// Parse FP representation.
2374+
APFloat RealVal(APFloat::IEEEdouble());
2375+
auto Status =
2376+
RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero);
2377+
if (isNegative)
2378+
RealVal.changeSign();
2379+
2380+
if (AddFPZeroAsLiteral && RealVal.isPosZero()) {
2381+
Operands.push_back(
2382+
AArch64Operand::CreateToken("#0", false, S, getContext()));
2383+
Operands.push_back(
2384+
AArch64Operand::CreateToken(".0", false, S, getContext()));
2385+
} else
2386+
Operands.push_back(AArch64Operand::CreateFPImm(
2387+
RealVal, Status == APFloat::opOK, S, getContext()));
23312388
}
23322389

2333-
if (!Hash)
2334-
return MatchOperand_NoMatch;
2390+
Parser.Lex(); // Eat the token.
23352391

2336-
TokError("invalid floating point immediate");
2337-
return MatchOperand_ParseFail;
2392+
return MatchOperand_Success;
23382393
}
23392394

23402395
/// tryParseImmWithOptionalShift - Parse immediate operand, optionally with

lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,3 +1517,13 @@ void AArch64InstPrinter::printZPRasFPR(const MCInst *MI, unsigned OpNum,
15171517
unsigned Reg = MI->getOperand(OpNum).getReg();
15181518
O << getRegisterName(Reg - AArch64::Z0 + Base);
15191519
}
1520+
1521+
template <unsigned ImmIs0, unsigned ImmIs1>
1522+
void AArch64InstPrinter::printExactFPImm(const MCInst *MI, unsigned OpNum,
1523+
const MCSubtargetInfo &STI,
1524+
raw_ostream &O) {
1525+
auto *Imm0Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs0);
1526+
auto *Imm1Desc = AArch64ExactFPImm::lookupExactFPImmByEnum(ImmIs1);
1527+
unsigned Val = MI->getOperand(OpNum).getImm();
1528+
O << "#" << (Val ? Imm1Desc->Repr : Imm0Desc->Repr);
1529+
}

lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ class AArch64InstPrinter : public MCInstPrinter {
183183
template <int Width>
184184
void printZPRasFPR(const MCInst *MI, unsigned OpNum,
185185
const MCSubtargetInfo &STI, raw_ostream &O);
186+
template <unsigned ImmIs0, unsigned ImmIs1>
187+
void printExactFPImm(const MCInst *MI, unsigned OpNum,
188+
const MCSubtargetInfo &STI, raw_ostream &O);
186189
};
187190

188191
class AArch64AppleInstPrinter : public AArch64InstPrinter {

lib/Target/AArch64/SVEInstrFormats.td

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,18 @@ def addsub_imm8_opt_lsl_i64 : imm8_opt_lsl<64, "uint64_t", SVEAddSubImmOperand64
203203
return AArch64_AM::isSVEAddSubImm<int64_t>(Imm);
204204
}]>;
205205

206+
class SVEExactFPImm<string Suffix, string ValA, string ValB> : AsmOperandClass {
207+
let Name = "SVEExactFPImmOperand" # Suffix;
208+
let DiagnosticType = "Invalid" # Name;
209+
let ParserMethod = "tryParseFPImm<false>";
210+
let PredicateMethod = "isExactFPImm<" # ValA # ", " # ValB # ">";
211+
let RenderMethod = "addExactFPImmOperands<" # ValA # ", " # ValB # ">";
212+
}
213+
214+
class SVEExactFPImmOperand<string Suffix, string ValA, string ValB> : Operand<i32> {
215+
let PrintMethod = "printExactFPImm<" # ValA # ", " # ValB # ">";
216+
let ParserMatchClass = SVEExactFPImm<Suffix, ValA, ValB>;
217+
}
206218

207219
//===----------------------------------------------------------------------===//
208220
// SVE PTrue - These are used extensively throughout the pattern matching so

lib/Target/AArch64/Utils/AArch64BaseInfo.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ namespace llvm {
7474
}
7575
}
7676

77+
namespace llvm {
78+
namespace AArch64ExactFPImm {
79+
#define GET_EXACTFPIMM_IMPL
80+
#include "AArch64GenSystemOperands.inc"
81+
}
82+
}
83+
7784
namespace llvm {
7885
namespace AArch64PState {
7986
#define GET_PSTATE_IMPL

lib/Target/AArch64/Utils/AArch64BaseInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,16 @@ namespace AArch64SVEPredPattern {
352352
#include "AArch64GenSystemOperands.inc"
353353
}
354354

355+
namespace AArch64ExactFPImm {
356+
struct ExactFPImm {
357+
const char *Name;
358+
int Enum;
359+
const char *Repr;
360+
};
361+
#define GET_EXACTFPIMM_DECL
362+
#include "AArch64GenSystemOperands.inc"
363+
}
364+
355365
namespace AArch64PState {
356366
struct PState : SysAlias{
357367
using SysAlias::SysAlias;

0 commit comments

Comments
 (0)