Skip to content

[RISCV] Add MC layer support for Zicfiss. #66043

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 30, 2023
Merged

[RISCV] Add MC layer support for Zicfiss. #66043

merged 4 commits into from
Dec 30, 2023

Conversation

yetingk
Copy link
Contributor

@yetingk yetingk commented Sep 12, 2023

The patch adds the instructions in Zicfiss extension. Zicfiss extension is to support shadow stack for control flow integrity. This patch is based on version 0.3.1.

@yetingk yetingk requested a review from a team as a code owner September 12, 2023 04:56
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V mc Machine (object) code labels Sep 12, 2023
@llvmbot
Copy link
Member

llvmbot commented Sep 12, 2023

@llvm/pr-subscribers-clang

Changes

The patch adds the instructions in Zicfiss extension. Zicfiss extension is to support shadow stack for control flow integrity. This patch is based on version 0.3.1.

--

Patch is 23.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66043.diff

14 Files Affected:

  • (modified) clang/test/Preprocessor/riscv-target-features.c (+9)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/lib/Support/RISCVISAInfo.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+29)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+5-4)
  • (added) llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td (+86)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.td (+9)
  • (modified) llvm/test/MC/RISCV/attribute-arch.s (+3)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-valid.s (+103)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-valid.s (+103)
diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
index 02b67dc7944ba88..163eba81543ee5b 100644
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -113,6 +113,7 @@
 // CHECK-NOT: __riscv_zfa {{.*$}}
 // CHECK-NOT: __riscv_zfbfmin {{.*$}}
 // CHECK-NOT: __riscv_zicfilp {{.*$}}
+// CHECK-NOT: __riscv_zicfiss {{.*$}}
 // CHECK-NOT: __riscv_zicond {{.*$}}
 // CHECK-NOT: __riscv_ztso {{.*$}}
 // CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -1220,3 +1221,11 @@
 // RUN: -march=rv64i_zve32x_zvkt1p0 -x c -E -dM %s \
 // RUN: -o - | FileCheck --check-prefix=CHECK-ZVKT-EXT %s
 // CHECK-ZVKT-EXT: __riscv_zvkt 1000000{{$}}
+
+// RUN: %clang -target riscv32 -menable-experimental-extensions \
+// RUN: -march=rv32izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// RUN: %clang -target riscv64 -menable-experimental-extensions \
+// RUN: -march=rv64izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// CHECK-ZICFISS-EXT: __riscv_zicfiss 3000{{$}}
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 8d12d58738c609a..31c55def0a7694a 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -205,6 +205,9 @@ The primary goal of experimental support is to assist in the process of ratifica
 ``experimental-zicfilp``
   LLVM implements the `0.2 draft specification `__.
 
+``experimental-zicfiss``
+  LLVM implements the `0.3.1 draft specification `__.
+
 ``experimental-zicond``
   LLVM implements the `1.0-rc1 draft specification `__.
 
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index a02c9842e85839a..c414b62c5f31092 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -170,6 +170,8 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
     {"zfbfmin", RISCVExtensionVersion{0, 8}},
 
     {"zicfilp", RISCVExtensionVersion{0, 2}},
+    {"zicfiss", RISCVExtensionVersion{0, 3}},
+
     {"zicond", RISCVExtensionVersion{1, 0}},
 
     {"ztso", RISCVExtensionVersion{0, 1}},
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index d561d90d3088c1a..14b3122f0fecbdb 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -74,6 +74,17 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeGPRRARegisterClass(MCInst &Inst, uint32_t RegNo,
+                                             uint64_t Address,
+                                             const MCDisassembler *Decoder) {
+  MCRegister Reg = RISCV::X0 + RegNo;
+  if (Reg != RISCV::X1 && Reg != RISCV::X5)
+    return MCDisassembler::Fail;
+
+  Inst.addOperand(MCOperand::createReg(Reg));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus DecodeFPR16RegisterClass(MCInst &Inst, uint32_t RegNo,
                                              uint64_t Address,
                                              const MCDisassembler *Decoder) {
@@ -370,6 +381,10 @@ static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
 static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
                                     uint64_t Address, const void *Decoder);
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
 static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
@@ -384,6 +399,16 @@ static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder) {
+  uint32_t Rs1 = fieldFromInstruction(Insn, 7, 5);
+  DecodeStatus Result = DecodeGPRRARegisterClass(Inst, Rs1, Address, Decoder);
+  (void)Result;
+  assert(Result == MCDisassembler::Success && "Invalid register");
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, uint32_t Insn,
                                          uint64_t Address,
                                          const MCDisassembler *Decoder) {
@@ -527,6 +552,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                   "RV32Zdinx table (Double in Integer and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
                           "RVZfinx table (Float in Integer)");
+    TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZicfiss) &&
+                      !STI.hasFeature(RISCV::Feature64Bit),
+                  DecoderTableRV32Zicfiss32,
+                  "RV32Zicfiss table (Shadow stack and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,
                           DecoderTableXVentana32, "Ventana custom opcode table");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXTHeadBa, DecoderTableXTHeadBa32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 6381263b37613b3..286320c6c52eb12 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -79,6 +79,13 @@ def HasStdExtZihintntl : Predicate<"Subtarget->hasStdExtZihintntl()">,
                                     AssemblerPredicate<(all_of FeatureStdExtZihintntl),
                                     "'Zihintntl' (Non-Temporal Locality Hints)">;
 
+def FeatureStdExtZicfiss
+    : SubtargetFeature<"experimental-zicfiss", "HasStdExtZicfiss", "true",
+                       "'Zicfiss' (Shadow stack)">;
+def HasStdExtZicfiss : Predicate<"Subtarget->hasStdExtZicfiss()">,
+                                 AssemblerPredicate<(all_of FeatureStdExtZicfiss),
+                                 "'Zicfiss' (Shadow stack)">;
+
 def FeatureStdExtZifencei
     : SubtargetFeature<"zifencei", "HasStdExtZifencei", "true",
                        "'Zifencei' (fence.i)">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 582fe60fd0368e9..e6a8ba1fe2fc17d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1970,14 +1970,15 @@ include "RISCVInstrInfoZk.td"
 include "RISCVInstrInfoV.td"
 include "RISCVInstrInfoZvk.td"
 
-// Integer
-include "RISCVInstrInfoZicbo.td"
-include "RISCVInstrInfoZicond.td"
-
 // Compressed
 include "RISCVInstrInfoC.td"
 include "RISCVInstrInfoZc.td"
 
+// Integer
+include "RISCVInstrInfoZicbo.td"
+include "RISCVInstrInfoZicond.td"
+include "RISCVInstrInfoZicfiss.td"
+
 //===----------------------------------------------------------------------===//
 // Vendor extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
