Skip to content

[Xtensa] Implement Windowed Register Option. #121118

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

Merged
merged 4 commits into from
Jan 21, 2025

Conversation

andreisfr
Copy link
Contributor

No description provided.

@llvmbot llvmbot added mc Machine (object) code backend:Xtensa labels Dec 25, 2024
@andreisfr andreisfr requested review from arsenm and MaskRay December 25, 2024 23:24
@llvmbot
Copy link
Member

llvmbot commented Dec 25, 2024

@llvm/pr-subscribers-mc

@llvm/pr-subscribers-backend-xtensa

Author: Andrei Safronov (andreisfr)

Changes

Patch is 25.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/121118.diff

15 Files Affected:

  • (modified) llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp (+16)
  • (modified) llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp (+28-1)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp (+34)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h (+3)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp (+52)
  • (modified) llvm/lib/Target/Xtensa/Xtensa.td (+8-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaInstrInfo.td (+121)
  • (modified) llvm/lib/Target/Xtensa/XtensaOperands.td (+21)
  • (modified) llvm/lib/Target/Xtensa/XtensaRegisterInfo.td (+5-1)
  • (modified) llvm/lib/Target/Xtensa/XtensaSubtarget.h (+5)
  • (added) llvm/test/MC/Disassembler/Xtensa/windowed.txt (+64)
  • (added) llvm/test/MC/Disassembler/Xtensa/windowed_code_density.txt (+12)
  • (added) llvm/test/MC/Xtensa/windowed.s (+80)
  • (added) llvm/test/MC/Xtensa/windowed_code_density.s (+14)
  • (added) llvm/test/MC/Xtensa/windowed_invalid.s (+15)
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 731f9535ca251f..fc1f214efe6673 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -181,6 +181,8 @@ struct XtensaOperand : public MCParsedAsmOperand {
            ((cast<MCConstantExpr>(getImm())->getValue() & 0x3) == 0);
   }
 
+  bool isentry_imm12() const { return isImm(0, 32760); }
+
   bool isUimm4() const { return isImm(0, 15); }
 
   bool isUimm5() const { return isImm(0, 31); }
@@ -198,6 +200,11 @@ struct XtensaOperand : public MCParsedAsmOperand {
 
   bool isImm32n_95() const { return isImm(-32, 95); }
 
+  bool isImm64n_4n() const {
+    return isImm(-64, -4) &&
+           ((dyn_cast<MCConstantExpr>(getImm())->getValue() & 0x3) == 0);
+  }
+
   bool isB4const() const {
     if (Kind != Immediate)
       return false;
@@ -491,6 +498,12 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_InvalidImm32n_95:
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [-32, 95]");
+  case Match_InvalidImm64n_4n:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [-64, -4]");
+  case Match_InvalidImm8n_7:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [-8, 7]");
   case Match_InvalidShimm1_31:
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [1, 31]");
@@ -515,6 +528,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [0, 60], first 2 bits "
                  "should be zero");
+  case Match_Invalidentry_imm12:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [0, 32760]");
   }
 
   report_fatal_error("Unknown match type detected!");
diff --git a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
index c11c4b7038bdb7..1f4197f573ce6a 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -73,7 +73,8 @@ static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo,
   return MCDisassembler::Success;
 }
 
