Skip to content

[Xtensa] Implement SEXT, NSA, MINMAX and Loop Xtensa Options. #133818

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 2 commits into from
Apr 14, 2025

Conversation

andreisfr
Copy link
Contributor

Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option. The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and Loop Option.

Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option.
The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and
Loop Option.
@andreisfr andreisfr requested a review from arsenm March 31, 2025 23:02
@llvmbot llvmbot added mc Machine (object) code backend:Xtensa labels Mar 31, 2025
@andreisfr andreisfr requested a review from MaskRay March 31, 2025 23:02
@llvmbot
Copy link
Member

llvmbot commented Mar 31, 2025

@llvm/pr-subscribers-mc

Author: Andrei Safronov (andreisfr)

Changes

Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option. The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and Loop Option.


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

24 Files Affected:

  • (modified) llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp (+5)
  • (modified) llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp (+17)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp (+7-1)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h (+1)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp (+26)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h (+2)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp (+38)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp (+4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFeatures.td (+25)
  • (modified) llvm/lib/Target/Xtensa/XtensaISelLowering.cpp (+5-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaInstrInfo.td (+88)
  • (modified) llvm/lib/Target/Xtensa/XtensaOperands.td (+15)
  • (modified) llvm/lib/Target/Xtensa/XtensaRegisterInfo.td (+7-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaSubtarget.h (+10)
  • (added) llvm/test/CodeGen/Xtensa/minmax.ll (+52)
  • (added) llvm/test/CodeGen/Xtensa/sext.ll (+23)
  • (modified) llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s (+3-1)
  • (modified) llvm/test/MC/Xtensa/Relocations/fixups.s (+12-4)
  • (modified) llvm/test/MC/Xtensa/Relocations/relocations.s (+11-2)
  • (added) llvm/test/MC/Xtensa/loop.s (+35)
  • (added) llvm/test/MC/Xtensa/minmax.s (+24)
  • (added) llvm/test/MC/Xtensa/nsau.s (+14)
  • (added) llvm/test/MC/Xtensa/sext.s (+9)
  • (added) llvm/test/MC/Xtensa/sext_invalid.s (+9)
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 19160a599c27c..30c9ee34ade1c 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -273,6 +273,8 @@ struct XtensaOperand : public MCParsedAsmOperand {
     return false;
   }
 
+  bool isimm7_22() const { return isImm(7, 22); }
+
   /// getStartLoc - Gets location of the first token of this operand
   SMLoc getStartLoc() const override { return StartLoc; }
   /// getEndLoc - Gets location of the last token of this operand
@@ -538,6 +540,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [0, 32760], first 3 bits "
                  "should be zero");
+  case Match_Invalidimm7_22:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [7, 22]");
   }
 
   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 b949b893953fe..2c34755551b28 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -200,6 +200,16 @@ static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeLoopOperand(MCInst &Inst, uint64_t Imm,
+                                      int64_t Address, const void *Decoder) {
+
+  assert(isUInt<8>(Imm) && "Invalid immediate");
+  if (!tryAddingSymbolicOperand(Imm + 4 + Address, true, Address, 0, 3, Inst,
+                                Decoder))
+    Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm,
                                       int64_t Address, const void *Decoder) {
 
@@ -326,6 +336,13 @@ static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeImm7_22Operand(MCInst &Inst, uint64_t Imm,
+                                         int64_t Address, const void *Decoder) {
+  assert(isUInt<4>(Imm) && "Invalid immediate");
+  Inst.addOperand(MCOperand::createImm(Imm + 7));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm,
                                       int64_t Address, const void *Decoder) {
   assert(isUInt<12>(Imm) && "Invalid immediate");
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
index 1396eb45801af..ba2744d5facb5 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
@@ -64,7 +64,8 @@ XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
            MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
       {"fixup_xtensa_l32r_16", 8, 16,
        MCFixupKindInfo::FKF_IsPCRel |
-           MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}};
+           MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
+      {"fixup_xtensa_loop_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}};
 
   if (Kind < FirstTargetFixupKind)
     return MCAsmBackend::getFixupKindInfo(Kind);
@@ -116,6 +117,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
     if (Value & 0x3)
       Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
     return (Value & 0xffffc) >> 2;
+  case Xtensa::fixup_xtensa_loop_8:
+    Value -= 4;
+    if (!isUInt<8>(Value))
+      Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range");
+    return (Value & 0xff);
   case Xtensa::fixup_xtensa_l32r_16:
     unsigned Offset = Fixup.getOffset();
     if (Offset & 0x3)
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
index 57b114e709a8a..f6b1e58adf073 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
@@ -22,6 +22,7 @@ enum FixupKind {
   fixup_xtensa_jump_18,
   fixup_xtensa_call_18,
   fixup_xtensa_l32r_16,
+  fixup_xtensa_loop_8,
   fixup_xtensa_invalid,
   LastTargetFixupKind,
   NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index da7e9098f7544..bb013d5ac5681 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -105,6 +105,21 @@ void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum,
     llvm_unreachable("Invalid operand");
 }
 
+void XtensaInstPrinter::printLoopTarget(const MCInst *MI, int OpNum,
+                                        raw_ostream &OS) {
+  const MCOperand &MC = MI->getOperand(OpNum);
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Val = MC.getImm() + 4;
+    OS << ". ";
+    if (Val > 0)
+      OS << '+';
+    OS << Val;
+  } else if (MC.isExpr())
+    MC.getExpr()->print(OS, &MAI, true);
+  else
+    llvm_unreachable("Invalid operand");
+}
+
 void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum,
                                         raw_ostream &OS) {
   const MCOperand &MC = MI->getOperand(OpNum);
@@ -404,3 +419,14 @@ void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum,
   } else
     printOperand(MI, OpNum, O);
 }
