[llvm] [Xtensa] Implement support of the ESP32S2 target. (PR #200130)

Andrei Safronov via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 01:09:05 PDT 2026


https://github.com/andreisfr updated https://github.com/llvm/llvm-project/pull/200130

>From 11e39cd3865bf9076d5a4de5783a8b896d2a630b Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 28 May 2026 11:21:02 +0300
Subject: [PATCH 1/4] [Xtensa] Implement support of the ESP32S2 target.

---
 .../llvm/TargetParser/XtensaTargetParser.def  |  6 ++++
 .../llvm/TargetParser/XtensaTargetParser.h    |  3 +-
 .../Xtensa/AsmParser/XtensaAsmParser.cpp      |  5 +++
 .../Disassembler/XtensaDisassembler.cpp       |  8 +++++
 .../Xtensa/MCTargetDesc/XtensaInstPrinter.cpp | 11 ++++++
 .../Xtensa/MCTargetDesc/XtensaInstPrinter.h   |  1 +
 .../MCTargetDesc/XtensaMCCodeEmitter.cpp      | 16 +++++++++
 .../MCTargetDesc/XtensaMCTargetDesc.cpp       |  8 +++++
 llvm/lib/Target/Xtensa/XtensaFeatures.td      |  5 +++
 llvm/lib/Target/Xtensa/XtensaInstrInfo.td     | 34 +++++++++++++++++++
 llvm/lib/Target/Xtensa/XtensaOperands.td      |  7 ++++
 llvm/lib/Target/Xtensa/XtensaProcessors.td    |  5 +++
 llvm/lib/Target/Xtensa/XtensaRegisterInfo.td  |  6 +++-
 llvm/lib/Target/Xtensa/XtensaSubtarget.h      |  1 +
 llvm/test/CodeGen/Xtensa/cpus.ll              |  9 +++++
 15 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/TargetParser/XtensaTargetParser.def b/llvm/include/llvm/TargetParser/XtensaTargetParser.def
index b0afe6f161770..65a2fbacd1028 100644
--- a/llvm/include/llvm/TargetParser/XtensaTargetParser.def
+++ b/llvm/include/llvm/TargetParser/XtensaTargetParser.def
@@ -50,6 +50,7 @@ XTENSA_FEATURE(XF_TIMERS3,                 "timers3")
 XTENSA_FEATURE(XF_PRID,                    "prid")
 XTENSA_FEATURE(XF_REGPROTECT,              "regprotect")
 XTENSA_FEATURE(XF_MISCSR,                  "miscsr")
+XTENSA_FEATURE(XF_ESP32S2OPS,              "esp32s2ops")
 
 #undef XTENSA_FEATURE
 
@@ -69,6 +70,11 @@ XTENSA_CPU(ESP32,   {"esp32"},
                 XF_THREADPTR | XF_DIV32 | XF_DATACACHE | XF_DEBUG | XF_EXCEPTION | XF_HIGHPRIINTERRUPTS |
                 XF_HIGHPRIINTERRUPTSLEVEL7 | XF_COPROCESSOR | XF_INTERRUPT | XF_RVECTOR | XF_TIMERS3 | XF_PRID |
 				XF_REGPROTECT | XF_MISCSR))
+XTENSA_CPU(ESP32S2,   {"esp32s2"},
+               (XF_DENSITY | XF_WINDOWED | XF_SEXT | XF_NSA | XF_MUL16 | XF_MUL32 | XF_MUL32HIGH |
+                XF_THREADPTR | XF_DIV32 | XF_DATACACHE | XF_DEBUG | XF_EXCEPTION | XF_HIGHPRIINTERRUPTS |
+                XF_HIGHPRIINTERRUPTSLEVEL7 | XF_COPROCESSOR | XF_INTERRUPT | XF_RVECTOR | XF_TIMERS3 | XF_PRID |
+                XF_REGPROTECT | XF_MISCSR | XF_MINMAX | XF_CLAMPS | XF_ESP32S2OPS))
 
 #undef XTENSA_CPU
 