new file mode 100644
index 000000000000000..f787a260a8ca9da
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -0,0 +1,86 @@
+//===------ RISCVInstrInfoZicfiss.td - RISC-V Zicfiss -*- tablegen -*------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction class templates
+//===----------------------------------------------------------------------===//
+
+class RVC_SSInst rs1val, RegisterClass reg_class, string opcodestr> :
+  RVInst16<(outs), (ins reg_class:$rs1), opcodestr, "$rs1", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = rs1val;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+  let DecoderMethod = "decodeCSSPushPopchk";
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
+let DecoderNamespace = "RV32Zicfiss", Predicates = [HasStdExtZicfiss, IsRV32] in
+def SSLW : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "sslw", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+
+let Predicates = [HasStdExtZicfiss, IsRV64] in
+def SSLD : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "ssld", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Predicates = [HasStdExtZicfiss] in {
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
+def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs1), "sspopchk",
+                       "$rs1"> {
+  let rd = 0;
+  let imm12 = 0b100000011100;
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+def SSINCP : RVInstI<0b100, OPC_SYSTEM, (outs), (ins), "ssincp", ""> {
+  let imm12 = 0b100000011100;
+  let rs1 = 0b00000;
+  let rd = 0b00000;
+}
+
+def SSRDP : RVInstI<0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), (ins), "ssrdp", "$rd"> {
+  let imm12 = 0b100000011101;
+  let rs1 = 0b00000;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def SSPUSH : RVInstR<0b1000001, 0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs2),
+                     "sspush", "$rs2"> {
+  let rd = 0b00000;
+  let rs1 = 0b00000;
+}
+} // Predicates = [HasStdExtZicfiss]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtCOrZca] in {
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPOPCHK : RVC_SSInst<0b00101, GPRX5, "c.sspopchk">;
+} // Predicates = [HasStdExtZicfiss, HasStdExtCOrZca]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtC], Uses = [SSP], Defs = [SSP],
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def C_SSINCP : RVInst16<(outs), (ins), "c.ssincp", "", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = 0b00011;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 3e44cf4781f643c..7934da40ac4aadc 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -119,6 +119,9 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   markSuperRegs(Reserved, RISCV::FRM);
   markSuperRegs(Reserved, RISCV::FFLAGS);
 
+  // Shadow stack pointer.
+  markSuperRegs(Reserved, RISCV::SSP);
+
   assert(checkAllSuperRegsMarked(Reserved));
   return Reserved;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 1a6145f92908134..87ad1d5ecd179e9 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -137,6 +137,8 @@ def GPR : GPRRegisterClass<(add (sequence "X%u", 10, 17),
                                 (sequence "X%u", 0, 4))>;
 
 def GPRX0 : GPRRegisterClass<(add X0)>;
+def GPRX1 : GPRRegisterClass<(add X1)>;
+def GPRX5 : GPRRegisterClass<(add X5)>;
 
 def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)>;
 
@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
 def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
                                  (sequence "X%u", 18, 23))>;
 
+def GPRRA : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
+  let RegInfos = XLenRI;
+}
+
 // Floating point registers
 let RegAltNameIndices = [ABIRegAltName] in {
   def F0_H  : RISCVReg16<0, "f0", ["ft0"]>, DwarfRegNum<[32]>;
@@ -597,3 +603,6 @@ foreach m = LMULList in {
 // Special registers
 def FFLAGS : RISCVReg<0, "fflags">;
 def FRM    : RISCVReg<0, "frm">;
+
+// Shadow Stack register
+def SSP    : RISCVReg<0, "ssp">;
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index bf40eda456edf13..4f201d2afde3164 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -305,3 +305,6 @@
 
 .attribute arch, "rv32i_zicfilp0p2"
 # CHECK: attribute      5, "rv32i2p1_zicfilp0p2"
+
+.attribute arch, "rv32i_zicfiss0p3"
+# CHECK: .attribute     5, "rv32i2p1_zicfiss0p3"
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-invalid.s b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
new file mode 100644
index 000000000000000..6b4959043d0180b
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+sslw a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-valid.s b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
new file mode 100644
index 000000000000000..46a1d3103afac6e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
@@ -0,0 +1,103 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zicfiss,+c < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-zicfiss -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# RUN: not llvm-mc -triple riscv32 -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x1
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw ra
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x5
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw t0
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x1
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk ra
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x5
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk t0
+
+# CHECK-ASM-AND-OBJ: ssincp
+# CHECK-ASM: encoding: [0x73,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssincp
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x1
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush ra
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x5
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush t0
+
+# CHECK-ASM-AND-OBJ: ssrdp ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xd0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssrdp ra
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush x1
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush ra
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk x5
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk t0
+
+# CHECK-ASM-AND-OBJ: c.ssincp
+# CHECK-ASM: encoding: [0x81,0x61]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack)
+c.ssincp
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-invalid.s b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
new file mode 100644
index 000000000000000..aef5e17e33aff9e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv64 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+ssld a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-valid.s b/llvm/test/MC/RISCV/rv64zicfiss-valid.s
new file mode 100644
index 000000000000000..8bba15cc3b22bec
--- /dev/null
+++ b/llvm/test/MC/RI...

@llvmbot
Copy link
Member

llvmbot commented Sep 12, 2023

@llvm/pr-subscribers-mc

Changes

The patch adds the instructions in Zicfiss extension. Zicfiss extension is to support shadow stack for control flow integrity. This patch is based on version 0.3.1.

--

Patch is 23.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66043.diff

14 Files Affected:

  • (modified) clang/test/Preprocessor/riscv-target-features.c (+9)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/lib/Support/RISCVISAInfo.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+29)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+5-4)
  • (added) llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td (+86)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.td (+9)
  • (modified) llvm/test/MC/RISCV/attribute-arch.s (+3)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-valid.s (+103)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-valid.s (+103)
diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
index 02b67dc7944ba88..163eba81543ee5b 100644
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -113,6 +113,7 @@
 // CHECK-NOT: __riscv_zfa {{.*$}}
 // CHECK-NOT: __riscv_zfbfmin {{.*$}}
 // CHECK-NOT: __riscv_zicfilp {{.*$}}
+// CHECK-NOT: __riscv_zicfiss {{.*$}}
 // CHECK-NOT: __riscv_zicond {{.*$}}
 // CHECK-NOT: __riscv_ztso {{.*$}}
 // CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -1220,3 +1221,11 @@
 // RUN: -march=rv64i_zve32x_zvkt1p0 -x c -E -dM %s \
 // RUN: -o - | FileCheck --check-prefix=CHECK-ZVKT-EXT %s
 // CHECK-ZVKT-EXT: __riscv_zvkt 1000000{{$}}
+
+// RUN: %clang -target riscv32 -menable-experimental-extensions \
+// RUN: -march=rv32izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// RUN: %clang -target riscv64 -menable-experimental-extensions \
+// RUN: -march=rv64izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// CHECK-ZICFISS-EXT: __riscv_zicfiss 3000{{$}}
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 8d12d58738c609a..31c55def0a7694a 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -205,6 +205,9 @@ The primary goal of experimental support is to assist in the process of ratifica
 ``experimental-zicfilp``
   LLVM implements the `0.2 draft specification `__.
 