+
+void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum,
+                                                raw_ostream &O) {
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Value = MI->getOperand(OpNum).getImm();
+    assert((Value >= 7 && Value <= 22) &&
+           "Invalid argument, value must be in range <7,22>");
+    O << Value;
+  } else
+    printOperand(MI, OpNum, O);
+}
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
index 630b4dd60108f..34d72dfa1c69a 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
@@ -46,6 +46,7 @@ class XtensaInstPrinter : public MCInstPrinter {
   void printOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O);
   void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O);
+  void printLoopTarget(const MCInst *MI, int OpNum, raw_ostream &O);
   void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O);
   void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O);
@@ -69,6 +70,7 @@ class XtensaInstPrinter : public MCInstPrinter {
   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);
+  void printImm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index e6cdd3d0020fc..8231a8a9a44d4 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -67,6 +67,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
                                    SmallVectorImpl<MCFixup> &Fixups,
                                    const MCSubtargetInfo &STI) const;
 
+  uint32_t getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
+                                 SmallVectorImpl<MCFixup> &Fixups,
+                                 const MCSubtargetInfo &STI) const;
+
   uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum,
                            SmallVectorImpl<MCFixup> &Fixups,
                            const MCSubtargetInfo &STI) const;
@@ -134,6 +138,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
   uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo,
                               SmallVectorImpl<MCFixup> &Fixups,
                               const MCSubtargetInfo &STI) const;
+
+  uint32_t getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
+                             SmallVectorImpl<MCFixup> &Fixups,
+                             const MCSubtargetInfo &STI) const;
 };
 } // namespace
 
@@ -220,6 +228,23 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding(
   }
 }
 
+uint32_t
+XtensaMCCodeEmitter::getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
+                                           SmallVectorImpl<MCFixup> &Fixups,
+                                           const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNum);
+  if (MO.isImm())
+    return static_cast<uint32_t>(MO.getImm());
+
+  assert((MO.isExpr()) && "Unexpected operand value!");
+
+  const MCExpr *Expr = MO.getExpr();
+
+  Fixups.push_back(MCFixup::create(
+      0, Expr, MCFixupKind(Xtensa::fixup_xtensa_loop_8), MI.getLoc()));
+  return 0;
+}
+
 uint32_t
 XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum,
                                      SmallVectorImpl<MCFixup> &Fixups,
@@ -554,4 +579,17 @@ XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo,
 
   return Res;
 }