diff --git a/llvm/include/llvm/TargetParser/XtensaTargetParser.h b/llvm/include/llvm/TargetParser/XtensaTargetParser.h
index 41369b1d64499..cc08558e6f5d6 100644
--- a/llvm/include/llvm/TargetParser/XtensaTargetParser.h
+++ b/llvm/include/llvm/TargetParser/XtensaTargetParser.h
@@ -64,7 +64,8 @@ enum XtensaFeatureKind : uint64_t {
   XF_TIMERS3 = 1ULL << 33,
   XF_PRID = 1ULL << 34,
   XF_REGPROTECT = 1ULL << 35,
-  XF_MISCSR = 1ULL << 36
+  XF_MISCSR = 1ULL << 36,
+  XF_ESP32S2OPS = 1ULL << 37
 };
 
 CPUKind parseCPUKind(StringRef CPU);
diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
index dc33295c16f28..f2714d9b3e21c 100644
--- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
+++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp
@@ -282,6 +282,8 @@ struct XtensaOperand : public MCParsedAsmOperand {
 
   bool isimm7_22() const { return isImm(7, 22); }
 
+  bool isSelect_256() const { return isImm(0, 255); }
+
   /// 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
@@ -544,6 +546,9 @@ bool XtensaAsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   case Match_Invalidimm7_22:
     return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
                  "expected immediate in range [7, 22]");
+  case Match_InvalidSelect_256:
+    return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo),
+                 "expected immediate in range [0, 255]");
   }
 
   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 7d22a0489a951..807a2d6d35fdc 100644
--- a/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
+++ b/llvm/lib/Target/Xtensa/Disassembler/XtensaDisassembler.cpp
@@ -415,6 +415,14 @@ static DecodeStatus decodeImm7_22Operand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeSelect_256Operand(MCInst &Inst, uint64_t Imm,
+                                            int64_t Address,
+                                            const void *Decoder) {
+  assert(isUInt<8>(Imm) && "Invalid immediate");
+  Inst.addOperand(MCOperand::createImm(Imm));
+  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/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index f1c11d47bc8b9..8cd41e3f81636 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -439,3 +439,14 @@ void XtensaInstPrinter::printImm7_22_AsmOperand(const MCInst *MI, int OpNum,
   } else
     printOperand(MI, OpNum, O);
 }
+
+void XtensaInstPrinter::printSelect_256_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 <= 255) &&
+           "Invalid argument, value must be in range [0,255]");
+    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 e25e36ed61ccf..657996dd607e6 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h
@@ -77,6 +77,7 @@ class XtensaInstPrinter : public MCInstPrinter {
   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);
+  void printSelect_256_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 5977a276b1236..5aaa0f855da8d 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -142,6 +142,10 @@ class XtensaMCCodeEmitter : public MCCodeEmitter {
   uint32_t getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
                              SmallVectorImpl<MCFixup> &Fixups,
                              const MCSubtargetInfo &STI) const;
+
+  uint8_t getSelect_256OpValue(const MCInst &MI, unsigned OpNo,
+                               SmallVectorImpl<MCFixup> &Fixups,
+                               const MCSubtargetInfo &STI) const;
 };
 } // namespace
 
@@ -606,4 +610,16 @@ XtensaMCCodeEmitter::getImm7_22OpValue(const MCInst &MI, unsigned OpNo,
 
   return res;
 }
