[PowerPC] Add ROP Protection Instructions for PowerPC

There are four new PowerPC instructions that are introduced in
Power 10. They are hashst, hashchk, hashstp, hashchkp.

These instructions will be used for ROP Protection.
This patch adds the four instructions.

Reviewed By: nemanjai, amyk, #powerpc

Differential Revision: https://reviews.llvm.org/D99375

GitOrigin-RevId: f28cb01be071a52e817c8ba84a5ef503a614b86e
diff --git a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index ba40e23..54e7313 100644
--- a/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -359,6 +359,15 @@
   bool isS16ImmX4() const { return Kind == Expression ||
                                    (Kind == Immediate && isInt<16>(getImm()) &&
                                     (getImm() & 3) == 0); }
+
+  bool isHashImmX8() const {
+    // The Hash Imm form is used for instructions that check or store a hash.
+    // These instructions have a small immediate range that spans between
+    // -8 and -512.
+    return (Kind == Immediate && getImm() <= -8 && getImm() >= -512 &&
+            (getImm() & 7) == 0);
+  }
+
   bool isS16ImmX16() const { return Kind == Expression ||
                                     (Kind == Immediate && isInt<16>(getImm()) &&
                                      (getImm() & 15) == 0); }
diff --git a/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp b/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
index 3e9286f..44f9920 100644
--- a/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
+++ b/lib/Target/PowerPC/Disassembler/PPCDisassembler.cpp
@@ -279,6 +279,23 @@
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeMemRIHashOperands(MCInst &Inst, uint64_t Imm,
+                                            int64_t Address,
+                                            const void *Decoder) {
+  // Decode the memrix field for a hash store or hash check operation.
+  // The field is composed of a register and an immediate value that is 6 bits
+  // and covers the range -8 to -512. The immediate is always negative and 2s
+  // complement which is why we sign extend a 7 bit value.
+  const uint64_t Base = Imm >> 6;
+  const int64_t Disp = SignExtend64<7>((Imm & 0x3F) + 64) * 8;
+
+  assert(Base < 32 && "Invalid base register");
+
+  Inst.addOperand(MCOperand::createImm(Disp));
+  Inst.addOperand(MCOperand::createReg(RRegs[Base]));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeMemRIX16Operands(MCInst &Inst, uint64_t Imm,
                                          int64_t Address, const void *Decoder) {
   // Decode the memrix16 field (imm, reg), which has the low 12-bits as the
diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
index a291a34..3f6497a 100644
--- a/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -514,6 +514,15 @@
   O << ')';
 }
 
+void PPCInstPrinter::printMemRegImmHash(const MCInst *MI, unsigned OpNo,
+                                        const MCSubtargetInfo &STI,
+                                        raw_ostream &O) {
+  O << MI->getOperand(OpNo).getImm();
+  O << '(';
+  printOperand(MI, OpNo + 1, STI, O);
+  O << ')';
+}
+
 void PPCInstPrinter::printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo,
                                            const MCSubtargetInfo &STI,
                                            raw_ostream &O) {
diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h b/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
index 5e9b014..8f676da 100644
--- a/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
+++ b/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h
@@ -97,6 +97,8 @@
 
   void printMemRegImm(const MCInst *MI, unsigned OpNo,
                       const MCSubtargetInfo &STI, raw_ostream &O);
+  void printMemRegImmHash(const MCInst *MI, unsigned OpNo,
+                          const MCSubtargetInfo &STI, raw_ostream &O);
   void printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo,
                              const MCSubtargetInfo &STI, raw_ostream &O);
   void printMemRegImm34(const MCInst *MI, unsigned OpNo,
diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
index 5f0769f..4dfa7d5 100644
--- a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
+++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp
@@ -203,6 +203,24 @@
   return RegBits;
 }
 