+
+uint32_t
+XtensaMCCodeEmitter::getImm7_22OpValue(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());
+
+  res -= 7;
+  assert(((res & 0xf) == res) && "Unexpected operand value!");
+
+  return res;
+}
 #include "XtensaGenMCCodeEmitter.inc"
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
index adaa9a71a905c..792faf811aca9 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -79,6 +79,10 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
   switch (RegNo) {
   case Xtensa::BREG:
     return FeatureBits[Xtensa::FeatureBoolean];
+  case Xtensa::LBEG:
+  case Xtensa::LEND:
+  case Xtensa::LCOUNT:
+    return FeatureBits[Xtensa::FeatureLoop];
   case Xtensa::WINDOWBASE:
   case Xtensa::WINDOWSTART:
     return FeatureBits[Xtensa::FeatureWindowed];
diff --git a/llvm/lib/Target/Xtensa/XtensaFeatures.td b/llvm/lib/Target/Xtensa/XtensaFeatures.td
index 184828cd253f3..8b2d351dae386 100644
--- a/llvm/lib/Target/Xtensa/XtensaFeatures.td
+++ b/llvm/lib/Target/Xtensa/XtensaFeatures.td
@@ -22,3 +22,28 @@ def FeatureBoolean          : SubtargetFeature<"bool", "HasBoolean", "true",
                                                "Enable Xtensa Boolean extension">;
 def HasBoolean              : Predicate<"Subtarget->hasBoolean()">,
                                          AssemblerPredicate<(all_of FeatureBoolean)>;
+
+def FeatureLoop : SubtargetFeature<"loop", "HasLoop", "true",
+                                   "Enable Xtensa Loop extension">;
+def HasLoop : Predicate<"Subtarget->hasLoop()">,
+              AssemblerPredicate<(all_of FeatureLoop)>;
+
+def FeatureSEXT : SubtargetFeature<"sext", "HasSEXT", "true",
+                                   "Enable Xtensa Sign Extend option">;
+def HasSEXT : Predicate<"Subtarget->hasSEXT()">,
+              AssemblerPredicate<(all_of FeatureSEXT)>;
+
+def FeatureCLAMPS : SubtargetFeature<"clamps", "HasCLAMPS", "true",
+                                     "Enable Xtensa CLAMPS option">;
+def HasCLAMPS : Predicate<"Subtarget->hasCLAMPS()">,
+                AssemblerPredicate<(all_of FeatureCLAMPS)>;
+
+def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true",
+                                  "Enable Xtensa NSA option">;
+def HasNSA : Predicate<"Subtarget->hasNSA()">,
+             AssemblerPredicate<(all_of FeatureNSA)>;
+
+def FeatureMINMAX : SubtargetFeature<"minmax", "HasMINMAX", "true",
+                                     "Enable Xtensa MINMAX option">;
+def HasMINMAX : Predicate<"Subtarget->hasMINMAX()">,
+                AssemblerPredicate<(all_of FeatureMINMAX)>;
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index d4ee2ca72ad38..9ba87cf6d5878 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -75,8 +75,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
   setBooleanContents(ZeroOrOneBooleanContent);
 
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, {MVT::i8, MVT::i16},
+                     Subtarget.hasSEXT() ? Legal : Expand);
 
   setOperationAction(ISD::BITCAST, MVT::i32, Expand);
   setOperationAction(ISD::BITCAST, MVT::f32, Expand);
@@ -141,6 +141,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
   setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand);
 
+  setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}, MVT::i32,
+                     Subtarget.hasMINMAX() ? Legal : Expand);
+
   // Implement custom stack allocations
   setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
   // Implement custom stack save and restore
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 2de19f62e14c5..9734e914db335 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -868,6 +868,94 @@ let Constraints = "$dr = $r,@earlyclobber $dr" in {
                    "movt\t$r, $s, $t", []>, Requires<[HasBoolean]>;
 }
 
+//===----------------------------------------------------------------------===//
+// SEXT Instruction
+//===----------------------------------------------------------------------===//
+
+def SEXT : RRR_Inst<0x00, 0x03, 0x02, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
+                   "sext\t$r, $s, $imm", []>, Requires<[HasSEXT]> {
+  bits<4> imm;
+
+  let t = imm;
+}
+
+def : Pat<(i32 (sext_inreg AR:$s, i8)), (SEXT AR:$s, (i32 7))>;
+def : Pat<(i32 (sext_inreg AR:$s, i16)), (SEXT AR:$s, (i32 15))>;
+
+//===----------------------------------------------------------------------===//
+// CLAMPS Instruction
+//===----------------------------------------------------------------------===//
+
+def CLAMPS : RRR_Inst<0x00, 0x03, 0x03, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
+                   "clamps\t$r, $s, $imm", []>, Requires<[HasCLAMPS]> {
+  bits<4> imm;
+
+  let t = imm;
+}
+
+//===----------------------------------------------------------------------===//
+// NSA Instructions
+//===----------------------------------------------------------------------===//
+
+def NSA : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
+                  "nsa\t$t, $s", []>, Requires<[HasNSA]> {
+  let r = 0xE;
+}
+
+def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
+                   "nsau\t$t, $s",
+                   [(set AR:$t, (ctlz AR:$s))]>, Requires<[HasNSA]> {
+  let r = 0xF;
+}
+
+//===----------------------------------------------------------------------===//
+// MINMAX Instructions
+//===----------------------------------------------------------------------===//
+
+let Predicates = [HasMINMAX] in {
+  def MIN   : ArithLogic_RRR<0x04, 0x03, "min", smin, 1>;
+  def MAX   : ArithLogic_RRR<0x05, 0x03, "max", smax, 1>;
+  def MINU  : ArithLogic_RRR<0x06, 0x03, "minu", umin, 1>;
+  def MAXU  : ArithLogic_RRR<0x07, 0x03, "maxu", umax, 1>;
+}
+
+//===----------------------------------------------------------------------===//
+// Loop Instructions
+//===----------------------------------------------------------------------===//
+
+def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                    "loop\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x08;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loop\t$s, $target", (LOOP AR:$s, ltarget:$target)>;
+
+def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                       "loopgtz\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x0A;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loopgtz\t$s, $target", (LOOPGTZ AR:$s, ltarget:$target)>;
+
+def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                       "loopnez\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x09;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loopnez\t$s, $target", (LOOPNEZ AR:$s, ltarget:$target)>;
+
 //===----------------------------------------------------------------------===//
 // DSP Instructions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index 402e05a5c3dd1..6f893c56378e5 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -167,6 +167,14 @@ def b4constu: Immediate<i32,
   let EncoderMethod = "getB4constuOpValue";
   let DecoderMethod = "decodeB4constuOperand";
 }
