[llvm] [PowerPC] Add mnemonics to paddis (PR #179979)
Lei Huang via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 2 06:58:32 PST 2026
https://github.com/lei137 updated https://github.com/llvm/llvm-project/pull/179979
>From bcb74a60038c0a90bdf382a86eccd8932de915bc 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 | 8 ++++++
.../PowerPC/MCTargetDesc/PPCInstPrinter.cpp | 11 ++++++++
.../PowerPC/MCTargetDesc/PPCInstPrinter.h | 2 ++
llvm/lib/Target/PowerPC/PPCInstrFuture.td | 9 ++++++
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 | 28 +++++++++++++++++--
8 files changed, 76 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index b07f95018ca90..13408cb8628e0 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -640,6 +640,14 @@ 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()));
+ else
+ Inst.addOperand(MCOperand::createExpr(getExpr()));
+ }
+
void addBranchTargetOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
if (Kind == Immediate)
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
index 46d6093be3c17..bbd604ad59175 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -441,6 +441,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 2fbd06c5a96cf..93b9526626c20 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
@@ -82,6 +82,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 717454f78e2a4..0d3f457bc087e 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrFuture.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
@@ -605,6 +605,15 @@ let Predicates = [HasVSX, IsISAFuture] 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)>;
+def : InstAlias<"psubis $RT, $SI", (PADDIS gprc:$RT, ZERO, neg_s32imm:$SI)>;
+def : InstAlias<"psubis $RT, $SI", (PADDIS8 g8rc:$RT, ZERO8, neg_s32imm64:$SI)>;
+
let Predicates = [HasVSX, IsISAFuture] 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 f2603fb4ed788..95700b4e83372 100644
--- a/llvm/lib/Target/PowerPC/PPCOperands.td
+++ b/llvm/lib/Target/PowerPC/PPCOperands.td
@@ -84,6 +84,16 @@ multiclass SignedImmediateWithPCRel<ValueType vt, code pred,
defm _pcrel : SignedImmediate<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
//===----------------------------------------------------------------------===//
@@ -107,6 +117,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
@@ -153,6 +164,9 @@ defm s32imm : SignedImmediateWithPCRel<i32,
defm s34imm : SignedImmediate<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
@@ -164,6 +178,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..1868bb0f07244 100644
--- a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
+++ b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
@@ -419,10 +419,16 @@
#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 # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME: 0x3d,0x4c,0xca,0x00]
+#CHECK-LE: paddis 10, 12, 1000000000 # 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: paddis 10, 12, 1000000000 # 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: paddis 10, 12, 1000000000 # encoding: [0x9a,0x3b,0x00,0x06,
#CHECK-LE-SAME: 0x00,0xca,0x4c,0x3d]
paddis 10, 0, 1000000000, 1
@@ -431,6 +437,24 @@
#CHECK-LE: paddis 10, 0, 1000000000, 1 # encoding: [0x9a,0x3b,0x10,0x06,
#CHECK-LE-SAME: 0x00,0xca,0x40,0x3d]
+ plis 10, 1000000000
+#CHECK-BE: paddis 10, 0, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME: 0x3d,0x40,0xca,0x00]
+#CHECK-LE: paddis 10, 0, 1000000000 # encoding: [0x9a,0x3b,0x00,0x06,
+#CHECK-LE-SAME: 0x00,0xca,0x40,0x3d]
+
+ psubis 10, 1000000000
+#CHECK-BE: paddis 10, 0, -1000000000 # encoding: [0x06,0x00,0xc4,0x65,
+#CHECK-BE-SAME: 0x3d,0x40,0x36,0x00]
+#CHECK-LE: paddis 10, 0, -1000000000 # encoding: [0x65,0xc4,0x00,0x06,
+#CHECK-LE-SAME: 0x00,0x36,0x40,0x3d]
+
+ psubis 10, -1000000000
+#CHECK-BE: paddis 10, 0, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE-SAME: 0x3d,0x40,0xca,0x00]
+#CHECK-LE: paddis 10, 0, 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 73e1dd9b9be92ef568da2adf483ff7033e13c79b Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Thu, 26 Feb 2026 16:11:05 -0500
Subject: [PATCH 2/5] fix psubis def
---
llvm/lib/Target/PowerPC/PPCInstrFuture.td | 8 +++-
llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s | 43 +++++++++++--------
2 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCInstrFuture.td b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
index 0d3f457bc087e..e07ae4eb0c962 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrFuture.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrFuture.td
@@ -611,8 +611,12 @@ 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)>;
-def : InstAlias<"psubis $RT, $SI", (PADDIS gprc:$RT, ZERO, neg_s32imm:$SI)>;
-def : InstAlias<"psubis $RT, $SI", (PADDIS8 g8rc:$RT, ZERO8, neg_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 = [HasVSX, IsISAFuture] in {
def : InstAlias<"xxaes128encp $XTp, $XAp, $XBp",
diff --git a/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s b/llvm/test/MC/PowerPC/ppc-encoding-ISAFuture.s
index 1868bb0f07244..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
@@ -420,17 +419,35 @@
#CHECK-LE: mtlpl 3, 4 # encoding: [0x26,0x1a,0x80,0x7c]
paddis 10, 12, 1000000000
-#CHECK-BE: paddis 10, 12, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
+#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 # encoding: [0x9a,0x3b,0x00,0x06,
+#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 # encoding: [0x06,0x00,0x3b,0x9a,
+#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 # encoding: [0x9a,0x3b,0x00,0x06,
+#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]
@@ -438,21 +455,9 @@
#CHECK-LE-SAME: 0x00,0xca,0x40,0x3d]
plis 10, 1000000000
-#CHECK-BE: paddis 10, 0, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
-#CHECK-BE-SAME: 0x3d,0x40,0xca,0x00]
-#CHECK-LE: paddis 10, 0, 1000000000 # encoding: [0x9a,0x3b,0x00,0x06,
-#CHECK-LE-SAME: 0x00,0xca,0x40,0x3d]
-
- psubis 10, 1000000000
-#CHECK-BE: paddis 10, 0, -1000000000 # encoding: [0x06,0x00,0xc4,0x65,
-#CHECK-BE-SAME: 0x3d,0x40,0x36,0x00]
-#CHECK-LE: paddis 10, 0, -1000000000 # encoding: [0x65,0xc4,0x00,0x06,
-#CHECK-LE-SAME: 0x00,0x36,0x40,0x3d]
-
- psubis 10, -1000000000
-#CHECK-BE: paddis 10, 0, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
+#CHECK-BE: plis 10, 1000000000 # encoding: [0x06,0x00,0x3b,0x9a,
#CHECK-BE-SAME: 0x3d,0x40,0xca,0x00]
-#CHECK-LE: paddis 10, 0, 1000000000 # encoding: [0x9a,0x3b,0x00,0x06,
+#CHECK-LE: plis 10, 1000000000 # encoding: [0x9a,0x3b,0x00,0x06,
#CHECK-LE-SAME: 0x00,0xca,0x40,0x3d]
xxmulmul 8, 3, 4, 2
>From 0c5c5edfca98326e7a33bc03c9e673a992d16685 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Fri, 27 Feb 2026 10:48:03 -0500
Subject: [PATCH 3/5] Add doc for addNegOperand()
---
.../Target/PowerPC/AsmParser/PPCAsmParser.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 13408cb8628e0..900ab21b91c50 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -799,6 +799,24 @@ void PPCOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
}
}
+// 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()) {
>From 354db594ed523ff890053a7661467ea605c10100 Mon Sep 17 00:00:00 2001
From: Lei Huang <lei at ca.ibm.com>
Date: Fri, 27 Feb 2026 13:16:17 -0500
Subject: [PATCH 4/5] add Ctx to Operand
---
.../Target/PowerPC/AsmParser/PPCAsmParser.cpp | 141 ++++++++++--------
1 file changed, 77 insertions(+), 64 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 900ab21b91c50..80874314bafe8 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;
@@ -642,10 +684,16 @@ struct PPCOperand : public MCParsedAsmOperand {
void addNegImmOperands(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
- if (Kind == Immediate)
+
+ if (Kind == Immediate) {
Inst.addOperand(MCOperand::createImm(-getImm()));
- else
- Inst.addOperand(MCOperand::createExpr(getExpr()));
+ 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 {
@@ -669,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
@@ -694,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;
@@ -706,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:
@@ -799,47 +853,6 @@ void PPCOperand::print(raw_ostream &OS, const MCAsmInfo &MAI) const {
}
}
-// 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)));
-}
-
void PPCAsmParser::processInstruction(MCInst &Inst,
const OperandVector &Operands) {
int Opcode = Inst.getOpcode();
@@ -1480,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:
@@ -1501,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";
@@ -1548,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
@@ -1579,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;
@@ -1608,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
>From f05ae26295cfa310fd7bef0a0194ea8560d5274a 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 5/5] add MC test for psubis
---
llvm/test/MC/PowerPC/ppc64-psubis.s | 108 ++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 llvm/test/MC/PowerPC/ppc64-psubis.s
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
More information about the llvm-commits
mailing list