Skip to content

[Xtensa] Implement Xtensa Interrupt/Exception/Debug Options. #143820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ class XtensaAsmParser : public MCTargetAsmParser {
#include "XtensaGenAsmMatcher.inc"

ParseStatus parseImmediate(OperandVector &Operands);
ParseStatus parseRegister(OperandVector &Operands, bool AllowParens = false,
bool SR = false);
ParseStatus
parseRegister(OperandVector &Operands, bool AllowParens = false,
bool SR = false,
Xtensa::RegisterAccessType RAType = Xtensa::REGISTER_EXCHANGE);
ParseStatus parseOperandWithModifier(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic,
bool SR = false);
bool
parseOperand(OperandVector &Operands, StringRef Mnemonic, bool SR = false,
Xtensa::RegisterAccessType RAType = Xtensa::REGISTER_EXCHANGE);
bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands);
ParseStatus tryParseRegister(MCRegister &Reg, SMLoc &StartLoc,
Expand Down Expand Up @@ -586,7 +589,8 @@ bool XtensaAsmParser::parseRegister(MCRegister &Reg, SMLoc &StartLoc,
}

ParseStatus XtensaAsmParser::parseRegister(OperandVector &Operands,
bool AllowParens, bool SR) {
bool AllowParens, bool SR,
Xtensa::RegisterAccessType RAType) {
SMLoc FirstS = getLoc();
bool HadParens = false;
AsmToken Buf[2];
Expand Down Expand Up @@ -630,7 +634,7 @@ ParseStatus XtensaAsmParser::parseRegister(OperandVector &Operands,
return ParseStatus::NoMatch;
}

if (!Xtensa::checkRegister(RegNo, getSTI().getFeatureBits()))
if (!Xtensa::checkRegister(RegNo, getSTI().getFeatureBits(), RAType))
return ParseStatus::NoMatch;

if (HadParens)
Expand Down Expand Up @@ -691,7 +695,7 @@ ParseStatus XtensaAsmParser::parseOperandWithModifier(OperandVector &Operands) {
/// from this information, adding to Operands.
/// If operand was parsed, returns false, else true.
bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
bool SR) {
bool SR, Xtensa::RegisterAccessType RAType) {
// Check if the current operand has a custom associated parser, if so, try to
// custom parse the operand, or fallback to the general approach.
ParseStatus Res = MatchOperandParserImpl(Operands, Mnemonic);
Expand All @@ -705,7 +709,7 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
return true;

// Attempt to parse token as register
if (parseRegister(Operands, true, SR).isSuccess())
if (parseRegister(Operands, true, SR, RAType).isSuccess())
return false;

// Attempt to parse token as an immediate
Expand All @@ -719,6 +723,11 @@ bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic,
bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
StringRef Name, SMLoc NameLoc,
OperandVector &Operands) {
Xtensa::RegisterAccessType RAType =
Name[0] == 'w' ? Xtensa::REGISTER_WRITE
: (Name[0] == 'r' ? Xtensa::REGISTER_READ
: Xtensa::REGISTER_EXCHANGE);

if ((Name.starts_with("wsr.") || Name.starts_with("rsr.") ||
Name.starts_with("xsr.")) &&
(Name.size() > 4)) {
Expand All @@ -734,7 +743,7 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
if (RegNo == 0)
RegNo = MatchRegisterAltName(RegName);

if (!Xtensa::checkRegister(RegNo, getSTI().getFeatureBits()))
if (!Xtensa::checkRegister(RegNo, getSTI().getFeatureBits(), RAType))
return Error(NameLoc, "invalid register name");

// Parse operand
Expand All @@ -759,7 +768,7 @@ bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info,
}

// Parse second operand
if (parseOperand(Operands, Name, true))
if (parseOperand(Operands, Name, true, RAType))
return true;
}

Expand Down
56 changes: 47 additions & 9 deletions llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,64 @@ struct DecodeRegister {
};

const DecodeRegister SRDecoderTable[] = {
{Xtensa::LBEG, 0}, {Xtensa::LEND, 1}, {Xtensa::LCOUNT, 2},
{Xtensa::SAR, 3}, {Xtensa::BREG, 4}, {Xtensa::SAR, 3},
{Xtensa::LITBASE, 5}, {Xtensa::ACCLO, 16}, {Xtensa::ACCHI, 17},
{Xtensa::M0, 32}, {Xtensa::M1, 33}, {Xtensa::M2, 34},
{Xtensa::M3, 35}, {Xtensa::WINDOWBASE, 72}, {Xtensa::WINDOWSTART, 73},
{Xtensa::MEMCTL, 97}, {Xtensa::VECBASE, 231}, {Xtensa::MISC0, 244},
{Xtensa::MISC1, 245}, {Xtensa::MISC2, 246}, {Xtensa::MISC3, 247}};
{Xtensa::LBEG, 0}, {Xtensa::LEND, 1},
{Xtensa::LCOUNT, 2}, {Xtensa::SAR, 3},
{Xtensa::BREG, 4}, {Xtensa::LITBASE, 5},
{Xtensa::ACCLO, 16}, {Xtensa::ACCHI, 17},
{Xtensa::M0, 32}, {Xtensa::M1, 33},
{Xtensa::M2, 34}, {Xtensa::M3, 35},
{Xtensa::WINDOWBASE, 72}, {Xtensa::WINDOWSTART, 73},
{Xtensa::IBREAKENABLE, 96}, {Xtensa::MEMCTL, 97},
{Xtensa::DDR, 104}, {Xtensa::IBREAKA0, 128},
{Xtensa::IBREAKA1, 129}, {Xtensa::DBREAKA0, 144},
{Xtensa::DBREAKA1, 145}, {Xtensa::DBREAKC0, 160},
{Xtensa::DBREAKC1, 161}, {Xtensa::CONFIGID0, 176},
{Xtensa::EPC1, 177}, {Xtensa::EPC2, 178},
{Xtensa::EPC3, 179}, {Xtensa::EPC4, 180},
{Xtensa::EPC5, 181}, {Xtensa::EPC6, 182},
{Xtensa::EPC7, 183}, {Xtensa::DEPC, 192},
{Xtensa::EPS2, 194}, {Xtensa::EPS3, 195},
{Xtensa::EPS4, 196}, {Xtensa::EPS5, 197},
{Xtensa::EPS6, 198}, {Xtensa::EPS7, 199},
{Xtensa::CONFIGID1, 208}, {Xtensa::EXCSAVE1, 209},
{Xtensa::EXCSAVE2, 210}, {Xtensa::EXCSAVE3, 211},
{Xtensa::EXCSAVE4, 212}, {Xtensa::EXCSAVE5, 213},
{Xtensa::EXCSAVE6, 214}, {Xtensa::EXCSAVE7, 215},
{Xtensa::CPENABLE, 224}, {Xtensa::INTERRUPT, 226},
{Xtensa::INTCLEAR, 227}, {Xtensa::INTENABLE, 228},
{Xtensa::PS, 230}, {Xtensa::VECBASE, 231},
{Xtensa::EXCCAUSE, 232}, {Xtensa::DEBUGCAUSE, 233},
{Xtensa::CCOUNT, 234}, {Xtensa::PRID, 235},
{Xtensa::ICOUNT, 236}, {Xtensa::ICOUNTLEVEL, 237},
{Xtensa::EXCVADDR, 238}, {Xtensa::CCOMPARE0, 240},
{Xtensa::CCOMPARE1, 241}, {Xtensa::CCOMPARE2, 242},
{Xtensa::MISC0, 244}, {Xtensa::MISC1, 245},
{Xtensa::MISC2, 246}, {Xtensa::MISC3, 247}};

static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 255)
return MCDisassembler::Fail;

