[llvm] [PowerPC] Add mnemonics to paddis (PR #179979)

Lei Huang via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 22 10:48:13 PDT 2026


https://github.com/lei137 updated https://github.com/llvm/llvm-project/pull/179979

>From 0575d518f6b770762ede54ac29340dc89d9a54ec Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Thu, 19 Feb 2026 16:05:02 -0500
Subject: [PATCH 1/5] [PowerPC] Add mnemonics to paddis

Add extended mnemonics to paddis:

  paddis RT,RA,SI  -> paddis RT,RA,SI,0
  plis RT,SI       -> paddis RT,0,SI,0
  psubis RT,RA,si  -> paddis RT,RA,-si,0
---
 .../Target/PowerPC/AsmParser/PPCAsmParser.cpp | 125 ++++++++++++------
 .../PowerPC/MCTargetDesc/PPCInstPrinter.cpp   |  11 ++
 .../PowerPC/MCTargetDesc/PPCInstPrinter.h     |   2 +
 llvm/lib/Target/PowerPC/PPCInstrFuture.td     |  13 ++
 llvm/lib/Target/PowerPC/PPCOperands.td        |  18 +++
 .../PowerPC/ppc-encoding-ISAFuture.txt        |   2 +-
 .../PowerPC/ppc64le-encoding-ISAFuture.txt    |   2 +-
 llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s |  31 ++++-
 8 files changed, 158 insertions(+), 46 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 7b07c0881d453..5c66f889488ca 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -161,6 +161,47 @@ class PPCAsmParser : public MCTargetAsmParser {
                                MCContext &Ctx) override;
 };
 
+// Helper function to negate an operand - used by both PPCOperand and PPCAsmParser
+// Adds the negation of \p Op as an operand to \p Inst.
+//
+// This helper is used to lower pseudo-subtraction mnemonics (e.g. SUBI,
+// SUBIS, SUBIC, SUBIC_rec, PSUBI) into their real ADD-family equivalents by
+// negating the immediate or expression operand before appending it.
+//
+// The negation is performed as follows:
+// - If \p Op is an immediate, the negated integer value is added directly.
+// - If \p Op is a unary-minus expression (i.e. \c -E), the inner
+//   sub-expression \c E is added, effectively cancelling the double negation.
+// - If \p Op is a binary-subtraction expression (i.e. \c LHS-RHS), the
+//   operands are swapped to produce \c RHS-LHS.
+// - Otherwise, a new unary-minus expression wrapping \p Op's expression is
+//   created and added.
+//
+// \param Inst  The instruction being built; the negated operand is appended.
+// \param Op    The source operand whose value is to be negated.
+// \param Ctx   The MC context used to allocate new expression nodes.
+static void addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) {
+  if (Op.isImm()) {
+    Inst.addOperand(MCOperand::createImm(-Op.getImm()));
+    return;
+  }
+  const MCExpr *Expr = Op.getExpr();
+  if (const MCUnaryExpr *UnExpr = dyn_cast<MCUnaryExpr>(Expr)) {
+    if (UnExpr->getOpcode() == MCUnaryExpr::Minus) {
+      Inst.addOperand(MCOperand::createExpr(UnExpr->getSubExpr()));
+      return;
+    }
+  } else if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Expr)) {
+    if (BinExpr->getOpcode() == MCBinaryExpr::Sub) {
+      const MCExpr *NE = MCBinaryExpr::createSub(BinExpr->getRHS(),
+                                                 BinExpr->getLHS(), Ctx);
+      Inst.addOperand(MCOperand::createExpr(NE));
+      return;
+    }
+  }
+  Inst.addOperand(MCOperand::createExpr(MCUnaryExpr::createMinus(Expr, Ctx)));
+}
+
 /// PPCOperand - Instances of this class represent a parsed PowerPC machine
 /// instruction.
 struct PPCOperand : public MCParsedAsmOperand {
@@ -174,6 +215,7 @@ struct PPCOperand : public MCParsedAsmOperand {
 
   SMLoc StartLoc, EndLoc;
   bool IsPPC64;
+  MCContext *Ctx;
 
   struct TokOp {
     const char *Data;
@@ -640,6 +682,20 @@ struct PPCOperand : public MCParsedAsmOperand {
     }
   }
 
+  void addNegImmOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+
+    if (Kind == Immediate) {
+      Inst.addOperand(MCOperand::createImm(-getImm()));
+      return;
+    }
+
+    // Create an MCOperand and use the static helper
+    assert(Ctx && "MCContext is required for addNegImmOperands");
+    MCOperand Op = MCOperand::createExpr(getExpr());
+    addNegOperand(Inst, Op, *Ctx);
+  }
+
   void addBranchTargetOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     if (Kind == Immediate)
@@ -661,18 +717,19 @@ struct PPCOperand : public MCParsedAsmOperand {
   void print(raw_ostream &OS, const MCAsmInfo &MAI) const override;
 
   static std::unique_ptr<PPCOperand> CreateToken(StringRef Str, SMLoc S,
-                                                 bool IsPPC64) {
+                                                 bool IsPPC64, MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(Token);
     Op->Tok.Data = Str.data();
     Op->Tok.Length = Str.size();
     Op->StartLoc = S;
     Op->EndLoc = S;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateTokenWithStringCopy(StringRef Str, SMLoc S, bool IsPPC64) {
+  CreateTokenWithStringCopy(StringRef Str, SMLoc S, bool IsPPC64, MCContext *Ctx = nullptr) {
     // Allocate extra memory for the string and copy it.
     // FIXME: This is incorrect, Operands are owned by unique_ptr with a default
     // deleter which will destroy them by simply using "delete", not correctly
@@ -686,11 +743,12 @@ struct PPCOperand : public MCParsedAsmOperand {
     Op->StartLoc = S;
     Op->EndLoc = S;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand> CreateImm(int64_t Val, SMLoc S, SMLoc E,
-                                               bool IsPPC64,
+                                               bool IsPPC64, MCContext *Ctx = nullptr,
                                                bool IsMemOpBase = false) {
     auto Op = std::make_unique<PPCOperand>(Immediate);
     Op->Imm.Val = Val;
@@ -698,57 +756,61 @@ struct PPCOperand : public MCParsedAsmOperand {
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand> CreateExpr(const MCExpr *Val, SMLoc S,
-                                                SMLoc E, bool IsPPC64) {
+                                                SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(Expression);
     Op->Expr.Val = Val;
     Op->Expr.CRVal = EvaluateCRExpr(Val);
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateTLSReg(const MCSymbolRefExpr *Sym, SMLoc S, SMLoc E, bool IsPPC64) {
+  CreateTLSReg(const MCSymbolRefExpr *Sym, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(TLSRegister);
     Op->TLSReg.Sym = Sym;
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64) {
+  CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(ContextImmediate);
     Op->Imm.Val = Val;
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
+    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64) {
+  CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
     if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Val))
-      return CreateImm(CE->getValue(), S, E, IsPPC64);
+      return CreateImm(CE->getValue(), S, E, IsPPC64, Ctx);
 
     if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(Val))
       if (getSpecifier(SRE) == PPC::S_TLS ||
           getSpecifier(SRE) == PPC::S_TLS_PCREL)
-        return CreateTLSReg(SRE, S, E, IsPPC64);
+        return CreateTLSReg(SRE, S, E, IsPPC64, Ctx);
 
     if (const auto *SE = dyn_cast<MCSpecifierExpr>(Val)) {
       int64_t Res;
       if (PPC::evaluateAsConstant(*SE, Res))
-        return CreateContextImm(Res, S, E, IsPPC64);
+        return CreateContextImm(Res, S, E, IsPPC64, Ctx);
     }
 
-    return CreateExpr(Val, S, E, IsPPC64);
+    return CreateExpr(Val, S, E, IsPPC64, Ctx);
   }
 
 private:
@@ -791,29 +853,6 @@ void PPCOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
   }
 }
 
-static void
-addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) {
-  if (Op.isImm()) {
-    Inst.addOperand(MCOperand::createImm(-Op.getImm()));
-    return;
-  }
-  const MCExpr *Expr = Op.getExpr();
-  if (const MCUnaryExpr *UnExpr = dyn_cast<MCUnaryExpr>(Expr)) {
-    if (UnExpr->getOpcode() == MCUnaryExpr::Minus) {
-      Inst.addOperand(MCOperand::createExpr(UnExpr->getSubExpr()));
-      return;
-    }
-  } else if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Expr)) {
-    if (BinExpr->getOpcode() == MCBinaryExpr::Sub) {
-      const MCExpr *NE = MCBinaryExpr::createSub(BinExpr->getRHS(),
-                                                 BinExpr->getLHS(), Ctx);
-      Inst.addOperand(MCOperand::createExpr(NE));
-      return;
-    }
-  }
-  Inst.addOperand(MCOperand::createExpr(MCUnaryExpr::createMinus(Expr, Ctx)));
-}
-
 void PPCAsmParser::processInstruction(MCInst &Inst,
                                       const OperandVector &Operands) {
   int Opcode = Inst.getOpcode();
@@ -1454,7 +1493,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
     if (!matchRegisterName(IntVal))
       return Error(S, "invalid register name");
 
-    Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64()));
+    Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext()));
     return false;
   }
   case AsmToken::Identifier:
