[llvm] PPC750cl, and initial support for paired singles (PR #211463)

Cynthia Coan via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 26 20:09:24 PDT 2026


https://github.com/Mythra updated https://github.com/llvm/llvm-project/pull/211463

>From cb461c9ad0c55ad4569260b4904949827f5641d3 Mon Sep 17 00:00:00 2001
From: Cynthia <cynthia at coan.dev>
Date: Thu, 23 Jul 2026 04:40:03 +0000
Subject: [PATCH 1/3] PPC750cl, and initial support for paired singles
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

***Prior Art & Quick Summary of Differences***

this commit is mostly a revival of an old PowerPC Phabricator
PR by ( @DarkKirb ): <https://reviews.llvm.org/D85137>. this commit
is mostly the same as it in spirit (defining the PPC 750CL series
processors), and adding in intrinsic definitions for Paired Single
instructions.

Paired Singles are an extension that add a very simple version of
SIMD like behaviors. Each "Paired Single" can operator on 2 32-bit
floats in parallel. HOWEVER, unlike the patch this commit & PR aim
to model the behaviors 'correctly'. Effectively, each Floating Point
register actually is 64 bits, and not 32 bits. All FP instructions
actually perform operations in double precision then round the output to
single precision. so a `fadds` actually becomes equivalent to
`fadd+frsp`. Each register is actually a pair, and the second one only
ever gets used by PS instructions. the original patchset author
mentioned to me:

> in the patch i modeled the paired single registers as being
> independent of the regular floating point registers, but they
> really shouldn’t be. the lower 32 bits appear to be shared
> between the two, while the upper half is independent (why? who knows!)

well this is why. The PS0 & PS1 registers that actually make up each
floating point register is the cause, and is why we do _not_ actually
model them as unique registers in this patchset. this is why we instead
model them as f8rc (or a 64-bit floating point register class).

other than that the patchset is _mostly_ the same.

***Instructions Added***

adding support for:

PSQ_L/PSQ_LU/PSQ_LX/PSQ_LUX - load a paired single from a mem location
PSQ_ST/PSQ_STU/PSQ_STX/PSQ_STUX - store a paired single at a mem location
PS_ADD/PS_SUB/PS_MUL/PS_DIV - add/subtract/multiply/divide
ps_madd/ps_nmadd - multiply-add/negative multiply-add
ps_msub/ps_nmsub - multiple-subtract/negative multiply-subtract
ps_res - reciprocal estimate
ps_rsqrte - reciprocal square root estimate
ps_muls0/ps_muls1 - multiply a with the 1st/2nd element of b (depending on the name)
ps_madds0/ps_madds1 - are multiply-accumulate a c + b with the 1st or 2nd
   element of c being used for both elements respectively
ps_sum0/ps_sum1 - will replace the 1st/2nd element of c with the sum of
   the first element of a and the second element of b
ps_merge00/ps_merge01/ps_merge10/ps_merge11 - merges the 1st/2nd element of the
   first vector with the 1st/2nd element of the second vector and creates a
   new vector
ps_sel - is a dynamic variant of the merge* functions. It will take an
   element of vector a if the corresponding control entry is smaller
   than 0 and will use b otherwise
ps_neg - negate
ps_mr - move
ps_abs/ps_nabs - absolute/negative absolute
ps_cmpu0/ps_cmpu1 - unordered comparison
ps_cmpo0/ps_cmpo1 - ordered comparison
dcbz_l - zero-fill allocates the locked L1 data-cache.
  NOTE this is *different* than `dcbzl`, and because it requires
  the cache being locked I felt it prudent to mark it having side
 o1 - ordered comparison
dcbz_l - zero-fill allocates the locked L1 data-cache.
  NOTE this is *different* than `dcbzl`, and because it requires
  the cache being locked I felt it prudent to mark it having side
  effects so hopefullyeffects so hopefully it's not reordered.

***Final Notes***

I've confirmed the encoding of these is the same as binutils which
has had paired singles support for a long long time. this patch set
*does not* introduce generating any of these yet, simply allowing
folks to write in the instructions.

This is also my first time writing TableGen, and I will admit I'm still
not fully confident I didn't screw something up (or make a simple
mistake). I've tried reviewing this quite a bit to make sure it lines
up like the original, and did try matching other styles, but if I made
some simple mistakes I apologize!
---
 .../PowerPC/Disassembler/PPCDisassembler.cpp  |  13 ++
 .../PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp |   9 +
 .../PowerPC/MCTargetDesc/PPCMCCodeEmitter.h   |   3 +
 llvm/lib/Target/PowerPC/PPC.td                |   8 +
 llvm/lib/Target/PowerPC/PPCInstrInfo.td       |   1 +
 .../Target/PowerPC/PPCInstrPairedSingles.td   | 221 ++++++++++++++++++
 llvm/lib/Target/PowerPC/PPCOperands.td        |   9 +
 llvm/lib/Target/PowerPC/PPCRegisterInfo.td    |   5 +
 llvm/lib/Target/PowerPC/PPCScheduleP10.td     |   2 +-
 llvm/lib/Target/PowerPC/PPCScheduleP9.td      |   5 +-
 llvm/lib/Target/PowerPC/PPCSubtarget.cpp      |  10 +
 .../Disassembler/PowerPC/ppc-encoding-ps.txt  | 173 ++++++++++++++
 llvm/test/MC/PowerPC/ppc-encoding-ps.s        | 134 +++++++++++
 13 files changed, 589 insertions(+), 4 deletions(-)
 create mode 100644 llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
 create mode 100644 llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ps.txt
 create mode 100644 llvm/test/MC/PowerPC/ppc-encoding-ps.s