+
+// imm7_22 predicate - Immediate in the range [7,22] for sign extend and clamps
+def Imm7_22_AsmOperand: ImmAsmOperand<"imm7_22">;
+def imm7_22: Immediate<i32, [{ return Imm >= 7 && Imm <= 22; }], "Imm7_22_AsmOperand"> {
+  let EncoderMethod = "getImm7_22OpValue";
+  let DecoderMethod = "decodeImm7_22Operand";
+}
+
 //===----------------------------------------------------------------------===//
 // Memory address operands
 //===----------------------------------------------------------------------===//
@@ -230,6 +238,13 @@ def jumptarget : Operand<OtherVT> {
   let ParserMatchClass = XtensaPCRelTargetAsmOperand;
 }
 
+def ltarget : Operand<OtherVT> {
+  let PrintMethod = "printLoopTarget";
+  let EncoderMethod = "getLoopTargetEncoding";
+  let DecoderMethod = "decodeLoopOperand";
+  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
+}
+
 def L32Rtarget : Operand<i32> {
   let PrintMethod = "printL32RTarget";
   let EncoderMethod = "getL32RTargetEncoding";
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index 2934018318406..2a40431adc7f0 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -73,6 +73,11 @@ class SRReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
   let AltNames = alt;
 }
 
+// Loop Option Registers
+def LBEG : SRReg<0, "lbeg", ["LBEG", "0"]>;
+def LEND : SRReg<1, "lend", ["LEND", "1"]>;
+def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>;
+
 // Shift Amount Register
 def SAR : SRReg<3, "sar", ["SAR","3"]>;
 
@@ -95,8 +100,8 @@ def MR01 :  RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>;
 def MR23 :  RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>;
 def MR   :  RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>;
 