+
+uint8_t
+XtensaMCCodeEmitter::getSelect_256OpValue(const MCInst &MI, unsigned OpNo,
+                                          SmallVectorImpl<MCFixup> &Fixups,
+                                          const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  uint8_t Res = static_cast<uint8_t>(MO.getImm());
+
+  assert(((Res >= 0) && (Res <= 255)) && "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 8ccf8c83c0921..1dbec6565853d 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -203,6 +203,10 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits,
   case Xtensa::ATOMCTL:
   case Xtensa::SCOMPARE1:
     return FeatureBits[Xtensa::FeatureS32C1I];
+    return FeatureBits[Xtensa::FeatureWindowed];
+  case Xtensa::GPIO_OUT:
+  case Xtensa::EXPSTATE:
+    return FeatureBits[Xtensa::FeatureESP32S2Ops];
   case Xtensa::NoRegister:
     return false;
   }
@@ -226,6 +230,10 @@ MCRegister Xtensa::getUserRegister(unsigned Code, const MCRegisterInfo &MRI) {
     UserReg = Xtensa::F64S;
   } else if (MRI.getEncodingValue(Xtensa::THREADPTR) == Code) {
     UserReg = Xtensa::THREADPTR;
+  } else if (MRI.getEncodingValue(Xtensa::GPIO_OUT) == Code) {
+    UserReg = Xtensa::GPIO_OUT;
+  } else if (MRI.getEncodingValue(Xtensa::EXPSTATE) == Code) {
+    UserReg = Xtensa::EXPSTATE;
   }
 
   return UserReg;
diff --git a/llvm/lib/Target/Xtensa/XtensaFeatures.td b/llvm/lib/Target/Xtensa/XtensaFeatures.td
index d6f3ef0f15e32..5b0732bf78ad3 100644
--- a/llvm/lib/Target/Xtensa/XtensaFeatures.td
+++ b/llvm/lib/Target/Xtensa/XtensaFeatures.td
@@ -163,3 +163,8 @@ def FeatureDFPAccel : SubtargetFeature<"dfpaccel", "HasDFPAccel", "true",
                                        "Enable Xtensa Double Precision FP acceleration">;
 def HasDFPAccel : Predicate<"Subtarget->hasDFPAccel()">,
                   AssemblerPredicate<(all_of FeatureDFPAccel)>;
+
+def FeatureESP32S2Ops : SubtargetFeature<"esp32s2ops", "HasESP32S2Ops", "true",
+                                         "Support Xtensa esp32-s2 ISA extension">;
+def HasESP32S2Ops : Predicate<"Subtarget->hasESP32S2Ops()">,
+                               AssemblerPredicate<(all_of FeatureESP32S2Ops)>;
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index 632c6a2fba1b6..90e20b7cd6334 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -1540,6 +1540,40 @@ let usesCustomInserter = 1, Predicates = [HasS32C1I] in {
                                    [(set AR:$dst, (atomic_cmp_swap_i32 AR:$ptr, AR:$cmp, AR:$swap))]>;
 }
 
+//===----------------------------------------------------------------------===//
+// Xtensa ESP32S2 Instructions
+//===----------------------------------------------------------------------===//
+let Predicates = [HasESP32S2Ops] in {
+  def WR_MASK_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins AR:$s, AR:$t),
+                                 "wr_mask_gpio_out\t$s, $t", []> {
+    let r = 0x2;
+  }
+
+  def SET_BIT_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins select_256:$imm),
+                                 "set_bit_gpio_out\t$imm", []> {
+    bits<8> imm;
+
+    let r = 0x1;
+    let s = imm{7-4};
+    let t = imm{3-0};
+  }
+
+  def CLR_BIT_GPIO_OUT : RRR_Inst<0x0, 0x06, 0x0, (outs), (ins select_256:$imm),
+                                 "clr_bit_gpio_out\t$imm", []> {
+    bits<8> imm;
+
+    let r = 0x0;
+    let s = imm{7-4};
+    let t = imm{3-0};
+  }
+
+  def GET_GPIO_IN : RRR_Inst<0x0, 0x06, 0x0, (outs AR:$t), (ins),
+                            "get_gpio_in\t$t", []> {
+    let r = 0x3;
+    let s = 0x0;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // DSP Instructions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td
index d0f454736e500..76629f107d4b5 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperands.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperands.td
@@ -175,6 +175,13 @@ def imm7_22: Immediate<i32, [{ return Imm >= 7 && Imm <= 22; }], "Imm7_22_AsmOpe
   let DecoderMethod = "decodeImm7_22Operand";
 }
 