@@ -1475,7 +1514,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
   }
 
   // Push the parsed operand into the list of operands
-  Operands.push_back(PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64()));
+  Operands.push_back(PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64(), &getContext()));
 
   // Check whether this is a TLS call expression
   const char TlsGetAddr[] = "__tls_get_addr";
@@ -1522,10 +1561,10 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
         EVal = MCBinaryExpr::createAdd(EVal, TlsCallAddend, getContext());
       // Add a __tls_get_addr operand with addend a, b, or a+b.
       Operands.back() = PPCOperand::CreateFromMCExpr(
-          EVal, S, Parser.getTok().getLoc(), false);
+          EVal, S, Parser.getTok().getLoc(), false, &getContext());
     }
 
-    Operands.push_back(PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64()));
+    Operands.push_back(PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64(), &getContext()));
   }
 
   // Otherwise, check for D-form memory operands
@@ -1553,7 +1592,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
     if (parseToken(AsmToken::RParen, "missing ')'"))
       return true;
     Operands.push_back(
-        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), /*IsMemOpBase=*/true));
+        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext(), /*IsMemOpBase=*/true));
   }
 
   return false;
@@ -1582,17 +1621,17 @@ bool PPCAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
   StringRef Mnemonic = Name.slice(0, Dot);
   if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
     Operands.push_back(
-        PPCOperand::CreateTokenWithStringCopy(Mnemonic, NameLoc, isPPC64()));
+        PPCOperand::CreateTokenWithStringCopy(Mnemonic, NameLoc, isPPC64(), &getContext()));
   else
-    Operands.push_back(PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64()));
+    Operands.push_back(PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64(), &getContext()));
   if (Dot != StringRef::npos) {
     SMLoc DotLoc = SMLoc::getFromPointer(NameLoc.getPointer() + Dot);
     StringRef DotStr = Name.substr(Dot);
     if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
       Operands.push_back(
-          PPCOperand::CreateTokenWithStringCopy(DotStr, DotLoc, isPPC64()));
+          PPCOperand::CreateTokenWithStringCopy(DotStr, DotLoc, isPPC64(), &getContext()));
     else
-      Operands.push_back(PPCOperand::CreateToken(DotStr, DotLoc, isPPC64()));
+      Operands.push_back(PPCOperand::CreateToken(DotStr, DotLoc, isPPC64(), &getContext()));
   }
 
   // If there are no more operands then finish
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
index c9b5dda0f9406..3f455223f401d 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -383,6 +383,17 @@ void PPCInstPrinter::printS32ImmOperand(const MCInst *MI, unsigned OpNo,
     printOperand(MI, OpNo, STI, O);
 }
 