Xtensa::RegisterAccessType RAType =
Inst.getOpcode() == Xtensa::WSR
? Xtensa::REGISTER_WRITE
: (Inst.getOpcode() == Xtensa::RSR ? Xtensa::REGISTER_READ
: Xtensa::REGISTER_EXCHANGE);

for (unsigned i = 0; i < std::size(SRDecoderTable); i++) {
if (SRDecoderTable[i].RegNo == RegNo) {
MCPhysReg Reg = SRDecoderTable[i].Reg;

if (!Xtensa::checkRegister(Reg,
Decoder->getSubtargetInfo().getFeatureBits()))
// Handle special case. The INTERRUPT/INTSET registers use the same
// encoding, but INTERRUPT used for read and INTSET for write.
if (Reg == Xtensa::INTERRUPT && RAType == Xtensa::REGISTER_WRITE) {
Reg = Xtensa::INTSET;
}

if (!Xtensa::checkRegister(
Reg, Decoder->getSubtargetInfo().getFeatureBits(), RAType))
return MCDisassembler::Fail;

Inst.addOperand(MCOperand::createReg(Reg));
Expand Down
89 changes: 88 additions & 1 deletion llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,95 @@ bool Xtensa::isValidAddrOffsetForOpcode(unsigned Opcode, int64_t Offset) {
}

// Verify Special Register
bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits,
RegisterAccessType RAType) {
switch (RegNo) {
case Xtensa::BREG:
return FeatureBits[Xtensa::FeatureBoolean];
case Xtensa::CCOUNT:
case Xtensa::CCOMPARE0:
if (FeatureBits[Xtensa::FeatureTimers1])
return true;
LLVM_FALLTHROUGH;
case Xtensa::CCOMPARE1:
if (FeatureBits[Xtensa::FeatureTimers2])
return true;
LLVM_FALLTHROUGH;
case Xtensa::CCOMPARE2:
if (FeatureBits[Xtensa::FeatureTimers3])
return true;
return false;
case Xtensa::CONFIGID0:
return RAType != Xtensa::REGISTER_EXCHANGE;
case Xtensa::CONFIGID1:
return RAType == Xtensa::REGISTER_READ;
case Xtensa::CPENABLE:
return FeatureBits[Xtensa::FeatureCoprocessor];
case Xtensa::DEBUGCAUSE:
return RAType == Xtensa::REGISTER_READ && FeatureBits[Xtensa::FeatureDebug];
case Xtensa::DEPC:
case Xtensa::EPC1:
case Xtensa::EXCCAUSE:
case Xtensa::EXCSAVE1:
case Xtensa::EXCVADDR:
return FeatureBits[Xtensa::FeatureException];
LLVM_FALLTHROUGH;
case Xtensa::EPC2:
case Xtensa::EPS2:
case Xtensa::EXCSAVE2:
if (FeatureBits[Xtensa::FeatureHighPriInterrupts])
return true;
LLVM_FALLTHROUGH;
case Xtensa::EPC3:
case Xtensa::EPS3:
case Xtensa::EXCSAVE3:
if (FeatureBits[Xtensa::FeatureHighPriInterruptsLevel3])
return true;
LLVM_FALLTHROUGH;
case Xtensa::EPC4:
case Xtensa::EPS4:
case Xtensa::EXCSAVE4:
if (FeatureBits[Xtensa::FeatureHighPriInterruptsLevel4])
return true;
LLVM_FALLTHROUGH;
case Xtensa::EPC5:
case Xtensa::EPS5:
case Xtensa::EXCSAVE5:
if (FeatureBits[Xtensa::FeatureHighPriInterruptsLevel5])
return true;
LLVM_FALLTHROUGH;
case Xtensa::EPC6:
case Xtensa::EPS6:
case Xtensa::EXCSAVE6:
if (FeatureBits[Xtensa::FeatureHighPriInterruptsLevel6])
return true;
LLVM_FALLTHROUGH;
case Xtensa::EPC7:
case Xtensa::EPS7:
case Xtensa::EXCSAVE7:
if (FeatureBits[Xtensa::FeatureHighPriInterruptsLevel7])
return true;
return false;
case Xtensa::INTENABLE:
return FeatureBits[Xtensa::FeatureInterrupt];
case Xtensa::INTERRUPT:
return RAType == Xtensa::REGISTER_READ &&
FeatureBits[Xtensa::FeatureInterrupt];
case Xtensa::INTSET:
case Xtensa::INTCLEAR:
return RAType == Xtensa::REGISTER_WRITE &&
FeatureBits[Xtensa::FeatureInterrupt];
case Xtensa::ICOUNT:
case Xtensa::ICOUNTLEVEL:
case Xtensa::IBREAKENABLE:
case Xtensa::DDR:
case Xtensa::IBREAKA0:
case Xtensa::IBREAKA1:
case Xtensa::DBREAKA0:
case Xtensa::DBREAKA1:
case Xtensa::DBREAKC0:
case Xtensa::DBREAKC1:
return FeatureBits[Xtensa::FeatureDebug];
case Xtensa::LBEG:
case Xtensa::LEND:
case Xtensa::LCOUNT:
Expand All @@ -99,6 +184,8 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
case Xtensa::MISC2:
case Xtensa::MISC3:
return FeatureBits[Xtensa::FeatureMiscSR];
case Xtensa::PRID:
return RAType == Xtensa::REGISTER_READ && FeatureBits[Xtensa::FeaturePRID];
case Xtensa::VECBASE:
return FeatureBits[Xtensa::FeatureRelocatableVector];
case Xtensa::WINDOWBASE:
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,15 @@ bool isValidAddrOffset(int Scale, int64_t OffsetVal);
// Check address offset for load/store instructions.
bool isValidAddrOffsetForOpcode(unsigned Opcode, int64_t Offset);

enum RegisterAccessType {
REGISTER_WRITE = 1,
REGISTER_READ = 2,
REGISTER_EXCHANGE = 3
};

// Verify if it's correct to use a special register.
bool checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits);
bool checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits,
RegisterAccessType RA);
} // namespace Xtensa
} // end namespace llvm

Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/Target/Xtensa/XtensaFeatures.td
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,43 @@ def FeatureDataCache : SubtargetFeature<"dcache", "HasDataCache", "true",
"Enable Xtensa Data Cache option">;
def HasDataCache : Predicate<"Subtarget->hasDataCache()">,
AssemblerPredicate<(all_of FeatureDataCache)>;

