Skip to content
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

Add a "xcheri-std-compat" mode to LLVM #756

Open
wants to merge 18 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5d2b79a
[CHERI-RISC-V] Add instruction aliases for the new getter mnemonics
arichardson Feb 15, 2025
c2c8a03
[CHERI-RISC-V] Add instruction aliases for the new modification mnemo…
arichardson Feb 16, 2025
abff069
[CHERI-RISC-V] Support scss and sceq mnemonics
arichardson Feb 16, 2025
6efdb89
[CHERI-RISC-V] Support unprefixed jump instructions
arichardson Feb 16, 2025
95dd7c6
[CHERI-RISC-V][NFCI] Split xcheri feature into cheri-common and xcheri
arichardson Jan 31, 2025
c19293b
[CHERI StdCompat] Add a flag to disable non-standard instructions
arichardson Jan 31, 2025
dc0e64c
[CHERI StdCompat] Expand CGetOffset
arichardson Feb 1, 2025
6892a85
[CHERI StdCompat] Expand CGetSealed
arichardson Mar 17, 2023
cea4ec0
[CHERI StdCompat] Expand CSetOffset to a CSetAddr sequence
arichardson Mar 17, 2023
e724e83
[CHERI StdCompat] Expand (CClearTag x) to (CSetHigh x, (CGetHigh x))
arichardson Apr 19, 2023
75caa2b
[CHERI StdCompat] Expand CRRL to the equivalent CRAM sequence
arichardson Mar 16, 2023
9b3a67f
[CHERI StdCompat] Emit a Clang error for unsupported builtins
arichardson Apr 19, 2023
cfa1923
[CHERI StdCompat] Disable more unsupported intrinsics
arichardson Feb 3, 2025
93090cd
[CHERI StdCompat] Add a baseline test for a broken pre-defined macro
arichardson Apr 20, 2023
d990221
[CHERI StdCompat] Correctly define a __riscv_xcheri_std_compat macro
arichardson Apr 20, 2023
3018644
[CHERI StdCompat] Add MC support for the modesw.{cap,int} instructions
arichardson Feb 4, 2025
b35db52
[CHERI StdCompat] Expand explicit mode loads using mode-switching
arichardson Apr 21, 2023
a3b146b
[CHERI StdCompat] Expand explicit mode stores using mode-switching
arichardson Apr 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3911,6 +3911,14 @@ def mno_xcheri_norvc : Flag<["-"], "mno-xcheri-norvc">, Group<m_riscv_Features_G
HelpText<"Enable using compressed CHERI instructions">;
def mxcheri_rvc : Flag<["-"], "mxcheri-rvc">, Alias<mno_xcheri_norvc>;

def mxcheri_std_compat : Flag<["-"], "mxcheri-std-compat">,
Group<m_riscv_Features_Group>,
HelpText<"Enable the subset of CHERI features that "
"are compatible with the upcoming standard">;
def mno_xcheri_std_compat : Flag<["-"], "mno-xcheri-std-compat">,
Group<m_riscv_Features_Group>,
HelpText<"Enable non-standard CHERI features">;

def munaligned_access : Flag<["-"], "munaligned-access">, Group<m_Group>,
HelpText<"Allow memory accesses to be unaligned (AArch32/AArch64/LoongArch only)">;
def mno_unaligned_access : Flag<["-"], "mno-unaligned-access">, Group<m_Group>,
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,11 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
auto ExtName = Extension.first;
auto ExtInfo = Extension.second;

// Replace '-' with '_' to ensure the result is a single PP token.
std::string EscapedName = ExtName;
std::replace(EscapedName.begin(), EscapedName.end(), '-', '_');
Builder.defineMacro(
Twine("__riscv_", ExtName),
Twine("__riscv_", EscapedName),
Twine(getVersionValue(ExtInfo.MajorVersion, ExtInfo.MinorVersion)));
}

Expand Down
18 changes: 18 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ static bool SemaBuiltinCHERICapCreate(Sema &S, CallExpr *TheCall) {
return false;
}