-static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3};
+static const unsigned SRDecoderTable[] = {
+    Xtensa::SAR, 3, Xtensa::WINDOWBASE, 72, Xtensa::WINDOWSTART, 73};
 
 static DecodeStatus DecodeSRRegisterClass(MCInst &Inst, uint64_t RegNo,
                                           uint64_t Address,
@@ -210,6 +211,32 @@ static DecodeStatus decodeImm32n_95Operand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeImm8n_7Operand(MCInst &Inst, uint64_t Imm,
+                                         int64_t Address, const void *Decoder) {
+  assert(isUInt<4>(Imm) && "Invalid immediate");
+  if (Imm > 7)
+    Inst.addOperand(MCOperand::createImm(Imm - 16));
+  else
+    Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeImm64n_4nOperand(MCInst &Inst, uint64_t Imm,
+                                           int64_t Address,
+                                           const void *Decoder) {
+  assert(isUInt<6>(Imm) && ((Imm & 0x3) == 0) && "Invalid immediate");
+  Inst.addOperand(MCOperand::createImm((~0x3f) | (Imm)));
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus decodeEntry_Imm12OpValue(MCInst &Inst, uint64_t Imm,
+                                             int64_t Address,
+                                             const void *Decoder) {
+  assert(isUInt<15>(Imm) && ((Imm & 0x7) == 0) && "Invalid immediate");
+  Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeShimm1_31Operand(MCInst &Inst, uint64_t Imm,
                                            int64_t Address,
                                            const void *Decoder) {
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index df8a0854f06f41..868c7f6c0b9c3c 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -264,6 +264,28 @@ void XtensaInstPrinter::printImm32n_95_AsmOperand(const MCInst *MI, int OpNum,
     printOperand(MI, OpNum, O);
 }
 
+void XtensaInstPrinter::printImm8n_7_AsmOperand(const MCInst *MI, int OpNum,
+                                                raw_ostream &O) {
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Value = MI->getOperand(OpNum).getImm();
+    assert((Value >= -8 && Value <= 7) &&
+           "Invalid argument, value must be in ranges <-8,7>");
+    O << Value;
+  } else
+    printOperand(MI, OpNum, O);
+}
+
+void XtensaInstPrinter::printImm64n_4n_AsmOperand(const MCInst *MI, int OpNum,
+                                                  raw_ostream &O) {
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Value = MI->getOperand(OpNum).getImm();
+    assert((Value >= -64 && Value <= -4) & ((Value & 0x3) == 0) &&
+           "Invalid argument, value must be in ranges <-64,-4>");
+    O << Value;
+  } else
+    printOperand(MI, OpNum, O);
+}
+
 void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum,
                                                   raw_ostream &O) {
   if (MI->getOperand(OpNum).isImm()) {
@@ -309,6 +331,18 @@ void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum,
     printOperand(MI, OpNum, O);
 }
 
+void XtensaInstPrinter::printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum,
+                                                    raw_ostream &O) {
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Value = MI->getOperand(OpNum).getImm();
+    assert((Value >= 0 && Value <= 32760) &&
+           "Invalid argument, value must be multiples of eight in range "
+           "<0,32760>");
+    O << Value;
+  } else
+    printOperand(MI, OpNum, O);
+}
+
 void XtensaInstPrinter::printB4const_AsmOperand(const MCInst *MI, int OpNum,
                                                 raw_ostream &O) {
   if (MI->getOperand(OpNum).isImm()) {
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
index e5bc67869e103d..630b4dd60108ff 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
@@ -60,10 +60,13 @@ class XtensaInstPrinter : public MCInstPrinter {
   void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printImm1n_15_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printImm32n_95_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+  void printImm8n_7_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+  void printImm64n_4n_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
+  void printEntry_Imm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printB4const_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printB4constu_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
 };
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index 51d4b8a9cc5fc5..e6cdd3d0020fc0 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -111,6 +111,18 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
                                SmallVectorImpl<MCFixup> &Fixups,
                                const MCSubtargetInfo &STI) const;
 
+  uint32_t getImm8n_7OpValue(const MCInst &MI, unsigned OpNo,
+                             SmallVectorImpl<MCFixup> &Fixups,
+                             const MCSubtargetInfo &STI) const;
+
+  uint32_t getImm64n_4nOpValue(const MCInst &MI, unsigned OpNo,
+                               SmallVectorImpl<MCFixup> &Fixups,
+                               const MCSubtargetInfo &STI) const;
+
+  uint32_t getEntry_Imm12OpValue(const MCInst &MI, unsigned OpNo,
+                                 SmallVectorImpl<MCFixup> &Fixups,
+                                 const MCSubtargetInfo &STI) const;
+
   uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo,
                                SmallVectorImpl<MCFixup> &Fixups,
                                const MCSubtargetInfo &STI) const;
@@ -405,6 +417,46 @@ XtensaMCCodeEmitter::getImm32n_95OpValue(const MCInst &MI, unsigned OpNo,
   return Res;
 }
 
+uint32_t
+XtensaMCCodeEmitter::getImm8n_7OpValue(const MCInst &MI, unsigned OpNo,
+                                       SmallVectorImpl<MCFixup> &Fixups,
+                                       const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  int32_t Res = static_cast<int32_t>(MO.getImm());
+
+  assert(((Res >= -8) && (Res <= 7)) && "Unexpected operand value!");
+
+  if (Res < 0)
+    return Res + 16;
+
+  return Res;
+}
+
+uint32_t
+XtensaMCCodeEmitter::getImm64n_4nOpValue(const MCInst &MI, unsigned OpNo,
+                                         SmallVectorImpl<MCFixup> &Fixups,
+                                         const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  int32_t Res = static_cast<int32_t>(MO.getImm());
+
+  assert(((Res >= -64) && (Res <= -4) && ((Res & 0x3) == 0)) &&
+         "Unexpected operand value!");
+
+  return Res & 0x3f;
+}
+
+uint32_t
+XtensaMCCodeEmitter::getEntry_Imm12OpValue(const MCInst &MI, unsigned OpNo,
+                                           SmallVectorImpl<MCFixup> &Fixups,
+                                           const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  uint32_t res = static_cast<uint32_t>(MO.getImm());
+
+  assert(((res & 0x7) == 0) && "Unexpected operand value!");
+
+  return res;
+}
+
 uint32_t
 XtensaMCCodeEmitter::getB4constOpValue(const MCInst &MI, unsigned OpNo,
                                        SmallVectorImpl<MCFixup> &Fixups,
diff --git a/llvm/lib/Target/Xtensa/Xtensa.td b/llvm/lib/Target/Xtensa/Xtensa.td
index 460a15e808b3a4..d6dedb6c760ab5 100644
--- a/llvm/lib/Target/Xtensa/Xtensa.td
+++ b/llvm/lib/Target/Xtensa/Xtensa.td
@@ -18,9 +18,15 @@ include "llvm/Target/Target.td"
 // Subtarget Features.
 //===----------------------------------------------------------------------===//
 def FeatureDensity : SubtargetFeature<"density", "HasDensity", "true",
-                    "Enable Density instructions">;
+                                      "Enable Density instructions">;
 def HasDensity : Predicate<"Subtarget->hasDensity()">,
-                     AssemblerPredicate<(all_of FeatureDensity)>;
+                 AssemblerPredicate<(all_of FeatureDensity)>;
+
+def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true",
+                                       "Enable Xtensa Windowed Register option">;
+def HasWindowed : Predicate<"Subtarget->hasWindowed()">,
+                  AssemblerPredicate<(all_of FeatureWindowed)>;
+
 //===----------------------------------------------------------------------===//
 // Xtensa supported processors.
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 699d0d6cf80445..d09c4264dd166b 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -678,3 +678,124 @@ let isReturn = 1, isTerminator = 1,
     let t = 0;
   }
 }