-def SR :  RegisterClass<"Xtensa", [i32], 32, (add SAR, BREG, MR,
-  WINDOWBASE, WINDOWSTART)>;
+def SR :  RegisterClass<"Xtensa", [i32], 32, (add
+  LBEG, LEND, LCOUNT, SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>;
 
 //===----------------------------------------------------------------------===//
 // Boolean registers
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 05c0c07e93a96..cb7ff30ea1846 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -72,6 +72,16 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
 
   bool ha...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Mar 31, 2025

@llvm/pr-subscribers-backend-xtensa

Author: Andrei Safronov (andreisfr)

Changes

Implement basic support of the several simple Xtensa Options with 1-4 instructions for each option. The Sign Extend Option (SEXT). The NSA Option. The Minimum/Maximum Integer 32-bit Option and Loop Option.


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

24 Files Affected:

  • (modified) llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp (+5)
  • (modified) llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp (+17)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp (+7-1)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h (+1)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp (+26)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h (+2)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp (+38)
  • (modified) llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp (+4)
  • (modified) llvm/lib/Target/Xtensa/XtensaFeatures.td (+25)
  • (modified) llvm/lib/Target/Xtensa/XtensaISelLowering.cpp (+5-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaInstrInfo.td (+88)
  • (modified) llvm/lib/Target/Xtensa/XtensaOperands.td (+15)
  • (modified) llvm/lib/Target/Xtensa/XtensaRegisterInfo.td (+7-2)
  • (modified) llvm/lib/Target/Xtensa/XtensaSubtarget.h (+10)
  • (added) llvm/test/CodeGen/Xtensa/minmax.ll (+52)
  • (added) llvm/test/CodeGen/Xtensa/sext.ll (+23)
  • (modified) llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s (+3-1)
  • (modified) llvm/test/MC/Xtensa/Relocations/fixups.s (+12-4)
  • (modified) llvm/test/MC/Xtensa/Relocations/relocations.s (+11-2)
  • (added) llvm/test/MC/Xtensa/loop.s (+35)
  • (added) llvm/test/MC/Xtensa/minmax.s (+24)
  • (added) llvm/test/MC/Xtensa/nsau.s (+14)
  • (added) llvm/test/MC/Xtensa/sext.s (+9)
  • (added) llvm/test/MC/Xtensa/sext_invalid.s (+9)
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index 19160a599c27c..30c9ee34ade1c 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -273,6 +273,8 @@ struct XtensaOperand : public MCParsedAsmOperand {
     return false;
   }
 
+  bool isimm7_22() const { return isImm(7, 22); }
+
   /// getStartLoc - Gets location of the first token of this operand
   SMLoc getStartLoc() const override { return StartLoc; }
   /// getEndLoc - Gets location of the last token of this operand
@@ -538,6 +540,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [0, 32760], first 3 bits "
                  "should be zero");
+  case Match_Invalidimm7_22:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [7, 22]");
   }
 
   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 b949b893953fe..2c34755551b28 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -200,6 +200,16 @@ static DecodeStatus decodeBranchOperand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeLoopOperand(MCInst &Inst, uint64_t Imm,
+                                      int64_t Address, const void *Decoder) {
+
+  assert(isUInt<8>(Imm) && "Invalid immediate");
+  if (!tryAddingSymbolicOperand(Imm + 4 + Address, true, Address, 0, 3, Inst,
+                                Decoder))
+    Inst.addOperand(MCOperand::createImm(Imm));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeL32ROperand(MCInst &Inst, uint64_t Imm,
                                       int64_t Address, const void *Decoder) {
 
@@ -326,6 +336,13 @@ static DecodeStatus decodeB4constuOperand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeImm7_22Operand(MCInst &Inst, uint64_t Imm,
+                                         int64_t Address, const void *Decoder) {
+  assert(isUInt<4>(Imm) && "Invalid immediate");
+  Inst.addOperand(MCOperand::createImm(Imm + 7));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeMem8Operand(MCInst &Inst, uint64_t Imm,
                                       int64_t Address, const void *Decoder) {
   assert(isUInt<12>(Imm) && "Invalid immediate");
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
index 1396eb45801af..ba2744d5facb5 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaAsmBackend.cpp
@@ -64,7 +64,8 @@ XtensaMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
            MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
       {"fixup_xtensa_l32r_16", 8, 16,
        MCFixupKindInfo::FKF_IsPCRel |
-           MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}};
+           MCFixupKindInfo::FKF_IsAlignedDownTo32Bits},
+      {"fixup_xtensa_loop_8", 16, 8, MCFixupKindInfo::FKF_IsPCRel}};
 
   if (Kind < FirstTargetFixupKind)
     return MCAsmBackend::getFixupKindInfo(Kind);
@@ -116,6 +117,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
     if (Value & 0x3)
       Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned");
     return (Value & 0xffffc) >> 2;
+  case Xtensa::fixup_xtensa_loop_8:
+    Value -= 4;
+    if (!isUInt<8>(Value))
+      Ctx.reportError(Fixup.getLoc(), "loop fixup value out of range");
+    return (Value & 0xff);
   case Xtensa::fixup_xtensa_l32r_16:
     unsigned Offset = Fixup.getOffset();
     if (Offset & 0x3)
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
index 57b114e709a8a..f6b1e58adf073 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaFixupKinds.h
@@ -22,6 +22,7 @@ enum FixupKind {
   fixup_xtensa_jump_18,
   fixup_xtensa_call_18,
   fixup_xtensa_l32r_16,
+  fixup_xtensa_loop_8,
   fixup_xtensa_invalid,
   LastTargetFixupKind,
   NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index da7e9098f7544..bb013d5ac5681 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -105,6 +105,21 @@ void XtensaInstPrinter::printBranchTarget(const MCInst *MI, int OpNum,
     llvm_unreachable("Invalid operand");
 }
 
+void XtensaInstPrinter::printLoopTarget(const MCInst *MI, int OpNum,
+                                        raw_ostream &OS) {
+  const MCOperand &MC = MI->getOperand(OpNum);
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Val = MC.getImm() + 4;
+    OS << ". ";
+    if (Val > 0)
+      OS << '+';
+    OS << Val;
+  } else if (MC.isExpr())
+    MC.getExpr()->print(OS, &MAI, true);
+  else
+    llvm_unreachable("Invalid operand");
+}
+
 void XtensaInstPrinter::printJumpTarget(const MCInst *MI, int OpNum,
                                         raw_ostream &OS) {
   const MCOperand &MC = MI->getOperand(OpNum);
@@ -404,3 +419,14 @@ void XtensaInstPrinter::printB4constu_AsmOperand(const MCInst *MI, int OpNum,
   } else
     printOperand(MI, OpNum, O);
 }
+
+void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum,
+                                                raw_ostream &O) {
+  if (MI->getOperand(OpNum).isImm()) {
+    int64_t Value = MI->getOperand(OpNum).getImm();
+    assert((Value >= 7 && Value <= 22) &&
+           "Invalid argument, value must be in range <7,22>");
+    O << Value;
+  } else
+    printOperand(MI, OpNum, O);
+}
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
index 630b4dd60108f..34d72dfa1c69a 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
@@ -46,6 +46,7 @@ class XtensaInstPrinter : public MCInstPrinter {
   void printOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O);
   void printBranchTarget(const MCInst *MI, int OpNum, raw_ostream &O);