+void PPCInstPrinter::printNegS32ImmOperand(const MCInst *MI, unsigned OpNo,
+                                           const MCSubtargetInfo &STI,
+                                           raw_ostream &O) {
+  if (MI->getOperand(OpNo).isImm()) {
+    long long Value = MI->getOperand(OpNo).getImm();
+    assert(isInt<32>(Value) && "Invalid s32imm argument!");
+    O << (long long)Value;
+  } else
+    printOperand(MI, OpNo, STI, O);
+}
+
 void PPCInstPrinter::printS34ImmOperand(const MCInst *MI, unsigned OpNo,
                                         const MCSubtargetInfo &STI,
                                         raw_ostream &O) {
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
index f6781b66756cf..56804a1c43948 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
@@ -72,6 +72,8 @@ class PPCInstPrinter : public MCInstPrinter {
                           const MCSubtargetInfo &STI, raw_ostream &O);
   void printS32ImmOperand(const MCInst *MI, unsigned OpNo,
                           const MCSubtargetInfo &STI, raw_ostream &O);
+  void printNegS32ImmOperand(const MCInst *MI, unsigned OpNo,
+                             const MCSubtargetInfo &STI, raw_ostream &O);
   void printS34ImmOperand(const MCInst *MI, unsigned OpNo,
                           const MCSubtargetInfo &STI, raw_ostream &O);
   void printU16ImmOperand(const MCInst *MI, unsigned OpNo,
diff --git a/llvm/lib/Target/PowerPC/PPCInstrFuture.td b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
index 8d89056e6afaf..c1f95de578dbe 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrFuture.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
@@ -714,6 +714,19 @@ let Predicates = [HasFutureVector], AddedComplexity = 400 in {
 // Predicate combinations available:
 // [HasVSX, IsISAFuture]
 
+def : InstAlias<"paddis $RT, $RA, $SI", (PADDIS gprc:$RT, gprc_nor0:$RA,
+                                            s32imm:$SI)>;
+def : InstAlias<"paddis $RT, $RA, $SI", (PADDIS8 g8rc:$RT, g8rc_nox0:$RA,
+                                            s32imm64:$SI)>;
+def : InstAlias<"plis $RT, $SI", (PADDIS gprc:$RT, ZERO, s32imm:$SI)>;
+def : InstAlias<"plis $RT, $SI", (PADDIS8 g8rc:$RT, ZERO8, s32imm64:$SI)>;
+// psubis: subtract immediate from register
+// For assembly: psubis $RT, $RA, $SI -> paddis $RT, $RA, -$SI, 0
+def : InstAlias<"psubis $RT, $RA, $SI", (PADDIS gprc:$RT, gprc_nor0:$RA,
+                                            neg_s32imm:$SI)>;
+def : InstAlias<"psubis $RT, $RA, $SI", (PADDIS8 g8rc:$RT, g8rc_nox0:$RA,
+                                            neg_s32imm64:$SI)>;
+
 let Predicates = [HasFutureVector] in {
   def : InstAlias<"xxaes128encp $XTp, $XAp, $XBp",
                   (XXAESENCP vsrprc:$XTp, vsrprc:$XAp, vsrprc:$XBp, 0)>;
diff --git a/llvm/lib/Target/PowerPC/PPCOperands.td b/llvm/lib/Target/PowerPC/PPCOperands.td
index af39d218a4c3d..25ee7bfaa94fc 100644
--- a/llvm/lib/Target/PowerPC/PPCOperands.td
+++ b/llvm/lib/Target/PowerPC/PPCOperands.td
@@ -103,6 +103,16 @@ multiclass SignedImmediateWithPCRel<ValueType vt, code pred, SDNodeXForm xform,
   defm _pcrel : SignedImmediateReloc<vt, pred, xform, asmop, width, fixup_pcrel>;
 }
 
+//===----------------------------------------------------------------------===//
+// Immediate transformation functions
+//===----------------------------------------------------------------------===//
+
+// NEG_S32 - Negate a signed 32-bit immediate value
+def NEG_S32 : SDNodeXForm<imm, [{
+  // Transformation function: -imm
+  return getI32Imm(-N->getSExtValue(), SDLoc(N));
+}]>;
+
 //===----------------------------------------------------------------------===//
 // Immediate AsmOperand definitions
 //===----------------------------------------------------------------------===//
@@ -127,6 +137,7 @@ def S16Imm : ImmediateAsmOperand<"isS16Imm","addS16ImmOperands">;
 def S17Imm : ImmediateAsmOperand<"isS17Imm","addS16ImmOperands">;
 def S32Imm : ImmediateAsmOperand<"isS32Imm">;
 def S34Imm : ImmediateAsmOperand<"isS34Imm">;
+def NegS32Imm : ImmediateAsmOperand<"isS32Imm","addNegImmOperands">;
 
 //===----------------------------------------------------------------------===//
 // i32 immediate operands
@@ -183,6 +194,9 @@ defm s32imm : SignedImmediateWithPCRel<i32,
 defm s34imm : SignedImmediateReloc<i32,
   [{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
   "S34Imm", 34, "PPC::fixup_ppc_imm34">;
+defm neg_s32imm : SignedImmediate<i32,
+  [{ return isInt<32>(Imm); }], NEG_S32,
+  "NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
 
 //===----------------------------------------------------------------------===//
 // i64 immediate operands
@@ -194,6 +208,10 @@ defm s32imm64 : SignedImmediateWithPCRel<i64,
 defm s34imm64 : SignedImmediateWithPCRel<i64,
   [{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
   "S34Imm", 34, "PPC::fixup_ppc_imm34", "PPC::fixup_ppc_pcrel34">;
+defm neg_s32imm64 : SignedImmediate<i64,
+  [{ return isInt<32>(Imm); }], NEG_S32,
+  "NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
+
 
 //===----------------------------------------------------------------------===//
 // Special case immediate operands
diff --git a/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ISAFuture.txt b/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ISAFuture.txt
index 1024c6b546c4a..a93b920c80cd7 100644
--- a/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ISAFuture.txt
+++ b/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ISAFuture.txt
@@ -298,7 +298,7 @@
 #CHECK: mtlpl 3, 4
 0x7c,0x80,0x1a,0x26
 
-#CHECK: paddis 10, 12, 1000000000, 0
+#CHECK: paddis 10, 12, 1000000000
 0x06,0x00,0x3b,0x9a,0x3d,0x4c,0xca,0x00
 
 #CHECK: paddis 10, 0, 1000000000, 1
diff --git a/llvm/test/MC/Disassembler/PowerPC/ppc64le-encoding-ISAFuture.txt b/llvm/test/MC/Disassembler/PowerPC/ppc64le-encoding-ISAFuture.txt
index bda8d1e69442f..2a1077c159845 100644
--- a/llvm/test/MC/Disassembler/PowerPC/ppc64le-encoding-ISAFuture.txt
+++ b/llvm/test/MC/Disassembler/PowerPC/ppc64le-encoding-ISAFuture.txt
@@ -292,7 +292,7 @@
 #CHECK: mtlpl 3, 4
 0x26,0x1a,0x80,0x7c
 
-#CHECK: paddis 10, 12, 1000000000, 0
+#CHECK: paddis 10, 12, 1000000000
 0x9a,0x3b,0x00,0x06,0x00,0xca,0x4c,0x3d
 
 #CHECK: paddis 10, 0, 1000000000, 1
diff --git a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
index eb616a15500f1..04a26848582b7 100644
--- a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
+++ b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
@@ -40,7 +40,6 @@
 # CHECK-BE: dmxxinstdmr512 1, 2, 34, 0   # encoding: [0xf0,0x82,0x17,0x52]
 # CHECK-LE: dmxxinstdmr512 1, 2, 34, 0   # encoding: [0x52,0x17,0x82,0xf0]
             dmxxinstdmr512 1, 2, 34, 0
-
 # CHECK-BE: dmxxinstdmr512 1, 2, 34, 1   # encoding: [0xf0,0x83,0x17,0x52]
 # CHECK-LE: dmxxinstdmr512 1, 2, 34, 1   # encoding: [0x52,0x17,0x83,0xf0]
             dmxxinstdmr512 1, 2, 34, 1
@@ -419,18 +418,48 @@
 #CHECK-BE: mtlpl 3, 4                     # encoding: [0x7c,0x80,0x1a,0x26]
 #CHECK-LE: mtlpl 3, 4                     # encoding: [0x26,0x1a,0x80,0x7c]
 
+           paddis 10, 12, 1000000000
+#CHECK-BE: paddis 10, 12, 1000000000, 0   # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME:                                        0x3d,0x4c,0xca,0x00]
+#CHECK-LE: paddis 10, 12, 1000000000, 0   # encoding: [0x9a,0x3b,0x00,0x06,
+#CHECK-LE-SAME:                                        0x00,0xca,0x4c,0x3d]
+
            paddis 10, 12, 1000000000, 0
 #CHECK-BE: paddis 10, 12, 1000000000, 0   # encoding: [0x06,0x00,0x3b,0x9a,
 #CHECK-BE-SAME:                                        0x3d,0x4c,0xca,0x00]
 #CHECK-LE: paddis 10, 12, 1000000000, 0   # encoding: [0x9a,0x3b,0x00,0x06,
 #CHECK-LE-SAME:                                        0x00,0xca,0x4c,0x3d]
 
+           psubis 10, 12, -1000000000
+#CHECK-BE: paddis 10, 12, 1000000000, 0    # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME:                                         0x3d,0x4c,0xca,0x00]
+#CHECK-LE: paddis 10, 12, 1000000000, 0    # encoding: [0x9a,0x3b,0x00,0x06,
+#CHECK-LE-SAME:                                         0x00,0xca,0x4c,0x3d]
+
+           paddis 10, 12, -1000000000
+#CHECK-BE: paddis 10, 12, -1000000000, 0   # encoding: [0x06,0x00,0xc4,0x65,
+#CHECK-BE-SAME:                                         0x3d,0x4c,0x36,0x00]
+#CHECK-LE: paddis 10, 12, -1000000000, 0   # encoding: [0x65,0xc4,0x00,0x06,
+#CHECK-LE-SAME:                                         0x00,0x36,0x4c,0x3d]
+
+           psubis 10, 12, 1000000000
+#CHECK-BE: paddis 10, 12, -1000000000, 0   # encoding: [0x06,0x00,0xc4,0x65,
+#CHECK-BE-SAME:                                         0x3d,0x4c,0x36,0x00]
+#CHECK-LE: paddis 10, 12, -1000000000, 0   # encoding: [0x65,0xc4,0x00,0x06,
+#CHECK-LE-SAME:                                         0x00,0x36,0x4c,0x3d]
+
            paddis 10, 0, 1000000000, 1
 #CHECK-BE: paddis 10, 0, 1000000000, 1    # encoding: [0x06,0x10,0x3b,0x9a,
 #CHECK-BE-SAME:                                        0x3d,0x40,0xca,0x00]
 #CHECK-LE: paddis 10, 0, 1000000000, 1    # encoding: [0x9a,0x3b,0x10,0x06,
 #CHECK-LE-SAME:                                        0x00,0xca,0x40,0x3d]
 
+           plis 10, 1000000000
+#CHECK-BE: plis 10, 1000000000           # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME:                                       0x3d,0x40,0xca,0x00]
+#CHECK-LE: plis 10, 1000000000           # encoding: [0x9a,0x3b,0x00,0x06,
+#CHECK-LE-SAME:                                       0x00,0xca,0x40,0x3d]
+
            xxmulmul 8, 3, 4, 2
 #CHECK-BE: xxmulmul 8, 3, 4, 2          # encoding: [0xed,0x03,0x22,0x08]
 #CHECK-LE: xxmulmul 8, 3, 4, 2          # encoding: [0x08,0x22,0x03,0xed]

>From 44929f946750e859d77f040735d6f4146d194937 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Mon, 2 Mar 2026 09:58:16 -0500
Subject: [PATCH 2/5] add MC test for psubis

---
 .../Target/PowerPC/AsmParser/PPCAsmParser.cpp |  71 +++++++-----
 llvm/test/MC/PowerPC/ppc64-psubis.s           | 108 ++++++++++++++++++
 2 files changed, 150 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/MC/PowerPC/ppc64-psubis.s

diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 5c66f889488ca..5325b416743b4 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -161,12 +161,13 @@ class PPCAsmParser : public MCTargetAsmParser {
                                MCContext &Ctx) override;
 };
 
-// Helper function to negate an operand - used by both PPCOperand and PPCAsmParser
-// Adds the negation of \p Op as an operand to \p Inst.
+// Helper function to negate an operand - used by both PPCOperand and
+// PPCAsmParser to add the negation of \p Op as an operand to \p Inst.
 //
-// This helper is used to lower pseudo-subtraction mnemonics (e.g. SUBI,
-// SUBIS, SUBIC, SUBIC_rec, PSUBI) into their real ADD-family equivalents by
-// negating the immediate or expression operand before appending it.
+// Originally this helper is only used to lower pseudo-subtraction mnemonics
+// (e.g. SUBI, SUBIS, SUBIC, SUBIC_rec, PSUBI) into their real ADD-family
+// equivalents by negating the immediate or expression operand before
+// appending it.  Now it's also used by PPCOperand for PSUBIS.
 //
 // The negation is performed as follows:
 // - If \p Op is an immediate, the negated integer value is added directly.
@@ -193,8 +194,8 @@ static void addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) {
     }
   } else if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Expr)) {
     if (BinExpr->getOpcode() == MCBinaryExpr::Sub) {
-      const MCExpr *NE = MCBinaryExpr::createSub(BinExpr->getRHS(),
-                                                 BinExpr->getLHS(), Ctx);
+      const MCExpr *NE =
+          MCBinaryExpr::createSub(BinExpr->getRHS(), BinExpr->getLHS(), Ctx);
       Inst.addOperand(MCOperand::createExpr(NE));
       return;
     }
@@ -690,8 +691,8 @@ struct PPCOperand : public MCParsedAsmOperand {
       return;
     }
 
-    // Create an MCOperand and use the static helper
-    assert(Ctx && "MCContext is required for addNegImmOperands");
+    // Create an MCOperand using the static helper function.
+    assert(Ctx && "MCContext is required for for non immediates");
     MCOperand Op = MCOperand::createExpr(getExpr());
     addNegOperand(Inst, Op, *Ctx);
   }
@@ -716,8 +717,8 @@ struct PPCOperand : public MCParsedAsmOperand {
 
   void print(raw_ostream &OS, const MCAsmInfo &MAI) const override;
 
-  static std::unique_ptr<PPCOperand> CreateToken(StringRef Str, SMLoc S,
-                                                 bool IsPPC64, MCContext *Ctx = nullptr) {
+  static std::unique_ptr<PPCOperand>
+  CreateToken(StringRef Str, SMLoc S, bool IsPPC64, MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(Token);
     Op->Tok.Data = Str.data();
     Op->Tok.Length = Str.size();
@@ -729,7 +730,8 @@ struct PPCOperand : public MCParsedAsmOperand {
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateTokenWithStringCopy(StringRef Str, SMLoc S, bool IsPPC64, MCContext *Ctx = nullptr) {
+  CreateTokenWithStringCopy(StringRef Str, SMLoc S, bool IsPPC64,
+                            MCContext *Ctx = nullptr) {
     // Allocate extra memory for the string and copy it.
     // FIXME: This is incorrect, Operands are owned by unique_ptr with a default
     // deleter which will destroy them by simply using "delete", not correctly
@@ -748,7 +750,8 @@ struct PPCOperand : public MCParsedAsmOperand {
   }
 
   static std::unique_ptr<PPCOperand> CreateImm(int64_t Val, SMLoc S, SMLoc E,
-                                               bool IsPPC64, MCContext *Ctx = nullptr,
+                                               bool IsPPC64,
+                                               MCContext *Ctx = nullptr,
                                                bool IsMemOpBase = false) {
     auto Op = std::make_unique<PPCOperand>(Immediate);
     Op->Imm.Val = Val;
@@ -761,7 +764,8 @@ struct PPCOperand : public MCParsedAsmOperand {
   }
 
   static std::unique_ptr<PPCOperand> CreateExpr(const MCExpr *Val, SMLoc S,
-                                                SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
+                                                SMLoc E, bool IsPPC64,
+                                                MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(Expression);
     Op->Expr.Val = Val;
     Op->Expr.CRVal = EvaluateCRExpr(Val);
@@ -772,8 +776,10 @@ struct PPCOperand : public MCParsedAsmOperand {
     return Op;
   }
 
-  static std::unique_ptr<PPCOperand>
-  CreateTLSReg(const MCSymbolRefExpr *Sym, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
+  static std::unique_ptr<PPCOperand> CreateTLSReg(const MCSymbolRefExpr *Sym,
+                                                  SMLoc S, SMLoc E,
+                                                  bool IsPPC64,
+                                                  MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(TLSRegister);
     Op->TLSReg.Sym = Sym;
     Op->StartLoc = S;
@@ -784,7 +790,8 @@ struct PPCOperand : public MCParsedAsmOperand {
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
+  CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64,
+                   MCContext *Ctx = nullptr) {
     auto Op = std::make_unique<PPCOperand>(ContextImmediate);
     Op->Imm.Val = Val;
     Op->StartLoc = S;
@@ -795,7 +802,8 @@ struct PPCOperand : public MCParsedAsmOperand {
   }
 
   static std::unique_ptr<PPCOperand>
-  CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64, MCContext *Ctx = nullptr) {
+  CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64,
+                   MCContext *Ctx = nullptr) {
     if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Val))
       return CreateImm(CE->getValue(), S, E, IsPPC64, Ctx);
 
@@ -1493,7 +1501,8 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
     if (!matchRegisterName(IntVal))
       return Error(S, "invalid register name");
 
-    Operands.push_back(PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext()));
+    Operands.push_back(
+        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext()));
     return false;
   }
   case AsmToken::Identifier:
@@ -1514,7 +1523,8 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
   }
 
   // Push the parsed operand into the list of operands
-  Operands.push_back(PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64(), &getContext()));
+  Operands.push_back(
+      PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64(), &getContext()));
 
   // Check whether this is a TLS call expression
   const char TlsGetAddr[] = "__tls_get_addr";
@@ -1564,7 +1574,8 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
           EVal, S, Parser.getTok().getLoc(), false, &getContext());
     }
 
-    Operands.push_back(PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64(), &getContext()));
+    Operands.push_back(
+        PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64(), &getContext()));
   }
 
   // Otherwise, check for D-form memory operands