+unsigned
+PPCMCCodeEmitter::getMemRIHashEncoding(const MCInst &MI, unsigned OpNo,
+                                       SmallVectorImpl<MCFixup> &Fixups,
+                                       const MCSubtargetInfo &STI) const {
+  // Encode (imm, reg) for the hash load/store to stack for the ROP Protection
+  // instructions.
+  const MCOperand &RegMO = MI.getOperand(OpNo + 1);
+  const MCOperand &MO = MI.getOperand(OpNo);
+
+  assert(RegMO.isReg() && "Base address must be a register.");
+  assert(MO.isImm() && "Expecting an immediate operand.");
+  assert(!(MO.getImm() % 8) && "Expecting offset to be 8 byte aligned.");
+
+  unsigned RegBits = getMachineOpValue(MI, RegMO, Fixups, STI) << 6;
+  unsigned DX = (MO.getImm() >> 3) & 0x3F;
+  return RegBits | DX;
+}
+
 uint64_t
 PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
                                           SmallVectorImpl<MCFixup> &Fixups,
diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
index 347e163..39b2f12 100644
--- a/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
+++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h
@@ -69,6 +69,9 @@
   unsigned getMemRIX16Encoding(const MCInst &MI, unsigned OpNo,
                                SmallVectorImpl<MCFixup> &Fixups,
                                const MCSubtargetInfo &STI) const;
+  unsigned getMemRIHashEncoding(const MCInst &MI, unsigned OpNo,
+                                SmallVectorImpl<MCFixup> &Fixups,
+                                const MCSubtargetInfo &STI) const;
   uint64_t getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
                                    SmallVectorImpl<MCFixup> &Fixups,
                                    const MCSubtargetInfo &STI) const;
diff --git a/lib/Target/PowerPC/P9InstrResources.td b/lib/Target/PowerPC/P9InstrResources.td
index 05fbe38..76f52c7 100644
--- a/lib/Target/PowerPC/P9InstrResources.td
+++ b/lib/Target/PowerPC/P9InstrResources.td
@@ -1409,6 +1409,7 @@
   (instregex "NOP_GT_PWR(6|7)$"),
   (instregex "TLB(IA|IVAX|SX|SX2|SX2D|LD|LI|RE|RE2|WE|WE2)$"),
   (instregex "WRTEE(I)?$"),
+  (instregex "HASH(ST|STP|CHK|CHKP)$"),
   ATTN,
   CLRBHRB,
   MFBHRBE,
diff --git a/lib/Target/PowerPC/PPCInstr64Bit.td b/lib/Target/PowerPC/PPCInstr64Bit.td
index 4fcc48e..386d143 100644
--- a/lib/Target/PowerPC/PPCInstr64Bit.td
+++ b/lib/Target/PowerPC/PPCInstr64Bit.td
@@ -1521,6 +1521,29 @@
                         [(set f64:$frD, (PPCany_fctiwuz f64:$frB))]>, isPPC64;
 }
 
+// These instructions store a hash computed from the value of the link register
+// and the value of the stack pointer.
+let mayStore = 1 in {
+def HASHST : XForm_XD6_RA5_RB5<31, 722, (outs),
+                               (ins g8rc:$RB, memrihash:$D_RA_XD),
+                               "hashst $RB, $D_RA_XD", IIC_IntGeneral, []>;
+def HASHSTP : XForm_XD6_RA5_RB5<31, 658, (outs),
+                                (ins g8rc:$RB, memrihash:$D_RA_XD),
+                                "hashstp $RB, $D_RA_XD", IIC_IntGeneral, []>;
+}
+
+// These instructions check a hash computed from the value of the link register
+// and the value of the stack pointer. The hasSideEffects flag is needed as the
+// instruction may TRAP if the hash does not match the hash stored at the
+// specified address.
+let mayLoad = 1, hasSideEffects = 1 in {
+def HASHCHK : XForm_XD6_RA5_RB5<31, 754, (outs),
+                                (ins g8rc:$RB, memrihash:$D_RA_XD),
+                                "hashchk $RB, $D_RA_XD", IIC_IntGeneral, []>;
+def HASHCHKP : XForm_XD6_RA5_RB5<31, 690, (outs),
+                                 (ins g8rc:$RB, memrihash:$D_RA_XD),
+                                 "hashchkp $RB, $D_RA_XD", IIC_IntGeneral, []>;
+}
 
 //===----------------------------------------------------------------------===//
 // Instruction Patterns
diff --git a/lib/Target/PowerPC/PPCInstrFormats.td b/lib/Target/PowerPC/PPCInstrFormats.td
index 646efe6..bb25e42 100644
--- a/lib/Target/PowerPC/PPCInstrFormats.td
+++ b/lib/Target/PowerPC/PPCInstrFormats.td
@@ -1195,6 +1195,21 @@
   let Inst{31}    = XT{5};
 }
 