+
+//===----------------------------------------------------------------------===//
+// Windowed instructions
+//===----------------------------------------------------------------------===//
+
+def ENTRY : BRI12_Inst<0x06, 0x3, 0x0, (outs), (ins AR:$s, entry_imm12:$imm),
+                     "entry\t$s, $imm", []>, Requires<[HasWindowed]> {
+  bits<15> imm;
+
+  let imm12{11-0} = imm{14-3};
+  let Defs = [SP];
+}
+
+let isCall = 1, Defs = [A0] in {
+  def CALL4 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset),
+                      "call4\t$offset", []>, Requires<[HasWindowed]> {
+    let n = 1;
+  }
+
+  def CALL8 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset),
+                       "call8\t$offset", []>, Requires<[HasWindowed]> {
+    let n = 2;
+  }
+
+  def CALL12 : CALL_Inst<0x05, (outs), (ins pcrel32call:$offset),
+                        "call12\t$offset", []>, Requires<[HasWindowed]> {
+    let n = 3;
+  }
+
+  def CALLX4 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s),
+                         "callx4\t$s", []>, Requires<[HasWindowed]> {
+    let m = 0x3;
+    let n = 0x1;
+    let r = 0;
+  }
+
+  def CALLX8 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s),
+                         "callx8\t$s", []>, Requires<[HasWindowed]> {
+    let m = 0x3;
+    let n = 0x2;
+    let r = 0;
+  }
+
+  def CALLX12 : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins AR:$s),
+                          "callx12\t$s", []>, Requires<[HasWindowed]> {
+    let m = 0x3;
+    let n = 0x3;
+    let r = 0;
+  }
+}
+
+def MOVSP : RRR_Inst<0x00, 0x00, 0x00, (outs AR:$t), (ins AR:$s),
+                    "movsp\t$t, $s", []>, Requires<[HasWindowed]> {
+  let r = 0x01;
+}
+
+let isReturn = 1, isTerminator = 1,
+    isBarrier = 1, Uses = [A0] in {
+  def RETW_N : RRRN_Inst<0x0D, (outs), (ins),
+                        "retw.n", []>, Requires<[HasWindowed, HasDensity]> {
+    let r = 0x0F;
+    let s = 0;
+    let t = 1;
+  }
+
+  def RETW : CALLX_Inst<0x00, 0x00, 0x00, (outs), (ins),
+                       "retw", []>, Requires<[HasWindowed]> {
+    let m = 0x2;
+    let n = 0x1;
+    let s = 0;
+    let r = 0;
+  }
+}
+
+def : InstAlias<"_retw", (RETW)>;
+def : InstAlias<"_retw.n", (RETW_N)>;
+
+def S32E : RRI4_Inst<0x00, 0x09, (outs), (ins AR:$t, AR:$s, imm64n_4n:$imm),
+                    "s32e\t$t, $s, $imm", []>, Requires<[HasWindowed]> {
+  bits<6> imm;
+
+  let r = imm{5-2};
+  let imm4 = 0x4;
+  let mayStore = 1;
+}
+
+def L32E : RRI4_Inst<0x00, 0x09, (outs), (ins AR:$t, AR:$s, imm64n_4n:$imm),
+                    "l32e\t$t, $s, $imm", []>, Requires<[HasWindowed]> {
+  bits<6> imm;
+
+  let r = imm{5-2};
+  let imm4 = 0x0;
+  let mayLoad = 1;
+}
+
+def RFWU : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins),
+                   "rfwu", []>, Requires<[HasWindowed]> {
+  bits<4> imm;
+
+  let r = 0x3;
+  let s = 0x5;
+  let t = 0x0;
+}
+
+def RFWO : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins),
+                   "rfwo", []>, Requires<[HasWindowed]> {
+  bits<4> imm;
+
+  let r = 0x3;
+  let s = 0x4;
+  let t = 0x0;
+}
+
+def ROTW : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins imm8n_7:$imm),
+                   "rotw\t$imm", []>, Requires<[HasWindowed]> {
+  bits<4> imm;
+
+  let r = 0x8;
+  let s = 0x0;
+  let t = imm{3-0};
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index aa72fa0a56a6f5..dd12bd23904992 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -37,6 +37,20 @@ def imm8_sh8 : Immediate<i32, [{ return Imm >= -32768 && Imm <= 32512 && ((Imm &
   let DecoderMethod = "decodeImm8_sh8Operand";
 }
 
+// imm8n_7 predicate - Immediate in the range [-8,7]
+def Imm8n_7_AsmOperand: ImmAsmOperand<"Imm8n_7">;
+def imm8n_7: Immediate<i32, [{ return Imm >= -8 && Imm <= 7; }], "Imm8n_7_AsmOperand"> {
+  let EncoderMethod = "getImm8n_7OpValue";
+  let DecoderMethod = "decodeImm8n_7Operand";
+}
+
+// imm64n_4n predicate - Immediate in the range [-64,-4]
+def Imm64n_4n_AsmOperand: ImmAsmOperand<"Imm64n_4n">;
+def imm64n_4n: Immediate<i32, [{ return Imm >= -64 && Imm <= -4; }], "Imm64n_4n_AsmOperand"> {
+  let EncoderMethod = "getImm64n_4nOpValue";
+  let DecoderMethod = "decodeImm64n_4nOperand";
+}
+
 // imm12 predicate - Immediate in the range [-2048,2047]
 def Imm12_AsmOperand : ImmAsmOperand<"Imm12">;
 def imm12 : Immediate<i32, [{ return Imm >= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> {
@@ -117,6 +131,13 @@ def offset4m32 : Immediate<i32,
     [{ return Imm >= 0 && Imm <= 60 && (Imm & 0x3 == 0); }],
     "Offset4m32_AsmOperand">;
 
+// entry_imm12 predicate - Immediate in the range [0,32760], ENTRY parameter
+def Entry_Imm12_AsmOperand: ImmAsmOperand<"entry_imm12">;
+def entry_imm12: Immediate<i32, [{ return Imm >= 0 && Imm <= 32760 && (Imm & 0x3 == 0); }], "Entry_Imm12_AsmOperand"> {
+  let EncoderMethod = "getEntry_Imm12OpValue";
+  let DecoderMethod = "decodeEntry_Imm12OpValue";
+}
+
 // b4const predicate - Branch Immediate 4-bit signed operand
 def B4const_AsmOperand: ImmAsmOperand<"B4const">;
 def b4const: Immediate<i32,
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index 5c07386b060cd9..09087edc86712d 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -75,4 +75,8 @@ class SRReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
 // Shift Amount Register
 def SAR : SRReg<3, "sar", ["SAR","3"]>;
 
-def SR :  RegisterClass<"Xtensa", [i32], 32, (add SAR)>;
+// Windowed Register Option registers
+def WINDOWBASE : SRReg<72, "windowbase", ["WINDOWBASE", "72"]>;
+def WINDOWSTART : SRReg<73, "windowstart", ["WINDOWSTART", "73"]>;
+
+def SR :  RegisterClass<"Xtensa", [i32], 32, (add SAR, WINDOWBASE, WINDOWSTART)>;
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 948dcbc5278eaa..1cdd0f9f5baf7e 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -39,6 +39,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
   // Enabled Xtensa Density extension
   bool HasDensity;
 
+  // Enabled Xtensa Windowed Register Option
+  bool HasWindowed;
+
   XtensaSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS);
 
 public:
@@ -64,6 +67,8 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
 
   bool hasDensity() const { return HasDensity; }
 
+  bool hasWindowed() const { return HasWindowed; }
+
   // Automatically generated by tblgen.
   void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
 };
diff --git a/llvm/test/MC/Disassembler/Xtensa/windowed.txt b/llvm/test/MC/Disassembler/Xtensa/windowed.txt
new file mode 100644
index 00000000000000..880a691af9ddf0
--- /dev/null
+++ b/llvm/test/MC/Disassembler/Xtensa/windowed.txt
@@ -0,0 +1,64 @@
+# RUN: llvm-mc -triple=xtensa -mattr=+windowed -disassemble %s | FileCheck -check-prefixes=CHECK-WINDOWED %s
+# RUN: not llvm-mc -triple=xtensa -disassemble %s 2>&1 | FileCheck --implicit-check-not=warning: -check-prefixes=CHECK-CORE %s
+
+#------------------------------------------------------------------------------
+# Verify that binary code is correctly disassembled with
+# code density option enabled. Also verify that dissasembling without
+# density option generates warnings.
+#------------------------------------------------------------------------------
+
+[0x36,0x03,0x01]
+# CHECK-WINDOWED: entry a3, 128
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x30,0x14,0x00]
+# CHECK-WINDOWED: movsp a3, a4
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x15,0x10,0x00]
+# CHECK-WINDOWED: call4 . +260
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x25,0x10,0x00]
+# CHECK-WINDOWED: call8 . +260
+# CHECK-CORE: [[#@LINE-2]]:2: warning: invalid instruction encoding
+
+[0x35,0x10,0x00]
+# CHECK-WINDOWED: call12 . +260
+# CHECK-CORE: [[#@LINE-2]]:2: w...
[truncated]

@@ -198,6 +200,11 @@ struct XtensaOperand : public MCParsedAsmOperand {

bool isImm32n_95() const { return isImm(-32, 95); }

bool isImm64n_4n() const {
return isImm(-64, -4) &&
((dyn_cast<MCConstantExpr>(getImm())->getValue() & 0x3) == 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unchecked dyn_cast. Should be cast? But I don't understand the usage. How can "getImm" return an MCConstantExpr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for comments. I corrected code and use cast instead of dyn_cast. About "getImm", you mean that getImm should return integer value instead of MCExpr or we should rename getImm() function? Actually I used the same approach (by analogy) with "getImm" function like it is done in ARM backend(

const MCExpr *getImm() const {
) and in some other backends.

Comment on lines 217 to 220
if (Imm > 7)
Inst.addOperand(MCOperand::createImm(Imm - 16));
else
Inst.addOperand(MCOperand::createImm(Imm));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (Imm > 7)
Inst.addOperand(MCOperand::createImm(Imm - 16));
else
Inst.addOperand(MCOperand::createImm(Imm));
Inst.addOperand(MCOperand::createImm(Imm > 7 ? Imm - 16 : Imm));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

AssemblerPredicate<(all_of FeatureDensity)>;

def FeatureWindowed : SubtargetFeature<"windowed", "HasWindowed", "true",
"Enable Xtensa Windowed Register option">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this an "option". Is this terminology used in the ISA manual? This is a subtarget featur e

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ISA summary refers to these extensions as options, calling this particular one "Windowed Register Option".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created special file XtensaFeatures.td for Xtensa ISA extensions/features.

@@ -39,6 +39,9 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
// Enabled Xtensa Density extension
bool HasDensity;

// Enabled Xtensa Windowed Register Option
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Option/Feature/?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm , may I ask you for advice, what naming scheme should be used for Xtensa extensions( or options)?
Like @bugadani noted ,the Xtensa architecture have some ISA Options (in other words standard extensions) in documentation. It is differs a bit from for example RISCV terminology and other architectures, the documentation for RISCV architecture usually use "ISA extension" phrase is such cases. The Xtensa architecture allows to define user specific ISA and such case it is named TIE extensions (TIE language).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The LLVM concept you are using is a "subtarget feature".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed "Xtensa Density extension" to "Xtensa Density Option".

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like you only implement the MC support (and no codegen support) for windowed registers, could you put that in either your title and/or description?

Comment on lines 6 to 7
# code density option enabled. Also verify that dissasembling without
# density option generates warnings.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# code density option enabled. Also verify that dissasembling without
# density option generates warnings.
# windowed register option enabled. Also verify that dissasembling without
# windowed register option generates warnings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for comment. Fixed.

Comment on lines 6 to 7
# code density option enabled. Also verify that dissasembling without
# density option generates warnings.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# code density option enabled. Also verify that dissasembling without
# density option generates warnings.
# code density and windowed register options enabled. Also verify that dissasembling without
# these options generates warnings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fxied.

@@ -117,6 +131,13 @@ def offset4m32 : Immediate<i32,
[{ return Imm >= 0 && Imm <= 60 && (Imm & 0x3 == 0); }],
"Offset4m32_AsmOperand">;

// entry_imm12 predicate - Immediate in the range [0,32760], ENTRY parameter
def Entry_Imm12_AsmOperand: ImmAsmOperand<"entry_imm12">;
def entry_imm12: Immediate<i32, [{ return Imm >= 0 && Imm <= 32760 && (Imm & 0x3 == 0); }], "Entry_Imm12_AsmOperand"> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def entry_imm12: Immediate<i32, [{ return Imm >= 0 && Imm <= 32760 && (Imm & 0x3 == 0); }], "Entry_Imm12_AsmOperand"> {
def entry_imm12: Immediate<i32, [{ return Imm >= 0 && Imm <= 32760 && (Imm & 0x7 == 0); }], "Entry_Imm12_AsmOperand"> {

I believe the mask should be 7 instead of 3 (but even better would be % 8 == 0 if that is supported).

The stack frame size is specified as the 12-bit unsigned imm12 field in units of eight bytes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

# Out of range immediates

# entry_imm12
entry a3, -1

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test a positive parameter that is not divisible by 8 - may be 4 to catch the issue in my other comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added more tests for "entry" instruction.

@@ -826,6 +855,22 @@ ParseStatus XtensaAsmParser::parseDirective(AsmToken DirectiveID) {
return ParseStatus::NoMatch;
}

// Verify Special Register
bool XtensaAsmParser::checkRegister(MCRegister RegNo) {
bool Res = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be rewritten with a simpler expression without any conditional assign and break

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote the function code.

@@ -73,17 +73,42 @@ static DecodeStatus DecodeARRegisterClass(MCInst &Inst, uint64_t RegNo,
return MCDisassembler::Success;
}

static const unsigned SRDecoderTable[] = {Xtensa::SAR, 3};
// Verify SR
bool CheckRegister(unsigned RegNo, MCSubtargetInfo STI) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, also this is the same function? Also should start with lowercase, and not pass MCSubtargetInfo by value

Copy link
Contributor Author

@andreisfr andreisfr Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rewrote the function code and name. This function is almost the same as "checkRegister" in asm parser. I plan to make version asm parser more complex (then disassembler version) in future commits (probably it will require additional arguments). Am I understand correctly that your suggestion is to create single variant of this function in XtensaUtils.*?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm , I placed "checkRegister" function to the "XtensaUtils.cpp" in new commit. Could you please take a look?

@andreisfr andreisfr requested a review from arsenm January 21, 2025 00:21
@andreisfr andreisfr merged commit 0dcb16e into llvm:main Jan 21, 2025
8 checks passed
sylvestre added a commit that referenced this pull request Jan 22, 2025
sylvestre added a commit that referenced this pull request Jan 22, 2025
github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 22, 2025
if (RegNo > 255)
return MCDisassembler::Fail;

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

if (!checkRegister(Reg, Decoder->getSubtargetInfo().getFeatureBits()))
Copy link
Member

@MaskRay MaskRay Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XtensaDisassembler cannot use functions defined in XtensaCodeGen (Xtensa/CMakeFiles.txt).

After #123969 , you can place checkRegister in MCTargetDesc/

For CMake changes, best to check both BUILD_SHARED_LIBS=on and off builds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much!

MaskRay added a commit that referenced this pull request Jan 26, 2025
PR #121118 attempted to introduce `checkRegister` used by
XtensaDisassembler. Since `checkRegister` and other functions in
XtensaUtils.cpp cannot link against XtensaCodeGen, move them to
XtensaDesc, which can be used by XtensaDisassembler.

Pull Request: #123969
andreisfr added a commit to andreisfr/llvm-project that referenced this pull request Jan 30, 2025
This patch implements Xtensa ISA option "Windowed Register Option".
It implements subtarget feature, instructions descriptions and support
of these instruction in asm parser and disassembler.

This is the second version of the Windowed Register Option implementation.
Previous implementation llvm#121118. In this variant "checkRegister"
function placed in XtensaMCTargetDesc.
andreisfr added a commit that referenced this pull request Feb 3, 2025
 This patch implements Xtensa ISA option "Windowed Register Option".  It implements subtarget feature, instructions descriptions and support of these instructions in asm parser and disassembler.

 This is the second version of the Windowed Register Option implementation ( previous implementation #121118). In this variant "checkRegister"  function is placed in XtensaMCTargetDesc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:Xtensa mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants