[llvm] [Xtensa] Implement SEXT, NSA, MINMAX and Loop Xtensa Options. (PR #133818)

Andrei Safronov via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 31 16:02:40 PDT 2025


https://github.com/andreisfr created https://github.com/llvm/llvm-project/pull/133818

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.

>From 06b3708282c8bcf7156180043f520254f2980487 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Tue, 1 Apr 2025 01:54:27 +0300
Subject: [PATCH] [Xtensa] Implement SEXT, NSA, MINMAX and Loop Xtensa Options.

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.
---
 .../Xtensa/AsmParser/XtensaAsmParser.cpp      |  5 ++
 .../Disassembler/XtensaDisassembler.cpp       | 17 ++++
 .../Xtensa/MCTargetDesc/XtensaAsmBackend.cpp  |  8 +-
 .../Xtensa/MCTargetDesc/XtensaFixupKinds.h    |  1 +
 .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 26 ++++++
 .../Xtensa/MCTargetDesc/XtensaInstPrinter.h   |  2 +
 .../MCTargetDesc/XtensaMCCodeEmitter.cpp      | 38 ++++++++
 .../MCTargetDesc/XtensaMCTargetDesc.cpp       |  4 +
 llvm/lib/Target/Xtensa/XtensaFeatures.td      | 25 ++++++
 llvm/lib/Target/Xtensa/XtensaISelLowering.cpp |  7 +-
 llvm/lib/Target/Xtensa/XtensaInstrInfo.td     | 88 +++++++++++++++++++
 llvm/lib/Target/Xtensa/XtensaOperands.td      | 15 ++++
 llvm/lib/Target/Xtensa/XtensaRegisterInfo.td  |  9 +-
 llvm/lib/Target/Xtensa/XtensaSubtarget.h      | 10 +++
 llvm/test/CodeGen/Xtensa/minmax.ll            | 52 +++++++++++
 llvm/test/CodeGen/Xtensa/sext.ll              | 23 +++++
 .../Xtensa/Relocations/fixups-diagnostics.s   |  4 +-
 llvm/test/MC/Xtensa/Relocations/fixups.s      | 16 +++-
 llvm/test/MC/Xtensa/Relocations/relocations.s | 13 ++-
 llvm/test/MC/Xtensa/loop.s                    | 35 ++++++++
 llvm/test/MC/Xtensa/minmax.s                  | 24 +++++
 llvm/test/MC/Xtensa/nsau.s                    | 14 +++
 llvm/test/MC/Xtensa/sext.s                    |  9 ++
 llvm/test/MC/Xtensa/sext_invalid.s            |  9 ++
 24 files changed, 442 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/Xtensa/minmax.ll
 create mode 100644 llvm/test/CodeGen/Xtensa/sext.ll
 create mode 100644 llvm/test/MC/Xtensa/loop.s
 create mode 100644 llvm/test/MC/Xtensa/minmax.s
 create mode 100644 llvm/test/MC/Xtensa/nsau.s
 create mode 100644 llvm/test/MC/Xtensa/sext.s
 create mode 100644 llvm/test/MC/Xtensa/sext_invalid.s

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, at 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 hasBoolean() const { return HasBoolean; }
 
+  bool hasLoop() const { return HasLoop; }
+
+  bool hasSEXT() const { return HasSEXT; }
+
+  bool hasCLAMPS() const { return HasCLAMPS; }
+
+  bool hasNSA() const { return HasNSA; }
+
+  bool hasMINMAX() const { return HasMINMAX; }
+
   bool isWindowedABI() const { return hasWindowed(); }
 
   // Automatically generated by tblgen.
diff --git a/llvm/test/CodeGen/Xtensa/minmax.ll b/llvm/test/CodeGen/Xtensa/minmax.ll
new file mode 100644
index 0000000000000..2f95c78170897
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/minmax.ll
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa --mattr=+minmax -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=XTENSA %s
+
+declare i32 @llvm.smin.i32(i32, i32)
+declare i32 @llvm.umin.i32(i32, i32)
+declare i32 @llvm.smax.i32(i32, i32)
+declare i32 @llvm.umax.i32(i32, i32)
+
+define i32 @test_smin(i32 %x, i32 %y) {
+; XTENSA-LABEL: test_smin:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0: # %entry
+; XTENSA-NEXT:    min a2, a2, a3
+; XTENSA-NEXT:    ret
+entry:
+  %res = call i32 @llvm.smin.i32(i32 %x, i32 %y)
+  ret i32 %res
+}
+
+define i32 @test_umin(i32 %x, i32 %y) {
+; XTENSA-LABEL: test_umin:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0: # %entry
+; XTENSA-NEXT:    minu a2, a2, a3
+; XTENSA-NEXT:    ret
+entry:
+  %res = call i32 @llvm.umin.i32(i32 %x, i32 %y)
+  ret i32 %res
+}
+
+define i32 @test_smax(i32 %x, i32 %y) {
+; XTENSA-LABEL: test_smax:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0: # %entry
+; XTENSA-NEXT:    max a2, a2, a3
+; XTENSA-NEXT:    ret
+entry:
+  %res = call i32 @llvm.smax.i32(i32 %x, i32 %y)
+  ret i32 %res
+}
+
+define i32 @test_umax(i32 %x, i32 %y) {
+; XTENSA-LABEL: test_umax:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0: # %entry
+; XTENSA-NEXT:    maxu a2, a2, a3
+; XTENSA-NEXT:    ret
+entry:
+  %res = call i32 @llvm.umax.i32(i32 %x, i32 %y)
+  ret i32 %res
+}
diff --git a/llvm/test/CodeGen/Xtensa/sext.ll b/llvm/test/CodeGen/Xtensa/sext.ll
new file mode 100644
index 0000000000000..36a1c9b32903e
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/sext.ll
@@ -0,0 +1,23 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa --mattr=+sext -verify-machineinstrs < %s \
+; RUN:   | FileCheck -check-prefix=XTENSA %s
+
+define i32 @sext_i8(i8 %a) {
+; XTENSA-LABEL: sext_i8:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0:
+; XTENSA-NEXT:    sext a2, a2, 7
+; XTENSA-NEXT:    ret
+  %res = sext i8 %a to i32
+  ret i32 %res
+}
+
+define i32 @sext_i16(i16 %a) {
+; XTENSA-LABEL: sext_i16:
+; XTENSA:         .cfi_startproc
+; XTENSA-NEXT:  # %bb.0:
+; XTENSA-NEXT:    sext a2, a2, 15
+; XTENSA-NEXT:    ret
+  %res = sext i16 %a to i32
+  ret i32 %res
+}
diff --git a/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s b/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s
index e0eac900552ce..9a81ade9fe284 100644
--- a/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s
+++ b/llvm/test/MC/Xtensa/Relocations/fixups-diagnostics.s
@@ -1,4 +1,4 @@
-# RUN: not llvm-mc -triple xtensa -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s
+# RUN: not llvm-mc -triple xtensa --mattr=+loop -filetype obj < %s -o /dev/null 2>&1 | FileCheck %s
 
   .align 4
 
@@ -8,6 +8,8 @@ LBL0:
 
   call0 LBL0 # CHECK: :[[@LINE]]:3: error: fixup value must be 4-byte aligned
 
+  loop a3, LBL0 # CHECK: :[[@LINE]]:3: error: loop fixup value out of range
+
   .space 1<<8
 LBL1:
   .space 1<<12
diff --git a/llvm/test/MC/Xtensa/Relocations/fixups.s b/llvm/test/MC/Xtensa/Relocations/fixups.s
index 0a3a9eeef1159..b722cf6976385 100644
--- a/llvm/test/MC/Xtensa/Relocations/fixups.s
+++ b/llvm/test/MC/Xtensa/Relocations/fixups.s
@@ -1,7 +1,7 @@
-# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
+# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \
 # RUN:     | FileCheck -check-prefix=CHECK-FIXUP %s
-# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
-# RUN:     | llvm-objdump --mattr=+density -d - | FileCheck -check-prefix=CHECK-INSTR %s
+# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \
+# RUN:     | llvm-objdump --mattr=+density,loop -d - | FileCheck -check-prefix=CHECK-INSTR %s
 
 
 # Checks that fixups that can be resolved within the same object file are
@@ -16,7 +16,7 @@ beqz.n a2, LBL1
 # CHECK-INSTR: beqz.n a2, . +29
 
 beq a0, a1, LBL0
-# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind: fixup_xtensa_branch_8
+# CHECK-FIXUP: fixup A - offset: 0, value: LBL0, kind:
 # CHECK-INSTR: beq a0, a1, . -14
 
 beq a0, a1, LBL1
@@ -57,3 +57,11 @@ LBL1:
 
 .align 4
 LBL2:
+
+loop a3, LBL3
+# CHECK-FIXUP: fixup A - offset: 0, value: LBL3, kind: fixup_xtensa_loop_8
+# CHECK-INSTR: loop a3, . +203
+
+.fill 200
+
+LBL3:
diff --git a/llvm/test/MC/Xtensa/Relocations/relocations.s b/llvm/test/MC/Xtensa/Relocations/relocations.s
index 339f6cb44bfcf..7937d5d729870 100644
--- a/llvm/test/MC/Xtensa/Relocations/relocations.s
+++ b/llvm/test/MC/Xtensa/Relocations/relocations.s
@@ -1,6 +1,6 @@
-# RUN: llvm-mc -triple xtensa --mattr=+density < %s -show-encoding \
+# RUN: llvm-mc -triple xtensa --mattr=+density,loop < %s -show-encoding \
 # RUN:     | FileCheck -check-prefix=INSTR -check-prefix=FIXUP %s
-# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density < %s \
+# RUN: llvm-mc -filetype=obj -triple xtensa --mattr=+density,loop < %s \
 # RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s
 
 # Check prefixes:
@@ -183,3 +183,12 @@ l32r a6, func
 # RELOC: R_XTENSA_SLOT0_OP
 # INSTR: l32r    a6, func
 # FIXUP: fixup A - offset: 0, value: func, kind: fixup_xtensa_l32r_16
+
+loop a3, LBL
+# RELOC: R_XTENSA_SLOT0_OP
+# INSTR: loop    a3, LBL
+# FIXUP: fixup A - offset: 0, value: LBL, kind: fixup_xtensa_loop_8
+
+.fill 200
+
+LBL:
diff --git a/llvm/test/MC/Xtensa/loop.s b/llvm/test/MC/Xtensa/loop.s
new file mode 100644
index 0000000000000..cdcb23f276f7b
--- /dev/null
+++ b/llvm/test/MC/Xtensa/loop.s
@@ -0,0 +1,35 @@
+# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+loop \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align	4
+
+# Instruction format BRI8
+# CHECK-INST: loop a3, LBL
+# CHECK: encoding: [0x76,0x83,A]
+loop a3, LBL
+
+# Instruction format BRI8
+# CHECK-INST: loopnez a3, LBL
+# CHECK: encoding: [0x76,0x93,A]
+loopnez a3, LBL
+
+# Instruction format BRI8
+# CHECK-INST: loopgtz a3, LBL
+# CHECK: encoding: [0x76,0xa3,A]
+loopgtz a3, LBL
+
+# CHECK-INST: xsr a3, lbeg
+# CHECK: # encoding: [0x30,0x00,0x61]
+xsr a3, lbeg
+
+# CHECK-INST: xsr a3, lend
+# CHECK: # encoding: [0x30,0x01,0x61]
+xsr a3, lend
+
+# CHECK-INST: xsr a3, lcount
+# CHECK: # encoding: [0x30,0x02,0x61]
+xsr a3, lcount
+
+.fill 200
+
+LBL:
diff --git a/llvm/test/MC/Xtensa/minmax.s b/llvm/test/MC/Xtensa/minmax.s
new file mode 100644
index 0000000000000..4ee5849ff7bf1
--- /dev/null
+++ b/llvm/test/MC/Xtensa/minmax.s
@@ -0,0 +1,24 @@
+# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+minmax \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align	4
+
+# Instruction format RRR
+# CHECK-INST: max a3, a4, a5
+# CHECK: encoding: [0x50,0x34,0x53]
+max a3, a4, a5
+
+# Instruction format RRR
+# CHECK-INST: maxu a3, a4, a5
+# CHECK: encoding: [0x50,0x34,0x73]
+maxu a3, a4, a5
+
+# Instruction format RRR
+# CHECK-INST: min a3, a4, a5
+# CHECK: encoding: [0x50,0x34,0x43]
+min a3, a4, a5
+
+# Instruction format RRR
+# CHECK-INST: minu a3, a4, a5
+# CHECK: encoding: [0x50,0x34,0x63]
+minu a3, a4, a5
diff --git a/llvm/test/MC/Xtensa/nsau.s b/llvm/test/MC/Xtensa/nsau.s
new file mode 100644
index 0000000000000..791485b1ed751
--- /dev/null
+++ b/llvm/test/MC/Xtensa/nsau.s
@@ -0,0 +1,14 @@
+# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+nsa \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align	4
+
+# Instruction format RRR
+# CHECK-INST: nsa a3, a4
+# CHECK: encoding: [0x30,0xe4,0x40]
+nsa a3, a4
+
+# Instruction format RRR
+# CHECK-INST: nsau a3, a4
+# CHECK: encoding: [0x30,0xf4,0x40]
+nsau a3, a4
diff --git a/llvm/test/MC/Xtensa/sext.s b/llvm/test/MC/Xtensa/sext.s
new file mode 100644
index 0000000000000..11efe614a1103
--- /dev/null
+++ b/llvm/test/MC/Xtensa/sext.s
@@ -0,0 +1,9 @@
+# RUN: llvm-mc %s -triple=xtensa -show-encoding --mattr=+sext \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align	4
+
+# Instruction format RRR
+# CHECK-INST: sext a3, a4, 7
+# CHECK: encoding: [0x00,0x34,0x23]
+sext a3, a4, 7
diff --git a/llvm/test/MC/Xtensa/sext_invalid.s b/llvm/test/MC/Xtensa/sext_invalid.s
new file mode 100644
index 0000000000000..c4aa48c67b645
--- /dev/null
+++ b/llvm/test/MC/Xtensa/sext_invalid.s
@@ -0,0 +1,9 @@
+# RUN: not llvm-mc -triple xtensa --mattr=+sext %s 2>&1 | FileCheck %s
+
+.align	4
+
+# Out of range immediates
+
+# imm7_22
+sext a3, a4, 6
+# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [7, 22]



More information about the llvm-commits mailing list