+class XForm_XD6_RA5_RB5<bits<6> opcode, bits<10> xo, dag OOL, dag IOL,
+                        string asmstr, InstrItinClass itin, list<dag> pattern>
+  : I<opcode, OOL, IOL, asmstr, itin> {
+  bits<11> D_RA_XD;
+  bits<5> RB;
+
+  let Pattern = pattern;
+
+  let Inst{6-10}  = D_RA_XD{4-0};  // D
+  let Inst{11-15} = D_RA_XD{10-6}; // RA
+  let Inst{16-20} = RB;
+  let Inst{21-30} = xo;
+  let Inst{31}    = D_RA_XD{5};    // DX
+}
+
 class XX3Form<bits<6> opcode, bits<8> xo, dag OOL, dag IOL, string asmstr, 
               InstrItinClass itin, list<dag> pattern>
   : I<opcode, OOL, IOL, asmstr, itin> {
diff --git a/lib/Target/PowerPC/PPCInstrInfo.td b/lib/Target/PowerPC/PPCInstrInfo.td
index aa820ee..61c22f8 100644
--- a/lib/Target/PowerPC/PPCInstrInfo.td
+++ b/lib/Target/PowerPC/PPCInstrInfo.td
@@ -991,6 +991,13 @@
 def dispRIX : Operand<iPTR> {
   let ParserMatchClass = PPCDispRIXOperand;
 }
+def PPCDispRIHashOperand : AsmOperandClass {
+  let Name = "DispRIHash"; let PredicateMethod = "isHashImmX8";
+  let RenderMethod = "addImmOperands";
+}
+def dispRIHash : Operand<iPTR> {
+  let ParserMatchClass = PPCDispRIHashOperand;
+}
 def PPCDispRIX16Operand : AsmOperandClass {
  let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16";
  let RenderMethod = "addImmOperands";
@@ -1039,6 +1046,14 @@
   let DecoderMethod = "decodeMemRIXOperands";
   let OperandType = "OPERAND_MEMORY";
 }
+def memrihash : Operand<iPTR> {
+  // memrihash 8-aligned for ROP Protection Instructions.
+  let PrintMethod = "printMemRegImmHash";
+  let MIOperandInfo = (ops dispRIHash:$imm, ptr_rc_nor0:$reg);
+  let EncoderMethod = "getMemRIHashEncoding";
+  let DecoderMethod = "decodeMemRIHashOperands";
+  let OperandType = "OPERAND_MEMORY";
+}
 def memrix16 : Operand<iPTR> { // memri, imm is 16-aligned, 12-bit, Inst{16:27}
   let PrintMethod = "printMemRegImm";
   let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg);
diff --git a/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt b/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt
index edbeeaf..7b4f2cb 100644
--- a/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt
+++ b/test/MC/Disassembler/PowerPC/ppc64-encoding-ISA31.txt
@@ -767,3 +767,40 @@
 
 # CHECK: xvcvbf16spn 33, 34
 0xf0 0x30 0x17 0x6f
+
+# CHECK: hashst 5, -8(1)
+0x7f 0xe1 0x2d 0xa5
+
+# CHECK: hashst 0, -8(30)
+0x7f 0xfe 0x05 0xa5
+
+# CHECK: hashst 5, -512(1)
+0x7c 0x01 0x2d 0xa4
+
+# CHECK: hashchk 5, -8(1)
+0x7f 0xe1 0x2d 0xe5
+
+# CHECK: hashchk 0, -8(30)
+0x7f 0xfe 0x05 0xe5
+
+# CHECK: hashchk 5, -512(1)
+0x7c 0x01 0x2d 0xe4
+
+# CHECK: hashstp 5, -8(1)
+0x7f 0xe1 0x2d 0x25
+
+# CHECK: hashstp 0, -8(30)
+0x7f 0xfe 0x05 0x25
+
+# CHECK: hashstp 5, -512(1)
+0x7c 0x01 0x2d 0x24
+
+# CHECK: hashchkp 5, -8(1)
+0x7f 0xe1 0x2d 0x65
+
+# CHECK: hashchkp 0, -8(30)
+0x7f 0xfe 0x05 0x65
+
+# CHECK: hashchkp 5, -512(1)
+0x7c 0x01 0x2d 0x64
+
diff --git a/test/MC/PowerPC/ppc64-encoding-ISA31.s b/test/MC/PowerPC/ppc64-encoding-ISA31.s
index 7ff7e02..f237a68 100644
--- a/test/MC/PowerPC/ppc64-encoding-ISA31.s
+++ b/test/MC/PowerPC/ppc64-encoding-ISA31.s
@@ -963,3 +963,39 @@
 # CHECK-BE: xvcvbf16spn 33, 34                    # encoding: [0xf0,0x30,0x17,0x6f]
 # CHECK-LE: xvcvbf16spn 33, 34                    # encoding: [0x6f,0x17,0x30,0xf0]
             xvcvbf16spn 33, 34
+# CHECK-BE: hashst 5, -8(1)                       # encoding: [0x7f,0xe1,0x2d,0xa5]
+# CHECK-LE: hashst 5, -8(1)                       # encoding: [0xa5,0x2d,0xe1,0x7f]
+            hashst 5, -8(1)
+# CHECK-BE: hashst 0, -8(30)                      # encoding: [0x7f,0xfe,0x05,0xa5]
+# CHECK-LE: hashst 0, -8(30)                      # encoding: [0xa5,0x05,0xfe,0x7f]
+            hashst 0, -8(30)
+# CHECK-BE: hashst 5, -512(1)                     # encoding: [0x7c,0x01,0x2d,0xa4]
+# CHECK-LE: hashst 5, -512(1)                     # encoding: [0xa4,0x2d,0x01,0x7c]
+            hashst 5, -512(1)
+# CHECK-BE: hashchk 5, -8(1)                      # encoding: [0x7f,0xe1,0x2d,0xe5]
+# CHECK-LE: hashchk 5, -8(1)                      # encoding: [0xe5,0x2d,0xe1,0x7f]
+            hashchk 5, -8(1)
+# CHECK-BE: hashchk 0, -8(30)                     # encoding: [0x7f,0xfe,0x05,0xe5]
+# CHECK-LE: hashchk 0, -8(30)                     # encoding: [0xe5,0x05,0xfe,0x7f]
+            hashchk 0, -8(30)
+# CHECK-BE: hashchk 5, -512(1)                    # encoding: [0x7c,0x01,0x2d,0xe4]
+# CHECK-LE: hashchk 5, -512(1)                    # encoding: [0xe4,0x2d,0x01,0x7c]
+            hashchk 5, -512(1)
+# CHECK-BE: hashstp 5, -8(1)                      # encoding: [0x7f,0xe1,0x2d,0x25]
+# CHECK-LE: hashstp 5, -8(1)                      # encoding: [0x25,0x2d,0xe1,0x7f]
+            hashstp 5, -8(1)
+# CHECK-BE: hashstp 0, -8(30)                     # encoding: [0x7f,0xfe,0x05,0x25]
+# CHECK-LE: hashstp 0, -8(30)                     # encoding: [0x25,0x05,0xfe,0x7f]
+            hashstp 0, -8(30)
+# CHECK-BE: hashstp 5, -512(1)                    # encoding: [0x7c,0x01,0x2d,0x24]
+# CHECK-LE: hashstp 5, -512(1)                    # encoding: [0x24,0x2d,0x01,0x7c]
+            hashstp 5, -512(1)
+# CHECK-BE: hashchkp 5, -8(1)                     # encoding: [0x7f,0xe1,0x2d,0x65]
+# CHECK-LE: hashchkp 5, -8(1)                     # encoding: [0x65,0x2d,0xe1,0x7f]
+            hashchkp 5, -8(1)
+# CHECK-BE: hashchkp 0, -8(30)                    # encoding: [0x7f,0xfe,0x05,0x65]
+# CHECK-LE: hashchkp 0, -8(30)                    # encoding: [0x65,0x05,0xfe,0x7f]
+            hashchkp 0, -8(30)
+# CHECK-BE: hashchkp 5, -512(1)                   # encoding: [0x7c,0x01,0x2d,0x64]
+# CHECK-LE: hashchkp 5, -512(1)                   # encoding: [0x64,0x2d,0x01,0x7c]
+            hashchkp 5, -512(1)