+// select_256 predicate - Immediate in the range [0,255]
+def Select_256_AsmOperand: ImmAsmOperand<"Select_256">;
+def select_256: Immediate<i32, [{ return Imm >= 0 && Imm <= 255; }], "Select_256_AsmOperand"> {
+  let EncoderMethod = "getSelect_256OpValue";
+  let DecoderMethod = "decodeSelect_256Operand";
+}
+
 //===----------------------------------------------------------------------===//
 // Memory address operands
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Xtensa/XtensaProcessors.td b/llvm/lib/Target/Xtensa/XtensaProcessors.td
index 0faf07d99aaf7..b977de596762c 100644
--- a/llvm/lib/Target/Xtensa/XtensaProcessors.td
+++ b/llvm/lib/Target/Xtensa/XtensaProcessors.td
@@ -25,3 +25,8 @@ def : Proc<"esp32", [FeatureDensity, FeatureSingleFloat, FeatureLoop, FeatureMAC
 def : Proc<"esp8266", [FeatureDensity, FeatureNSA, FeatureMul16, FeatureMul32, FeatureExtendedL32R, FeatureDebug, FeatureException,
                        FeatureHighPriInterrupts, FeatureHighPriInterruptsLevel3, FeatureInterrupt, FeatureRelocatableVector, FeatureTimers1,
 					   FeatureRegionProtection, FeaturePRID]>;
+
+def : Proc<"esp32s2", [FeatureDensity, FeatureWindowed, FeatureSEXT, FeatureNSA,  FeatureMul16, FeatureMul32, FeatureMul32High, FeatureTHREADPTR,
+                       FeatureDiv32, FeatureDataCache, FeatureDebug, FeatureException, FeatureHighPriInterrupts, FeatureHighPriInterruptsLevel7,
+                       FeatureCoprocessor, FeatureInterrupt, FeatureRelocatableVector,	FeatureTimers3, FeaturePRID, FeatureRegionProtection,
+                       FeatureMiscSR, FeatureMINMAX, FeatureCLAMPS, FeatureESP32S2Ops]>;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index d1f2c6b8e43a3..29d1ca06d324f 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -240,6 +240,10 @@ class URReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
   let AltNames = alt;
 }
 
+// ESP32S2 registers
+def GPIO_OUT : URReg<0, "gpio_out", ["GPIO_OUT"]>;
+def EXPSTATE : URReg<230, "expstate", ["EXPSTATE"]>;
+
 // Thread Pointer register
 def THREADPTR : URReg<231, "threadptr", ["THREADPTR"]>;
 
