@@ -66,6 +66,12 @@ enum class RegKind {
66
66
SVEPredicateVector
67
67
};
68
68
69
+ enum RegConstraintEqualityTy {
70
+ EqualsReg,
71
+ EqualsSuperReg,
72
+ EqualsSubReg
73
+ };
74
+
69
75
class AArch64AsmParser : public MCTargetAsmParser {
70
76
private:
71
77
StringRef Mnemonic; // /< Instruction mnemonic.
@@ -92,7 +98,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
92
98
bool parseOperand (OperandVector &Operands, bool isCondCode,
93
99
bool invertCondCode);
94
100
95
- bool showMatchError (SMLoc Loc, unsigned ErrCode, OperandVector &Operands);
101
+ bool showMatchError (SMLoc Loc, unsigned ErrCode, uint64_t ErrorInfo,
102
+ OperandVector &Operands);
96
103
97
104
bool parseDirectiveArch (SMLoc L);
98
105
bool parseDirectiveCPU (SMLoc L);
@@ -139,7 +146,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
139
146
bool tryParseNeonVectorRegister (OperandVector &Operands);
140
147
OperandMatchResultTy tryParseVectorIndex (OperandVector &Operands);
141
148
OperandMatchResultTy tryParseGPRSeqPair (OperandVector &Operands);
142
- template <bool ParseShiftExtend>
149
+ template <bool ParseShiftExtend,
150
+ RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg>
143
151
OperandMatchResultTy tryParseGPROperand (OperandVector &Operands);
144
152
template <bool ParseShiftExtend, bool ParseSuffix>
145
153
OperandMatchResultTy tryParseSVEDataVector (OperandVector &Operands);
@@ -177,6 +185,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
177
185
setAvailableFeatures (ComputeAvailableFeatures (getSTI ().getFeatureBits ()));
178
186
}
179
187
188
+ bool regsEqual (const MCParsedAsmOperand &Op1,
189
+ const MCParsedAsmOperand &Op2) const override ;
180
190
bool ParseInstruction (ParseInstructionInfo &Info, StringRef Name,
181
191
SMLoc NameLoc, OperandVector &Operands) override ;
182
192
bool ParseRegister (unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override ;
@@ -231,6 +241,10 @@ class AArch64Operand : public MCParsedAsmOperand {
231
241
RegKind Kind;
232
242
int ElementWidth;
233
243
244
+ // The register may be allowed as a different register class,
245
+ // e.g. for GPR64as32 or GPR32as64.
246
+ RegConstraintEqualityTy EqualityTy;
247
+
234
248
// In some cases the shift/extend needs to be explicitly parsed together
235
249
// with the register, rather than as a separate operand. This is needed
236
250
// for addressing modes where the instruction as a whole dictates the
@@ -446,6 +460,11 @@ class AArch64Operand : public MCParsedAsmOperand {
446
460
return Reg.RegNum ;
447
461
}
448
462
463
+ RegConstraintEqualityTy getRegEqualityTy () const {
464
+ assert (Kind == k_Register && " Invalid access!" );
465
+ return Reg.EqualityTy ;
466
+ }
467
+
449
468
unsigned getVectorListStart () const {
450
469
assert (Kind == k_VectorList && " Invalid access!" );
451
470
return VectorList.RegNum ;
@@ -554,14 +573,16 @@ class AArch64Operand : public MCParsedAsmOperand {
554
573
return DiagnosticPredicateTy::NearMatch;
555
574
}
556
575
557
- bool isSVEPattern () const {
576
+ DiagnosticPredicate isSVEPattern () const {
558
577
if (!isImm ())
559
- return false ;
578
+ return DiagnosticPredicateTy::NoMatch ;
560
579
auto *MCE = dyn_cast<MCConstantExpr>(getImm ());
561
580
if (!MCE)
562
- return false ;
581
+ return DiagnosticPredicateTy::NoMatch ;
563
582
int64_t Val = MCE->getValue ();
564
- return Val >= 0 && Val < 32 ;
583
+ if (Val >= 0 && Val < 32 )
584
+ return DiagnosticPredicateTy::Match;
585
+ return DiagnosticPredicateTy::NearMatch;
565
586
}
566
587
567
588
bool isSymbolicUImm12Offset (const MCExpr *Expr, unsigned Scale) const {
@@ -1002,6 +1023,11 @@ class AArch64Operand : public MCParsedAsmOperand {
1002
1023
AArch64MCRegisterClasses[AArch64::GPR64RegClassID].contains (Reg.RegNum );
1003
1024
}
1004
1025
1026
+ bool isGPR64as32 () const {
1027
+ return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
1028
+ AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains (Reg.RegNum );
1029
+ }
1030
+
1005
1031
bool isWSeqPair () const {
1006
1032
return Kind == k_Register && Reg.Kind == RegKind::Scalar &&
1007
1033
AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID].contains (
@@ -1318,6 +1344,18 @@ class AArch64Operand : public MCParsedAsmOperand {
1318
1344
Inst.addOperand (MCOperand::createReg (Reg));
1319
1345
}
1320
1346
1347
+ void addGPR64as32Operands (MCInst &Inst, unsigned N) const {
1348
+ assert (N == 1 && " Invalid number of operands!" );
1349
+ assert (
1350
+ AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains (getReg ()));
1351
+
1352
+ const MCRegisterInfo *RI = Ctx.getRegisterInfo ();
1353
+ uint32_t Reg = RI->getRegClass (AArch64::GPR64RegClassID).getRegister (
1354
+ RI->getEncodingValue (getReg ()));
1355
+
1356
+ Inst.addOperand (MCOperand::createReg (Reg));
1357
+ }
1358
+
1321
1359
template <int Width>
1322
1360
void addFPRasZPRRegOperands (MCInst &Inst, unsigned N) const {
1323
1361
unsigned Base;
@@ -1668,13 +1706,15 @@ class AArch64Operand : public MCParsedAsmOperand {
1668
1706
1669
1707
static std::unique_ptr<AArch64Operand>
1670
1708
CreateReg (unsigned RegNum, RegKind Kind, SMLoc S, SMLoc E, MCContext &Ctx,
1709
+ RegConstraintEqualityTy EqTy = RegConstraintEqualityTy::EqualsReg,
1671
1710
AArch64_AM::ShiftExtendType ExtTy = AArch64_AM::LSL,
1672
1711
unsigned ShiftAmount = 0 ,
1673
1712
unsigned HasExplicitAmount = false ) {
1674
1713
auto Op = make_unique<AArch64Operand>(k_Register, Ctx);
1675
1714
Op->Reg .RegNum = RegNum;
1676
1715
Op->Reg .Kind = Kind;
1677
1716
Op->Reg .ElementWidth = 0 ;
1717
+ Op->Reg .EqualityTy = EqTy;
1678
1718
Op->Reg .ShiftExtend .Type = ExtTy;
1679
1719
Op->Reg .ShiftExtend .Amount = ShiftAmount;
1680
1720
Op->Reg .ShiftExtend .HasExplicitAmount = HasExplicitAmount;
@@ -1692,7 +1732,7 @@ class AArch64Operand : public MCParsedAsmOperand {
1692
1732
assert ((Kind == RegKind::NeonVector || Kind == RegKind::SVEDataVector ||
1693
1733
Kind == RegKind::SVEPredicateVector) &&
1694
1734
" Invalid vector kind" );
1695
- auto Op = CreateReg (RegNum, Kind, S, E, Ctx, ExtTy, ShiftAmount,
1735
+ auto Op = CreateReg (RegNum, Kind, S, E, Ctx, EqualsReg, ExtTy, ShiftAmount,
1696
1736
HasExplicitAmount);
1697
1737
Op->Reg .ElementWidth = ElementWidth;
1698
1738
return Op;
@@ -3164,7 +3204,7 @@ AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) {
3164
3204
return MatchOperand_Success;
3165
3205
}
3166
3206
3167
- template <bool ParseShiftExtend>
3207
+ template <bool ParseShiftExtend, RegConstraintEqualityTy EqTy >
3168
3208
OperandMatchResultTy
3169
3209
AArch64AsmParser::tryParseGPROperand (OperandVector &Operands) {
3170
3210
SMLoc StartLoc = getLoc ();
@@ -3177,7 +3217,7 @@ AArch64AsmParser::tryParseGPROperand(OperandVector &Operands) {
3177
3217
// No shift/extend is the default.
3178
3218
if (!ParseShiftExtend || getParser ().getTok ().isNot (AsmToken::Comma)) {
3179
3219
Operands.push_back (AArch64Operand::CreateReg (
3180
- RegNum, RegKind::Scalar, StartLoc, getLoc (), getContext ()));
3220
+ RegNum, RegKind::Scalar, StartLoc, getLoc (), getContext (), EqTy ));
3181
3221
return MatchOperand_Success;
3182
3222
}
3183
3223
@@ -3191,10 +3231,10 @@ AArch64AsmParser::tryParseGPROperand(OperandVector &Operands) {
3191
3231
return Res;
3192
3232
3193
3233
auto Ext = static_cast <AArch64Operand*>(ExtOpnd.back ().get ());
3194
- Operands.push_back (AArch64Operand::CreateReg (RegNum, RegKind::Scalar,
3195
- StartLoc, Ext->getEndLoc (), getContext (),
3196
- Ext->getShiftExtendType (), Ext->getShiftExtendAmount (),
3197
- Ext->hasShiftExtendAmount ()));
3234
+ Operands.push_back (AArch64Operand::CreateReg (
3235
+ RegNum, RegKind::Scalar, StartLoc, Ext->getEndLoc (), getContext (), EqTy ,
3236
+ Ext->getShiftExtendType (), Ext->getShiftExtendAmount (),
3237
+ Ext->hasShiftExtendAmount ()));
3198
3238
3199
3239
return MatchOperand_Success;
3200
3240
}
@@ -3412,6 +3452,30 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
3412
3452
}
3413
3453
}
3414
3454
3455
+ bool AArch64AsmParser::regsEqual (const MCParsedAsmOperand &Op1,
3456
+ const MCParsedAsmOperand &Op2) const {
3457
+ auto &AOp1 = static_cast <const AArch64Operand&>(Op1);
3458
+ auto &AOp2 = static_cast <const AArch64Operand&>(Op2);
3459
+ if (AOp1.getRegEqualityTy () == RegConstraintEqualityTy::EqualsReg &&
3460
+ AOp2.getRegEqualityTy () == RegConstraintEqualityTy::EqualsReg)
3461
+ return MCTargetAsmParser::regsEqual (Op1, Op2);
3462
+
3463
+ assert (AOp1.isScalarReg () && AOp2.isScalarReg () &&
3464
+ " Testing equality of non-scalar registers not supported" );
3465
+
3466
+ // Check if a registers match their sub/super register classes.
3467
+ if (AOp1.getRegEqualityTy () == EqualsSuperReg)
3468
+ return getXRegFromWReg (Op1.getReg ()) == Op2.getReg ();
3469
+ if (AOp1.getRegEqualityTy () == EqualsSubReg)
3470
+ return getWRegFromXReg (Op1.getReg ()) == Op2.getReg ();
3471
+ if (AOp2.getRegEqualityTy () == EqualsSuperReg)
3472
+ return getXRegFromWReg (Op2.getReg ()) == Op1.getReg ();
3473
+ if (AOp2.getRegEqualityTy () == EqualsSubReg)
3474
+ return getWRegFromXReg (Op2.getReg ()) == Op1.getReg ();
3475
+
3476
+ return false ;
3477
+ }
3478
+
3415
3479
// / ParseInstruction - Parse an AArch64 instruction mnemonic followed by its
3416
3480
// / operands.
3417
3481
bool AArch64AsmParser::ParseInstruction (ParseInstructionInfo &Info,
@@ -3765,10 +3829,22 @@ static std::string AArch64MnemonicSpellCheck(StringRef S, uint64_t FBS,
3765
3829
unsigned VariantID = 0 );
3766
3830
3767
3831
bool AArch64AsmParser::showMatchError (SMLoc Loc, unsigned ErrCode,
3832
+ uint64_t ErrorInfo,
3768
3833
OperandVector &Operands) {
3769
3834
switch (ErrCode) {
3770
- case Match_InvalidTiedOperand:
3771
- return Error (Loc, " operand must match destination register" );
3835
+ case Match_InvalidTiedOperand: {
3836
+ RegConstraintEqualityTy EqTy =
3837
+ static_cast <const AArch64Operand &>(*Operands[ErrorInfo])
3838
+ .getRegEqualityTy ();
3839
+ switch (EqTy) {
3840
+ case RegConstraintEqualityTy::EqualsSubReg:
3841
+ return Error (Loc, " operand must be 64-bit form of destination register" );
3842
+ case RegConstraintEqualityTy::EqualsSuperReg:
3843
+ return Error (Loc, " operand must be 32-bit form of destination register" );
3844
+ case RegConstraintEqualityTy::EqualsReg:
3845
+ return Error (Loc, " operand must match destination register" );
3846
+ }
3847
+ }
3772
3848
case Match_MissingFeature:
3773
3849
return Error (Loc,
3774
3850
" instruction requires a CPU feature not currently enabled" );
@@ -4389,7 +4465,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
4389
4465
return Error (IDLoc, Msg);
4390
4466
}
4391
4467
case Match_MnemonicFail:
4392
- return showMatchError (IDLoc, MatchResult, Operands);
4468
+ return showMatchError (IDLoc, MatchResult, ErrorInfo, Operands);
4393
4469
case Match_InvalidOperand: {
4394
4470
SMLoc ErrorLoc = IDLoc;
4395
4471
@@ -4408,7 +4484,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
4408
4484
((AArch64Operand &)*Operands[ErrorInfo]).isTokenSuffix ())
4409
4485
MatchResult = Match_InvalidSuffix;
4410
4486
4411
- return showMatchError (ErrorLoc, MatchResult, Operands);
4487
+ return showMatchError (ErrorLoc, MatchResult, ErrorInfo, Operands);
4412
4488
}
4413
4489
case Match_InvalidTiedOperand:
4414
4490
case Match_InvalidMemoryIndexed1:
@@ -4546,7 +4622,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
4546
4622
SMLoc ErrorLoc = ((AArch64Operand &)*Operands[ErrorInfo]).getStartLoc ();
4547
4623
if (ErrorLoc == SMLoc ())
4548
4624
ErrorLoc = IDLoc;
4549
- return showMatchError (ErrorLoc, MatchResult, Operands);
4625
+ return showMatchError (ErrorLoc, MatchResult, ErrorInfo, Operands);
4550
4626
}
4551
4627
}
4552
4628
0 commit comments