@@ -1591,8 +1602,8 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
     E = Parser.getTok().getLoc();
     if (parseToken(AsmToken::RParen, "missing ')'"))
       return true;
-    Operands.push_back(
-        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext(), /*IsMemOpBase=*/true));
+    Operands.push_back(PPCOperand::CreateImm(
+        IntVal, S, E, isPPC64(), &getContext(), /*IsMemOpBase=*/true));
   }
 
   return false;
@@ -1620,18 +1631,20 @@ bool PPCAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
   size_t Dot = Name.find('.');
   StringRef Mnemonic = Name.slice(0, Dot);
   if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
-    Operands.push_back(
-        PPCOperand::CreateTokenWithStringCopy(Mnemonic, NameLoc, isPPC64(), &getContext()));
+    Operands.push_back(PPCOperand::CreateTokenWithStringCopy(
+        Mnemonic, NameLoc, isPPC64(), &getContext()));
   else
-    Operands.push_back(PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64(), &getContext()));
+    Operands.push_back(
+        PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64(), &getContext()));
   if (Dot != StringRef::npos) {
     SMLoc DotLoc = SMLoc::getFromPointer(NameLoc.getPointer() + Dot);
     StringRef DotStr = Name.substr(Dot);
     if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
-      Operands.push_back(
-          PPCOperand::CreateTokenWithStringCopy(DotStr, DotLoc, isPPC64(), &getContext()));
+      Operands.push_back(PPCOperand::CreateTokenWithStringCopy(
+          DotStr, DotLoc, isPPC64(), &getContext()));
     else
-      Operands.push_back(PPCOperand::CreateToken(DotStr, DotLoc, isPPC64(), &getContext()));
+      Operands.push_back(
+          PPCOperand::CreateToken(DotStr, DotLoc, isPPC64(), &getContext()));
   }
 
   // If there are no more operands then finish