+  void printLoopTarget(const MCInst *MI, int OpNum, raw_ostream &O);
   void printJumpTarget(const MCInst *MI, int OpNum, raw_ostream &O);
   void printCallOperand(const MCInst *MI, int OpNum, raw_ostream &O);
   void printL32RTarget(const MCInst *MI, int OpNum, raw_ostream &O);
@@ -69,6 +70,7 @@ class XtensaInstPrinter : public MCInstPrinter {
   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);
+  void printImm7_22_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O);
 };
 } // end namespace llvm
 
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index e6cdd3d0020fc..8231a8a9a44d4 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -67,6 +67,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
                                    SmallVectorImpl<MCFixup> &Fixups,
                                    const MCSubtargetInfo &STI) const;
 
+  uint32_t getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
+                                 SmallVectorImpl<MCFixup> &Fixups,
+                                 const MCSubtargetInfo &STI) const;
+
   uint32_t getCallEncoding(const MCInst &MI, unsigned int OpNum,
                            SmallVectorImpl<MCFixup> &Fixups,
                            const MCSubtargetInfo &STI) const;
@@ -134,6 +138,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
   uint32_t getB4constuOpValue(const MCInst &MI, unsigned OpNo,
                               SmallVectorImpl<MCFixup> &Fixups,
                               const MCSubtargetInfo &STI) const;
+
+  uint32_t getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
+                             SmallVectorImpl<MCFixup> &Fixups,
+                             const MCSubtargetInfo &STI) const;
 };
 } // namespace
 
@@ -220,6 +228,23 @@ uint32_t XtensaMCCodeEmitter::getBranchTargetEncoding(
   }
 }
 