diff --git a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
index 70e619cc22b197..242dbba2dcfb32 100644
--- a/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
+++ b/llvm/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
@@ -312,6 +312,13 @@ static DecodeStatus decodeDispRIX16Operand(MCInst &Inst, uint64_t Imm,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeDispPSQOperand(MCInst &Inst, uint64_t Imm,
+                                         int64_t Address,
+                                         const MCDisassembler *Decoder) {
+  Inst.addOperand(MCOperand::createImm(SignExtend64<12>(Imm)));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeDispSPE8Operand(MCInst &Inst, uint64_t Imm,
                                           int64_t Address,
                                           const MCDisassembler *Decoder) {
@@ -402,6 +409,12 @@ DecodeStatus PPCDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
     if (result != MCDisassembler::Fail)
       return result;
   }
+  if (STI.hasFeature(PPC::FeaturePairedSingles)) {
+    DecodeStatus result = decodeInstruction(DecoderTablePairedSingles32, MI,
+                                            Inst, Address, this, STI);
+    if (result != MCDisassembler::Fail)
+      return result;
+  }
 
   return decodeInstruction(DecoderTable32, MI, Inst, Address, this, STI);
 }
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
index 64427e97f729ca..f73839fb950d41 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
@@ -372,6 +372,15 @@ PPCMCCodeEmitter::getDispRI34Encoding(const MCInst &MI, unsigned OpNo,
   return (getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL;
 }
 
+unsigned
+PPCMCCodeEmitter::getDispPSQEncoding(const MCInst &MI, unsigned OpNo,
+                                     SmallVectorImpl<MCFixup> &Fixups,
+                                     const MCSubtargetInfo &STI) const {
+  const MCOperand &MO = MI.getOperand(OpNo);
+  assert(MO.isImm());
+  return getMachineOpValue(MI, MO, Fixups, STI) & 0xFFF;
+}
+
 unsigned
 PPCMCCodeEmitter::getDispSPE8Encoding(const MCInst &MI, unsigned OpNo,
                                       SmallVectorImpl<MCFixup> &Fixups,
diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
index 9c8ccbcb8425a5..2d3f90f46b7cd8 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
@@ -69,6 +69,9 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
   uint64_t getDispRI34Encoding(const MCInst &MI, unsigned OpNo,
                                SmallVectorImpl<MCFixup> &Fixups,
                                const MCSubtargetInfo &STI) const;
+  unsigned getDispPSQEncoding(const MCInst &MI, unsigned OpNo,
+                              SmallVectorImpl<MCFixup> &Fixups,
+                              const MCSubtargetInfo &STI) const;
   unsigned getDispSPE8Encoding(const MCInst &MI, unsigned OpNo,
                                SmallVectorImpl<MCFixup> &Fixups,
                                const MCSubtargetInfo &STI) const;
diff --git a/llvm/lib/Target/PowerPC/PPC.td b/llvm/lib/Target/PowerPC/PPC.td
index ba2a4e6a9695ce..a85833b2d37745 100644
--- a/llvm/lib/Target/PowerPC/PPC.td
+++ b/llvm/lib/Target/PowerPC/PPC.td
@@ -83,6 +83,10 @@ def FeatureCRBits    : SubtargetFeature<"crbits", "UseCRBits", "true",
 def FeatureFPU       : SubtargetFeature<"fpu","HasFPU","true",
                                         "Enable classic FPU instructions",
                                         [FeatureHardFloat]>;
+def FeaturePairedSingles : SubtargetFeature<"paired-singles", "HasPairedSingles",
+                                            "true",
+                                            "Enable 750CL Paired-Singles instructions",
+                                            [FeatureFPU]>;
 def FeatureAltivec   : SubtargetFeature<"altivec","HasAltivec", "true",
                                         "Enable Altivec instructions",
                                         [FeatureFPU]>;
@@ -389,6 +393,7 @@ def HasSYNC   : Predicate<"!Subtarget->hasOnlyMSYNC()">;
 def IsPPC4xx  : Predicate<"Subtarget->isPPC4xx()">;
 def IsPPC6xx  : Predicate<"Subtarget->isPPC6xx()">;
 def IsE500  : Predicate<"Subtarget->isE500()">;
+def HasPairedSingles : Predicate<"Subtarget->hasPairedSingles()">;
 def HasSPE  : Predicate<"Subtarget->hasSPE()">;
 def HasICBT : Predicate<"Subtarget->hasICBT()">;
 def HasPartwordAtomics : Predicate<"Subtarget->hasPartwordAtomics()">;
@@ -700,6 +705,9 @@ def : Processor<"620", G3Itineraries, [Directive620,
 def : Processor<"750", G4Itineraries, [Directive750,
                                        FeatureFRES, FeatureFRSQRTE,
                                        FeatureMFTB]>;
+def : Processor<"750cl", G4Itineraries, [Directive750,
+                                         FeatureFRES, FeatureFRSQRTE,
+                                         FeatureMFTB, FeaturePairedSingles]>;
 def : Processor<"g3", G3Itineraries, [Directive750,
                                       FeatureFRES, FeatureFRSQRTE,
                                       FeatureMFTB]>;
diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
index 59d33f8ee21dbd..7b403f1cbe5958 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td
@@ -3752,6 +3752,7 @@ include "PPCInstrFutureMMA.td"
 include "PPCInstrFuture.td"
 include "PPCInstrMMA.td"
 include "PPCInstrDFP.td"
+include "PPCInstrPairedSingles.td"
 
 // Patterns for arithmetic i1 operations.
 def : Pat<(add i1:$a, i1:$b),
diff --git a/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
new file mode 100644
index 00000000000000..c27614eb9fd014
--- /dev/null
+++ b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
@@ -0,0 +1,221 @@
+//===-- PPCInstrPairedSingles.td - PPC750CL Paired Singles -*- tablegen -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the paired-singles instructions of the IBM PPC750CL
+// family of processors.
+//
+// It's important to note that Paired Singles aren't actually independent
+// registers. Instead each floating point register is actually like a pair
+// of 32 bit registers. Regular floating point operations write to both, and
+// ignore the second one. Only Paired Singles operations actually "see" the
+// second one. It's like a 64+32-bit register, or 64+64-bit when it's a
+// rename register.
+//
+//===----------------------------------------------------------------------===//
+
+class PSForm_QD<bits<6> opcode, dag OOL, dag IOL, string asmstr,
+                InstrItinClass itin, list<dag> pattern>
+  : I<opcode, OOL, IOL, asmstr, itin>, MemriOp {
+  bits<5>  FRT;
+  bits<12> D;
+  bits<5>  RA;
+  bits<1>  W;
+  bits<3>  QI;
+
+  let Pattern = pattern;
+
+  let Inst{6...10}  = FRT;
+  let Inst{11...15} = RA;
+  let Inst{16}      = W;
+  let Inst{17...19} = QI;
+  let Inst{20...31} = D;
+}
+
+class PSForm_QX<bits<6> xo, dag OOL, dag IOL, string asmstr,
+                InstrItinClass itin, list<dag> pattern>
+  : I<4, OOL, IOL, asmstr, itin> {
+  bits<5> FRT;
+  bits<5> RA;
+  bits<5> RB;
+  bits<1> W;
+  bits<3> QI;
+
+  let Pattern = pattern;
+
+  let Inst{6...10}  = FRT;
+  let Inst{11...15} = RA;
+  let Inst{16...20} = RB;
+  let Inst{21}      = W;
+  let Inst{22...24} = QI;
+  let Inst{25...30} = xo;
+  let Inst{31}      = 0;
+}
+
+// NOTE: this is differrent than `dcbzl`, *this is* `dcbz_l` which is 750CL specific,
+// has separate encodings, slightly different semantics, and requires a locked cache.
+class PSForm_DCBZL<bits<10> xo, dag OOL, dag IOL, string asmstr,
+                   InstrItinClass itin, list<dag> pattern>
+  : I<4, OOL, IOL, asmstr, itin> {
+  bits<5> RA;
+  bits<5> RB;
+
+  let Pattern = pattern;
+
+  let Inst{6...10}  = 0;
+  let Inst{11...15} = RA;
+  let Inst{16...20} = RB;
+  let Inst{21...30} = xo;
+  let Inst{31}      = 0;
+}
+
+let DecoderNamespace = "PairedSingles", Predicates = [HasPairedSingles] in {
+
+let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in {
+def PSQ_L   : PSForm_QD<56, (outs f8rc:$FRT),
+                        (ins (psqdisp $D, $RA):$addr, u1imm:$W, u3imm:$QI),
+                        "psq_l $FRT, $addr, $W, $QI", IIC_LdStLFD, []>;
+def PSQ_LU  : PSForm_QD<57, (outs f8rc:$FRT, ptr_rc_nor0:$ea_result),
+                        (ins (psqdisp $D, $RA):$addr, u1imm:$W, u3imm:$QI),
+                        "psq_lu $FRT, $addr, $W, $QI", IIC_LdStLFDU, []>,
+              RegConstraint<"$addr.reg = $ea_result">;
+def PSQ_LX  : PSForm_QX<6, (outs f8rc:$FRT),
+                        (ins (memrr $RA, $RB):$addr, u1imm:$W, u3imm:$QI),
+                        "psq_lx $FRT, $addr, $W, $QI", IIC_LdStLFD, []>;
+def PSQ_LUX : PSForm_QX<38, (outs f8rc:$FRT, ptr_rc_nor0:$ea_result),
+                        (ins (memrr $RA, $RB):$addr, u1imm:$W, u3imm:$QI),
+                        "psq_lux $FRT, $addr, $W, $QI", IIC_LdStLFDU, []>,
+              RegConstraint<"$addr.ptrreg = $ea_result">;
+}
+
+let mayLoad = 0, mayStore = 1, hasSideEffects = 0 in {
+def PSQ_ST  : PSForm_QD<60, (outs),
+                        (ins f8rc:$FRT, (psqdisp $D, $RA):$dst, u1imm:$W,
+                             u3imm:$QI),
+                        "psq_st $FRT, $dst, $W, $QI", IIC_LdStSTFD, []>;
+def PSQ_STU : PSForm_QD<61, (outs ptr_rc_nor0:$ea_res),
+                        (ins f8rc:$FRT, (psqdisp $D, $RA):$dst, u1imm:$W,
+                             u3imm:$QI),
+                        "psq_stu $FRT, $dst, $W, $QI", IIC_LdStSTFDU, []>,
+              RegConstraint<"$dst.reg = $ea_res">;
+def PSQ_STX : PSForm_QX<7, (outs),
+                        (ins f8rc:$FRT, (memrr $RA, $RB):$dst, u1imm:$W,
+                             u3imm:$QI),
+                        "psq_stx $FRT, $dst, $W, $QI", IIC_LdStSTFD, []>;
+def PSQ_STUX : PSForm_QX<39, (outs ptr_rc_nor0:$ea_res),
+                         (ins f8rc:$FRT, (memrr $RA, $RB):$dst, u1imm:$W,
+                              u3imm:$QI),
+                         "psq_stux $FRT, $dst, $W, $QI", IIC_LdStSTFDU, []>,
+               RegConstraint<"$dst.ptrreg = $ea_res">;
+}
+
+let mayRaiseFPException = 1, hasSideEffects = 0 in {
+let isCommutable = 1 in {
+defm PS_ADD    : AForm_2r<4, 21, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRB),
+                          "ps_add", "$FRT, $FRA, $FRB", IIC_FPGeneral, []>;
+defm PS_MUL    : AForm_3r<4, 25, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC),
+                          "ps_mul", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+defm PS_MADD   : AForm_1r<4, 29, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_madd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+defm PS_NMADD  : AForm_1r<4, 31, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_nmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+}
+defm PS_SUB    : AForm_2r<4, 20, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRB),
+                          "ps_sub", "$FRT, $FRA, $FRB", IIC_FPGeneral, []>;
+defm PS_DIV    : AForm_2r<4, 18, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRB),
+                          "ps_div", "$FRT, $FRA, $FRB", IIC_FPDivS, []>;
+defm PS_MSUB   : AForm_1r<4, 28, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_msub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+defm PS_NMSUB  : AForm_1r<4, 30, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_nmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+defm PS_RES    : XForm_26r<4, 24, (outs f8rc:$RST), (ins f8rc:$RB),
+                           "ps_res", "$RST, $RB", IIC_FPGeneral, []>;
+defm PS_RSQRTE : XForm_26r<4, 26, (outs f8rc:$RST), (ins f8rc:$RB),
+                           "ps_rsqrte", "$RST, $RB", IIC_FPGeneral, []>;
+
+defm PS_MULS0  : AForm_3r<4, 12, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC),
+                          "ps_muls0", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+defm PS_MULS1  : AForm_3r<4, 13, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC),
+                          "ps_muls1", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+defm PS_MADDS0 : AForm_1r<4, 14, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_madds0", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+defm PS_MADDS1 : AForm_1r<4, 15, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_madds1", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
+                          []>;
+defm PS_SUM0   : AForm_1r<4, 10, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_sum0", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
+                          []>;
+defm PS_SUM1   : AForm_1r<4, 11, (outs f8rc:$FRT),
+                          (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                          "ps_sum1", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
+                          []>;
+}
+
+let hasSideEffects = 0 in {
+defm PS_SEL     : AForm_1r<4, 23, (outs f8rc:$FRT),
+                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
+                           "ps_sel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
+                           []>;
+defm PS_NEG     : XForm_26r<4, 40, (outs f8rc:$RST), (ins f8rc:$RB),
+                            "ps_neg", "$RST, $RB", IIC_FPGeneral, []>;
+defm PS_MR      : XForm_26r<4, 72, (outs f8rc:$RST), (ins f8rc:$RB),
+                            "ps_mr", "$RST, $RB", IIC_FPGeneral, []>;
+defm PS_NABS    : XForm_26r<4, 136, (outs f8rc:$RST), (ins f8rc:$RB),
+                            "ps_nabs", "$RST, $RB", IIC_FPGeneral, []>;
+defm PS_ABS     : XForm_26r<4, 264, (outs f8rc:$RST), (ins f8rc:$RB),
+                            "ps_abs", "$RST, $RB", IIC_FPGeneral, []>;
+defm PS_MERGE00 : XForm_28r<4, 528, (outs f8rc:$RST),
+                            (ins f8rc:$RA, f8rc:$RB),
+                            "ps_merge00", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+defm PS_MERGE01 : XForm_28r<4, 560, (outs f8rc:$RST),
+                            (ins f8rc:$RA, f8rc:$RB),
+                            "ps_merge01", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+defm PS_MERGE10 : XForm_28r<4, 592, (outs f8rc:$RST),
+                            (ins f8rc:$RA, f8rc:$RB),
+                            "ps_merge10", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+defm PS_MERGE11 : XForm_28r<4, 624, (outs f8rc:$RST),
+                            (ins f8rc:$RA, f8rc:$RB),
+                            "ps_merge11", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+}
+
+let mayRaiseFPException = 1, hasSideEffects = 0 in {
+def PS_CMPU0 : XForm_17<4, 0, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
+                        "ps_cmpu0 $BF, $RA, $RB", IIC_FPCompare>;
+def PS_CMPO0 : XForm_17<4, 32, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
+                        "ps_cmpo0 $BF, $RA, $RB", IIC_FPCompare>;
+def PS_CMPU1 : XForm_17<4, 64, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
+                        "ps_cmpu1 $BF, $RA, $RB", IIC_FPCompare>;
+def PS_CMPO1 : XForm_17<4, 96, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
+                        "ps_cmpo1 $BF, $RA, $RB", IIC_FPCompare>;
+}
+
+let hasSideEffects = 1 in {
+def DCBZ_L : PSForm_DCBZL<1014, (outs), (ins (memrr $RA, $RB):$addr),
+                          "dcbz_l $addr", IIC_LdStDCBF, []>;
+}
+
+} // DecoderNamespace = "PairedSingles", Predicates = [HasPairedSingles]
diff --git a/llvm/lib/Target/PowerPC/PPCOperands.td b/llvm/lib/Target/PowerPC/PPCOperands.td
index 08e8bf040c1991..ee729a90cc8c9e 100644
--- a/llvm/lib/Target/PowerPC/PPCOperands.td
+++ b/llvm/lib/Target/PowerPC/PPCOperands.td
@@ -384,6 +384,15 @@ def dispRIX16 : Operand<iPTR> {
   let EncoderMethod = "getDispRIX16Encoding";
   let DecoderMethod = "decodeDispRIX16Operand";
 }