diff --git a/llvm/test/MC/PowerPC/ppc64-psubis.s b/llvm/test/MC/PowerPC/ppc64-psubis.s
new file mode 100644
index 0000000000000..e0f4d8527800d
--- /dev/null
+++ b/llvm/test/MC/PowerPC/ppc64-psubis.s
@@ -0,0 +1,108 @@
+// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 6
+# RUN: llvm-mc -triple powerpc64-unknown-unknown --show-encoding \
+# RUN:   -mattr=+isa-future-instructions,+prefix-instrs %s | \
+# RUN:   FileCheck -check-prefix=CHECK-BE %s
+# RUN: llvm-mc -triple powerpc64le-unknown-unknown --show-encoding \
+# RUN:   -mattr=+isa-future-instructions,+prefix-instrs %s | \
+# RUN:   FileCheck -check-prefix=CHECK-LE %s
+
+# Tests for psubis encoding with various immediate inputs.
+# Created via AI.
+
+# psubis RT, RA, SI is an alias for paddis RT, RA, -SI, 0.
+# The neg_s32imm operand negates SI before encoding.
+
+# The 32-bit negated immediate is split:
+#   (-SI)[31:16] in the lower 16 bits of the prefix word,
+#   (-SI)[15:0]  in the lower 16 bits of the instruction word.
+# Prefix word (BE): 0x06 0x00 <(-SI)[31:16] high byte> <(-SI)[31:16] low byte>
+# Instr  word (BE): 0x3C <(RT<<3)|(RA>>2)> <(RA<<6)|(-SI)[15:8]> <(-SI)[7:0]>
+
+# psubis 3, 3, 1  ->  paddis 3, 3, -1, 0
+
+# -1 = 0xFFFFFFFF: prefix SI[31:16]=0xFFFF, instr SI[15:0]=0xFFFF
+# Prefix (BE): 06 00 FF FF
+# Instr  (BE): 3C 63 FF FF
+            psubis 3, 3, 1
+// CHECK-BE: paddis 3, 3, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xff,0xff]
+// CHECK-LE: paddis 3, 3, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x63,0x3c]
+
+# psubis 3, 3, -1  ->  paddis 3, 3, 1, 0
+
+# 1 = 0x00000001: prefix SI[31:16]=0x0000, instr SI[15:0]=0x0001
+# Prefix (BE): 06 00 00 00
+# Instr  (BE): 3C 63 00 01
+            psubis 3, 3, -1
+// CHECK-BE: paddis 3, 3, 1, 0                       # encoding: [0x06,0x00,0x00,0x00,0x3c,0x63,0x00,0x01]
+// CHECK-LE: paddis 3, 3, 1, 0                       # encoding: [0x00,0x00,0x00,0x06,0x01,0x00,0x63,0x3c]
+
+# psubis 3, 3, 0x1234  ->  paddis 3, 3, -0x1234, 0
+
+# -0x1234 = 0xFFFFEDCC: prefix SI[31:16]=0xFFFF, instr SI[15:0]=0xEDCC
+# Prefix (BE): 06 00 FF FF
+# Instr  (BE): 3C 63 ED CC
+            psubis 3, 3, 0x1234
+// CHECK-BE: paddis 3, 3, -4660, 0                   # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xed,0xcc]
+// CHECK-LE: paddis 3, 3, -4660, 0                   # encoding: [0xff,0xff,0x00,0x06,0xcc,0xed,0x63,0x3c]
+
+# psubis 3, 3, 0x12345678  ->  paddis 3, 3, -0x12345678, 0
+
+# -0x12345678 = 0xEDCBA988: prefix SI[31:16]=0xEDCB, instr SI[15:0]=0xA988
+# Prefix (BE): 06 00 ED CB
+# Instr  (BE): 3C 63 A9 88
+            psubis 3, 3, 0x12345678
+// CHECK-BE: paddis 3, 3, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x63,0xa9,0x88]
+// CHECK-LE: paddis 3, 3, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x63,0x3c]
+
+# psubis 1, 2, 1  ->  paddis 1, 2, -1, 0  (different RT and RA)
+
+# -1 = 0xFFFFFFFF: prefix SI[31:16]=0xFFFF, instr SI[15:0]=0xFFFF
+# Prefix (BE): 06 00 FF FF
+# Instr  (BE): 3C 22 FF FF
+            psubis 1, 2, 1
+// CHECK-BE: paddis 1, 2, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x22,0xff,0xff]
+// CHECK-LE: paddis 1, 2, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x22,0x3c]
+
+# psubis 1, 2, 0x12345678  ->  paddis 1, 2, -0x12345678, 0
+
+# -0x12345678 = 0xEDCBA988: prefix SI[31:16]=0xEDCB, instr SI[15:0]=0xA988
+# Prefix (BE): 06 00 ED CB
+# Instr  (BE): 3C 22 A9 88
+            psubis 1, 2, 0x12345678
+// CHECK-BE: paddis 1, 2, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x22,0xa9,0x88]
+// CHECK-LE: paddis 1, 2, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x22,0x3c]
+
+# psubis 3, 0, 1  ->  paddis 3, 0, -1, 0  (RA=0)
+
+# -1 = 0xFFFFFFFF: prefix SI[31:16]=0xFFFF, instr SI[15:0]=0xFFFF
+# Prefix (BE): 06 00 FF FF
+# Instr  (BE): 3C 60 FF FF
+            psubis 3, 0, 1
+// CHECK-BE: plis	3, -1                           # encoding: [0x06,0x00,0xff,0xff,0x3c,0x60,0xff,0xff]
+// CHECK-LE: plis	3, -1                           # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x60,0x3c]
+
+# psubis 3, 0, 0x7FFFFFFF  ->  paddis 3, 0, -0x7FFFFFFF, 0
+
+# -0x7FFFFFFF = 0x80000001: prefix SI[31:16]=0x8000, instr SI[15:0]=0x0001
+# Prefix (BE): 06 00 80 00
+# Instr  (BE): 3C 60 00 01
+            psubis 3, 0, 0x7FFFFFFF
+// CHECK-BE: plis	3, -2147483647                  # encoding: [0x06,0x00,0x80,0x00,0x3c,0x60,0x00,0x01]
+// CHECK-LE: plis	3, -2147483647                  # encoding: [0x00,0x80,0x00,0x06,0x01,0x00,0x60,0x3c]
+
+# psubis with a symbol reference: psubis 3, 3, target
+# -> paddis 3, 3, -target, 0
+
+# The fixup negates the symbol value; fixup kind is fixup_ppc_imm32.
+
+# At encode time SI=0, so:
+# Prefix (BE): 0x06'A' A A A
+# Instr  (BE): 3C 63 00 00
+target:
+// CHECK-BE: target:
+// CHECK-LE: target:
+            psubis 3, 3, target
+// CHECK-BE: paddis 3, 3, -target, 0                 # encoding: [0x06'A',A,A,A,0x3c,0x63,0x00,0x00]
+// CHECK-BE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32
+// CHECK-LE: paddis 3, 3, -target, 0                 # encoding: [A,A,A,0x06'A',0x00,0x00,0x63,0x3c]
+// CHECK-LE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32

>From b9e715e8eec8ff2909c3086bb3f966cb043443e0 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Fri, 20 Mar 2026 14:21:41 -0400
Subject: [PATCH 3/5] address review comments

---
 .../Target/PowerPC/AsmParser/PPCAsmParser.cpp | 71 ++++++++-----------
 llvm/lib/Target/PowerPC/PPCOperands.td        |  4 +-
 llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s |  1 +
 llvm/test/MC/PowerPC/ppc64-psubis.s           | 56 ++++++---------
 4 files changed, 55 insertions(+), 77 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 5325b416743b4..49c9934655538 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -94,6 +94,8 @@ EvaluateCRExpr(const MCExpr *E) {
   llvm_unreachable("Invalid expression kind!");
 }
 
+static void addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx);
+
 namespace {
 
 struct PPCOperand;
@@ -161,48 +163,6 @@ class PPCAsmParser : public MCTargetAsmParser {
                                MCContext &Ctx) override;
 };
 