+uint32_t
+XtensaMCCodeEmitter::getLoopTargetEncoding(const MCInst &MI, unsigned int OpNum,
+                                           SmallVectorImpl<MCFixup> &Fixups,
+                                           const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNum);
+  if (MO.isImm())
+    return static_cast<uint32_t>(MO.getImm());
+
+  assert((MO.isExpr()) && "Unexpected operand value!");
+
+  const MCExpr *Expr = MO.getExpr();
+
+  Fixups.push_back(MCFixup::create(
+      0, Expr, MCFixupKind(Xtensa::fixup_xtensa_loop_8), MI.getLoc()));
+  return 0;
+}
+
 uint32_t
 XtensaMCCodeEmitter::getCallEncoding(const MCInst &MI, unsigned int OpNum,
                                      SmallVectorImpl<MCFixup> &Fixups,
@@ -554,4 +579,17 @@ XtensaMCCodeEmitter::getB4constuOpValue(const MCInst &MI, unsigned OpNo,
 
   return Res;
 }
+
+uint32_t
+XtensaMCCodeEmitter::getImm7_22OpValue(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());
+
+  res -= 7;
+  assert(((res & 0xf) == res) && "Unexpected operand value!");
+
+  return res;
+}
 #include "XtensaGenMCCodeEmitter.inc"
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
index adaa9a71a905c..792faf811aca9 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -79,6 +79,10 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits) {
   switch (RegNo) {
   case Xtensa::BREG:
     return FeatureBits[Xtensa::FeatureBoolean];
+  case Xtensa::LBEG:
+  case Xtensa::LEND:
+  case Xtensa::LCOUNT:
+    return FeatureBits[Xtensa::FeatureLoop];
   case Xtensa::WINDOWBASE:
   case Xtensa::WINDOWSTART:
     return FeatureBits[Xtensa::FeatureWindowed];
diff --git a/llvm/lib/Target/Xtensa/XtensaFeatures.td b/llvm/lib/Target/Xtensa/XtensaFeatures.td
index 184828cd253f3..8b2d351dae386 100644
--- a/llvm/lib/Target/Xtensa/XtensaFeatures.td
+++ b/llvm/lib/Target/Xtensa/XtensaFeatures.td
@@ -22,3 +22,28 @@ def FeatureBoolean          : SubtargetFeature<"bool", "HasBoolean", "true",
                                                "Enable Xtensa Boolean extension">;
 def HasBoolean              : Predicate<"Subtarget->hasBoolean()">,
                                          AssemblerPredicate<(all_of FeatureBoolean)>;
+
+def FeatureLoop : SubtargetFeature<"loop", "HasLoop", "true",
+                                   "Enable Xtensa Loop extension">;
+def HasLoop : Predicate<"Subtarget->hasLoop()">,
+              AssemblerPredicate<(all_of FeatureLoop)>;
+
+def FeatureSEXT : SubtargetFeature<"sext", "HasSEXT", "true",
+                                   "Enable Xtensa Sign Extend option">;
+def HasSEXT : Predicate<"Subtarget->hasSEXT()">,
+              AssemblerPredicate<(all_of FeatureSEXT)>;
+
+def FeatureCLAMPS : SubtargetFeature<"clamps", "HasCLAMPS", "true",
+                                     "Enable Xtensa CLAMPS option">;
+def HasCLAMPS : Predicate<"Subtarget->hasCLAMPS()">,
+                AssemblerPredicate<(all_of FeatureCLAMPS)>;
+
+def FeatureNSA : SubtargetFeature<"nsa", "HasNSA", "true",
+                                  "Enable Xtensa NSA option">;
+def HasNSA : Predicate<"Subtarget->hasNSA()">,
+             AssemblerPredicate<(all_of FeatureNSA)>;
+
+def FeatureMINMAX : SubtargetFeature<"minmax", "HasMINMAX", "true",
+                                     "Enable Xtensa MINMAX option">;
+def HasMINMAX : Predicate<"Subtarget->hasMINMAX()">,
+                AssemblerPredicate<(all_of FeatureMINMAX)>;
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index d4ee2ca72ad38..9ba87cf6d5878 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -75,8 +75,8 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
   setBooleanContents(ZeroOrOneBooleanContent);
 
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
-  setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+  setOperationAction(ISD::SIGN_EXTEND_INREG, {MVT::i8, MVT::i16},
+                     Subtarget.hasSEXT() ? Legal : Expand);
 
   setOperationAction(ISD::BITCAST, MVT::i32, Expand);
   setOperationAction(ISD::BITCAST, MVT::f32, Expand);
@@ -141,6 +141,9 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
   setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
   setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand);
 
+  setOperationAction({ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}, MVT::i32,
+                     Subtarget.hasMINMAX() ? Legal : Expand);
+
   // Implement custom stack allocations
   setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
   // Implement custom stack save and restore
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 2de19f62e14c5..9734e914db335 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -868,6 +868,94 @@ let Constraints = "$dr = $r,@earlyclobber $dr" in {
                    "movt\t$r, $s, $t", []>, Requires<[HasBoolean]>;
 }
 
+//===----------------------------------------------------------------------===//
+// SEXT Instruction
+//===----------------------------------------------------------------------===//
+
+def SEXT : RRR_Inst<0x00, 0x03, 0x02, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
+                   "sext\t$r, $s, $imm", []>, Requires<[HasSEXT]> {
+  bits<4> imm;
+
+  let t = imm;
+}
+
+def : Pat<(i32 (sext_inreg AR:$s, i8)), (SEXT AR:$s, (i32 7))>;
+def : Pat<(i32 (sext_inreg AR:$s, i16)), (SEXT AR:$s, (i32 15))>;
+
+//===----------------------------------------------------------------------===//
+// CLAMPS Instruction
+//===----------------------------------------------------------------------===//
+
+def CLAMPS : RRR_Inst<0x00, 0x03, 0x03, (outs AR:$r), (ins AR:$s, imm7_22:$imm),
+                   "clamps\t$r, $s, $imm", []>, Requires<[HasCLAMPS]> {
+  bits<4> imm;
+
+  let t = imm;
+}
+
+//===----------------------------------------------------------------------===//
+// NSA Instructions
+//===----------------------------------------------------------------------===//
+
+def NSA : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
+                  "nsa\t$t, $s", []>, Requires<[HasNSA]> {
+  let r = 0xE;
+}
+
+def NSAU : RRR_Inst<0x00, 0x00, 0x04, (outs AR:$t), (ins AR:$s),
+                   "nsau\t$t, $s",
+                   [(set AR:$t, (ctlz AR:$s))]>, Requires<[HasNSA]> {
+  let r = 0xF;
+}
+
+//===----------------------------------------------------------------------===//
+// MINMAX Instructions
+//===----------------------------------------------------------------------===//
+
+let Predicates = [HasMINMAX] in {
+  def MIN   : ArithLogic_RRR<0x04, 0x03, "min", smin, 1>;
+  def MAX   : ArithLogic_RRR<0x05, 0x03, "max", smax, 1>;
+  def MINU  : ArithLogic_RRR<0x06, 0x03, "minu", umin, 1>;
+  def MAXU  : ArithLogic_RRR<0x07, 0x03, "maxu", umax, 1>;
+}
+
+//===----------------------------------------------------------------------===//
+// Loop Instructions
+//===----------------------------------------------------------------------===//
+
+def LOOP : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                    "loop\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x08;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loop\t$s, $target", (LOOP AR:$s, ltarget:$target)>;
+
+def LOOPGTZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                       "loopgtz\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x0A;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loopgtz\t$s, $target", (LOOPGTZ AR:$s, ltarget:$target)>;
+
+def LOOPNEZ : RRI8_Inst<0x06, (outs), (ins AR:$s, ltarget:$target),
+                       "loopnez\t$s, $target", []>, Requires<[HasLoop]> {
+  bits<8> target;
+
+  let r = 0x09;
+  let t = 0x07;
+  let imm8 = target;
+}
+
+def : InstAlias<"_loopnez\t$s, $target", (LOOPNEZ AR:$s, ltarget:$target)>;
+
 //===----------------------------------------------------------------------===//
 // DSP Instructions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index 402e05a5c3dd1..6f893c56378e5 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -167,6 +167,14 @@ def b4constu: Immediate<i32,
   let EncoderMethod = "getB4constuOpValue";
   let DecoderMethod = "decodeB4constuOperand";
 }