+``experimental-zicfiss``
+  LLVM implements the `0.3.1 draft specification `__.
+
 ``experimental-zicond``
   LLVM implements the `1.0-rc1 draft specification `__.
 
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index a02c9842e85839a..c414b62c5f31092 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -170,6 +170,8 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
     {"zfbfmin", RISCVExtensionVersion{0, 8}},
 
     {"zicfilp", RISCVExtensionVersion{0, 2}},
+    {"zicfiss", RISCVExtensionVersion{0, 3}},
+
     {"zicond", RISCVExtensionVersion{1, 0}},
 
     {"ztso", RISCVExtensionVersion{0, 1}},
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index d561d90d3088c1a..14b3122f0fecbdb 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -74,6 +74,17 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeGPRRARegisterClass(MCInst &Inst, uint32_t RegNo,
+                                             uint64_t Address,
+                                             const MCDisassembler *Decoder) {
+  MCRegister Reg = RISCV::X0 + RegNo;
+  if (Reg != RISCV::X1 && Reg != RISCV::X5)
+    return MCDisassembler::Fail;
+
+  Inst.addOperand(MCOperand::createReg(Reg));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus DecodeFPR16RegisterClass(MCInst &Inst, uint32_t RegNo,
                                              uint64_t Address,
                                              const MCDisassembler *Decoder) {
@@ -370,6 +381,10 @@ static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
 static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
                                     uint64_t Address, const void *Decoder);
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
 static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
@@ -384,6 +399,16 @@ static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder) {
+  uint32_t Rs1 = fieldFromInstruction(Insn, 7, 5);
+  DecodeStatus Result = DecodeGPRRARegisterClass(Inst, Rs1, Address, Decoder);
+  (void)Result;
+  assert(Result == MCDisassembler::Success && "Invalid register");
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, uint32_t Insn,
                                          uint64_t Address,
                                          const MCDisassembler *Decoder) {
@@ -527,6 +552,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                   "RV32Zdinx table (Double in Integer and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
                           "RVZfinx table (Float in Integer)");
+    TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZicfiss) &&
+                      !STI.hasFeature(RISCV::Feature64Bit),
+                  DecoderTableRV32Zicfiss32,
+                  "RV32Zicfiss table (Shadow stack and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,
                           DecoderTableXVentana32, "Ventana custom opcode table");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXTHeadBa, DecoderTableXTHeadBa32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 6381263b37613b3..286320c6c52eb12 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -79,6 +79,13 @@ def HasStdExtZihintntl : Predicate<"Subtarget->hasStdExtZihintntl()">,
                                     AssemblerPredicate<(all_of FeatureStdExtZihintntl),
                                     "'Zihintntl' (Non-Temporal Locality Hints)">;
 
+def FeatureStdExtZicfiss
+    : SubtargetFeature<"experimental-zicfiss", "HasStdExtZicfiss", "true",
+                       "'Zicfiss' (Shadow stack)">;
+def HasStdExtZicfiss : Predicate<"Subtarget->hasStdExtZicfiss()">,
+                                 AssemblerPredicate<(all_of FeatureStdExtZicfiss),
+                                 "'Zicfiss' (Shadow stack)">;
+
 def FeatureStdExtZifencei
     : SubtargetFeature<"zifencei", "HasStdExtZifencei", "true",
                        "'Zifencei' (fence.i)">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 582fe60fd0368e9..e6a8ba1fe2fc17d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1970,14 +1970,15 @@ include "RISCVInstrInfoZk.td"
 include "RISCVInstrInfoV.td"
 include "RISCVInstrInfoZvk.td"
 
-// Integer
-include "RISCVInstrInfoZicbo.td"
-include "RISCVInstrInfoZicond.td"
-
 // Compressed
 include "RISCVInstrInfoC.td"
 include "RISCVInstrInfoZc.td"
 
+// Integer
+include "RISCVInstrInfoZicbo.td"
+include "RISCVInstrInfoZicond.td"
+include "RISCVInstrInfoZicfiss.td"
+
 //===----------------------------------------------------------------------===//
 // Vendor extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
new file mode 100644
index 000000000000000..f787a260a8ca9da
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -0,0 +1,86 @@
+//===------ RISCVInstrInfoZicfiss.td - RISC-V Zicfiss -*- tablegen -*------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction class templates
+//===----------------------------------------------------------------------===//
+
+class RVC_SSInst rs1val, RegisterClass reg_class, string opcodestr> :
+  RVInst16<(outs), (ins reg_class:$rs1), opcodestr, "$rs1", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = rs1val;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+  let DecoderMethod = "decodeCSSPushPopchk";
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
+let DecoderNamespace = "RV32Zicfiss", Predicates = [HasStdExtZicfiss, IsRV32] in
+def SSLW : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "sslw", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+
+let Predicates = [HasStdExtZicfiss, IsRV64] in
+def SSLD : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "ssld", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Predicates = [HasStdExtZicfiss] in {
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
+def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs1), "sspopchk",
+                       "$rs1"> {
+  let rd = 0;
+  let imm12 = 0b100000011100;
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+def SSINCP : RVInstI<0b100, OPC_SYSTEM, (outs), (ins), "ssincp", ""> {
+  let imm12 = 0b100000011100;
+  let rs1 = 0b00000;
+  let rd = 0b00000;
+}
+
+def SSRDP : RVInstI<0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), (ins), "ssrdp", "$rd"> {
+  let imm12 = 0b100000011101;
+  let rs1 = 0b00000;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def SSPUSH : RVInstR<0b1000001, 0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs2),
+                     "sspush", "$rs2"> {
+  let rd = 0b00000;
+  let rs1 = 0b00000;
+}
+} // Predicates = [HasStdExtZicfiss]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtCOrZca] in {
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPOPCHK : RVC_SSInst<0b00101, GPRX5, "c.sspopchk">;
+} // Predicates = [HasStdExtZicfiss, HasStdExtCOrZca]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtC], Uses = [SSP], Defs = [SSP],
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def C_SSINCP : RVInst16<(outs), (ins), "c.ssincp", "", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = 0b00011;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 3e44cf4781f643c..7934da40ac4aadc 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -119,6 +119,9 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   markSuperRegs(Reserved, RISCV::FRM);
   markSuperRegs(Reserved, RISCV::FFLAGS);
 
+  // Shadow stack pointer.
+  markSuperRegs(Reserved, RISCV::SSP);
+
   assert(checkAllSuperRegsMarked(Reserved));
   return Reserved;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 1a6145f92908134..87ad1d5ecd179e9 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -137,6 +137,8 @@ def GPR : GPRRegisterClass<(add (sequence "X%u", 10, 17),
                                 (sequence "X%u", 0, 4))>;
 
 def GPRX0 : GPRRegisterClass<(add X0)>;
+def GPRX1 : GPRRegisterClass<(add X1)>;
+def GPRX5 : GPRRegisterClass<(add X5)>;
 
 def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)>;
 
@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
 def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
                                  (sequence "X%u", 18, 23))>;
 
