Skip to content

Commit ad45eb4

Browse files
[ARM] Fix problems with register list in vscclrm (#111825)
The register list in vscclrm is unusual in three ways: * The encoded size can be zero, meaning the list contains only vpr. * Double-precision registers past d15 are permitted even when the subtarget doesn't have them, they are instead ignored when the instruction executes. * The single-precision variant allows double-precision registers d16 onwards, which are encoded as a pair of single-precision registers. Fixing this also incidentally changes a vlldm/vlstm error message: when the first register is in the range d16-d31 we now get the "operand must be exactly..." error instead of "register expected".
1 parent b091701 commit ad45eb4

File tree

8 files changed

+202
-38
lines changed

8 files changed

+202
-38
lines changed

llvm/lib/Target/ARM/ARMRegisterInfo.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,9 @@ def FPEXC : ARMReg<8, "fpexc">;
200200
def FPINST : ARMReg<9, "fpinst">;
201201
def FPINST2 : ARMReg<10, "fpinst2">;
202202
// These encodings aren't actual instruction encodings, their encoding depends
203-
// on the instruction they are used in and for VPR 32 was chosen such that it
203+
// on the instruction they are used in and for VPR 64 was chosen such that it
204204
// always comes last in spr_reglist_with_vpr.
205-
def VPR : ARMReg<32, "vpr">;
205+
def VPR : ARMReg<64, "vpr">;
206206
def FPSCR_NZCVQC
207207
: ARMReg<2, "fpscr_nzcvqc">;
208208
def P0 : ARMReg<13, "p0">;

llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,8 @@ class ARMAsmParser : public MCTargetAsmParser {
446446
int tryParseShiftRegister(OperandVector &);
447447
std::optional<ARM_AM::ShiftOpc> tryParseShiftToken();
448448
bool parseRegisterList(OperandVector &, bool EnforceOrder = true,
449-
bool AllowRAAC = false,
450-
bool AllowOutOfBoundReg = false);
449+
bool AllowRAAC = false, bool IsLazyLoadStore = false,
450+
bool IsVSCCLRM = false);
451451
bool parseMemory(OperandVector &);
452452
bool parseOperand(OperandVector &, StringRef Mnemonic);
453453
bool parseImmExpr(int64_t &Out);
@@ -3811,6 +3811,10 @@ class ARMOperand : public MCParsedAsmOperand {
38113811
Kind = k_FPSRegisterListWithVPR;
38123812
else
38133813
Kind = k_SPRRegisterList;
3814+
} else if (Regs.front().second == ARM::VPR) {
3815+
assert(Regs.size() == 1 &&
3816+
"Register list starting with VPR expected to only contain VPR");
3817+
Kind = k_FPSRegisterListWithVPR;
38143818
}
38153819

38163820
if (Kind == k_RegisterList && Regs.back().second == ARM::APSR)
@@ -4608,7 +4612,8 @@ insertNoDuplicates(SmallVectorImpl<std::pair<unsigned, MCRegister>> &Regs,
46084612

46094613
/// Parse a register list.
46104614
bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
4611-
bool AllowRAAC, bool AllowOutOfBoundReg) {
4615+
bool AllowRAAC, bool IsLazyLoadStore,
4616+
bool IsVSCCLRM) {
46124617
MCAsmParser &Parser = getParser();
46134618
if (Parser.getTok().isNot(AsmToken::LCurly))
46144619
return TokError("Token is not a Left Curly Brace");
@@ -4618,15 +4623,23 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
46184623

46194624
// Check the first register in the list to see what register class
46204625
// this is a list of.
4621-
MCRegister Reg = tryParseRegister();
4626+
bool AllowOutOfBoundReg = IsLazyLoadStore || IsVSCCLRM;
4627+
MCRegister Reg = tryParseRegister(AllowOutOfBoundReg);
46224628
if (!Reg)
46234629
return Error(RegLoc, "register expected");
46244630
if (!AllowRAAC && Reg == ARM::RA_AUTH_CODE)
46254631
return Error(RegLoc, "pseudo-register not allowed");
4626-
// The reglist instructions have at most 16 registers, so reserve
4632+
// The reglist instructions have at most 32 registers, so reserve
46274633
// space for that many.
46284634
int EReg = 0;
4629-
SmallVector<std::pair<unsigned, MCRegister>, 16> Registers;
4635+
SmallVector<std::pair<unsigned, MCRegister>, 32> Registers;
4636+
4637+
// Single-precision VSCCLRM can have double-precision registers in the
4638+
// register list. When VSCCLRMAdjustEncoding is true then we've switched from
4639+
// single-precision to double-precision and we pretend that these registers
4640+
// are encoded as S32 onwards, which we can do by adding 16 to the encoding
4641+
// value.
4642+
bool VSCCLRMAdjustEncoding = false;
46304643

46314644
// Allow Q regs and just interpret them as the two D sub-registers.
46324645
if (ARMMCRegisterClasses[ARM::QPRRegClassID].contains(Reg)) {
@@ -4645,6 +4658,8 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
46454658
RC = &ARMMCRegisterClasses[ARM::SPRRegClassID];
46464659
else if (ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains(Reg))
46474660
RC = &ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID];
4661+
else if (Reg == ARM::VPR)
4662+
RC = &ARMMCRegisterClasses[ARM::FPWithVPRRegClassID];
46484663
else
46494664
return Error(RegLoc, "invalid register in register list");
46504665

@@ -4685,6 +4700,8 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
46854700
while (Reg != EndReg) {
46864701
Reg = getNextRegister(Reg);
46874702
EReg = MRI->getEncodingValue(Reg);
4703+
if (VSCCLRMAdjustEncoding)
4704+
EReg += 16;
46884705
if (!insertNoDuplicates(Registers, EReg, Reg)) {
46894706
Warning(AfterMinusLoc, StringRef("duplicated register (") +
46904707
ARMInstPrinter::getRegisterName(Reg) +
@@ -4696,6 +4713,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
46964713
Parser.Lex(); // Eat the comma.
46974714
RegLoc = Parser.getTok().getLoc();
46984715
MCRegister OldReg = Reg;
4716+
int EOldReg = EReg;
46994717
const AsmToken RegTok = Parser.getTok();
47004718
Reg = tryParseRegister(AllowOutOfBoundReg);
47014719
if (!Reg)
@@ -4727,6 +4745,12 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
47274745
}
47284746
continue;
47294747
}
4748+
// VSCCLRM can switch from single-precision to double-precision only when
4749+
// S31 is followed by D16.
4750+
if (IsVSCCLRM && OldReg == ARM::S31 && Reg == ARM::D16) {
4751+
VSCCLRMAdjustEncoding = true;
4752+
RC = &ARMMCRegisterClasses[ARM::FPWithVPRRegClassID];
4753+
}
47304754
// The register must be in the same register class as the first.
47314755
if ((Reg == ARM::RA_AUTH_CODE &&
47324756
RC != &ARMMCRegisterClasses[ARM::GPRRegClassID]) ||
@@ -4736,8 +4760,10 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
47364760
// exception is CLRM, which is order-independent anyway, so
47374761
// there's no potential for confusion if you write clrm {r2,r1}
47384762
// instead of clrm {r1,r2}.
4739-
if (EnforceOrder &&
4740-
MRI->getEncodingValue(Reg) < MRI->getEncodingValue(OldReg)) {
4763+
EReg = MRI->getEncodingValue(Reg);
4764+
if (VSCCLRMAdjustEncoding)
4765+
EReg += 16;
4766+
if (EnforceOrder && EReg < EOldReg) {
47414767
if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg))
47424768
Warning(RegLoc, "register list not in ascending order");
47434769
else if (!ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains(Reg))
@@ -4746,9 +4772,9 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder,
47464772
// VFP register lists must also be contiguous.
47474773
if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] &&
47484774
RC != &ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID] &&
4749-
Reg != OldReg + 1)
4775+
EReg != EOldReg + 1)
47504776
return Error(RegLoc, "non-contiguous register range");
4751-
EReg = MRI->getEncodingValue(Reg);
4777+
47524778
if (!insertNoDuplicates(Registers, EReg, Reg)) {
47534779
Warning(RegLoc, "duplicated register (" + RegTok.getString() +
47544780
") in register list");
@@ -6336,9 +6362,10 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
63366362
case AsmToken::LBrac:
63376363
return parseMemory(Operands);
63386364
case AsmToken::LCurly: {
6339-
bool AllowOutOfBoundReg = Mnemonic == "vlldm" || Mnemonic == "vlstm";
6365+
bool IsLazyLoadStore = Mnemonic == "vlldm" || Mnemonic == "vlstm";
6366+
bool IsVSCCLRM = Mnemonic == "vscclrm";
63406367
return parseRegisterList(Operands, !Mnemonic.starts_with("clr"), false,
6341-
AllowOutOfBoundReg);
6368+
IsLazyLoadStore, IsVSCCLRM);
63426369
}
63436370
case AsmToken::Dollar:
63446371
case AsmToken::Hash: {

llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,15 +1529,19 @@ static const uint16_t DPRDecoderTable[] = {
15291529
ARM::D28, ARM::D29, ARM::D30, ARM::D31
15301530
};
15311531

1532-
static DecodeStatus DecodeDPRRegisterClass(MCInst &Inst, unsigned RegNo,
1533-
uint64_t Address,
1534-
const MCDisassembler *Decoder) {
1532+
// Does this instruction/subtarget permit use of registers d16-d31?
1533+
static bool PermitsD32(const MCInst &Inst, const MCDisassembler *Decoder) {
1534+
if (Inst.getOpcode() == ARM::VSCCLRMD || Inst.getOpcode() == ARM::VSCCLRMS)
1535+
return true;
15351536
const FeatureBitset &featureBits =
15361537
((const MCDisassembler*)Decoder)->getSubtargetInfo().getFeatureBits();
1538+
return featureBits[ARM::FeatureD32];
1539+
}
15371540

1538-
bool hasD32 = featureBits[ARM::FeatureD32];
1539-
1540-
if (RegNo > 31 || (!hasD32 && RegNo > 15))
1541+
static DecodeStatus DecodeDPRRegisterClass(MCInst &Inst, unsigned RegNo,
1542+
uint64_t Address,
1543+
const MCDisassembler *Decoder) {
1544+
if (RegNo > (PermitsD32(Inst, Decoder) ? 31 : 15))
15411545
return MCDisassembler::Fail;
15421546

15431547
unsigned Register = DPRDecoderTable[RegNo];
@@ -1816,10 +1820,11 @@ static DecodeStatus DecodeDPRRegListOperand(MCInst &Inst, unsigned Val,
18161820
unsigned regs = fieldFromInstruction(Val, 1, 7);
18171821

18181822
// In case of unpredictable encoding, tweak the operands.
1819-
if (regs == 0 || regs > 16 || (Vd + regs) > 32) {
1820-
regs = Vd + regs > 32 ? 32 - Vd : regs;
1823+
unsigned MaxReg = PermitsD32(Inst, Decoder) ? 32 : 16;
1824+
if (regs == 0 || (Vd + regs) > MaxReg) {
1825+
regs = Vd + regs > MaxReg ? MaxReg - Vd : regs;
18211826
regs = std::max( 1u, regs);
1822-
regs = std::min(16u, regs);
1827+
regs = std::min(MaxReg, regs);
18231828
S = MCDisassembler::SoftFail;
18241829
}
18251830

@@ -6447,20 +6452,31 @@ static DecodeStatus DecodeVSCCLRM(MCInst &Inst, unsigned Insn, uint64_t Address,
64476452

64486453
Inst.addOperand(MCOperand::createImm(ARMCC::AL));
64496454
Inst.addOperand(MCOperand::createReg(0));
6450-
if (Inst.getOpcode() == ARM::VSCCLRMD) {
6451-
unsigned reglist = (fieldFromInstruction(Insn, 1, 7) << 1) |
6452-
(fieldFromInstruction(Insn, 12, 4) << 8) |
6455+
unsigned regs = fieldFromInstruction(Insn, 0, 8);
6456+
if (regs == 0) {
6457+
// Register list contains only VPR
6458+
} else if (Inst.getOpcode() == ARM::VSCCLRMD) {
6459+
unsigned reglist = regs | (fieldFromInstruction(Insn, 12, 4) << 8) |
64536460
(fieldFromInstruction(Insn, 22, 1) << 12);
64546461
if (!Check(S, DecodeDPRRegListOperand(Inst, reglist, Address, Decoder))) {
64556462
return MCDisassembler::Fail;
64566463
}
64576464
} else {
6458-
unsigned reglist = fieldFromInstruction(Insn, 0, 8) |
6459-
(fieldFromInstruction(Insn, 22, 1) << 8) |
6460-
(fieldFromInstruction(Insn, 12, 4) << 9);
6461-
if (!Check(S, DecodeSPRRegListOperand(Inst, reglist, Address, Decoder))) {
6462-
return MCDisassembler::Fail;
6463-
}
6465+
unsigned Vd = (fieldFromInstruction(Insn, 12, 4) << 1) |
6466+
fieldFromInstruction(Insn, 22, 1);
6467+
// Registers past s31 are permitted and treated as being half of a d
6468+
// register, though both halves of each d register must be present.
6469+
unsigned max_reg = Vd + regs;
6470+
if (max_reg > 64 || (max_reg > 32 && (max_reg & 1)))
6471+
S = MCDisassembler::SoftFail;
6472+
unsigned max_sreg = std::min(32u, max_reg);
6473+
unsigned max_dreg = std::min(32u, max_reg / 2);
6474+
for (unsigned i = Vd; i < max_sreg; ++i)
6475+
if (!Check(S, DecodeSPRRegisterClass(Inst, i, Address, Decoder)))
6476+
return MCDisassembler::Fail;
6477+
for (unsigned i = 16; i < max_dreg; ++i)
6478+
if (!Check(S, DecodeDPRRegisterClass(Inst, i, Address, Decoder)))
6479+
return MCDisassembler::Fail;
64646480
}
64656481
Inst.addOperand(MCOperand::createReg(ARM::VPR));
64666482

llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ void ARMInstPrinter::printPKHASRShiftImm(const MCInst *MI, unsigned OpNum,
851851
void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum,
852852
const MCSubtargetInfo &STI,
853853
raw_ostream &O) {
854-
if (MI->getOpcode() != ARM::t2CLRM) {
854+
if (MI->getOpcode() != ARM::t2CLRM && MI->getOpcode() != ARM::VSCCLRMS) {
855855
assert(is_sorted(drop_begin(*MI, OpNum),
856856
[&](const MCOperand &LHS, const MCOperand &RHS) {
857857
return MRI.getEncodingValue(LHS.getReg()) <

llvm/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,15 +1743,28 @@ getRegisterListOpValue(const MCInst &MI, unsigned Op,
17431743

17441744
unsigned Binary = 0;
17451745

1746-
if (SPRRegs || DPRRegs) {
1746+
if (SPRRegs || DPRRegs || Reg == ARM::VPR) {
17471747
// VLDM/VSTM/VSCCLRM
17481748
unsigned RegNo = CTX.getRegisterInfo()->getEncodingValue(Reg);
17491749
unsigned NumRegs = (MI.getNumOperands() - Op) & 0xff;
17501750
Binary |= (RegNo & 0x1f) << 8;
17511751

1752-
// Ignore VPR
1753-
if (MI.getOpcode() == ARM::VSCCLRMD || MI.getOpcode() == ARM::VSCCLRMS)
1752+
if (MI.getOpcode() == ARM::VSCCLRMD)
1753+
// Ignore VPR
17541754
--NumRegs;
1755+
else if (MI.getOpcode() == ARM::VSCCLRMS) {
1756+
// The register list can contain both S registers and D registers, with D
1757+
// registers counting as two registers. VPR doesn't count towards the
1758+
// number of registers.
1759+
NumRegs = 0;
1760+
for (unsigned I = Op, E = MI.getNumOperands(); I < E; ++I) {
1761+
Reg = MI.getOperand(I).getReg();
1762+
if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg))
1763+
NumRegs += 1;
1764+
else if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Reg))
1765+
NumRegs += 2;
1766+
}
1767+
}
17551768
if (SPRRegs)
17561769
Binary |= NumRegs;
17571770
else

llvm/test/MC/ARM/vlstm-vlldm-diag.s

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ vlldm r8, {d3 - d31}
3636
// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2)
3737
// ERR-NEXT: vlldm r8, {d3 - d31}
3838

39+
vlstm r8, {d31}
40+
// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2)
41+
// ERR-NEXT: vlstm r8, {d31}
42+
43+
vlldm r8, {d31}
44+
// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2)
45+
// ERR-NEXT: vlldm r8, {d31}
46+
3947
vlstm r8, {d0 - d35}
4048
// ERR: error: register expected
4149
// ERR-NEXT: vlstm r8, {d0 - d35}

llvm/test/MC/ARM/vscclrm-asm.s

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,62 @@ it hi
3535
// CHECK: vscclrmhi {s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31, vpr} @ encoding: [0xdf,0xec,0x1d,0x1a]
3636
vscclrmhi {s3-s31, vpr}
3737

38+
// CHECK: vscclrm {vpr} @ encoding: [0x9f,0xec,0x00,0x0a]
39+
vscclrm {vpr}
40+
41+
// CHECK: vscclrm {d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31, vpr} @ encoding: [0x9f,0xec,0x40,0x0b]
42+
vscclrm {d0-d31, vpr}
43+
44+
// CHECK: vscclrm {d31, vpr} @ encoding: [0xdf,0xec,0x02,0xfb]
45+
vscclrm {d31, vpr}
46+
47+
// CHECK: vscclrm {s31, d16, vpr} @ encoding: [0xdf,0xec,0x03,0xfa]
48+
vscclrm {s31, d16, vpr}
49+
50+
// CHECK: vscclrm {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31, vpr} @ encoding: [0x9f,0xec,0x40,0x0a]
51+
vscclrm {s0-s31, d16-d31, vpr}
52+
53+
// CHECK: vscclrm {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31, vpr} @ encoding: [0x9f,0xec,0x40,0x0a]
54+
vscclrm {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30, s31, d16, d17, d18, d19, d20, d21, d22, d23, d24, d25, d26, d27, d28, d29, d30, d31, vpr}
55+
3856
// ERROR: non-contiguous register range
3957
vscclrm {s0, s3-s4, vpr}
4058

59+
// ERROR: non-contiguous register range
60+
vscclrm {s31, d16, s30, vpr}
61+
4162
// ERROR: register expected
4263
vscclrm {s32, vpr}
4364

65+
// ERROR: register expected
66+
vscclrm {d32, vpr}
67+
68+
// ERROR: register expected
69+
vscclrm {s31-s32, vpr}
70+
71+
// ERROR: register expected
72+
vscclrm {d31-d32, vpr}
73+
4474
// ERROR: invalid operand for instruction
4575
vscclrm {s0-s1}
76+
77+
// ERROR: register list not in ascending order
78+
vscclrm {vpr, s0}
79+
80+
// ERROR: register list not in ascending order
81+
vscclrm {vpr, s31}
82+
83+
// ERROR: register list not in ascending order
84+
vscclrm {vpr, d0}
85+
86+
// ERROR: register list not in ascending order
87+
vscclrm {vpr, d31}
88+
89+
// ERROR: invalid register in register list
90+
vscclrm {s0, d0, vpr}
91+
92+
// ERROR: invalid register in register list
93+
vscclrm {s0, d1, vpr}
94+
95+
// ERROR: invalid register in register list
96+
vscclrm {d16, s31, vpr}

0 commit comments

Comments
 (0)