@@ -252,7 +256,7 @@ def F64R_HI : URReg<235, "f64r_hi", ["F64R_HI"]>;
 def F64S : URReg<236, "f64s", ["F64S"]>;
 
 def UR :  RegisterClass<"Xtensa", [i32], 32, (add
-  THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>;
+  GPIO_OUT, EXPSTATE, THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>;
 
 //===----------------------------------------------------------------------===//
 // Floating-Point registers
diff --git a/llvm/lib/Target/Xtensa/XtensaSubtarget.h b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
index 6a5201b6f6f32..cbe5d9a720501 100644
--- a/llvm/lib/Target/Xtensa/XtensaSubtarget.h
+++ b/llvm/lib/Target/Xtensa/XtensaSubtarget.h
@@ -94,6 +94,7 @@ class XtensaSubtarget : public XtensaGenSubtargetInfo {
   bool hasInterrupt() const { return HasInterrupt; }
   bool hasException() const { return HasException; }
   bool hasTHREADPTR() const { return HasTHREADPTR; }
+  bool hasESP32S2Ops() const { return HasESP32S2Ops; }
   bool isWindowedABI() const { return hasWindowed(); }
 
   // Automatically generated by tblgen.
diff --git a/llvm/test/CodeGen/Xtensa/cpus.ll b/llvm/test/CodeGen/Xtensa/cpus.ll
index d04ee16882381..d59ef0e7a90da 100644
--- a/llvm/test/CodeGen/Xtensa/cpus.ll
+++ b/llvm/test/CodeGen/Xtensa/cpus.ll
@@ -3,6 +3,7 @@
 
 ; RUN: llc < %s --mtriple=xtensa --mcpu=esp8266 2>&1 | FileCheck -check-prefix=XTENSA-ESP8266  %s
 ; RUN: llc < %s --mtriple=xtensa --mcpu=esp32 2>&1 | FileCheck -check-prefix=XTENSA-ESP32 %s
+; RUN: llc < %s --mtriple=xtensa --mcpu=esp32s2 2>&1 | FileCheck -check-prefix=XTENSA-ESP32S2 %s
 ; RUN: llc < %s --mtriple=xtensa --mcpu=generic 2>&1 | FileCheck -check-prefix=XTENSA-GENERIC %s
 
 define i32 @f(i32 %z) {
@@ -20,6 +21,14 @@ define i32 @f(i32 %z) {
 ; XTENSA-ESP32-NEXT:    movi a2, 0
 ; XTENSA-ESP32-NEXT:    retw.n
 ;
+; XTENSA-ESP32S2-LABEL: f:
+; XTENSA-ESP32S2:         .cfi_startproc
+; XTENSA-ESP32S2-NEXT:  # %bb.0:
+; XTENSA-ESP32S2-NEXT:    entry a1, 32
+; XTENSA-ESP32S2-NEXT:    .cfi_def_cfa_offset 32
+; XTENSA-ESP32S2-NEXT:    movi.n a2, 0
+; XTENSA-ESP32S2-NEXT:    retw.n
+;
 ; XTENSA-GENERIC-LABEL: f:
 ; XTENSA-GENERIC:         .cfi_startproc
 ; XTENSA-GENERIC-NEXT:  # %bb.0:

>From 91d8e345f608265edf61c406ab5f2758d4e7a6e3 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 11 Jun 2026 01:06:54 +0300
Subject: [PATCH 2/4] [Xtensa] Minor fixes.

Minor fixes of the check immediate. Also fixed test.
---
 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp   | 3 +--
 llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp | 2 +-
 llvm/test/CodeGen/Xtensa/cpus.ll                            | 2 +-
 3 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
index 8cd41e3f81636..4540f16f34801 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp
@@ -314,8 +314,7 @@ void XtensaInstPrinter::printOffset8m8_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 <= 255) &&
-           "Invalid argument, value must be in range [0,255]");
+    assert(isUInt<8> && "Invalid argument, value must be in range [0,255]");
     O << Value;
   } else
     printOperand(MI, OpNum, O);
diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
index 5aaa0f855da8d..b35e5e3e03b07 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp
@@ -618,7 +618,7 @@ XtensaMCCodeEmitter::getSelect_256OpValue(const MCInst &MI, unsigned OpNo,
   const MCOperand &MO = MI.getOperand(OpNo);
   uint8_t Res = static_cast<uint8_t>(MO.getImm());
 
-  assert(((Res >= 0) && (Res <= 255)) && "Unexpected operand value!");
+  assert(isUInt<8> && "Unexpected operand value!");
 
   return Res;
 }
diff --git a/llvm/test/CodeGen/Xtensa/cpus.ll b/llvm/test/CodeGen/Xtensa/cpus.ll
index d59ef0e7a90da..95ae845888e5c 100644
--- a/llvm/test/CodeGen/Xtensa/cpus.ll
+++ b/llvm/test/CodeGen/Xtensa/cpus.ll
@@ -26,7 +26,7 @@ define i32 @f(i32 %z) {
 ; XTENSA-ESP32S2-NEXT:  # %bb.0:
 ; XTENSA-ESP32S2-NEXT:    entry a1, 32
 ; XTENSA-ESP32S2-NEXT:    .cfi_def_cfa_offset 32
-; XTENSA-ESP32S2-NEXT:    movi.n a2, 0
+; XTENSA-ESP32S2-NEXT:    movi a2, 0
 ; XTENSA-ESP32S2-NEXT:    retw.n
 ;
 ; XTENSA-GENERIC-LABEL: f:

>From 2bf9195e835c9ec803dda5f86e1a5f76a3630864 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 11 Jun 2026 03:20:32 +0300
Subject: [PATCH 3/4] [Xtensa] Remove EXPSTATE register and renmae GPIO_OUT
 register.

---
 .../Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp    | 9 +++------
 llvm/lib/Target/Xtensa/XtensaRegisterInfo.td             | 5 ++---
 2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
index 1dbec6565853d..cb8c3aca3502c 100644
--- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
+++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCTargetDesc.cpp
@@ -204,8 +204,7 @@ bool Xtensa::checkRegister(MCRegister RegNo, const FeatureBitset &FeatureBits,
   case Xtensa::SCOMPARE1:
     return FeatureBits[Xtensa::FeatureS32C1I];
     return FeatureBits[Xtensa::FeatureWindowed];
-  case Xtensa::GPIO_OUT:
-  case Xtensa::EXPSTATE:
+  case Xtensa::GPIO_OUT_S2:
     return FeatureBits[Xtensa::FeatureESP32S2Ops];
   case Xtensa::NoRegister:
     return false;
@@ -230,10 +229,8 @@ MCRegister Xtensa::getUserRegister(unsigned Code, const MCRegisterInfo &MRI) {
     UserReg = Xtensa::F64S;
   } else if (MRI.getEncodingValue(Xtensa::THREADPTR) == Code) {
     UserReg = Xtensa::THREADPTR;
-  } else if (MRI.getEncodingValue(Xtensa::GPIO_OUT) == Code) {
-    UserReg = Xtensa::GPIO_OUT;
-  } else if (MRI.getEncodingValue(Xtensa::EXPSTATE) == Code) {
-    UserReg = Xtensa::EXPSTATE;
+  } else if (MRI.getEncodingValue(Xtensa::GPIO_OUT_S2) == Code) {
+    UserReg = Xtensa::GPIO_OUT_S2;
   }
 
   return UserReg;
diff --git a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
index 29d1ca06d324f..6c4f35e832f3f 100644
--- a/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaRegisterInfo.td
@@ -241,8 +241,7 @@ class URReg<bits<8> num, string n, list<string> alt = []> : XtensaReg<n> {
 }
 
 // ESP32S2 registers
-def GPIO_OUT : URReg<0, "gpio_out", ["GPIO_OUT"]>;
-def EXPSTATE : URReg<230, "expstate", ["EXPSTATE"]>;
+def GPIO_OUT_S2 : URReg<0, "gpio_out", ["GPIO_OUT"]>;
 
 // Thread Pointer register
 def THREADPTR : URReg<231, "threadptr", ["THREADPTR"]>;
@@ -256,7 +255,7 @@ def F64R_HI : URReg<235, "f64r_hi", ["F64R_HI"]>;
 def F64S : URReg<236, "f64s", ["F64S"]>;
 
 def UR :  RegisterClass<"Xtensa", [i32], 32, (add
-  GPIO_OUT, EXPSTATE, THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>;
+  GPIO_OUT_S2, THREADPTR, FCR, FSR, F64R_LO, F64R_HI, F64S)>;
 
 //===----------------------------------------------------------------------===//
 // Floating-Point registers

>From fe6ed6989b04b960cd25142c48297b9322772fcc Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Thu, 11 Jun 2026 11:05:35 +0300
Subject: [PATCH 4/4] [Xtensa] Add test for esp32s2 target specific
 instructions.

---
 llvm/test/MC/xtensa-esp32s2-valid.s | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 llvm/test/MC/xtensa-esp32s2-valid.s

diff --git a/llvm/test/MC/xtensa-esp32s2-valid.s b/llvm/test/MC/xtensa-esp32s2-valid.s
new file mode 100644
index 0000000000000..4fef46023b30f
--- /dev/null
+++ b/llvm/test/MC/xtensa-esp32s2-valid.s
@@ -0,0 +1,21 @@
+# RUN: llvm-mc %s -triple=xtensa  -mattr=+esp32s2ops -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK,CHECK-INST %s
+
+.align	4
+LBL0:
+
+# CHECK-INST:  clr_bit_gpio_out  52
+# CHECK: encoding: [0x40,0x03,0x06]
+clr_bit_gpio_out 52
+
+# CHECK-INST:  get_gpio_in  a2
+# CHECK: encoding: [0x20,0x30,0x06]
+get_gpio_in a2
+
+# CHECK-INST:  set_bit_gpio_out  18
+# CHECK: encoding: [0x20,0x11,0x06]
+set_bit_gpio_out 18
+
+# CHECK-INST:  wr_mask_gpio_out	a3, a2
+# CHECK: encoding: [0x20,0x23,0x06]
+wr_mask_gpio_out	a3, a2



More information about the llvm-commits mailing list