-// Helper function to negate an operand - used by both PPCOperand and
-// PPCAsmParser to add the negation of \p Op as an operand to \p Inst.
-//
-// Originally this helper is only used to lower pseudo-subtraction mnemonics
-// (e.g. SUBI, SUBIS, SUBIC, SUBIC_rec, PSUBI) into their real ADD-family
-// equivalents by negating the immediate or expression operand before
-// appending it.  Now it's also used by PPCOperand for PSUBIS.
-//
-// The negation is performed as follows:
-// - If \p Op is an immediate, the negated integer value is added directly.
-// - If \p Op is a unary-minus expression (i.e. \c -E), the inner
-//   sub-expression \c E is added, effectively cancelling the double negation.
-// - If \p Op is a binary-subtraction expression (i.e. \c LHS-RHS), the
-//   operands are swapped to produce \c RHS-LHS.
-// - Otherwise, a new unary-minus expression wrapping \p Op's expression is
-//   created and added.
-//
-// \param Inst  The instruction being built; the negated operand is appended.
-// \param Op    The source operand whose value is to be negated.
-// \param Ctx   The MC context used to allocate new expression nodes.
-static void addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) {
-  if (Op.isImm()) {
-    Inst.addOperand(MCOperand::createImm(-Op.getImm()));
-    return;
-  }
-  const MCExpr *Expr = Op.getExpr();
-  if (const MCUnaryExpr *UnExpr = dyn_cast<MCUnaryExpr>(Expr)) {
-    if (UnExpr->getOpcode() == MCUnaryExpr::Minus) {
-      Inst.addOperand(MCOperand::createExpr(UnExpr->getSubExpr()));
-      return;
-    }
-  } else if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Expr)) {
-    if (BinExpr->getOpcode() == MCBinaryExpr::Sub) {
-      const MCExpr *NE =
-          MCBinaryExpr::createSub(BinExpr->getRHS(), BinExpr->getLHS(), Ctx);
-      Inst.addOperand(MCOperand::createExpr(NE));
-      return;
-    }
-  }
-  Inst.addOperand(MCOperand::createExpr(MCUnaryExpr::createMinus(Expr, Ctx)));
-}
-
 /// PPCOperand - Instances of this class represent a parsed PowerPC machine
 /// instruction.
 struct PPCOperand : public MCParsedAsmOperand {
@@ -861,6 +821,33 @@ void PPCOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
   }
 }
 