// Xtensa Interrupts Options.
def FeatureHighPriInterrupts : SubtargetFeature<"highpriinterrupts",
"HasHighPriInterrupts", "true",
"Enable Xtensa HighPriInterrupts option">;
def HasHighPriInterrupts : Predicate<"Subtarget->hasHighPriInterrupts()">,
AssemblerPredicate<(all_of FeatureHighPriInterrupts)>;

foreach i = {3-7} in
def FeatureHighPriInterruptsLevel#i : SubtargetFeature<"highpriinterrupts-level"#i,
"HasHighPriInterruptsLevel"#i#"", "true", "Enable Xtensa HighPriInterrupts Level"#i, [FeatureHighPriInterrupts]>;

def FeatureInterrupt : SubtargetFeature<"interrupt", "HasInterrupt", "true",
"Enable Xtensa Interrupt option">;
def HasInterrupt : Predicate<"Subtarget->hasInterrupt()">,
AssemblerPredicate<(all_of FeatureInterrupt)>;

def FeatureException : SubtargetFeature<"exception", "HasException", "true",
"Enable Xtensa Exception option">;
def HasException : Predicate<"Subtarget->hasException()">,
AssemblerPredicate<(all_of FeatureException)>;

def FeatureDebug : SubtargetFeature<"debug", "HasDebug", "true",
"Enable Xtensa Debug option">;
def HasDebug : Predicate<"Subtarget->hasDebug()">,
AssemblerPredicate<(all_of FeatureDebug)>;

foreach i = {1-3} in
def FeatureTimers#i : SubtargetFeature<"timers"#i,
"HasTimers"#i#"", "true", "Enable Xtensa Timers "#i>;

def FeaturePRID : SubtargetFeature<"prid", "HasPRID", "true",
"Enable Xtensa Processor ID option">;
def HasPRID : Predicate<"Subtarget->hasPRID()">,
AssemblerPredicate<(all_of FeaturePRID)>;

def FeatureCoprocessor : SubtargetFeature<"coprocessor", "HasCoprocessor", "true",
"Enable Xtensa Coprocessor option">;
def HasCoprocessor : Predicate<"Subtarget->hasCoprocessor()">,
AssemblerPredicate<(all_of FeatureCoprocessor)>;
Loading