+def GPRRA : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
+  let RegInfos = XLenRI;
+}
+
 // Floating point registers
 let RegAltNameIndices = [ABIRegAltName] in {
   def F0_H  : RISCVReg16<0, "f0", ["ft0"]>, DwarfRegNum<[32]>;
@@ -597,3 +603,6 @@ foreach m = LMULList in {
 // Special registers
 def FFLAGS : RISCVReg<0, "fflags">;
 def FRM    : RISCVReg<0, "frm">;
+
+// Shadow Stack register
+def SSP    : RISCVReg<0, "ssp">;
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index bf40eda456edf13..4f201d2afde3164 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -305,3 +305,6 @@
 
 .attribute arch, "rv32i_zicfilp0p2"
 # CHECK: attribute      5, "rv32i2p1_zicfilp0p2"
+
+.attribute arch, "rv32i_zicfiss0p3"
+# CHECK: .attribute     5, "rv32i2p1_zicfiss0p3"
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-invalid.s b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
new file mode 100644
index 000000000000000..6b4959043d0180b
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+sslw a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-valid.s b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
new file mode 100644
index 000000000000000..46a1d3103afac6e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
@@ -0,0 +1,103 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zicfiss,+c < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-zicfiss -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# RUN: not llvm-mc -triple riscv32 -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x1
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw ra
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x5
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw t0
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x1
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk ra
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x5
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk t0
+
+# CHECK-ASM-AND-OBJ: ssincp
+# CHECK-ASM: encoding: [0x73,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssincp
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x1
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush ra
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x5
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush t0
+
+# CHECK-ASM-AND-OBJ: ssrdp ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xd0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssrdp ra
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush x1
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush ra
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk x5
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk t0
+
+# CHECK-ASM-AND-OBJ: c.ssincp
+# CHECK-ASM: encoding: [0x81,0x61]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack)
+c.ssincp
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-invalid.s b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
new file mode 100644
index 000000000000000..aef5e17e33aff9e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv64 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+ssld a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-valid.s b/llvm/test/MC/RISCV/rv64zicfiss-valid.s
new file mode 100644
index 000000000000000..8bba15cc3b22bec
--- /dev/null
+++ b/llvm/test/MC/RI...

@llvmbot
Copy link
Member

llvmbot commented Sep 12, 2023

@llvm/pr-subscribers-backend-risc-v

Changes

The patch adds the instructions in Zicfiss extension. Zicfiss extension is to support shadow stack for control flow integrity. This patch is based on version 0.3.1.

--

Patch is 23.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66043.diff

14 Files Affected:

  • (modified) clang/test/Preprocessor/riscv-target-features.c (+9)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/lib/Support/RISCVISAInfo.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+29)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+5-4)
  • (added) llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td (+86)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.td (+9)
  • (modified) llvm/test/MC/RISCV/attribute-arch.s (+3)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-valid.s (+103)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-valid.s (+103)
diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
index 02b67dc7944ba88..163eba81543ee5b 100644
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -113,6 +113,7 @@
 // CHECK-NOT: __riscv_zfa {{.*$}}
 // CHECK-NOT: __riscv_zfbfmin {{.*$}}
 // CHECK-NOT: __riscv_zicfilp {{.*$}}
+// CHECK-NOT: __riscv_zicfiss {{.*$}}
 // CHECK-NOT: __riscv_zicond {{.*$}}
 // CHECK-NOT: __riscv_ztso {{.*$}}
 // CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -1220,3 +1221,11 @@
 // RUN: -march=rv64i_zve32x_zvkt1p0 -x c -E -dM %s \
 // RUN: -o - | FileCheck --check-prefix=CHECK-ZVKT-EXT %s
 // CHECK-ZVKT-EXT: __riscv_zvkt 1000000{{$}}
+
+// RUN: %clang -target riscv32 -menable-experimental-extensions \
+// RUN: -march=rv32izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// RUN: %clang -target riscv64 -menable-experimental-extensions \
+// RUN: -march=rv64izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// CHECK-ZICFISS-EXT: __riscv_zicfiss 3000{{$}}
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 8d12d58738c609a..31c55def0a7694a 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -205,6 +205,9 @@ The primary goal of experimental support is to assist in the process of ratifica
 ``experimental-zicfilp``
   LLVM implements the `0.2 draft specification `__.
 
+``experimental-zicfiss``
+  LLVM implements the `0.3.1 draft specification `__.
+
 ``experimental-zicond``
   LLVM implements the `1.0-rc1 draft specification `__.
 
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index a02c9842e85839a..c414b62c5f31092 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -170,6 +170,8 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
     {"zfbfmin", RISCVExtensionVersion{0, 8}},
 
     {"zicfilp", RISCVExtensionVersion{0, 2}},
+    {"zicfiss", RISCVExtensionVersion{0, 3}},
+
     {"zicond", RISCVExtensionVersion{1, 0}},
 
     {"ztso", RISCVExtensionVersion{0, 1}},
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index d561d90d3088c1a..14b3122f0fecbdb 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -74,6 +74,17 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeGPRRARegisterClass(MCInst &Inst, uint32_t RegNo,
+                                             uint64_t Address,
+                                             const MCDisassembler *Decoder) {
+  MCRegister Reg = RISCV::X0 + RegNo;
+  if (Reg != RISCV::X1 && Reg != RISCV::X5)
+    return MCDisassembler::Fail;
+
+  Inst.addOperand(MCOperand::createReg(Reg));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus DecodeFPR16RegisterClass(MCInst &Inst, uint32_t RegNo,
                                              uint64_t Address,
                                              const MCDisassembler *Decoder) {
@@ -370,6 +381,10 @@ static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
 static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
                                     uint64_t Address, const void *Decoder);
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
 static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
@@ -384,6 +399,16 @@ static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder) {
+  uint32_t Rs1 = fieldFromInstruction(Insn, 7, 5);
+  DecodeStatus Result = DecodeGPRRARegisterClass(Inst, Rs1, Address, Decoder);
+  (void)Result;
+  assert(Result == MCDisassembler::Success && "Invalid register");
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, uint32_t Insn,
                                          uint64_t Address,
                                          const MCDisassembler *Decoder) {
@@ -527,6 +552,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                   "RV32Zdinx table (Double in Integer and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
                           "RVZfinx table (Float in Integer)");
+    TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZicfiss) &&
+                      !STI.hasFeature(RISCV::Feature64Bit),
+                  DecoderTableRV32Zicfiss32,
+                  "RV32Zicfiss table (Shadow stack and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,
                           DecoderTableXVentana32, "Ventana custom opcode table");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXTHeadBa, DecoderTableXTHeadBa32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 6381263b37613b3..286320c6c52eb12 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -79,6 +79,13 @@ def HasStdExtZihintntl : Predicate<"Subtarget->hasStdExtZihintntl()">,
                                     AssemblerPredicate<(all_of FeatureStdExtZihintntl),
                                     "'Zihintntl' (Non-Temporal Locality Hints)">;
 