+static void
+addNegOperand(MCInst &Inst, MCOperand &Op, MCContext &Ctx) {
+  if (Op.isImm()) {
+    Inst.addOperand(MCOperand::createImm(-Op.getImm()));
+    return;
+  }
+  const MCExpr *Expr = Op.getExpr();
+  if (const MCUnaryExpr *UnExpr = dyn_cast<MCUnaryExpr>(Expr)) {
+    // For unary-minus expression (i.e. -E), the inner sub-expression E
+    // is added, effectively cancelling the double negation.
+    if (UnExpr->getOpcode() == MCUnaryExpr::Minus) {
+      Inst.addOperand(MCOperand::createExpr(UnExpr->getSubExpr()));
+      return;
+    }
+  } else if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Expr)) {
+    // For binary-subtraction expression (i.e. LHS-RHS), the operands
+    // are swapped to produce RHS-LHS.
+    if (BinExpr->getOpcode() == MCBinaryExpr::Sub) {
+      const MCExpr *NE = MCBinaryExpr::createSub(BinExpr->getRHS(),
+                                                 BinExpr->getLHS(), Ctx);
+      Inst.addOperand(MCOperand::createExpr(NE));
+      return;
+    }
+  }
+  Inst.addOperand(MCOperand::createExpr(MCUnaryExpr::createMinus(Expr, Ctx)));
+}
+
 void PPCAsmParser::processInstruction(MCInst &Inst,
                                       const OperandVector &Operands) {
   int Opcode = Inst.getOpcode();
diff --git a/llvm/lib/Target/PowerPC/PPCOperands.td b/llvm/lib/Target/PowerPC/PPCOperands.td
index 25ee7bfaa94fc..08e8bf040c199 100644
--- a/llvm/lib/Target/PowerPC/PPCOperands.td
+++ b/llvm/lib/Target/PowerPC/PPCOperands.td
@@ -194,7 +194,7 @@ defm s32imm : SignedImmediateWithPCRel<i32,
 defm s34imm : SignedImmediateReloc<i32,
   [{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
   "S34Imm", 34, "PPC::fixup_ppc_imm34">;
-defm neg_s32imm : SignedImmediate<i32,
+defm neg_s32imm : SignedImmediateReloc<i32,
   [{ return isInt<32>(Imm); }], NEG_S32,
   "NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
 
@@ -208,7 +208,7 @@ defm s32imm64 : SignedImmediateWithPCRel<i64,
 defm s34imm64 : SignedImmediateWithPCRel<i64,
   [{ return isInt<34>(Imm); }], NOOP_SDNodeXForm,
   "S34Imm", 34, "PPC::fixup_ppc_imm34", "PPC::fixup_ppc_pcrel34">;
-defm neg_s32imm64 : SignedImmediate<i64,
+defm neg_s32imm64 : SignedImmediateReloc<i64,
   [{ return isInt<32>(Imm); }], NEG_S32,
   "NegS32Imm", 32, "PPC::fixup_ppc_imm32">;
 
diff --git a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
index 04a26848582b7..1b816a97e1b28 100644
--- a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
+++ b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
@@ -40,6 +40,7 @@
 # CHECK-BE: dmxxinstdmr512 1, 2, 34, 0   # encoding: [0xf0,0x82,0x17,0x52]
 # CHECK-LE: dmxxinstdmr512 1, 2, 34, 0   # encoding: [0x52,0x17,0x82,0xf0]
             dmxxinstdmr512 1, 2, 34, 0
+
 # CHECK-BE: dmxxinstdmr512 1, 2, 34, 1   # encoding: [0xf0,0x83,0x17,0x52]
 # CHECK-LE: dmxxinstdmr512 1, 2, 34, 1   # encoding: [0x52,0x17,0x83,0xf0]
             dmxxinstdmr512 1, 2, 34, 1
diff --git a/llvm/test/MC/PowerPC/ppc64-psubis.s b/llvm/test/MC/PowerPC/ppc64-psubis.s
index e0f4d8527800d..6a60b0349fc73 100644
--- a/llvm/test/MC/PowerPC/ppc64-psubis.s
+++ b/llvm/test/MC/PowerPC/ppc64-psubis.s
@@ -1,4 +1,4 @@
-// NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 6
+#  NOTE: Assertions have been autogenerated by utils/update_mc_test_checks.py UTC_ARGS: --version 6
 # RUN: llvm-mc -triple powerpc64-unknown-unknown --show-encoding \
 # RUN:   -mattr=+isa-future-instructions,+prefix-instrs %s | \
 # RUN:   FileCheck -check-prefix=CHECK-BE %s
@@ -6,17 +6,7 @@
 # RUN:   -mattr=+isa-future-instructions,+prefix-instrs %s | \
 # RUN:   FileCheck -check-prefix=CHECK-LE %s
 
-# Tests for psubis encoding with various immediate inputs.
-# Created via AI.
-
 # psubis RT, RA, SI is an alias for paddis RT, RA, -SI, 0.
-# The neg_s32imm operand negates SI before encoding.
-
-# The 32-bit negated immediate is split:
-#   (-SI)[31:16] in the lower 16 bits of the prefix word,
-#   (-SI)[15:0]  in the lower 16 bits of the instruction word.
-# Prefix word (BE): 0x06 0x00 <(-SI)[31:16] high byte> <(-SI)[31:16] low byte>
-# Instr  word (BE): 0x3C <(RT<<3)|(RA>>2)> <(RA<<6)|(-SI)[15:8]> <(-SI)[7:0]>
 
 # psubis 3, 3, 1  ->  paddis 3, 3, -1, 0
 
@@ -24,8 +14,8 @@
 # Prefix (BE): 06 00 FF FF
 # Instr  (BE): 3C 63 FF FF
             psubis 3, 3, 1
-// CHECK-BE: paddis 3, 3, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xff,0xff]
-// CHECK-LE: paddis 3, 3, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x63,0x3c]
+# CHECK-BE: paddis 3, 3, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xff,0xff]
+# CHECK-LE: paddis 3, 3, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x63,0x3c]
 
 # psubis 3, 3, -1  ->  paddis 3, 3, 1, 0
 
@@ -33,8 +23,8 @@
 # Prefix (BE): 06 00 00 00
 # Instr  (BE): 3C 63 00 01
             psubis 3, 3, -1
-// CHECK-BE: paddis 3, 3, 1, 0                       # encoding: [0x06,0x00,0x00,0x00,0x3c,0x63,0x00,0x01]
-// CHECK-LE: paddis 3, 3, 1, 0                       # encoding: [0x00,0x00,0x00,0x06,0x01,0x00,0x63,0x3c]
+# CHECK-BE: paddis 3, 3, 1, 0                       # encoding: [0x06,0x00,0x00,0x00,0x3c,0x63,0x00,0x01]
+# CHECK-LE: paddis 3, 3, 1, 0                       # encoding: [0x00,0x00,0x00,0x06,0x01,0x00,0x63,0x3c]
 
 # psubis 3, 3, 0x1234  ->  paddis 3, 3, -0x1234, 0
 
@@ -42,8 +32,8 @@
 # Prefix (BE): 06 00 FF FF
 # Instr  (BE): 3C 63 ED CC
             psubis 3, 3, 0x1234
-// CHECK-BE: paddis 3, 3, -4660, 0                   # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xed,0xcc]
-// CHECK-LE: paddis 3, 3, -4660, 0                   # encoding: [0xff,0xff,0x00,0x06,0xcc,0xed,0x63,0x3c]
+# CHECK-BE: paddis 3, 3, -4660, 0                   # encoding: [0x06,0x00,0xff,0xff,0x3c,0x63,0xed,0xcc]
+# CHECK-LE: paddis 3, 3, -4660, 0                   # encoding: [0xff,0xff,0x00,0x06,0xcc,0xed,0x63,0x3c]
 
 # psubis 3, 3, 0x12345678  ->  paddis 3, 3, -0x12345678, 0
 
@@ -51,8 +41,8 @@
 # Prefix (BE): 06 00 ED CB
 # Instr  (BE): 3C 63 A9 88
             psubis 3, 3, 0x12345678
-// CHECK-BE: paddis 3, 3, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x63,0xa9,0x88]
-// CHECK-LE: paddis 3, 3, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x63,0x3c]
+# CHECK-BE: paddis 3, 3, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x63,0xa9,0x88]
+# CHECK-LE: paddis 3, 3, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x63,0x3c]
 
 # psubis 1, 2, 1  ->  paddis 1, 2, -1, 0  (different RT and RA)
 
@@ -60,8 +50,8 @@
 # Prefix (BE): 06 00 FF FF
 # Instr  (BE): 3C 22 FF FF
             psubis 1, 2, 1
-// CHECK-BE: paddis 1, 2, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x22,0xff,0xff]
-// CHECK-LE: paddis 1, 2, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x22,0x3c]
+# CHECK-BE: paddis 1, 2, -1, 0                      # encoding: [0x06,0x00,0xff,0xff,0x3c,0x22,0xff,0xff]
+# CHECK-LE: paddis 1, 2, -1, 0                      # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x22,0x3c]
 
 # psubis 1, 2, 0x12345678  ->  paddis 1, 2, -0x12345678, 0
 
@@ -69,8 +59,8 @@
 # Prefix (BE): 06 00 ED CB
 # Instr  (BE): 3C 22 A9 88
             psubis 1, 2, 0x12345678
-// CHECK-BE: paddis 1, 2, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x22,0xa9,0x88]
-// CHECK-LE: paddis 1, 2, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x22,0x3c]
+# CHECK-BE: paddis 1, 2, -305419896, 0              # encoding: [0x06,0x00,0xed,0xcb,0x3c,0x22,0xa9,0x88]
+# CHECK-LE: paddis 1, 2, -305419896, 0              # encoding: [0xcb,0xed,0x00,0x06,0x88,0xa9,0x22,0x3c]
 
 # psubis 3, 0, 1  ->  paddis 3, 0, -1, 0  (RA=0)
 
@@ -78,8 +68,8 @@
 # Prefix (BE): 06 00 FF FF
 # Instr  (BE): 3C 60 FF FF
             psubis 3, 0, 1
-// CHECK-BE: plis	3, -1                           # encoding: [0x06,0x00,0xff,0xff,0x3c,0x60,0xff,0xff]
-// CHECK-LE: plis	3, -1                           # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x60,0x3c]
+# CHECK-BE: plis	3, -1                           # encoding: [0x06,0x00,0xff,0xff,0x3c,0x60,0xff,0xff]
+# CHECK-LE: plis	3, -1                           # encoding: [0xff,0xff,0x00,0x06,0xff,0xff,0x60,0x3c]
 
 # psubis 3, 0, 0x7FFFFFFF  ->  paddis 3, 0, -0x7FFFFFFF, 0
 
@@ -87,8 +77,8 @@
 # Prefix (BE): 06 00 80 00
 # Instr  (BE): 3C 60 00 01
             psubis 3, 0, 0x7FFFFFFF
-// CHECK-BE: plis	3, -2147483647                  # encoding: [0x06,0x00,0x80,0x00,0x3c,0x60,0x00,0x01]
-// CHECK-LE: plis	3, -2147483647                  # encoding: [0x00,0x80,0x00,0x06,0x01,0x00,0x60,0x3c]
+# CHECK-BE: plis	3, -2147483647                  # encoding: [0x06,0x00,0x80,0x00,0x3c,0x60,0x00,0x01]
+# CHECK-LE: plis	3, -2147483647                  # encoding: [0x00,0x80,0x00,0x06,0x01,0x00,0x60,0x3c]
 
 # psubis with a symbol reference: psubis 3, 3, target
 # -> paddis 3, 3, -target, 0
@@ -99,10 +89,10 @@
 # Prefix (BE): 0x06'A' A A A
 # Instr  (BE): 3C 63 00 00
 target:
-// CHECK-BE: target:
-// CHECK-LE: target:
+# CHECK-BE: target:
+# CHECK-LE: target:
             psubis 3, 3, target
-// CHECK-BE: paddis 3, 3, -target, 0                 # encoding: [0x06'A',A,A,A,0x3c,0x63,0x00,0x00]
-// CHECK-BE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32
-// CHECK-LE: paddis 3, 3, -target, 0                 # encoding: [A,A,A,0x06'A',0x00,0x00,0x63,0x3c]
-// CHECK-LE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32
+# CHECK-BE: paddis 3, 3, -target, 0                 # encoding: [0x06'A',A,A,A,0x3c,0x63,0x00,0x00]
+# CHECK-BE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32
+# CHECK-LE: paddis 3, 3, -target, 0                 # encoding: [A,A,A,0x06'A',0x00,0x00,0x63,0x3c]
+# CHECK-LE-NEXT: #   fixup A - offset: 0, value: -target, kind: fixup_ppc_imm32

>From 9690e1cc7ae54a295c327005a67a4dbaccafb2a2 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Wed, 22 Apr 2026 12:11:42 -0400
Subject: [PATCH 4/5] Update MCContext a reference

---
 .../Target/PowerPC/AsmParser/PPCAsmParser.cpp | 60 +++++++++----------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 49c9934655538..875596973f6c7 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -176,7 +176,10 @@ struct PPCOperand : public MCParsedAsmOperand {
 
   SMLoc StartLoc, EndLoc;
   bool IsPPC64;
-  MCContext *Ctx;
+
+  // Keep the MCContext around as the MCExprs may need manipulated during
+  // the add<>Operands() calls.
+  MCContext &Ctx;
 
   struct TokOp {
     const char *Data;
@@ -204,10 +207,10 @@ struct PPCOperand : public MCParsedAsmOperand {
     struct TLSRegOp TLSReg;
   };
 
-  PPCOperand(KindTy K) : Kind(K) {}
+  PPCOperand(KindTy K, MCContext &Ctx) : Kind(K), Ctx(Ctx) {}
 
 public:
-  PPCOperand(const PPCOperand &o) : MCParsedAsmOperand() {
+  PPCOperand(const PPCOperand &o) : MCParsedAsmOperand(), Ctx(o.Ctx) {
     Kind = o.Kind;
     StartLoc = o.StartLoc;
     EndLoc = o.EndLoc;
@@ -678,92 +681,85 @@ struct PPCOperand : public MCParsedAsmOperand {
   void print(raw_ostream &OS, const MCAsmInfo &MAI) const override;
 
   static std::unique_ptr<PPCOperand>
-  CreateToken(StringRef Str, SMLoc S, bool IsPPC64, MCContext *Ctx = nullptr) {
-    auto Op = std::make_unique<PPCOperand>(Token);
+  CreateToken(StringRef Str, SMLoc S, bool IsPPC64, MCContext &Ctx) {
+    auto Op = std::make_unique<PPCOperand>(Token, Ctx);
     Op->Tok.Data = Str.data();
     Op->Tok.Length = Str.size();
     Op->StartLoc = S;
     Op->EndLoc = S;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
   CreateTokenWithStringCopy(StringRef Str, SMLoc S, bool IsPPC64,
-                            MCContext *Ctx = nullptr) {
+                            MCContext &Ctx) {
     // Allocate extra memory for the string and copy it.
     // FIXME: This is incorrect, Operands are owned by unique_ptr with a default
     // deleter which will destroy them by simply using "delete", not correctly
     // calling operator delete on this extra memory after calling the dtor
     // explicitly.
     void *Mem = ::operator new(sizeof(PPCOperand) + Str.size());
-    std::unique_ptr<PPCOperand> Op(new (Mem) PPCOperand(Token));
+    std::unique_ptr<PPCOperand> Op(new (Mem) PPCOperand(Token, Ctx));
     Op->Tok.Data = reinterpret_cast<const char *>(Op.get() + 1);
     Op->Tok.Length = Str.size();
     std::memcpy(const_cast<char *>(Op->Tok.Data), Str.data(), Str.size());
     Op->StartLoc = S;
     Op->EndLoc = S;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand> CreateImm(int64_t Val, SMLoc S, SMLoc E,
-                                               bool IsPPC64,
-                                               MCContext *Ctx = nullptr,
+                                               bool IsPPC64, MCContext &Ctx,
                                                bool IsMemOpBase = false) {
-    auto Op = std::make_unique<PPCOperand>(Immediate);
+    auto Op = std::make_unique<PPCOperand>(Immediate, Ctx);
     Op->Imm.Val = Val;
     Op->Imm.IsMemOpBase = IsMemOpBase;
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand> CreateExpr(const MCExpr *Val, SMLoc S,
                                                 SMLoc E, bool IsPPC64,
-                                                MCContext *Ctx = nullptr) {
-    auto Op = std::make_unique<PPCOperand>(Expression);
+                                                MCContext &Ctx) {
+    auto Op = std::make_unique<PPCOperand>(Expression, Ctx);
     Op->Expr.Val = Val;
     Op->Expr.CRVal = EvaluateCRExpr(Val);
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand> CreateTLSReg(const MCSymbolRefExpr *Sym,
                                                   SMLoc S, SMLoc E,
                                                   bool IsPPC64,
-                                                  MCContext *Ctx = nullptr) {
-    auto Op = std::make_unique<PPCOperand>(TLSRegister);
+                                                  MCContext &Ctx) {
+    auto Op = std::make_unique<PPCOperand>(TLSRegister, Ctx);
     Op->TLSReg.Sym = Sym;
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
   CreateContextImm(int64_t Val, SMLoc S, SMLoc E, bool IsPPC64,
-                   MCContext *Ctx = nullptr) {
-    auto Op = std::make_unique<PPCOperand>(ContextImmediate);
+                   MCContext &Ctx) {
+    auto Op = std::make_unique<PPCOperand>(ContextImmediate, Ctx);
     Op->Imm.Val = Val;
     Op->StartLoc = S;
     Op->EndLoc = E;
     Op->IsPPC64 = IsPPC64;
-    Op->Ctx = Ctx;
     return Op;
   }
 
   static std::unique_ptr<PPCOperand>
   CreateFromMCExpr(const MCExpr *Val, SMLoc S, SMLoc E, bool IsPPC64,
-                   MCContext *Ctx = nullptr) {
+                   MCContext &Ctx) {
     if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Val))
       return CreateImm(CE->getValue(), S, E, IsPPC64, Ctx);
 
@@ -1489,7 +1485,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
       return Error(S, "invalid register name");
 
     Operands.push_back(
-        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), &getContext()));
+        PPCOperand::CreateImm(IntVal, S, E, isPPC64(), getContext()));
     return false;
   }
   case AsmToken::Identifier:
@@ -1511,7 +1507,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
 
   // Push the parsed operand into the list of operands
   Operands.push_back(
-      PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64(), &getContext()));
+      PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64(), getContext()));
 
   // Check whether this is a TLS call expression
   const char TlsGetAddr[] = "__tls_get_addr";
@@ -1558,11 +1554,11 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
         EVal = MCBinaryExpr::createAdd(EVal, TlsCallAddend, getContext());
       // Add a __tls_get_addr operand with addend a, b, or a+b.
       Operands.back() = PPCOperand::CreateFromMCExpr(
-          EVal, S, Parser.getTok().getLoc(), false, &getContext());
+          EVal, S, Parser.getTok().getLoc(), false, getContext());
     }
 
     Operands.push_back(
-        PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64(), &getContext()));
+        PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64(), getContext()));
   }
 
   // Otherwise, check for D-form memory operands