+
+// imm7_22 predicate - Immediate in the range [7,22] for sign extend and clamps
+def Imm7_22_AsmOperand: ImmAsmOperand<"imm7_22">;
+def imm7_22: Immediate<i32, [{ return Imm >= 7 && Imm <= 22; }], "Imm7_22_AsmOperand"> {
+  let EncoderMethod = "getImm7_22OpValue";
+  let DecoderMethod = "decodeImm7_22Operand";
+}
+
 //===----------------------------------------------------------------------===//
 // Memory address operands
 //===----------------------------------------------------------------------===//
@@ -230,6 +238,13 @@ def jumptarget : Operand<OtherVT> {
   let ParserMatchClass = XtensaPCRelTargetAsmOperand;
 }
 
+def ltarget : Operand<OtherVT> {
+  let PrintMethod = "printLoopTarget";
+  let EncoderMethod = "getLoopTargetEncoding";
+  let DecoderMethod = "decodeLoopOperand";
+  let ParserMatchClass = XtensaPCRelTargetAsmOperand;
+}
+
 def L32Rtarget : Operand<i32> {
   let PrintMethod = "printL32RTarget";
   let EncoderMethod = "getL32RTargetEncoding";
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index 2934018318406..2a40431adc7f0 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -73,6 +73,11 @@ class SRReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
   let AltNames = alt;
 }
 
+// Loop Option Registers
+def LBEG : SRReg<0, "lbeg", ["LBEG", "0"]>;
+def LEND : SRReg<1, "lend", ["LEND", "1"]>;
+def LCOUNT : SRReg<2, "lcount", ["LCOUNT", "2"]>;
+
 // Shift Amount Register
 def SAR : SRReg<3, "sar", ["SAR","3"]>;
 
@@ -95,8 +100,8 @@ def MR01 :  RegisterClass<"Xtensa", [i32], 32, (add M0, M1)>;
 def MR23 :  RegisterClass<"Xtensa", [i32], 32, (add M2, M3)>;
 def MR   :  RegisterClass<"Xtensa", [i32], 32, (add MR01, MR23)>;
 
-def SR :  RegisterClass<"Xtensa", [i32], 32, (add SAR, BREG, MR,
-  WINDOWBASE, WINDOWSTART)>;
+def SR :  RegisterClass<"Xtensa", [i32], 32, (add
+  LBEG, LEND, LCOUNT, SAR, BREG, MR, WINDOWBASE, WINDOWSTART)>;
 
 //===----------------------------------------------------------------------===//
 // Boolean registers
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 05c0c07e93a96..cb7ff30ea1846 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -72,6 +72,16 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
 
   bool ha...
[truncated]

const MCOperand &MC = MI->getOperand(OpNum);
if (MI->getOperand(OpNum).isImm()) {
int64_t Val = MC.getImm() + 4;
OS << ". ";
Copy link
Member

Choose a reason for hiding this comment

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

If the operand is an address, you'd need OPERAND_PCREL. See https://reviews.llvm.org/D72172

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MaskRay , thank you very much for comments. I fixed descriptions for several address operands (added OPERAND_PCREL to descriptions), could you PTAL?

@@ -72,6 +72,16 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {

bool hasBoolean() const { return HasBoolean; }

Copy link
Member

Choose a reason for hiding this comment

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

the blank lines between these has* functions are not necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Corrected

@andreisfr andreisfr merged commit 68806b9 into llvm:main Apr 14, 2025
11 checks passed
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
…33818)

Implement basic support of the several simple Xtensa Options with 1-4
instructions for each option. The Sign Extend Option (SEXT). The NSA
Option. The Minimum/Maximum Integer 32-bit Option and Loop Option.
Fixed address operands, added OPERAND_PCREL to operands descriptions.
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.

4 participants