+def FeatureStdExtZicfiss
+    : SubtargetFeature<"experimental-zicfiss", "HasStdExtZicfiss", "true",
+                       "'Zicfiss' (Shadow stack)">;
+def HasStdExtZicfiss : Predicate<"Subtarget->hasStdExtZicfiss()">,
+                                 AssemblerPredicate<(all_of FeatureStdExtZicfiss),
+                                 "'Zicfiss' (Shadow stack)">;
+
 def FeatureStdExtZifencei
     : SubtargetFeature<"zifencei", "HasStdExtZifencei", "true",
                        "'Zifencei' (fence.i)">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 582fe60fd0368e9..e6a8ba1fe2fc17d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1970,14 +1970,15 @@ include "RISCVInstrInfoZk.td"
 include "RISCVInstrInfoV.td"
 include "RISCVInstrInfoZvk.td"
 
-// Integer
-include "RISCVInstrInfoZicbo.td"
-include "RISCVInstrInfoZicond.td"
-
 // Compressed
 include "RISCVInstrInfoC.td"
 include "RISCVInstrInfoZc.td"
 
+// Integer
+include "RISCVInstrInfoZicbo.td"
+include "RISCVInstrInfoZicond.td"
+include "RISCVInstrInfoZicfiss.td"
+
 //===----------------------------------------------------------------------===//
 // Vendor extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
new file mode 100644
index 000000000000000..f787a260a8ca9da
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -0,0 +1,86 @@
+//===------ RISCVInstrInfoZicfiss.td - RISC-V Zicfiss -*- tablegen -*------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction class templates
+//===----------------------------------------------------------------------===//
+
+class RVC_SSInst rs1val, RegisterClass reg_class, string opcodestr> :
+  RVInst16<(outs), (ins reg_class:$rs1), opcodestr, "$rs1", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = rs1val;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+  let DecoderMethod = "decodeCSSPushPopchk";
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
+let DecoderNamespace = "RV32Zicfiss", Predicates = [HasStdExtZicfiss, IsRV32] in
+def SSLW : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "sslw", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+
+let Predicates = [HasStdExtZicfiss, IsRV64] in
+def SSLD : RVInstI<0b100, OPC_SYSTEM, (outs GPRRA:$rd), (ins), "ssld", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Predicates = [HasStdExtZicfiss] in {
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
+def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs1), "sspopchk",
+                       "$rs1"> {
+  let rd = 0;
+  let imm12 = 0b100000011100;
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+def SSINCP : RVInstI<0b100, OPC_SYSTEM, (outs), (ins), "ssincp", ""> {
+  let imm12 = 0b100000011100;
+  let rs1 = 0b00000;
+  let rd = 0b00000;
+}
+
+def SSRDP : RVInstI<0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), (ins), "ssrdp", "$rd"> {
+  let imm12 = 0b100000011101;
+  let rs1 = 0b00000;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def SSPUSH : RVInstR<0b1000001, 0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs2),
+                     "sspush", "$rs2"> {
+  let rd = 0b00000;
+  let rs1 = 0b00000;
+}
+} // Predicates = [HasStdExtZicfiss]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtCOrZca] in {
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPOPCHK : RVC_SSInst<0b00101, GPRX5, "c.sspopchk">;
+} // Predicates = [HasStdExtZicfiss, HasStdExtCOrZca]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtC], Uses = [SSP], Defs = [SSP],
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def C_SSINCP : RVInst16<(outs), (ins), "c.ssincp", "", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = 0b00011;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 3e44cf4781f643c..7934da40ac4aadc 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -119,6 +119,9 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   markSuperRegs(Reserved, RISCV::FRM);
   markSuperRegs(Reserved, RISCV::FFLAGS);
 
+  // Shadow stack pointer.
+  markSuperRegs(Reserved, RISCV::SSP);
+
   assert(checkAllSuperRegsMarked(Reserved));
   return Reserved;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 1a6145f92908134..87ad1d5ecd179e9 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -137,6 +137,8 @@ def GPR : GPRRegisterClass<(add (sequence "X%u", 10, 17),
                                 (sequence "X%u", 0, 4))>;
 
 def GPRX0 : GPRRegisterClass<(add X0)>;
+def GPRX1 : GPRRegisterClass<(add X1)>;
+def GPRX5 : GPRRegisterClass<(add X5)>;
 
 def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)>;
 
@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
 def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
                                  (sequence "X%u", 18, 23))>;
 
