Skip to content

Commit 9a0636a

Browse files
committed
[AArch64][llvm] Add support for optional register in SYS alias instructions
Add support for future AArch64 instructions in the `SYS` alias encoding space which may support an optional register as an operand. For example: ``` SYS #4, c8, c5, #2, {<Xt>} ``` Currently, AArch64 `SYS` alias instructions fall into two categories: * a register value must be present (indicated by any value except `XZR`) * no register value must be present (this value must be `XZR`) This is defined by the optional "needsreg" parameter in TableGen (e.g. see the multiclass definition for TLBI), which defaults to requiring a register operand for the instruction to be valid. Expand the code so that if an optional register operand is specified in TableGen, then if it's not `XZR`, encode this value in the `SYS` alias and for disassembly, print this value if it's not `XZR`. Don't produce an error message if the register operand is missing or unexpected, if it is specified as an optional register. If a mandatory or optional register is not specified in the TableGen (i.e. no register operand should be present), then disassemble to a SYS alias instead if the register value is not xzr/x31 (encoded as 0b11111). For instructions taking no register operands, this is specified in the Arm ARM, with language similar to: ``` Rt should be encoded as 0b11111. If the Rt field is not set to 0b11111, it is CONSTRAINED UNPREDICTABLE whether: * The instruction is UNDEFINED. * The instruction behaves as if the Rt field is set to 0b11111. ``` and since we want to follow "should" directives, and not encourage undefined behaviour, these are not considered valid instructions, so should not be assembled or disassembled as such.
1 parent 25285b3 commit 9a0636a

File tree

3 files changed

+33
-8
lines changed

3 files changed

+33
-8
lines changed

llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,6 +3908,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
39083908
StringRef Op = Tok.getString();
39093909
SMLoc S = Tok.getLoc();
39103910
bool ExpectRegister = true;
3911+
bool OptionalRegister = false;
3912+
bool hasAll = getSTI().hasFeature(AArch64::FeatureAll);
39113913

39123914
if (Mnemonic == "ic") {
39133915
const AArch64IC::IC *IC = AArch64IC::lookupICByName(Op);
@@ -3956,7 +3958,6 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
39563958
if (Op.lower() != "rctx")
39573959
return TokError("invalid operand for prediction restriction instruction");
39583960

3959-
bool hasAll = getSTI().hasFeature(AArch64::FeatureAll);
39603961
bool hasPredres = hasAll || getSTI().hasFeature(AArch64::FeaturePredRes);
39613962
bool hasSpecres2 = hasAll || getSTI().hasFeature(AArch64::FeatureSPECRES2);
39623963

@@ -3989,10 +3990,12 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
39893990
HasRegister = true;
39903991
}
39913992

3992-
if (ExpectRegister && !HasRegister)
3993-
return TokError("specified " + Mnemonic + " op requires a register");
3994-
else if (!ExpectRegister && HasRegister)
3995-
return TokError("specified " + Mnemonic + " op does not use a register");
3993+
if (!OptionalRegister) {
3994+
if (ExpectRegister && !HasRegister)
3995+
return TokError("specified " + Mnemonic + " op requires a register");
3996+
else if (!ExpectRegister && HasRegister)
3997+
return TokError("specified " + Mnemonic + " op does not use a register");
3998+
}
39963999

39974000
if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list"))
39984001
return true;

llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
917917
Encoding |= Op1Val << 11;
918918

919919
bool NeedsReg;
920+
bool OptionalReg = false;
920921
std::string Ins;
921922
std::string Name;
922923

@@ -1017,13 +1018,24 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
10171018
else
10181019
return false;
10191020

1021+
StringRef Reg = getRegisterName(MI->getOperand(4).getReg());
1022+
bool NotXZR = Reg != "xzr";
1023+
1024+
// If a mandatory or optional register is not specified in the TableGen
1025+
// (i.e. no register operand should be present), and the register value
1026+
// is not xzr/x31, then disassemble to a SYS alias instead.
1027+
if (NotXZR && !NeedsReg && !OptionalReg)
1028+
return false;
1029+
10201030
std::string Str = Ins + Name;
10211031
llvm::transform(Str, Str.begin(), ::tolower);
10221032

10231033
O << '\t' << Str;
1024-
if (NeedsReg) {
1025-
O << ", ";
1026-
printRegName(O, MI->getOperand(4).getReg());
1034+
1035+
// For optional registers, don't print the value if it's xzr/x31
1036+
// since this defaults to xzr/x31 if register is not specified.
1037+
if (NeedsReg || (OptionalReg && NotXZR)) {
1038+
O << ", " << Reg;
10271039
}
10281040

10291041
return true;

llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,16 @@ struct SysAliasReg : SysAlias {
409409
: SysAlias(N, E, F), NeedsReg(R) {}
410410
};
411411

412+
struct SysAliasOptionalReg : SysAlias {
413+
bool NeedsReg;
414+
bool OptionalReg;
415+
constexpr SysAliasOptionalReg(const char *N, uint16_t E, bool R, bool O)
416+
: SysAlias(N, E), NeedsReg(R), OptionalReg(O) {}
417+
constexpr SysAliasOptionalReg(const char *N, uint16_t E, bool R, bool O,
418+
FeatureBitset F)
419+
: SysAlias(N, E, F), NeedsReg(R), OptionalReg(O) {}
420+
};
421+
412422
struct SysAliasImm : SysAlias {
413423
uint16_t ImmValue;
414424
constexpr SysAliasImm(const char *N, uint16_t E, uint16_t I)

0 commit comments

Comments
 (0)