/// Check whether we are targeting the RISC-V CHERI standard, and if we are emit
/// an appropriate error message
static bool checkNonStdCheriIntrin(Sema &S, CallExpr *TheCall) {
const auto &TI = S.Context.getTargetInfo();
if (TI.getTriple().isRISCV() && TI.hasFeature("xcheri-std-compat")) {
S.Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension)
<< true << TheCall->getSourceRange() << "xcheri (without std-compat)";
return true;
}
return false;
}

/// Check that argument \p ArgIndex is a capability type (or an array/function
/// that decays to a capability type.
static bool checkCapArg(Sema &S, CallExpr *TheCall, unsigned ArgIndex,
Expand Down Expand Up @@ -2639,10 +2651,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
break;
}
case Builtin::BI__builtin_cheri_cap_load_tags:
Copy link
Member Author

Choose a reason for hiding this comment

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

I guess we could expand this to lc+cgettag, but I think an error if it's not support might make it clearer that the optimized version does not exist?

if (checkNonStdCheriIntrin(*this, TheCall))
return ExprError(); // Not supported in standard CHERI RISC-V
break;
case Builtin::BI__builtin_cheri_seal:
case Builtin::BI__builtin_cheri_unseal:
case Builtin::BI__builtin_cheri_conditional_seal:
case Builtin::BI__builtin_cheri_cap_type_copy: {
if (checkNonStdCheriIntrin(*this, TheCall))
return ExprError(); // Not supported in standard CHERI RISC-V
// Seal/unseal work in almost same way as the setters: value to be
// unsealed/sealed comes first and should therefore be the result type,
// second argument is overloaded to be any capability type.
Expand Down
1 change: 1 addition & 0 deletions clang/test/CodeGen/cheri/riscv/riscv-default-ir-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
// RV32-NOCHERI-SAME: -xcheri,
// RV64-NOCHERI-SAME: -xcheri,
// XCHERI-RVC-SAME: -xcheri-norvc,
// CHECK-SAME: -xcheri-std-compat,
// CHECK-NOT: xcheri
// CHECK-SAME: }

Expand Down
14 changes: 14 additions & 0 deletions clang/test/Driver/riscv-default-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
// RUN: %clang --target=riscv32-unknown-elf -march=rv32ixcheri -S -mno-xcheri-norvc -emit-llvm %s -o - | FileCheck %s --check-prefixes=RV32-XCHERI,XCHERI,XCHERI-RVC
// RUN: %clang --target=riscv64-unknown-elf -march=rv64ixcheri -S -mno-xcheri-norvc -emit-llvm %s -o - | FileCheck %s --check-prefixes=RV64-XCHERI,XCHERI,XCHERI-RVC

/// The standards-compatible mode can be enable either using the arch string or the -mxcheri-std-compat flag
// RUN: %clang --target=riscv64-unknown-elf -march=rv64ixcheri -mxcheri-std-compat -S -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=RV64-XCHERI-STD-COMPAT
// RUN: %clang --target=riscv64-unknown-elf -march=rv64ixcheri_xcheri-std-compat -S -emit-llvm %s -o - 2>&1 | FileCheck %s -check-prefix=RV64-XCHERI-STD-COMPAT
// RUN: %clang --target=riscv64-unknown-elf -march=rv64ixcheri-std-compat -S -emit-llvm %s -o - | FileCheck %s -check-prefix=RV64-XCHERI-STD-COMPAT
/// In the case of rv64i -mxcheri-std-compat, +xcheri is not inferred, but this will be fixed in future upstream merges
// RUN: %clang --target=riscv64-unknown-elf -march=rv64i -mxcheri-std-compat -S -emit-llvm %s -o - | FileCheck %s -check-prefix=RV64-XCHERI-STD-COMPAT-ONLY
/// Check that we can override the flag with -mno-xcheri-std-compat
// RUN: %clang --target=riscv64-unknown-elf -march=rv64ixcheri -mxcheri-std-compat -mno-xcheri-std-compat -S -emit-llvm %s -o - | FileCheck %s -check-prefix=RV64-XCHERI


// RV32: "target-features"="+32bit,+a,+c,+m,+relax,
// RV32-SAME: -save-restore
// RV64: "target-features"="+64bit,+a,+c,+m,+relax,
Expand All @@ -32,10 +42,14 @@
// RV32-XCHERI-EXPLICIT-RVC: "target-features"="+32bit,+relax,+xcheri
// RV32-XCHERI-EXPLICIT-RVC-SAME -save-restore
// XCHERI-RVC-SAME: ,-xcheri-norvc,
// XCHERI-SAME: -xcheri-std-compat,
// RV64-XCHERI-EXPLICIT-RVC: "target-features"="+64bit,+relax,+xcheri

// XCHERI-NOT: xcheri

// RV64-XCHERI-STD-COMPAT: "target-features"="+64bit,+relax,+xcheri,+xcheri-std-compat,
// RV64-XCHERI-STD-COMPAT-ONLY: "target-features"="+64bit,+relax,+xcheri-std-compat,

// Dummy function
int foo(void){
return 3;
Expand Down
1 change: 1 addition & 0 deletions clang/test/Driver/riscv-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
// RUN: %clang --target=riscv32-unknown-elf -### %s -march=rv64ixcheri -mxcheri-norvc 2>&1 | FileCheck %s --check-prefixes=XCHERI,XCHERI-NORVC
// RUN: %clang --target=riscv32-unknown-elf -### %s -march=rv64ixcheri -mno-xcheri-rvc 2>&1 | FileCheck %s --check-prefixes=XCHERI,XCHERI-NORVC
// XCHERI: "-target-feature" "+xcheri"
// XCHERI: "-xcheri-std-compat"
// XCHERI-NOT: "{{[+|-]}}xcheri-
// XCHERI-EXPLICIT-RVC: "-target-feature" "-xcheri-norvc"
// XCHERI-NORVC: "-target-feature" "+xcheri-norvc"
Expand Down
36 changes: 36 additions & 0 deletions clang/test/Preprocessor/riscv-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -780,3 +780,39 @@
// 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 riscv64-unknown-none -march=rv64gcxcheri -x c -E -dM %s \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK-XCHERI --implicit-check-not=__riscv_
// RUN: %clang -target riscv64-unknown-none -march=rv64gcxcheri -mxcheri-std-compat -x c -E -dM %s \
// RUN: -o - | FileCheck %s --check-prefixes=CHECK-XCHERI,CHECK-XCHERI-STD-COMPAT --implicit-check-not=__riscv_


// CHECK-XCHERI: #define __riscv 1
// CHECK-XCHERI-NEXT: #define __riscv_a 2001000
// CHECK-XCHERI-NEXT: #define __riscv_arch_test 1
// CHECK-XCHERI-NEXT: #define __riscv_atomic 1
// CHECK-XCHERI-NEXT: #define __riscv_c 2000000
// CHECK-XCHERI-NEXT: #define __riscv_clen 128
// CHECK-XCHERI-NEXT: #define __riscv_cmodel_medlow 1
// CHECK-XCHERI-NEXT: #define __riscv_compressed 1
// CHECK-XCHERI-NEXT: #define __riscv_d 2002000
// CHECK-XCHERI-NEXT: #define __riscv_div 1
// CHECK-XCHERI-NEXT: #define __riscv_f 2002000
// CHECK-XCHERI-NEXT: #define __riscv_fdiv 1
// CHECK-XCHERI-NEXT: #define __riscv_flen 64
// CHECK-XCHERI-NEXT: #define __riscv_float_abi_double 1
// CHECK-XCHERI-NEXT: #define __riscv_fsqrt 1
// CHECK-XCHERI-NEXT: #define __riscv_i 2001000
// CHECK-XCHERI-NEXT: #define __riscv_m 2000000
// CHECK-XCHERI-NEXT: #define __riscv_mul 1
// CHECK-XCHERI-NEXT: #define __riscv_muldiv 1
// CHECK-XCHERI-NEXT: #define __riscv_xcheri 0
// CHECK-XCHERI-NEXT: #define __riscv_xcheri_mode_dependent_jumps 1
// CHECK-XCHERI-NEXT: #define __riscv_xcheri_no_relocation 1
// CHECK-XCHERI-STD-COMPAT-NEXT: #define __riscv_xcheri_std_compat 0
// CHECK-XCHERI-NEXT: #define __riscv_xcheri_tag_clear 1
// CHECK-XCHERI-NEXT: #define __riscv_xlen 64
// CHECK-XCHERI-NEXT: #define __riscv_zicsr 2000000
// CHECK-XCHERI-NEXT: #define __riscv_zifencei 2000000


25 changes: 25 additions & 0 deletions clang/test/Sema/cheri/cheri-std-unsupported-builtins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// In the RISC-V standard compat mode not all builtins are supported since we do not perform the expansion in the backend.
// RUN: %riscv64_cheri_purecap_cc1 -target-feature +xcheri %s -fsyntax-only -verify=xcheri
// RUN: %riscv64_cheri_purecap_cc1 -target-feature +xcheri-std-compat %s -fsyntax-only -verify=std-compat
// xcheri-no-diagnostics

void *cseal(void *a, void *b) {
_Static_assert(__has_builtin(__builtin_cheri_seal), ""); // TODO: would be nice to report false here
return __builtin_cheri_seal(a, b); // std-compat-error{{builtin requires at least one of the following extensions to be enabled: xcheri (without std-compat)}}
}
void *cunseal(void *a, void *b) {
_Static_assert(__has_builtin(__builtin_cheri_unseal), ""); // TODO: would be nice to report false here
return __builtin_cheri_unseal(a, b); // std-compat-error{{builtin requires at least one of the following extensions to be enabled: xcheri (without std-compat)}}
}
void *ccseal(void *a, void *b) {
_Static_assert(__has_builtin(__builtin_cheri_conditional_seal), ""); // TODO: would be nice to report false here
return __builtin_cheri_conditional_seal(a, b); // std-compat-error{{builtin requires at least one of the following extensions to be enabled: xcheri (without std-compat)}}
}
void *ccopytype(void *a, void *b) {
_Static_assert(__has_builtin(__builtin_cheri_cap_type_copy), ""); // TODO: would be nice to report false here
return __builtin_cheri_cap_type_copy(a, b); // std-compat-error{{builtin requires at least one of the following extensions to be enabled: xcheri (without std-compat)}}
}
unsigned long cloadtags(void *a) {
_Static_assert(__has_builtin(__builtin_cheri_cap_load_tags), ""); // TODO: would be nice to report false here
return __builtin_cheri_cap_load_tags(a); // std-compat-error{{builtin requires at least one of the following extensions to be enabled: xcheri (without std-compat)}}
}
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/TargetLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -3258,6 +3258,7 @@ class TargetLoweringBase {

// Return true if the target has a capability set address instruction.
virtual bool hasCapabilitySetAddress() const { return false; }
virtual bool hasCapabilitySetOffset() const { return true; }
MVT cheriCapabilityType() const { return CapType; }
bool cheriCapabilityTypeHasPreciseBounds() const {
return CapTypeHasPreciseBounds;
Expand Down
27 changes: 27 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7488,6 +7488,33 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
setValue(&I, Res);
return;
}
case Intrinsic::cheri_cap_offset_set: {
if (TLI.hasCapabilitySetOffset()) {
visitTargetIntrinsic(I, Intrinsic);
return;
}
assert(TLI.hasCapabilitySetAddress() &&
"Expansion of offset_set requires address_set!");
Value *CapV = I.getArgOperand(0);
SDValue Cap = getValue(CapV);
Value *OffsetV = I.getArgOperand(1);
SDValue Offset = getValue(OffsetV);
// offset_set(cap, offset) -> address_set(cap, base_get(cap) + offset)
EVT AddrVT = TLI.getPointerRangeTy(
DAG.getDataLayout(), CapV->getType()->getPointerAddressSpace());
EVT CapVT = TLI.getPointerTy(DAG.getDataLayout(),
CapV->getType()->getPointerAddressSpace());
SDValue CapBase = DAG.getNode(
ISD::INTRINSIC_WO_CHAIN, sdl, AddrVT,
DAG.getConstant(Intrinsic::cheri_cap_base_get, sdl, AddrVT), Cap);
SDValue NewAddr = DAG.getNode(ISD::ADD, sdl, AddrVT, CapBase, Offset);
Res = DAG.getNode(
ISD::INTRINSIC_WO_CHAIN, sdl, CapVT,
DAG.getConstant(Intrinsic::cheri_cap_address_set, sdl, AddrVT), Cap,
NewAddr);
setValue(&I, Res);
return;
}
case Intrinsic::threadlocal_address: {
setValue(&I, getValue(I.getOperand(0)));
return;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Support/RISCVISAInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ static const RISCVSupportedExtension SupportedExtensions[] = {

// vendor-defined ('X') extensions
{"xcheri", RISCVExtensionVersion{0, 0}},
{"xcheri-std-compat", RISCVExtensionVersion{0, 0}},
{"xcvbitmanip", RISCVExtensionVersion{1, 0}},
{"xcvmac", RISCVExtensionVersion{1, 0}},
{"xsfcie", RISCVExtensionVersion{1, 0}},
Expand Down Expand Up @@ -955,6 +956,7 @@ Error RISCVISAInfo::checkDependency() {
static const char *ImpliedExtsD[] = {"f"};
static const char *ImpliedExtsF[] = {"zicsr"};
static const char *ImpliedExtsV[] = {"zvl128b", "zve64d"};
static const char *ImpliedExtsXCheriStdCompat[] = {"xcheri"};
static const char *ImpliedExtsXTHeadVdot[] = {"v"};
static const char *ImpliedExtsXsfvcp[] = {"zve32x"};
static const char *ImpliedExtsZacas[] = {"a"};
Expand Down Expand Up @@ -1021,6 +1023,7 @@ static constexpr ImpliedExtsEntry ImpliedExts[] = {
{{"d"}, {ImpliedExtsD}},
{{"f"}, {ImpliedExtsF}},
{{"v"}, {ImpliedExtsV}},
{{"xcheri-std-compat"}, {ImpliedExtsXCheriStdCompat}},
{{"xsfvcp"}, {ImpliedExtsXsfvcp}},
{{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
{{"zacas"}, {ImpliedExtsZacas}},
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
ParseStatus parseDirective(AsmToken DirectiveID) override;

bool isCheri() const override {
return getSTI().getFeatureBits()[RISCV::FeatureCheri];
return getSTI().getFeatureBits()[RISCV::FeatureCheriCommon];
}

unsigned getCheriCapabilitySize() const override {
Expand Down Expand Up @@ -3064,7 +3064,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
if (Parser.parseEOL())
return true;

if (!getSTI().hasFeature(RISCV::FeatureCheri))
if (!getSTI().hasFeature(RISCV::FeatureXCheri))
return Error(Parser.getTok().getLoc(),
"option requires 'xcheri' extension");

Expand All @@ -3077,7 +3077,7 @@ bool RISCVAsmParser::parseDirectiveOption() {
if (Parser.parseEOL())
return true;

if (!getSTI().hasFeature(RISCV::FeatureCheri))
if (!getSTI().hasFeature(RISCV::FeatureXCheri))
return Error(Parser.getTok().getLoc(),
"option requires 'xcheri' extension");

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ ABI computeTargetABI(const Triple &TT, const FeatureBitset &FeatureBits,
"target-abi)\n";
TargetABI = ABI_Unknown;
} else if ((ABIName.startswith("il32pc") || ABIName.startswith("l64pc")) &&
!FeatureBits[RISCV::FeatureCheri]) {
!FeatureBits[RISCV::FeatureCheriCommon]) {
errs() << "Pure-capability ABI can't be used for a target that "
"doesn't support the XCheri instruction set extension (ignoring "
"doesn't support the CHERI instruction set extension (ignoring "
"target-abi)\n";
TargetABI = ABI_Unknown;
} else if (!IsRV64 && IsRVE && TargetABI != ABI_ILP32E &&
Expand Down
74 changes: 74 additions & 0 deletions llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class RISCVExpandPseudo : public MachineFunctionPass {
bool expandCapLoadTLSGDCap(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
bool expandCheriExplicitCapLoadStore(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned ExplicitModeOp,
unsigned OtherModeOp, bool IsCapOp);
bool expandCGetAddr(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
bool expandCCOp(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
MachineBasicBlock::iterator &NextMBBI);
Expand Down Expand Up @@ -130,6 +134,30 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
return expandCapLoadLocalCap(MBB, MBBI, NextMBBI);
case RISCV::PseudoCLGC:
return expandCapLoadGlobalCap(MBB, MBBI, NextMBBI);
#define EXPAND_MODE(insn) \
case RISCV::Pseudo_##insn##_CAP: \
return expandCheriExplicitCapLoadStore(MBB, MBBI, RISCV::insn##_CAP, \
RISCV::insn, true); \
case RISCV::Pseudo_##insn##_DDC: \
return expandCheriExplicitCapLoadStore(MBB, MBBI, RISCV::insn##_DDC, \
RISCV::C##insn, false);

EXPAND_MODE(LB)
EXPAND_MODE(LBU)
EXPAND_MODE(LH)
EXPAND_MODE(LHU)
EXPAND_MODE(LW)
EXPAND_MODE(LWU)
EXPAND_MODE(LD)
EXPAND_MODE(LC_64)
EXPAND_MODE(LC_128)
EXPAND_MODE(SB)
EXPAND_MODE(SH)
EXPAND_MODE(SW)
EXPAND_MODE(SD)
EXPAND_MODE(SC_64)
EXPAND_MODE(SC_128)

case RISCV::PseudoCLA_TLS_IE:
return expandCapLoadTLSIEAddress(MBB, MBBI, NextMBBI);
case RISCV::PseudoCLC_TLS_GD:
Expand Down Expand Up @@ -257,6 +285,52 @@ bool RISCVExpandPseudo::expandCapLoadTLSGDCap(
RISCV::CIncOffsetImm);
}

/// Expands an expilict capability load (in hybrid mode) to a mode switch around
/// the normal load/store operation to execute it in capability mode.
bool RISCVExpandPseudo::expandCheriExplicitCapLoadStore(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
unsigned ExplicitModeOp, unsigned OtherModeOp, bool IsCapOp) {
MachineFunction *MF = MBB.getParent();
MachineInstr &MI = *MBBI;
DebugLoc DL = MI.getDebugLoc();
if (MF->getSubtarget<RISCVSubtarget>().hasXCheriNonStd()) {
// If we have the non-standard extensions, use the explicit mode insns.
BuildMI(MBB, MBBI, DL, TII->get(ExplicitModeOp))
.add(MI.getOperand(0))
.add(MI.getOperand(1));
MI.eraseFromParent();
return true;
}
Register BaseReg;
auto *TRI = MF->getRegInfo().getTargetRegisterInfo();
if (IsCapOp)
BaseReg = TRI->getSubReg(MI.getOperand(1).getReg(), RISCV::sub_cap_addr);
else
BaseReg = TRI->getMatchingSuperReg(
MI.getOperand(1).getReg(), RISCV::sub_cap_addr, &RISCV::GPCRRegClass);

assert(BaseReg.isValid());

// NB: We emit the "wrong mode" load/store here since using the other
// instruction will result in e.g. "Attempting to emit CLB instruction but the
// Feature_IsCapMode predicate(s) are not met". This is safe since the raw
// encoding is the same.
// Note: This pass runs right at the end of the pipeline, so instructions will
// not move around (so we don't need a TargetOpcode::BUNDLE here which is
// not handled by the remaining RISC-V codegen infrastructure).
BuildMI(MBB, MBBI, DL,
TII->get(IsCapOp ? RISCV::ModeSwitchCap : RISCV::ModeSwitchInt));
BuildMI(MBB, MBBI, DL, TII->get(OtherModeOp))
.add(MI.getOperand(0))
.addReg(BaseReg, MI.getOperand(1).getTargetFlags())
.addImm(0);
BuildMI(MBB, MBBI, DL,
TII->get(IsCapOp ? RISCV::ModeSwitchInt : RISCV::ModeSwitchCap));
MI.eraseFromParent();

return true;
}

bool RISCVExpandPseudo::expandCGetAddr(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI) {
const auto &STI = MBB.getParent()->getSubtarget<RISCVSubtarget>();
Expand Down
Loading