+def PPCDispPSQOperand : AsmOperandClass {
+ let Name = "DispPSQ"; let PredicateMethod = "isSImm<12>";
+ let RenderMethod = "addImmOperands";
+}
+def dispPSQ : Operand<iPTR> {
+  let ParserMatchClass = PPCDispPSQOperand;
+  let DecoderMethod = "decodeDispPSQOperand";
+  let EncoderMethod = "getDispPSQEncoding";
+}
 def PPCDispSPE8Operand : AsmOperandClass {
  let Name = "DispSPE8"; let PredicateMethod = "isU8ImmX8";
  let RenderMethod = "addImmOperands";
diff --git a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
index 90c7be4297935a..9aeb64021da2d5 100644
--- a/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
+++ b/llvm/lib/Target/PowerPC/PPCRegisterInfo.td
@@ -571,6 +571,11 @@ def memrix16 : Operand<iPTR> { // memri, imm is 16-aligned, 12-bit, Inst{16:27}
   let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg);
   let OperandType = "OPERAND_MEMORY";
 }
+def psqdisp : Operand<iPTR> {   // Paired-singles displacement (12-bit signed).
+  let PrintMethod = "printMemRegImm";
+  let MIOperandInfo = (ops dispPSQ:$imm, ptr_rc_nor0:$reg);
+  let OperandType = "OPERAND_MEMORY";
+}
 def spe8dis : Operand<iPTR> {   // SPE displacement where the imm is 8-aligned.
   let PrintMethod = "printMemRegImm";
   let MIOperandInfo = (ops dispSPE8:$imm, ptr_rc_nor0:$reg);
diff --git a/llvm/lib/Target/PowerPC/PPCScheduleP10.td b/llvm/lib/Target/PowerPC/PPCScheduleP10.td
index 09b0affb719d84..785ff9ac25fadd 100644
--- a/llvm/lib/Target/PowerPC/PPCScheduleP10.td
+++ b/llvm/lib/Target/PowerPC/PPCScheduleP10.td
@@ -30,7 +30,7 @@ def P10Model : SchedMachineModel {
   let CompleteModel = 1;
 
   // Power 10 does not support instructions from SPE, Book E and HTM.
-  let UnsupportedFeatures = [HasSPE, IsE500, IsBookE, IsISAFuture, HasFutureVector, HasHTM];
+  let UnsupportedFeatures = [HasSPE, IsE500, IsBookE, IsISAFuture, HasFutureVector, HasHTM, HasPairedSingles];
 }
 
 let SchedModel = P10Model in {
diff --git a/llvm/lib/Target/PowerPC/PPCScheduleP9.td b/llvm/lib/Target/PowerPC/PPCScheduleP9.td
index 306bbf8e4e2769..bcfa18296e1458 100644
--- a/llvm/lib/Target/PowerPC/PPCScheduleP9.td
+++ b/llvm/lib/Target/PowerPC/PPCScheduleP9.td
@@ -44,7 +44,7 @@ def P9Model : SchedMachineModel {
   let UnsupportedFeatures = [HasSPE, PrefixInstrs, MMA,
                              PairedVectorMemops, IsBookE,
                              PCRelativeMemops, IsISA3_1, IsISAFuture,
-                             HasFutureVector];
+                             HasFutureVector, HasPairedSingles];
 }
 
 let SchedModel = P9Model in {
@@ -139,7 +139,7 @@ let SchedModel = P9Model in {
     let NumMicroOps = 0;
     let Latency = 1;
   }
-  // Dispatch Rules: 'E' 
+  // Dispatch Rules: 'E'
   // Even slice ('E')- certain operations must be sent only to an even slice.
   // Also consumes odd dispatch slice slot of the same superslice at dispatch
   def DISP_EVEN_1C : SchedWriteRes<[ DISPx02, DISPx13 ]> {
@@ -426,4 +426,3 @@ let SchedModel = P9Model in {
   include "P9InstrResources.td"
 
 }
-
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index 2dfb67ff4c33db..c5930e50461fe5 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -114,6 +114,16 @@ void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef TuneCPU,
     report_fatal_error(
         "SPE and traditional floating point cannot both be enabled.\n", false);
 
+  if (HasPairedSingles && IsPPC64)
+    report_fatal_error(
+        "Paired Singles are only supported for 32-bit targets.\n", false);
+  if (HasPairedSingles && HasAltivec)
+    report_fatal_error("Paired Singles and Altivec cannot both be enabled.\n",
+                       false);
+  if (HasPairedSingles && HasSPE)
+    report_fatal_error("Paired Singles and SPE cannot both be enabled.\n",
+                       false);
+
   // If not SPE, set standard FPU
   if (!HasSPE)
     HasFPU = true;
diff --git a/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ps.txt b/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ps.txt
new file mode 100644
index 00000000000000..603a7cd06dcfd4
--- /dev/null
+++ b/llvm/test/MC/Disassembler/PowerPC/ppc-encoding-ps.txt
@@ -0,0 +1,173 @@
+# RUN: llvm-mc --disassemble %s -triple powerpc-unknown-unknown -mcpu=750cl | FileCheck %s
+
+# CHECK: psq_l 2, 8(3), 0, 1
+0xe0 0x43 0x10 0x08
+# CHECK: psq_l 5, -8(0), 1, 7
+0xe0 0xa0 0xff 0xf8
+# CHECK: psq_l 31, 2047(31), 0, 0
+0xe3 0xff 0x07 0xff
+# CHECK: psq_l 0, -2048(1), 1, 3
+0xe0 0x01 0xb8 0x00
+
+# CHECK: psq_lu 4, 12(5), 1, 2
+0xe4 0x85 0xa0 0x0c
+
+# CHECK: psq_lx 6, 7, 8, 0, 3
+0x10 0xc7 0x41 0x8c
+
+# CHECK: psq_lux 9, 10, 11, 1, 4
+0x11 0x2a 0x5e 0x4c
+
+# CHECK: psq_st 2, 8(3), 0, 1
+0xf0 0x43 0x10 0x08
+
+# CHECK: psq_stu 4, -16(5), 1, 2
+0xf4 0x85 0xaf 0xf0
+
+# CHECK: psq_stx 6, 7, 8, 0, 3
+0x10 0xc7 0x41 0x8e
+
+# CHECK: psq_stux 9, 10, 11, 1, 4
+0x11 0x2a 0x5e 0x4e
+
+# CHECK: ps_div 2, 3, 4
+0x10 0x43 0x20 0x24
+# CHECK: ps_div. 2, 3, 4
+0x10 0x43 0x20 0x25
+
+# CHECK: ps_sub 2, 3, 4
+0x10 0x43 0x20 0x28
+# CHECK: ps_sub. 2, 3, 4
+0x10 0x43 0x20 0x29
+
+# CHECK: ps_add 2, 3, 4
+0x10 0x43 0x20 0x2a
+# CHECK: ps_add. 2, 3, 4
+0x10 0x43 0x20 0x2b
+
+# CHECK: ps_mul 2, 3, 4
+0x10 0x43 0x01 0x32
+# CHECK: ps_mul. 2, 3, 4
+0x10 0x43 0x01 0x33
+
+# CHECK: ps_muls0 2, 3, 4
+0x10 0x43 0x01 0x18
+# CHECK: ps_muls0. 2, 3, 4
+0x10 0x43 0x01 0x19
+
+# CHECK: ps_muls1 2, 3, 4
+0x10 0x43 0x01 0x1a
+# CHECK: ps_muls1. 2, 3, 4
+0x10 0x43 0x01 0x1b
+
+# CHECK: ps_sum0 2, 3, 4, 5
+0x10 0x43 0x29 0x14
+# CHECK: ps_sum0. 2, 3, 4, 5
+0x10 0x43 0x29 0x15
+
+# CHECK: ps_sum1 2, 3, 4, 5
+0x10 0x43 0x29 0x16
+# CHECK: ps_sum1. 2, 3, 4, 5
+0x10 0x43 0x29 0x17
+
+# CHECK: ps_madds0 2, 3, 4, 5
+0x10 0x43 0x29 0x1c
+# CHECK: ps_madds0. 2, 3, 4, 5
+0x10 0x43 0x29 0x1d
+
+# CHECK: ps_madds1 2, 3, 4, 5
+0x10 0x43 0x29 0x1e
+# CHECK: ps_madds1. 2, 3, 4, 5
+0x10 0x43 0x29 0x1f
+
+# CHECK: ps_sel 2, 3, 4, 5
+0x10 0x43 0x29 0x2e
+# CHECK: ps_sel. 2, 3, 4, 5
+0x10 0x43 0x29 0x2f
+
+# CHECK: ps_msub 2, 3, 4, 5
+0x10 0x43 0x29 0x38
+# CHECK: ps_msub. 2, 3, 4, 5
+0x10 0x43 0x29 0x39
+
+# CHECK: ps_madd 2, 3, 4, 5
+0x10 0x43 0x29 0x3a
+# CHECK: ps_madd. 2, 3, 4, 5
+0x10 0x43 0x29 0x3b
+
+# CHECK: ps_nmsub 2, 3, 4, 5
+0x10 0x43 0x29 0x3c
+# CHECK: ps_nmsub. 2, 3, 4, 5
+0x10 0x43 0x29 0x3d
+
+# CHECK: ps_nmadd 2, 3, 4, 5
+0x10 0x43 0x29 0x3e
+# CHECK: ps_nmadd. 2, 3, 4, 5
+0x10 0x43 0x29 0x3f
+
+# CHECK: ps_res 2, 3
+0x10 0x40 0x18 0x30
+# CHECK: ps_res. 2, 3
+0x10 0x40 0x18 0x31
+
+# CHECK: ps_rsqrte 2, 3
+0x10 0x40 0x18 0x34
+# CHECK: ps_rsqrte. 2, 3
+0x10 0x40 0x18 0x35
+
+# CHECK: ps_neg 2, 3
+0x10 0x40 0x18 0x50
+# CHECK: ps_neg. 2, 3
+0x10 0x40 0x18 0x51
+
+# CHECK: ps_mr 2, 3
+0x10 0x40 0x18 0x90
+# CHECK: ps_mr. 2, 3
+0x10 0x40 0x18 0x91
+
+# CHECK: ps_nabs 2, 3
+0x10 0x40 0x19 0x10
+# CHECK: ps_nabs. 2, 3
+0x10 0x40 0x19 0x11
+
+# CHECK: ps_abs 2, 3
+0x10 0x40 0x1a 0x10
+# CHECK: ps_abs. 2, 3
+0x10 0x40 0x1a 0x11
+
+# CHECK: ps_merge00 2, 3, 4
+0x10 0x43 0x24 0x20
+# CHECK: ps_merge00. 2, 3, 4
+0x10 0x43 0x24 0x21
+
+# CHECK: ps_merge01 2, 3, 4
+0x10 0x43 0x24 0x60
+# CHECK: ps_merge01. 2, 3, 4
+0x10 0x43 0x24 0x61
+
+# CHECK: ps_merge10 2, 3, 4
+0x10 0x43 0x24 0xa0
+# CHECK: ps_merge10. 2, 3, 4
+0x10 0x43 0x24 0xa1
+
+# CHECK: ps_merge11 2, 3, 4
+0x10 0x43 0x24 0xe0
+# CHECK: ps_merge11. 2, 3, 4
+0x10 0x43 0x24 0xe1
+
+# CHECK: ps_cmpu0 2, 3, 4
+0x11 0x03 0x20 0x00
+
+# CHECK: ps_cmpo0 2, 3, 4
+0x11 0x03 0x20 0x40
+
+# CHECK: ps_cmpu1 2, 3, 4
+0x11 0x03 0x20 0x80
+
+# CHECK: ps_cmpo1 2, 3, 4
+0x11 0x03 0x20 0xc0
+
+# CHECK: dcbz_l 3, 4
+0x10 0x03 0x27 0xec
+# CHECK: dcbz_l 0, 3
+0x10 0x00 0x1f 0xec
diff --git a/llvm/test/MC/PowerPC/ppc-encoding-ps.s b/llvm/test/MC/PowerPC/ppc-encoding-ps.s
new file mode 100644
index 00000000000000..5fe9c1c5aa92bf
--- /dev/null
+++ b/llvm/test/MC/PowerPC/ppc-encoding-ps.s
@@ -0,0 +1,134 @@
+# RUN: llvm-mc -triple powerpc-unknown-unknown -mcpu=750cl --show-encoding %s | FileCheck %s
+
+# CHECK: psq_l 2, 8(3), 0, 1              # encoding: [0xe0,0x43,0x10,0x08]
+         psq_l 2, 8(3), 0, 1
+# CHECK: psq_l 5, -8(0), 1, 7             # encoding: [0xe0,0xa0,0xff,0xf8]
+         psq_l 5, -8(0), 1, 7
+# CHECK: psq_l 31, 2047(31), 0, 0         # encoding: [0xe3,0xff,0x07,0xff]
+         psq_l 31, 2047(31), 0, 0
+# CHECK: psq_l 0, -2048(1), 1, 3          # encoding: [0xe0,0x01,0xb8,0x00]
+         psq_l 0, -2048(1), 1, 3
+# CHECK: psq_lu 4, 12(5), 1, 2            # encoding: [0xe4,0x85,0xa0,0x0c]
+         psq_lu 4, 12(5), 1, 2
+# CHECK: psq_lx 6, 7, 8, 0, 3             # encoding: [0x10,0xc7,0x41,0x8c]
+         psq_lx 6, 7, 8, 0, 3
+# CHECK: psq_lux 9, 10, 11, 1, 4          # encoding: [0x11,0x2a,0x5e,0x4c]
+         psq_lux 9, 10, 11, 1, 4
+# CHECK: psq_st 2, 8(3), 0, 1             # encoding: [0xf0,0x43,0x10,0x08]
+         psq_st 2, 8(3), 0, 1
+# CHECK: psq_stu 4, -16(5), 1, 2          # encoding: [0xf4,0x85,0xaf,0xf0]
+         psq_stu 4, -16(5), 1, 2
+# CHECK: psq_stx 6, 7, 8, 0, 3            # encoding: [0x10,0xc7,0x41,0x8e]
+         psq_stx 6, 7, 8, 0, 3
+# CHECK: psq_stux 9, 10, 11, 1, 4         # encoding: [0x11,0x2a,0x5e,0x4e]
+         psq_stux 9, 10, 11, 1, 4
+# CHECK: ps_div 2, 3, 4                   # encoding: [0x10,0x43,0x20,0x24]
+         ps_div 2, 3, 4
+# CHECK: ps_div. 2, 3, 4                  # encoding: [0x10,0x43,0x20,0x25]
+         ps_div. 2, 3, 4
+# CHECK: ps_sub 2, 3, 4                   # encoding: [0x10,0x43,0x20,0x28]
+         ps_sub 2, 3, 4
+# CHECK: ps_sub. 2, 3, 4                  # encoding: [0x10,0x43,0x20,0x29]
+         ps_sub. 2, 3, 4
+# CHECK: ps_add 2, 3, 4                   # encoding: [0x10,0x43,0x20,0x2a]
+         ps_add 2, 3, 4
+# CHECK: ps_add. 2, 3, 4                  # encoding: [0x10,0x43,0x20,0x2b]
+         ps_add. 2, 3, 4
+# CHECK: ps_mul 2, 3, 4                   # encoding: [0x10,0x43,0x01,0x32]
+         ps_mul 2, 3, 4
+# CHECK: ps_mul. 2, 3, 4                  # encoding: [0x10,0x43,0x01,0x33]
+         ps_mul. 2, 3, 4
+# CHECK: ps_muls0 2, 3, 4                 # encoding: [0x10,0x43,0x01,0x18]
+         ps_muls0 2, 3, 4
+# CHECK: ps_muls0. 2, 3, 4                # encoding: [0x10,0x43,0x01,0x19]
+         ps_muls0. 2, 3, 4
+# CHECK: ps_muls1 2, 3, 4                 # encoding: [0x10,0x43,0x01,0x1a]
+         ps_muls1 2, 3, 4
+# CHECK: ps_muls1. 2, 3, 4                # encoding: [0x10,0x43,0x01,0x1b]
+         ps_muls1. 2, 3, 4
+# CHECK: ps_sum0 2, 3, 4, 5               # encoding: [0x10,0x43,0x29,0x14]
+         ps_sum0 2, 3, 4, 5
+# CHECK: ps_sum0. 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x15]
+         ps_sum0. 2, 3, 4, 5
+# CHECK: ps_sum1 2, 3, 4, 5               # encoding: [0x10,0x43,0x29,0x16]
+         ps_sum1 2, 3, 4, 5
+# CHECK: ps_sum1. 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x17]
+         ps_sum1. 2, 3, 4, 5
+# CHECK: ps_madds0 2, 3, 4, 5             # encoding: [0x10,0x43,0x29,0x1c]
+         ps_madds0 2, 3, 4, 5
+# CHECK: ps_madds0. 2, 3, 4, 5            # encoding: [0x10,0x43,0x29,0x1d]
+         ps_madds0. 2, 3, 4, 5
+# CHECK: ps_madds1 2, 3, 4, 5             # encoding: [0x10,0x43,0x29,0x1e]
+         ps_madds1 2, 3, 4, 5
+# CHECK: ps_madds1. 2, 3, 4, 5            # encoding: [0x10,0x43,0x29,0x1f]
+         ps_madds1. 2, 3, 4, 5
+# CHECK: ps_sel 2, 3, 4, 5                # encoding: [0x10,0x43,0x29,0x2e]
+         ps_sel 2, 3, 4, 5
+# CHECK: ps_sel. 2, 3, 4, 5               # encoding: [0x10,0x43,0x29,0x2f]
+         ps_sel. 2, 3, 4, 5
+# CHECK: ps_msub 2, 3, 4, 5               # encoding: [0x10,0x43,0x29,0x38]
+         ps_msub 2, 3, 4, 5
+# CHECK: ps_msub. 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x39]
+         ps_msub. 2, 3, 4, 5
+# CHECK: ps_madd 2, 3, 4, 5               # encoding: [0x10,0x43,0x29,0x3a]
+         ps_madd 2, 3, 4, 5
+# CHECK: ps_madd. 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x3b]
+         ps_madd. 2, 3, 4, 5
+# CHECK: ps_nmsub 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x3c]
+         ps_nmsub 2, 3, 4, 5
+# CHECK: ps_nmsub. 2, 3, 4, 5             # encoding: [0x10,0x43,0x29,0x3d]
+         ps_nmsub. 2, 3, 4, 5
+# CHECK: ps_nmadd 2, 3, 4, 5              # encoding: [0x10,0x43,0x29,0x3e]
+         ps_nmadd 2, 3, 4, 5
+# CHECK: ps_nmadd. 2, 3, 4, 5             # encoding: [0x10,0x43,0x29,0x3f]
+         ps_nmadd. 2, 3, 4, 5
+# CHECK: ps_res 2, 3                      # encoding: [0x10,0x40,0x18,0x30]
+         ps_res 2, 3
+# CHECK: ps_res. 2, 3                     # encoding: [0x10,0x40,0x18,0x31]
+         ps_res. 2, 3
+# CHECK: ps_rsqrte 2, 3                   # encoding: [0x10,0x40,0x18,0x34]
+         ps_rsqrte 2, 3
+# CHECK: ps_rsqrte. 2, 3                  # encoding: [0x10,0x40,0x18,0x35]
+         ps_rsqrte. 2, 3
+# CHECK: ps_neg 2, 3                      # encoding: [0x10,0x40,0x18,0x50]
+         ps_neg 2, 3
+# CHECK: ps_neg. 2, 3                     # encoding: [0x10,0x40,0x18,0x51]
+         ps_neg. 2, 3
+# CHECK: ps_mr 2, 3                       # encoding: [0x10,0x40,0x18,0x90]
+         ps_mr 2, 3
+# CHECK: ps_mr. 2, 3                      # encoding: [0x10,0x40,0x18,0x91]
+         ps_mr. 2, 3
+# CHECK: ps_nabs 2, 3                     # encoding: [0x10,0x40,0x19,0x10]
+         ps_nabs 2, 3
+# CHECK: ps_nabs. 2, 3                    # encoding: [0x10,0x40,0x19,0x11]
+         ps_nabs. 2, 3
+# CHECK: ps_abs 2, 3                      # encoding: [0x10,0x40,0x1a,0x10]
+         ps_abs 2, 3
+# CHECK: ps_abs. 2, 3                     # encoding: [0x10,0x40,0x1a,0x11]
+         ps_abs. 2, 3
+# CHECK: ps_merge00 2, 3, 4               # encoding: [0x10,0x43,0x24,0x20]
+         ps_merge00 2, 3, 4
+# CHECK: ps_merge00. 2, 3, 4              # encoding: [0x10,0x43,0x24,0x21]
+         ps_merge00. 2, 3, 4
+# CHECK: ps_merge01 2, 3, 4               # encoding: [0x10,0x43,0x24,0x60]
+         ps_merge01 2, 3, 4
+# CHECK: ps_merge01. 2, 3, 4              # encoding: [0x10,0x43,0x24,0x61]
+         ps_merge01. 2, 3, 4
+# CHECK: ps_merge10 2, 3, 4               # encoding: [0x10,0x43,0x24,0xa0]
+         ps_merge10 2, 3, 4
+# CHECK: ps_merge10. 2, 3, 4              # encoding: [0x10,0x43,0x24,0xa1]
+         ps_merge10. 2, 3, 4
+# CHECK: ps_merge11 2, 3, 4               # encoding: [0x10,0x43,0x24,0xe0]
+         ps_merge11 2, 3, 4
+# CHECK: ps_merge11. 2, 3, 4              # encoding: [0x10,0x43,0x24,0xe1]
+         ps_merge11. 2, 3, 4
+# CHECK: ps_cmpu0 2, 3, 4                 # encoding: [0x11,0x03,0x20,0x00]
+         ps_cmpu0 2, 3, 4
+# CHECK: ps_cmpo0 2, 3, 4                 # encoding: [0x11,0x03,0x20,0x40]
+         ps_cmpo0 2, 3, 4
+# CHECK: ps_cmpu1 2, 3, 4                 # encoding: [0x11,0x03,0x20,0x80]
+         ps_cmpu1 2, 3, 4
+# CHECK: ps_cmpo1 2, 3, 4                 # encoding: [0x11,0x03,0x20,0xc0]
+         ps_cmpo1 2, 3, 4
+# CHECK: dcbz_l 3, 4                      # encoding: [0x10,0x03,0x27,0xec]
+         dcbz_l 3, 4

>From f9d823e57475721fa90fd0fac3e1ee5182aa51f2 Mon Sep 17 00:00:00 2001
From: Cynthia <cynthia at coan.dev>
Date: Thu, 24 Sep 2026 15:10:04 +0000
Subject: [PATCH 2/3] move instruction notes into td file

i only ended up moving the instructions I felt _required_ a note,
e.g. were not immediately obvious by the name itself like "ADD".
---
 .../Target/PowerPC/PPCInstrPairedSingles.td   | 30 ++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
index c27614eb9fd014..3384f8c171c90f 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
@@ -78,6 +78,7 @@ class PSForm_DCBZL<bits<10> xo, dag OOL, dag IOL, string asmstr,
 let DecoderNamespace = "PairedSingles", Predicates = [HasPairedSingles] in {
 
 let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in {
+// Load a PS from a specific memory location
 def PSQ_L   : PSForm_QD<56, (outs f8rc:$FRT),
                         (ins (psqdisp $D, $RA):$addr, u1imm:$W, u3imm:$QI),
                         "psq_l $FRT, $addr, $W, $QI", IIC_LdStLFD, []>;
@@ -95,6 +96,7 @@ def PSQ_LUX : PSForm_QX<38, (outs f8rc:$FRT, ptr_rc_nor0:$ea_result),
 }
 
 let mayLoad = 0, mayStore = 1, hasSideEffects = 0 in {
+// Store a PS at a specific memory location
 def PSQ_ST  : PSForm_QD<60, (outs),
                         (ins f8rc:$FRT, (psqdisp $D, $RA):$dst, u1imm:$W,
                              u3imm:$QI),
@@ -123,10 +125,12 @@ defm PS_ADD    : AForm_2r<4, 21, (outs f8rc:$FRT),
 defm PS_MUL    : AForm_3r<4, 25, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_mul", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+// Multiply Add
 defm PS_MADD   : AForm_1r<4, 29, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_madd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
+// Negative Multiply Add
 defm PS_NMADD  : AForm_1r<4, 31, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_nmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
@@ -138,29 +142,36 @@ defm PS_SUB    : AForm_2r<4, 20, (outs f8rc:$FRT),
 defm PS_DIV    : AForm_2r<4, 18, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRB),
                           "ps_div", "$FRT, $FRA, $FRB", IIC_FPDivS, []>;
+// Multiply Subtract
 defm PS_MSUB   : AForm_1r<4, 28, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_msub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
+// Negative Multiply Subtract
 defm PS_NMSUB  : AForm_1r<4, 30, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_nmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
+// Reciprocal Estimate
 defm PS_RES    : XForm_26r<4, 24, (outs f8rc:$RST), (ins f8rc:$RB),
                            "ps_res", "$RST, $RB", IIC_FPGeneral, []>;
+// Reciprocal Square Root Estimate
 defm PS_RSQRTE : XForm_26r<4, 26, (outs f8rc:$RST), (ins f8rc:$RB),
                            "ps_rsqrte", "$RST, $RB", IIC_FPGeneral, []>;
-
+// Multply A with the 1st element of B
 defm PS_MULS0  : AForm_3r<4, 12, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_muls0", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+// Multply A with the 2nd element of B
 defm PS_MULS1  : AForm_3r<4, 13, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_muls1", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
+// Multiply Acculate A with C+B 1st element.
 defm PS_MADDS0 : AForm_1r<4, 14, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_madds0", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
+// Multiply Acculate A with C+B 2nd element.
 defm PS_MADDS1 : AForm_1r<4, 15, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_madds1", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
@@ -176,44 +187,61 @@ defm PS_SUM1   : AForm_1r<4, 11, (outs f8rc:$FRT),
 }
 
 let hasSideEffects = 0 in {
+// Dynamic variant of merge* functions, Take element of vector A IF the
+// control entry is smaller than 0, otherwise use B.
 defm PS_SEL     : AForm_1r<4, 23, (outs f8rc:$FRT),
                            (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                            "ps_sel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral,
                            []>;
 defm PS_NEG     : XForm_26r<4, 40, (outs f8rc:$RST), (ins f8rc:$RB),
                             "ps_neg", "$RST, $RB", IIC_FPGeneral, []>;
+// Move.
 defm PS_MR      : XForm_26r<4, 72, (outs f8rc:$RST), (ins f8rc:$RB),
                             "ps_mr", "$RST, $RB", IIC_FPGeneral, []>;
+// Negative Absolute & Absolute.
 defm PS_NABS    : XForm_26r<4, 136, (outs f8rc:$RST), (ins f8rc:$RB),
                             "ps_nabs", "$RST, $RB", IIC_FPGeneral, []>;
 defm PS_ABS     : XForm_26r<4, 264, (outs f8rc:$RST), (ins f8rc:$RB),
                             "ps_abs", "$RST, $RB", IIC_FPGeneral, []>;
+// Merge the 1st element of the first vector with the 1st element of the
+// second.
 defm PS_MERGE00 : XForm_28r<4, 528, (outs f8rc:$RST),
                             (ins f8rc:$RA, f8rc:$RB),
                             "ps_merge00", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+// Merge the 1st element of the first vector with the 2nd element of the
+// second.
 defm PS_MERGE01 : XForm_28r<4, 560, (outs f8rc:$RST),
                             (ins f8rc:$RA, f8rc:$RB),
                             "ps_merge01", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+// Merge the 2nd element of the first vector with the 1st element of the
+// second.
 defm PS_MERGE10 : XForm_28r<4, 592, (outs f8rc:$RST),
                             (ins f8rc:$RA, f8rc:$RB),
                             "ps_merge10", "$RST, $RA, $RB", IIC_FPGeneral, []>;
+// Merge the 2nd element of the first vector with the 2nd element of the
+// second.
 defm PS_MERGE11 : XForm_28r<4, 624, (outs f8rc:$RST),
                             (ins f8rc:$RA, f8rc:$RB),
                             "ps_merge11", "$RST, $RA, $RB", IIC_FPGeneral, []>;
 }
 
 let mayRaiseFPException = 1, hasSideEffects = 0 in {
+// Unordered Comparison
 def PS_CMPU0 : XForm_17<4, 0, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpu0 $BF, $RA, $RB", IIC_FPCompare>;
+// Ordered Comparison
 def PS_CMPO0 : XForm_17<4, 32, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpo0 $BF, $RA, $RB", IIC_FPCompare>;
+// Unordered Comparison
 def PS_CMPU1 : XForm_17<4, 64, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpu1 $BF, $RA, $RB", IIC_FPCompare>;
+// Ordered Comparison
 def PS_CMPO1 : XForm_17<4, 96, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpo1 $BF, $RA, $RB", IIC_FPCompare>;
 }
 
 let hasSideEffects = 1 in {
+// Zero-fill a *LOCKED* l1 data cache.
 def DCBZ_L : PSForm_DCBZL<1014, (outs), (ins (memrr $RA, $RB):$addr),
                           "dcbz_l $addr", IIC_LdStDCBF, []>;
 }

>From e66e47259a9c68cc05ba865dd492f6ac79b27f4f Mon Sep 17 00:00:00 2001
From: Cynthia <cynthia at coan.dev>
Date: Thu, 24 Sep 2026 21:06:03 +0000
Subject: [PATCH 3/3] end all comments with '.'

---
 .../Target/PowerPC/PPCInstrPairedSingles.td   | 28 +++++++++----------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
index 3384f8c171c90f..9fe3f2defa92a8 100644
--- a/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
+++ b/llvm/lib/Target/PowerPC/PPCInstrPairedSingles.td
@@ -78,7 +78,7 @@ class PSForm_DCBZL<bits<10> xo, dag OOL, dag IOL, string asmstr,
 let DecoderNamespace = "PairedSingles", Predicates = [HasPairedSingles] in {
 
 let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in {
-// Load a PS from a specific memory location
+// Load a PS from a specific memory location.
 def PSQ_L   : PSForm_QD<56, (outs f8rc:$FRT),
                         (ins (psqdisp $D, $RA):$addr, u1imm:$W, u3imm:$QI),
                         "psq_l $FRT, $addr, $W, $QI", IIC_LdStLFD, []>;
@@ -96,7 +96,7 @@ def PSQ_LUX : PSForm_QX<38, (outs f8rc:$FRT, ptr_rc_nor0:$ea_result),
 }
 
 let mayLoad = 0, mayStore = 1, hasSideEffects = 0 in {
-// Store a PS at a specific memory location
+// Store a PS at a specific memory location.
 def PSQ_ST  : PSForm_QD<60, (outs),
                         (ins f8rc:$FRT, (psqdisp $D, $RA):$dst, u1imm:$W,
                              u3imm:$QI),
@@ -125,12 +125,12 @@ defm PS_ADD    : AForm_2r<4, 21, (outs f8rc:$FRT),
 defm PS_MUL    : AForm_3r<4, 25, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_mul", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
-// Multiply Add
+// Multiply Add.
 defm PS_MADD   : AForm_1r<4, 29, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_madd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
-// Negative Multiply Add
+// Negative Multiply Add.
 defm PS_NMADD  : AForm_1r<4, 31, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_nmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
@@ -142,27 +142,27 @@ defm PS_SUB    : AForm_2r<4, 20, (outs f8rc:$FRT),
 defm PS_DIV    : AForm_2r<4, 18, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRB),
                           "ps_div", "$FRT, $FRA, $FRB", IIC_FPDivS, []>;
-// Multiply Subtract
+// Multiply Subtract.
 defm PS_MSUB   : AForm_1r<4, 28, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_msub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
-// Negative Multiply Subtract
+// Negative Multiply Subtract.
 defm PS_NMSUB  : AForm_1r<4, 30, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB),
                           "ps_nmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused,
                           []>;
-// Reciprocal Estimate
+// Reciprocal Estimate.
 defm PS_RES    : XForm_26r<4, 24, (outs f8rc:$RST), (ins f8rc:$RB),
                            "ps_res", "$RST, $RB", IIC_FPGeneral, []>;
-// Reciprocal Square Root Estimate
+// Reciprocal Square Root Estimate.
 defm PS_RSQRTE : XForm_26r<4, 26, (outs f8rc:$RST), (ins f8rc:$RB),
                            "ps_rsqrte", "$RST, $RB", IIC_FPGeneral, []>;
-// Multply A with the 1st element of B
+// Multply A with the 1st element of B.
 defm PS_MULS0  : AForm_3r<4, 12, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_muls0", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
-// Multply A with the 2nd element of B
+// Multply A with the 2nd element of B.
 defm PS_MULS1  : AForm_3r<4, 13, (outs f8rc:$FRT),
                           (ins f8rc:$FRA, f8rc:$FRC),
                           "ps_muls1", "$FRT, $FRA, $FRC", IIC_FPGeneral, []>;
@@ -226,16 +226,16 @@ defm PS_MERGE11 : XForm_28r<4, 624, (outs f8rc:$RST),
 }
 
 let mayRaiseFPException = 1, hasSideEffects = 0 in {
-// Unordered Comparison
+// Unordered Comparison.
 def PS_CMPU0 : XForm_17<4, 0, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpu0 $BF, $RA, $RB", IIC_FPCompare>;
-// Ordered Comparison
+// Ordered Comparison.
 def PS_CMPO0 : XForm_17<4, 32, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpo0 $BF, $RA, $RB", IIC_FPCompare>;
-// Unordered Comparison
+// Unordered Comparison.
 def PS_CMPU1 : XForm_17<4, 64, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpu1 $BF, $RA, $RB", IIC_FPCompare>;
-// Ordered Comparison
+// Ordered Comparison.
 def PS_CMPO1 : XForm_17<4, 96, (outs crrc:$BF), (ins f8rc:$RA, f8rc:$RB),
                         "ps_cmpo1 $BF, $RA, $RB", IIC_FPCompare>;
 }



More information about the llvm-commits mailing list