+def GPRRA : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
+  let RegInfos = XLenRI;
+}
+
 // Floating point registers
 let RegAltNameIndices = [ABIRegAltName] in {
   def F0_H  : RISCVReg16<0, "f0", ["ft0"]>, DwarfRegNum<[32]>;
@@ -597,3 +603,6 @@ foreach m = LMULList in {
 // Special registers
 def FFLAGS : RISCVReg<0, "fflags">;
 def FRM    : RISCVReg<0, "frm">;
+
+// Shadow Stack register
+def SSP    : RISCVReg<0, "ssp">;
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index bf40eda456edf13..4f201d2afde3164 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -305,3 +305,6 @@
 
 .attribute arch, "rv32i_zicfilp0p2"
 # CHECK: attribute      5, "rv32i2p1_zicfilp0p2"
+
+.attribute arch, "rv32i_zicfiss0p3"
+# CHECK: .attribute     5, "rv32i2p1_zicfiss0p3"
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-invalid.s b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
new file mode 100644
index 000000000000000..6b4959043d0180b
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+sslw a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-valid.s b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
new file mode 100644
index 000000000000000..46a1d3103afac6e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
@@ -0,0 +1,103 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zicfiss,+c < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-zicfiss -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# RUN: not llvm-mc -triple riscv32 -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x1
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw ra
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x5
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw t0
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x1
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk ra
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x5
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk t0
+
+# CHECK-ASM-AND-OBJ: ssincp
+# CHECK-ASM: encoding: [0x73,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssincp
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x1
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush ra
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x5
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush t0
+
+# CHECK-ASM-AND-OBJ: ssrdp ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xd0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssrdp ra
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush x1
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush ra
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk x5
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk t0
+
+# CHECK-ASM-AND-OBJ: c.ssincp
+# CHECK-ASM: encoding: [0x81,0x61]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack)
+c.ssincp
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-invalid.s b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
new file mode 100644
index 000000000000000..aef5e17e33aff9e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv64 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+ssld a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-valid.s b/llvm/test/MC/RISCV/rv64zicfiss-valid.s
new file mode 100644
index 000000000000000..8bba15cc3b22bec
--- /dev/null
+++ b/llvm/test/MC/RI...

@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
(sequence "X%u", 18, 23))>;

def GPRRA : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is GPRX1X5 better?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@llvmbot
Copy link
Member

llvmbot commented Oct 3, 2023

@llvm/pr-subscribers-llvm-support

Changes

The patch adds the instructions in Zicfiss extension. Zicfiss extension is to support shadow stack for control flow integrity. This patch is based on version 0.3.1.


Patch is 23.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66043.diff

14 Files Affected:

  • (modified) clang/test/Preprocessor/riscv-target-features.c (+9)
  • (modified) llvm/docs/RISCVUsage.rst (+3)
  • (modified) llvm/lib/Support/RISCVISAInfo.cpp (+2)
  • (modified) llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp (+29)
  • (modified) llvm/lib/Target/RISCV/RISCVFeatures.td (+7)
  • (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+5-4)
  • (added) llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td (+86)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp (+3)
  • (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.td (+9)
  • (modified) llvm/test/MC/RISCV/attribute-arch.s (+3)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv32zicfiss-valid.s (+103)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-invalid.s (+20)
  • (added) llvm/test/MC/RISCV/rv64zicfiss-valid.s (+103)
diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c
index 02b67dc7944ba88..163eba81543ee5b 100644
--- a/clang/test/Preprocessor/riscv-target-features.c
+++ b/clang/test/Preprocessor/riscv-target-features.c
@@ -113,6 +113,7 @@
 // CHECK-NOT: __riscv_zfa {{.*$}}
 // CHECK-NOT: __riscv_zfbfmin {{.*$}}
 // CHECK-NOT: __riscv_zicfilp {{.*$}}
+// CHECK-NOT: __riscv_zicfiss {{.*$}}
 // CHECK-NOT: __riscv_zicond {{.*$}}
 // CHECK-NOT: __riscv_ztso {{.*$}}
 // CHECK-NOT: __riscv_zvbb {{.*$}}
@@ -1220,3 +1221,11 @@
 // RUN: -march=rv64i_zve32x_zvkt1p0 -x c -E -dM %s \
 // RUN: -o - | FileCheck --check-prefix=CHECK-ZVKT-EXT %s
 // CHECK-ZVKT-EXT: __riscv_zvkt 1000000{{$}}
+
+// RUN: %clang -target riscv32 -menable-experimental-extensions \
+// RUN: -march=rv32izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// RUN: %clang -target riscv64 -menable-experimental-extensions \
+// RUN: -march=rv64izicfiss0p3 -x c -E -dM %s \
+// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s
+// CHECK-ZICFISS-EXT: __riscv_zicfiss 3000{{$}}
diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst
index 8d12d58738c609a..31c55def0a7694a 100644
--- a/llvm/docs/RISCVUsage.rst
+++ b/llvm/docs/RISCVUsage.rst
@@ -205,6 +205,9 @@ The primary goal of experimental support is to assist in the process of ratifica
 ``experimental-zicfilp``
   LLVM implements the `0.2 draft specification <https://github.com/riscv/riscv-cfi/releases/tag/v0.2.0>`__.
 
+``experimental-zicfiss``
+  LLVM implements the `0.3.1 draft specification <https://github.com/riscv/riscv-cfi/releases/tag/v0.3.1>`__.
+
 ``experimental-zicond``
   LLVM implements the `1.0-rc1 draft specification <https://github.com/riscv/riscv-zicond/releases/tag/v1.0-rc1>`__.
 
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index a02c9842e85839a..c414b62c5f31092 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -170,6 +170,8 @@ static const RISCVSupportedExtension SupportedExperimentalExtensions[] = {
     {"zfbfmin", RISCVExtensionVersion{0, 8}},
 
     {"zicfilp", RISCVExtensionVersion{0, 2}},
+    {"zicfiss", RISCVExtensionVersion{0, 3}},
+
     {"zicond", RISCVExtensionVersion{1, 0}},
 
     {"ztso", RISCVExtensionVersion{0, 1}},
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index d561d90d3088c1a..9f088b6f3bf6492 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -74,6 +74,17 @@ static DecodeStatus DecodeGPRRegisterClass(MCInst &Inst, uint32_t RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeGPRX1X5RegisterClass(MCInst &Inst, uint32_t RegNo,
+                                               uint64_t Address,
+                                               const MCDisassembler *Decoder) {
+  MCRegister Reg = RISCV::X0 + RegNo;
+  if (Reg != RISCV::X1 && Reg != RISCV::X5)
+    return MCDisassembler::Fail;
+
+  Inst.addOperand(MCOperand::createReg(Reg));
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus DecodeFPR16RegisterClass(MCInst &Inst, uint32_t RegNo,
                                              uint64_t Address,
                                              const MCDisassembler *Decoder) {
@@ -370,6 +381,10 @@ static DecodeStatus decodeZcmpRlist(MCInst &Inst, unsigned Imm,
 static DecodeStatus decodeZcmpSpimm(MCInst &Inst, unsigned Imm,
                                     uint64_t Address, const void *Decoder);
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder);
+
 #include "RISCVGenDisassemblerTables.inc"
 
 static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
@@ -384,6 +399,16 @@ static DecodeStatus decodeRVCInstrRdRs1ImmZero(MCInst &Inst, uint32_t Insn,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus decodeCSSPushPopchk(MCInst &Inst, uint32_t Insn,
+                                        uint64_t Address,
+                                        const MCDisassembler *Decoder) {
+  uint32_t Rs1 = fieldFromInstruction(Insn, 7, 5);
+  DecodeStatus Result = DecodeGPRX1X5RegisterClass(Inst, Rs1, Address, Decoder);
+  (void)Result;
+  assert(Result == MCDisassembler::Success && "Invalid register");
+  return MCDisassembler::Success;
+}
+
 static DecodeStatus decodeRVCInstrRdSImm(MCInst &Inst, uint32_t Insn,
                                          uint64_t Address,
                                          const MCDisassembler *Decoder) {
@@ -527,6 +552,10 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                   "RV32Zdinx table (Double in Integer and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureStdExtZfinx, DecoderTableRVZfinx32,
                           "RVZfinx table (Float in Integer)");
+    TRY_TO_DECODE(STI.hasFeature(RISCV::FeatureStdExtZicfiss) &&
+                      !STI.hasFeature(RISCV::Feature64Bit),
+                  DecoderTableRV32Zicfiss32,
+                  "RV32Zicfiss table (Shadow stack and rv32)");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXVentanaCondOps,
                           DecoderTableXVentana32, "Ventana custom opcode table");
     TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXTHeadBa, DecoderTableXTHeadBa32,
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 6381263b37613b3..286320c6c52eb12 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -79,6 +79,13 @@ def HasStdExtZihintntl : Predicate<"Subtarget->hasStdExtZihintntl()">,
                                     AssemblerPredicate<(all_of FeatureStdExtZihintntl),
                                     "'Zihintntl' (Non-Temporal Locality Hints)">;
 
+def FeatureStdExtZicfiss
+    : SubtargetFeature<"experimental-zicfiss", "HasStdExtZicfiss", "true",
+                       "'Zicfiss' (Shadow stack)">;
+def HasStdExtZicfiss : Predicate<"Subtarget->hasStdExtZicfiss()">,
+                                 AssemblerPredicate<(all_of FeatureStdExtZicfiss),
+                                 "'Zicfiss' (Shadow stack)">;
+
 def FeatureStdExtZifencei
     : SubtargetFeature<"zifencei", "HasStdExtZifencei", "true",
                        "'Zifencei' (fence.i)">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 582fe60fd0368e9..e6a8ba1fe2fc17d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1970,14 +1970,15 @@ include "RISCVInstrInfoZk.td"
 include "RISCVInstrInfoV.td"
 include "RISCVInstrInfoZvk.td"
 
-// Integer
-include "RISCVInstrInfoZicbo.td"
-include "RISCVInstrInfoZicond.td"
-
 // Compressed
 include "RISCVInstrInfoC.td"
 include "RISCVInstrInfoZc.td"
 
+// Integer
+include "RISCVInstrInfoZicbo.td"
+include "RISCVInstrInfoZicond.td"
+include "RISCVInstrInfoZicfiss.td"
+
 //===----------------------------------------------------------------------===//
 // Vendor extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
new file mode 100644
index 000000000000000..95864664e43f2ae
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -0,0 +1,86 @@
+//===------ RISCVInstrInfoZicfiss.td - RISC-V Zicfiss -*- tablegen -*------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction class templates
+//===----------------------------------------------------------------------===//
+
+class RVC_SSInst<bits<5> rs1val, RegisterClass reg_class, string opcodestr> :
+  RVInst16<(outs), (ins reg_class:$rs1), opcodestr, "$rs1", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = rs1val;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+  let DecoderMethod = "decodeCSSPushPopchk";
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in {
+let DecoderNamespace = "RV32Zicfiss", Predicates = [HasStdExtZicfiss, IsRV32] in
+def SSLW : RVInstI<0b100, OPC_SYSTEM, (outs GPRX1X5:$rd), (ins), "sslw", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+
+let Predicates = [HasStdExtZicfiss, IsRV64] in
+def SSLD : RVInstI<0b100, OPC_SYSTEM, (outs GPRX1X5:$rd), (ins), "ssld", "$rd"> {
+  let rs1 = 0;
+  let imm12 = 0b100000011100;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Predicates = [HasStdExtZicfiss] in {
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
+def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs1), "sspopchk",
+                       "$rs1"> {
+  let rd = 0;
+  let imm12 = 0b100000011100;
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0
+
+let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
+def SSINCP : RVInstI<0b100, OPC_SYSTEM, (outs), (ins), "ssincp", ""> {
+  let imm12 = 0b100000011100;
+  let rs1 = 0b00000;
+  let rd = 0b00000;
+}
+
+def SSRDP : RVInstI<0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), (ins), "ssrdp", "$rd"> {
+  let imm12 = 0b100000011101;
+  let rs1 = 0b00000;
+}
+} // Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def SSPUSH : RVInstR<0b1000001, 0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs2),
+                     "sspush", "$rs2"> {
+  let rd = 0b00000;
+  let rs1 = 0b00000;
+}
+} // Predicates = [HasStdExtZicfiss]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtCOrZca] in {
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
+
+let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
+def C_SSPOPCHK : RVC_SSInst<0b00101, GPRX5, "c.sspopchk">;
+} // Predicates = [HasStdExtZicfiss, HasStdExtCOrZca]
+
+let Predicates = [HasStdExtZicfiss, HasStdExtC], Uses = [SSP], Defs = [SSP],
+    hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def C_SSINCP : RVInst16<(outs), (ins), "c.ssincp", "", [], InstFormatOther> {
+  let Inst{15-13} = 0b011;
+  let Inst{12} = 0;
+  let Inst{11-7} = 0b00011;
+  let Inst{6-2} = 0b00000;
+  let Inst{1-0} = 0b01;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 3e44cf4781f643c..7934da40ac4aadc 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -119,6 +119,9 @@ BitVector RISCVRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   markSuperRegs(Reserved, RISCV::FRM);
   markSuperRegs(Reserved, RISCV::FFLAGS);
 
+  // Shadow stack pointer.
+  markSuperRegs(Reserved, RISCV::SSP);
+
   assert(checkAllSuperRegsMarked(Reserved));
   return Reserved;
 }
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 1a6145f92908134..5a6ad940398cac1 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -137,6 +137,8 @@ def GPR : GPRRegisterClass<(add (sequence "X%u", 10, 17),
                                 (sequence "X%u", 0, 4))>;
 
 def GPRX0 : GPRRegisterClass<(add X0)>;
+def GPRX1 : GPRRegisterClass<(add X1)>;
+def GPRX5 : GPRRegisterClass<(add X5)>;
 
 def GPRNoX0 : GPRRegisterClass<(sub GPR, X0)>;
 
@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
 def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
                                  (sequence "X%u", 18, 23))>;
 
+def GPRX1X5 : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
+  let RegInfos = XLenRI;
+}
+
 // Floating point registers
 let RegAltNameIndices = [ABIRegAltName] in {
   def F0_H  : RISCVReg16<0, "f0", ["ft0"]>, DwarfRegNum<[32]>;
@@ -597,3 +603,6 @@ foreach m = LMULList in {
 // Special registers
 def FFLAGS : RISCVReg<0, "fflags">;
 def FRM    : RISCVReg<0, "frm">;
+
+// Shadow Stack register
+def SSP    : RISCVReg<0, "ssp">;
diff --git a/llvm/test/MC/RISCV/attribute-arch.s b/llvm/test/MC/RISCV/attribute-arch.s
index bf40eda456edf13..4f201d2afde3164 100644
--- a/llvm/test/MC/RISCV/attribute-arch.s
+++ b/llvm/test/MC/RISCV/attribute-arch.s
@@ -305,3 +305,6 @@
 
 .attribute arch, "rv32i_zicfilp0p2"
 # CHECK: attribute      5, "rv32i2p1_zicfilp0p2"
+
+.attribute arch, "rv32i_zicfiss0p3"
+# CHECK: .attribute     5, "rv32i2p1_zicfiss0p3"
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-invalid.s b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
new file mode 100644
index 000000000000000..6b4959043d0180b
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+sslw a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv32zicfiss-valid.s b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
new file mode 100644
index 000000000000000..46a1d3103afac6e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv32zicfiss-valid.s
@@ -0,0 +1,103 @@
+# RUN: llvm-mc %s -triple=riscv32 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+experimental-zicfiss,+c < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-zicfiss -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# RUN: not llvm-mc -triple riscv32 -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x1
+
+# CHECK-ASM-AND-OBJ: sslw ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw ra
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw x5
+
+# CHECK-ASM-AND-OBJ: sslw t0
+# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sslw t0
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x1
+
+# CHECK-ASM-AND-OBJ: sspopchk ra
+# CHECK-ASM: encoding: [0x73,0xc0,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk ra
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk x5
+
+# CHECK-ASM-AND-OBJ: sspopchk t0
+# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspopchk t0
+
+# CHECK-ASM-AND-OBJ: ssincp
+# CHECK-ASM: encoding: [0x73,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssincp
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x1
+
+# CHECK-ASM-AND-OBJ: sspush ra
+# CHECK-ASM: encoding: [0x73,0x40,0x10,0x82]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush ra
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush x5
+
+# check-asm-and-obj: sspush t0
+# check-asm: encoding: [0x73,0x40,0x50,0x82]
+# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+sspush t0
+
+# CHECK-ASM-AND-OBJ: ssrdp ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xd0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssrdp ra
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush x1
+
+# CHECK-ASM-AND-OBJ: c.sspush ra
+# CHECK-ASM: encoding: [0x81,0x60]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspush ra
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk x5
+
+# CHECK-ASM-AND-OBJ: c.sspopchk t0
+# CHECK-ASM: encoding: [0x81,0x62]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions) or 'Zca' (part of the C extension, excluding compressed floating point loads/stores), 'Zicfiss' (Shadow stack)
+c.sspopchk t0
+
+# CHECK-ASM-AND-OBJ: c.ssincp
+# CHECK-ASM: encoding: [0x81,0x61]
+# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack)
+c.ssincp
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-invalid.s b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
new file mode 100644
index 000000000000000..aef5e17e33aff9e
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zicfiss-invalid.s
@@ -0,0 +1,20 @@
+# RUN: not llvm-mc %s -triple=riscv64 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     2>&1 | FileCheck -check-prefixes=CHECK-ERR %s
+
+# CHECK-ERR: error: invalid operand for instruction
+ssld a0
+
+# CHECK-ERR: error: invalid operand for instruction
+sspopchk a1
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspush t0
+
+# CHECK-ERR: error: invalid operand for instruction
+c.sspopchk ra
+
+# CHECK-ERR: error: invalid operand for instruction
+sspush a0
+
+# CHECK-ERR: error: invalid operand for instruction
+ssrdp zero
diff --git a/llvm/test/MC/RISCV/rv64zicfiss-valid.s b/llvm/test/MC/RISCV/rv64zicfiss-valid.s
new file mode 100644
index 000000000000000..8bba15cc3b22bec
--- /dev/null
+++ b/llvm/test/MC/RISCV/rv64zicfiss-valid.s
@@ -0,0 +1,103 @@
+# RUN: llvm-mc %s -triple=riscv64 -mattr=+experimental-zicfiss,+c -riscv-no-aliases -show-encoding \
+# RUN:     | FileCheck -check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+experimental-zicfiss,+c < %s \
+# RUN:     | llvm-objdump --mattr=+experimental-zicfiss -M no-aliases -d -r - \
+# RUN:     | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s
+#
+# RUN: not llvm-mc -triple riscv64 -riscv-no-aliases -show-encoding < %s 2>&1 \
+# RUN:     | FileCheck -check-prefixes=CHECK-NO-EXT %s
+
+# CHECK-ASM-AND-OBJ: ssld ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack)
+ssld x1
+
+# CHECK-ASM-AND-OBJ: ssld ra
+# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81]
+# CHECK-NO-E...
[truncated]

} // Uses = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0

let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
def SSINCP : RVInstI<0b100, OPC_SYSTEM, (outs), (ins), "ssincp", ""> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should SSINCP also have Defs = [SSP]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yetingk
Copy link
Contributor Author

yetingk commented Dec 12, 2023

Rebase and bump to 0.4

@yetingk
Copy link
Contributor Author

yetingk commented Dec 13, 2023

Rebase and ping.

@@ -165,6 +167,10 @@ def SP : GPRRegisterClass<(add X2)>;
def SR07 : GPRRegisterClass<(add (sequence "X%u", 8, 9),
(sequence "X%u", 18, 23))>;

def GPRX1X5 : RegisterClass<"RISCV", [XLenVT], 32, (add X1, X5)> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use GPRRegisterClass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@yetingk
Copy link
Contributor Author

yetingk commented Dec 26, 2023

Ping.

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@wangpc-pp
Copy link
Contributor

Should this be rebased on Zimop(#75182) commit? Though I don't know why it has been merged yet...

@wangpc-pp
Copy link
Contributor

It seems that the author of Zimop implementation doesn't have commit access. @yetingk Would you mind to commit it and rebase your PR on that? It will make this PR simpler.

@yetingk
Copy link
Contributor Author

yetingk commented Dec 26, 2023

It seems that the author of Zimop implementation doesn't have commit access. @yetingk Would you mind to commit it and rebase your PR on that? It will make this PR simpler.

Sure.

@yetingk
Copy link
Contributor Author

yetingk commented Dec 26, 2023

Rebase.

It seems that the author of Zimop implementation doesn't have commit access. @yetingk Would you mind to commit it and rebase your PR on that? It will make this PR simpler.

It's weird that SSPUSH and SSPOPCHK are not fit into ZIMOP instruction now.


let Predicates = [HasStdExtZicfiss] in {
let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
def SSPOPCHK : RVInstI<0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs1), "sspopchk",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these instructions be aliases of MOPs now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They should use same encoding as some instructions of Zimop, but currently, there is no mop.r could be fitted to sspush and sspopchk. The 24th bit of sspush is 0 but the 24th bit of all mop.r is 1. The 25th bit of sspopchk is 0 but but the 25th bit of all mop.r is 1.

ref:
https://github.com/riscv/riscv-isa-manual/blob/main/src/images/wavedrom/mop-r.adoc
https://github.com/riscv/riscv-cfi/blob/main/cfi_backward.adoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I haven't looked at it in details, is this a document mistake? They should have the same encoding.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I don't find any mistake, sspush uses mop.rr and sspopchk uses mop.r.

The 25th bit of sspopchk is 0 but but the 25th bit of all mop.r is 1.

This is wrong as it's { bits: 4, name: 0x7 }, so its value is 0b0111.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I will give a fix for this.

Yeting Kuo added 3 commits December 28, 2023 14:49
The patch adds the instructions in Zicfiss extension. Zicfiss extension is
to support shadow stack for control flow integrity.

Differential Revision: https://reviews.llvm.org/D152793
@yetingk
Copy link
Contributor Author

yetingk commented Dec 28, 2023

Rebase but I didn't use alias to Zimop and Zcmop ways to achieve this code, since using them will lose some information like Uses = [SSP].

// Compress Instruction tablegen backend.
//===----------------------------------------------------------------------===//

let Predicates = [HasStdExtZicfiss, HasStdExtCOrZca] in {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remove some CompressPat since I don't know how to test sspush/sspopchk without transforming to compressed ones.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. If Zca isn't on the command line they should shouldn't compress.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you can't test is because Zicfiss implies Zcmop. But you should be able to disable compression with .option norvc

@@ -1024,6 +1024,7 @@ static const char *ImpliedExtsZfinx[] = {"zicsr"};
static const char *ImpliedExtsZhinx[] = {"zhinxmin"};
static const char *ImpliedExtsZhinxmin[] = {"zfinx"};
static const char *ImpliedExtsZicntr[] = {"zicsr"};
static const char *ImpliedExtsZicfiss[] = {"zicsr", "zimop", "zcmop"};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zcmop should not be here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I guess the spec does say that, but it seems weird. That would mean that there would be no need for sspush x1 if you can always use c.sspush x1. I'll file an issue on the spec.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's my issue riscv/riscv-cfi#201 (comment). From the response I got, I think we should drop Zcmop here and make the CompressPat depend on Zcmop.

Copy link
Contributor Author

@yetingk yetingk Dec 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a patch to not imply Zcmop and enable c.sspush when Zcmop enabled.

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@yetingk yetingk merged commit 3dc0638 into llvm:main Dec 30, 2023
@yetingk yetingk deleted the Zicfiss branch January 2, 2024 14:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang Clang issues not falling into any other category llvm:support mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants