diff --git a/clang/test/Preprocessor/riscv-target-features.c b/clang/test/Preprocessor/riscv-target-features.c --- a/clang/test/Preprocessor/riscv-target-features.c +++ b/clang/test/Preprocessor/riscv-target-features.c @@ -73,6 +73,7 @@ // CHECK-NOT: __riscv_zvfbfmin {{.*$}} // CHECK-NOT: __riscv_zvfbfwma {{.*$}} // CHECK-NOT: __riscv_zacas {{.*$}} +// CHECK-NOT: __riscv_zicfiss {{.*$}} // RUN: %clang -target riscv32-unknown-linux-gnu -march=rv32i -x c -E -dM %s \ // RUN: -o - | FileCheck %s @@ -780,3 +781,11 @@ // RUN: -march=rv64i_zacas1p0 -x c -E -dM %s \ // RUN: -o - | FileCheck --check-prefix=CHECK-ZACAS-EXT %s // CHECK-ZACAS-EXT: __riscv_zacas 1000000{{$}} + +// RUN: %clang -target riscv32 -menable-experimental-extensions \ +// RUN: -march=rv32izicfiss0p1 -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s +// RUN: %clang -target riscv64 -menable-experimental-extensions \ +// RUN: -march=rv64izicfiss0p1 -x c -E -dM %s \ +// RUN: -o - | FileCheck --check-prefix=CHECK-ZICFISS-EXT %s +// CHECK-ZICFISS-EXT: __riscv_zicfiss 1000{{$}} diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -164,6 +164,7 @@ {"zfa", RISCVExtensionVersion{0, 2}}, {"zfbfmin", RISCVExtensionVersion{0, 6}}, + {"zicfiss", RISCVExtensionVersion{0, 1}}, {"zicond", RISCVExtensionVersion{1, 0}}, {"zihintntl", RISCVExtensionVersion{0, 2}}, diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -660,6 +660,18 @@ bool isUImm6() const { return IsUImm<6>(); } bool isUImm7() const { return IsUImm<7>(); } bool isUImm8() const { return IsUImm<8>(); } + bool isUImm10() const { return IsUImm<10>(); } + + bool isUImm5NonZero() const { + if (!isImm()) + return false; + RISCVMCExpr::VariantKind VK = RISCVMCExpr::VK_RISCV_None; + int64_t Imm; + bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); + return IsConstantImm && Imm != 0 && + isUInt<5>(fixImmediateForRV32(Imm, isRV64Imm())) && + VK == RISCVMCExpr::VK_RISCV_None; + } bool isUImm8GE32() const { int64_t Imm; @@ -1406,12 +1418,16 @@ return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 4) - 1); case Match_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); + case Match_InvalidUImm5NonZero: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5) - 1); case Match_InvalidUImm6: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); case Match_InvalidUImm7: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 7) - 1); case Match_InvalidUImm8: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 8) - 1); + case Match_InvalidUImm10: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 10) - 1); case Match_InvalidUImm8GE32: return generateImmOutOfRangeError(Operands, ErrorInfo, 32, (1 << 8) - 1); case Match_InvalidSImm5: diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -74,6 +74,17 @@ 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) { diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -244,6 +244,7 @@ OPERAND_UIMM3, OPERAND_UIMM4, OPERAND_UIMM5, + OPERAND_UIMM5_NONZERO, OPERAND_UIMM6, OPERAND_UIMM7, OPERAND_UIMM7_LSB00, @@ -252,6 +253,7 @@ OPERAND_UIMM8_LSB000, OPERAND_UIMM8_GE32, OPERAND_UIMM9_LSB000, + OPERAND_UIMM10, OPERAND_UIMM10_LSB00_NONZERO, OPERAND_UIMM12, OPERAND_ZERO, diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -79,6 +79,13 @@ 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 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -230,6 +230,13 @@ let OperandNamespace = "RISCVOp"; } +def uimm10 : Operand, ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<10>; + let DecoderMethod = "decodeUImmOperand<10>"; + let OperandType = "OPERAND_UIMM10"; + let OperandNamespace = "RISCVOp"; +} + def InsnDirectiveOpcode : AsmOperandClass { let Name = "InsnDirectiveOpcode"; let ParserMethod = "parseInsnDirectiveOpcode"; @@ -1962,6 +1969,9 @@ include "RISCVInstrInfoC.td" include "RISCVInstrInfoZc.td" +// Control Flow Integerity +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 --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td @@ -0,0 +1,96 @@ +//===-------- RISCVInstrInfoZicfiss.td - RISC-V CFG -*- 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 +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Operand definitions. +//===----------------------------------------------------------------------===// + +def uimm5nonzero : Operand, + ImmLeaf(Imm);}]> { + let ParserMatchClass = UImmAsmOperand<5, "NonZero">; + let EncoderMethod = "getImmOpValue"; + let DecoderMethod = "decodeUImmNonZeroOperand<5>"; + let OperandType = "OPERAND_UIMM5_NONZERO"; + let OperandNamespace = "RISCVOp"; + let MCOperandPredicate = [{ + int64_t Imm; + if (MCOp.evaluateAsConstantImm(Imm)) + return (Imm != 0) && isUInt<5>(Imm); + return MCOp.isBareSymbolRef(); + }]; +} + +//===----------------------------------------------------------------------===// +// Instruction class templates +//===----------------------------------------------------------------------===// + +let Uses = [SSP] in { +let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in +class RV_SSPop _rd, bits<5> _rs1, string opcodestr, string argstr> : + RVInstI<0b100, OPC_SYSTEM, (outs GPR:$rd), (ins GPR:$rs1), opcodestr, argstr> { + let rd = _rd; + let rs1 = _rs1; + let imm12 = 0b100000011100; +} +} // Uses = [SSP] + +class RVC_SSInst rs1, string opcodestr, string argstr> : + RVInst16<(outs), (ins:$rs1), opcodestr, argstr, [], InstFormatOther> { + let Inst{15-13} = 0b011; + let Inst{12} = 0; + let Inst{11-7} = rs1; + let Inst{6-2} = 0b00000; + let Inst{1-0} = 0b01; +} + +//===----------------------------------------------------------------------===// +// Instructions +//===----------------------------------------------------------------------===// + +let Predicates = [HasStdExtZicfiss] in { +def SSLoadX1: RV_SSPop<0b00001, 0b00000, "ssload", "x1">; +def SSLoadX5: RV_SSPop<0b00101, 0b00000, "ssload", "x5">; +let Defs = [SSP] in { +def SSPopChkX1: RV_SSPop<0b00000, 0b00001, "sspopchk", "x1">; +def SSPopChkX5: RV_SSPop<0b00000, 0b00101, "sspopchk", "x5">; +} // Defs = [SSP] + +let Uses = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { +def SSPINC : RVInstI<0b100, OPC_SYSTEM, (outs), (ins uimm5nonzero:$rs1), + "sspinc", "$rs1"> { + let imm12 = 0b100000011101; + let rd = 0b00000; +} + +def SSPRR : RVInstR<0b1000011, 0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), (ins), + "ssprr", "$rd"> { + let rs2 = 0b00000; + 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<0b1000101, 0b100, OPC_SYSTEM, (outs), (ins GPRRA:$rs2), + "sspush", "$rs2"> { + let rd = 0b00000; + let rs1 = 0b00000; +} + +def SSAMOSWAP : + RVInstRAtomic<0b10000, 0, 1, 0b100, OPC_SYSTEM, (outs GPRNoX0:$rd), + (ins GPR:$rs2, GPR:$rs1), "ssamoswap", "$rd, $rs2, (${rs1})">; +} // Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 +} // Predicates = [HasStdExtZicfiss] + +let Predicates = [HasStdExtZicfiss, HasStdExtC] in { +let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +def C_SSPUSHX1 : RVC_SSInst<0b00001, "c.sspush", "x1">; + +let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in +def C_SSPopChkX5 : RVC_SSInst<0b00101, "c.sspopchk", "x5">; +}// Predicates = [HasStdExtZicfiss, HasStdExtC] diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -118,6 +118,9 @@ 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 --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td @@ -174,6 +174,10 @@ let RegInfos = XLenRI; } +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]>; @@ -595,3 +599,6 @@ // 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 --- a/llvm/test/MC/RISCV/attribute-arch.s +++ b/llvm/test/MC/RISCV/attribute-arch.s @@ -290,3 +290,6 @@ .attribute arch, "rv32i_xcvmac" # CHECK: attribute 5, "rv32i2p1_xcvmac1p0" + +.attribute arch, "rv32i_zicfiss0p1" +# CHECK: .attribute 5, "rv32i2p1_zicfiss0p1" diff --git a/llvm/test/MC/RISCV/zicfiss-invalid.s b/llvm/test/MC/RISCV/zicfiss-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/zicfiss-invalid.s @@ -0,0 +1,28 @@ +# 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 +# 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 +ssload 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: immediate must be an integer in the range [1, 31] +sspinc 32 + +# CHECK-ERR: error: invalid operand for instruction +sspush a0 + +# CHECK-ERR: error: invalid operand for instruction +ssprr zero + +# CHECK-ERR: error: invalid operand for instruction +ssamoswap zero, x0, (a0) diff --git a/llvm/test/MC/RISCV/zicfiss-valid.s b/llvm/test/MC/RISCV/zicfiss-valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/zicfiss-valid.s @@ -0,0 +1,110 @@ +# 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 %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=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: 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 riscv32 -riscv-no-aliases -show-encoding < %s 2>&1 \ +# RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %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: ssload x1 +# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssload x1 + +# CHECK-ASM-AND-OBJ: ssload x1 +# CHECK-ASM: encoding: [0xf3,0x40,0xc0,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssload ra + +# CHECK-ASM-AND-OBJ: ssload x5 +# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssload x5 + +# CHECK-ASM-AND-OBJ: ssload x5 +# CHECK-ASM: encoding: [0xf3,0x42,0xc0,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssload t0 + +# CHECK-ASM-AND-OBJ: sspopchk x1 +# 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 x1 +# 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 x5 +# 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 x5 +# CHECK-ASM: encoding: [0x73,0xc0,0xc2,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +sspopchk t0 + +# CHECK-ASM-AND-OBJ: sspinc 4 +# CHECK-ASM: encoding: [0x73,0x40,0xd2,0x81] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +sspinc 4 + +# CHECK-ASM-AND-OBJ: sspush ra +# CHECK-ASM: encoding: [0x73,0x40,0x10,0x8a] +# 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,0x8a] +# 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,0x8a] +# 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,0x8a] +# check-no-ext: error: instruction requires the following: 'Zicfiss' (Shadow stack) +sspush t0 + +# CHECK-ASM-AND-OBJ: ssprr ra +# CHECK-ASM: encoding: [0xf3,0x40,0x00,0x86] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssprr ra + +# CHECK-ASM-AND-OBJ: ssamoswap t0, zero, (a0) +# CHECK-ASM: encoding: [0xf3,0x42,0x05,0x82] +# CHECK-NO-EXT: error: instruction requires the following: 'Zicfiss' (Shadow stack) +ssamoswap t0, x0, (a0) + +# CHECK-ASM-AND-OBJ: c.sspush x1 +# CHECK-ASM: encoding: [0x81,0x60] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack) +c.sspush x1 + +# CHECK-ASM-AND-OBJ: c.sspush x1 +# CHECK-ASM: encoding: [0x81,0x60] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack) +c.sspush ra + +# CHECK-ASM-AND-OBJ: c.sspopchk x5 +# CHECK-ASM: encoding: [0x81,0x62] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack) +c.sspopchk x5 + +# CHECK-ASM-AND-OBJ: c.sspopchk x5 +# CHECK-ASM: encoding: [0x81,0x62] +# CHECK-NO-EXT: error: instruction requires the following: 'C' (Compressed Instructions), 'Zicfiss' (Shadow stack) +c.sspopchk t0