@@ -1590,7 +1586,7 @@ bool PPCAsmParser::parseOperand(OperandVector &Operands) {
     if (parseToken(AsmToken::RParen, "missing ')'"))
       return true;
     Operands.push_back(PPCOperand::CreateImm(
-        IntVal, S, E, isPPC64(), &getContext(), /*IsMemOpBase=*/true));
+        IntVal, S, E, isPPC64(), getContext(), /*IsMemOpBase=*/true));
   }
 
   return false;
@@ -1619,19 +1615,19 @@ bool PPCAsmParser::parseInstruction(ParseInstructionInfo &Info, StringRef Name,
   StringRef Mnemonic = Name.slice(0, Dot);
   if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
     Operands.push_back(PPCOperand::CreateTokenWithStringCopy(
-        Mnemonic, NameLoc, isPPC64(), &getContext()));
+        Mnemonic, NameLoc, isPPC64(), getContext()));
   else
     Operands.push_back(
-        PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64(), &getContext()));
+        PPCOperand::CreateToken(Mnemonic, NameLoc, isPPC64(), getContext()));
   if (Dot != StringRef::npos) {
     SMLoc DotLoc = SMLoc::getFromPointer(NameLoc.getPointer() + Dot);
     StringRef DotStr = Name.substr(Dot);
     if (!NewOpcode.empty()) // Underlying memory for Name is volatile.
       Operands.push_back(PPCOperand::CreateTokenWithStringCopy(
-          DotStr, DotLoc, isPPC64(), &getContext()));
+          DotStr, DotLoc, isPPC64(), getContext()));
     else
       Operands.push_back(
-          PPCOperand::CreateToken(DotStr, DotLoc, isPPC64(), &getContext()));
+          PPCOperand::CreateToken(DotStr, DotLoc, isPPC64(), getContext()));
   }
 
   // If there are no more operands then finish

>From 9841cb20b58cc57caf6abf466b040a04bdf11283 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Wed, 22 Apr 2026 12:29:49 -0400
Subject: [PATCH 5/5] remove assert since this is now a reference

---
 llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 875596973f6c7..3c2fb0bf73ecd 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -655,9 +655,8 @@ struct PPCOperand : public MCParsedAsmOperand {
     }
 
     // Create an MCOperand using the static helper function.
-    assert(Ctx && "MCContext is required for for non immediates");
     MCOperand Op = MCOperand::createExpr(getExpr());
-    addNegOperand(Inst, Op, *Ctx);
+    addNegOperand(Inst, Op, Ctx);
   }
 
   void addBranchTargetOperands(MCInst &Inst, unsigned N) const {



More information about the llvm-commits mailing list