From af9aeab8fb3bae341b14105c50e16baa07ddf810 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 30 Dec 2024 15:39:38 -0800 Subject: [PATCH 01/11] Silence downstream deprecation warnings These add unnecessary noise when running tests. --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 2 +- llvm/unittests/IR/MetadataTest.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 2ce54cc3c52ef..48e20a2b61105 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -98,7 +98,7 @@ GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) { Buf.LayoutStruct, /*isConstant*/ true, GlobalValue::LinkageTypes::ExternalLinkage, nullptr, llvm::formatv("{0}{1}", Buf.Name, Buf.IsCBuffer ? ".cb." : ".tb."), - GlobalValue::NotThreadLocal); + GlobalValue::NotThreadLocal, 0); return CBGV; } diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 362f8330dec8b..6fae2ff743c3a 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -4545,7 +4545,8 @@ TEST_F(DIArgListTest, UpdatesOnRAUW) { ConstantAsMetadata *CI = ConstantAsMetadata::get(ConstantInt::get(Context, APInt(8, 0))); std::unique_ptr GV0( - new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage, nullptr, "", + GlobalVariable::NotThreadLocal, 0)); auto *MD0 = ValueAsMetadata::get(GV0.get()); SmallVector VMs; @@ -4556,7 +4557,8 @@ TEST_F(DIArgListTest, UpdatesOnRAUW) { EXPECT_EQ(AL->getArgs()[1], MD0); std::unique_ptr GV1( - new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage)); + new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage, nullptr, "", + GlobalVariable::NotThreadLocal, 0)); auto *MD1 = ValueAsMetadata::get(GV1.get()); GV0->replaceAllUsesWith(GV1.get()); EXPECT_EQ(AL->getArgs()[0], CI); From 488f94b6a38ef252fd84a2003fb14185a7634264 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Tue, 7 Jan 2025 12:39:55 -0800 Subject: [PATCH 02/11] [CHERI-MIPS] Delete a useless test This test just checks that we don't crash and has no further information. --- clang/test/CodeGen/cheri/bn_x931p-crash.c | 34 ----------------------- 1 file changed, 34 deletions(-) delete mode 100644 clang/test/CodeGen/cheri/bn_x931p-crash.c diff --git a/clang/test/CodeGen/cheri/bn_x931p-crash.c b/clang/test/CodeGen/cheri/bn_x931p-crash.c deleted file mode 100644 index 0a5dd3bed73c0..0000000000000 --- a/clang/test/CodeGen/cheri/bn_x931p-crash.c +++ /dev/null @@ -1,34 +0,0 @@ -// REQUIRES: mips-registered-target - -// RUN: %cheri_purecap_cc1 -O2 -std=gnu89 -ftls-model=local-exec -fcolor-diagnostics -vectorize-loops -vectorize-slp -o /dev/null -S %s -// This previously caused clang to crash -struct a { - long *b -} c(struct a d, *e, *f, struct a g, struct a h, struct a i, *j, *k, *l) { - if (j) - m(); - n(); - if (f) - n(); - if (o()) - if (o()) - if (p()) - if (q()) - if (p()) - if (q()) - if (p()) - r() && s(); - if (t()) - if (s()) - for (;;) { - if (u()) - goto aa; - if (v()) - w(); - if (x()) - s(); - } - y(l); -aa: - z(); -} From 4e1d2bd5204edca7e6d3c3f2fb25dd6adb3d74c9 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Wed, 8 Jan 2025 14:53:34 -0800 Subject: [PATCH 03/11] [CHERI] Drop __builtin_assume_aligned_cap() hack Back in 2018 adding custom type checking to the intrinsic would have added a larger downstream diff, but since 8392f1cc7827 it has the custom type checking so we can overload it for capabilities. --- clang/include/clang/Basic/Builtins.td | 6 ---- clang/lib/AST/ExprConstant.cpp | 1 - clang/lib/CodeGen/CGBuiltin.cpp | 1 - clang/lib/Sema/SemaChecking.cpp | 28 +++++++++++++++++-- .../Checkers/BuiltinFunctionChecker.cpp | 1 - clang/test/CodeGen/cheri/assume-aligned.c | 2 +- .../cheri/csetbounds-stats-subobject.c | 2 +- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 93a6efb9f4aa5..644dcf1710cb8 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -839,12 +839,6 @@ def BuiltinAssumeAligned : Builtin { let Prototype = "void*(void const*, size_t, ...)"; } -def BuiltinAssumeAlignedCap : Builtin { - let Spellings = ["__builtin_assume_aligned_cap"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; - let Prototype = "void* __capability(void const* __capability, size_t, ...)"; -} - def BuiltinFree : Builtin { let Spellings = ["__builtin_free"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow]; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 40727ddf8b7f8..2b0b26c775f94 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9910,7 +9910,6 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__addressof: case Builtin::BI__builtin_addressof: return evaluateLValue(E->getArg(0), Result); - case Builtin::BI__builtin_assume_aligned_cap: case Builtin::BI__builtin_assume_aligned: { // We need to be very careful here because: if the pointer does not have the // asserted alignment, then the behavior is undefined, and undefined diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index a9386264ba299..d39415aad19db 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3833,7 +3833,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, FnExpect, {ArgValue, ExpectedValue, Confidence}, "expval"); return RValue::get(Result); } - case Builtin::BI__builtin_assume_aligned_cap: case Builtin::BI__builtin_assume_aligned: { const Expr *Ptr = E->getArg(0); Value *PtrValue = EmitScalarExpr(Ptr); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7b1e48dca588c..fcaddda369e7b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2060,7 +2060,8 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, } } -static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex); +static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex, + bool OverloadForHybrid = false); // Check if \p Ty is a valid type for the elementwise math builtins. If it is // not a valid type, emit an error message and return true. Otherwise return @@ -2374,7 +2375,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_assume_aligned: - case Builtin::BI__builtin_assume_aligned_cap: if (BuiltinAssumeAligned(TheCall)) return ExprError(); break; @@ -4585,7 +4585,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, /// them. /// /// Returns true on error. -static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { +static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex, + bool OverloadForHybrid) { FunctionDecl *Fn = E->getDirectCallee(); assert(Fn && "builtin call without direct callee!"); @@ -4594,6 +4595,18 @@ static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { InitializedEntity::InitializeParameter(S.Context, Param); ExprResult Arg = E->getArg(ArgIndex); + if (OverloadForHybrid) { + assert(Param->getType()->isPointerType()); + // In CHERI hybrid mode we have to update the argument to a + // capability-qualified type ensure that we don't get an initialization + // error. + if (Arg.get()->getType()->isCapabilityPointerType() && + !Param->getType()->isCapabilityPointerType()) { + QualType PtrTy = S.Context.getPointerType( + Param->getType()->getPointeeType(), PIK_Capability); + Entity = InitializedEntity::InitializeParameter(S.Context, PtrTy, false); + } + } Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; @@ -5704,7 +5717,16 @@ bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { << TheCall->getSourceRange(); return true; } + if (checkBuiltinArgument(*this, TheCall, 0, /*OverloadForHybrid=*/true)) + return true; TheCall->setArg(0, FirstArgResult.get()); + // We may also have to update the return type since this intrinsic is + // overloaded for hybrid mode. + if (const auto *PtrTy = + FirstArgResult.get()->getType()->getAs()) + TheCall->setType( + Context.getPointerType(TheCall->getType()->getPointeeType(), + PtrTy->getPointerInterpretation())); } // The alignment must be a constant integer. diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index a3d5e68a0b813..cfdd3c9faa360 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -311,7 +311,6 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call, case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: case Builtin::BI__builtin_assume_aligned: - case Builtin::BI__builtin_assume_aligned_cap: case Builtin::BI__builtin_addressof: case Builtin::BI__builtin_function_start: { // For __builtin_unpredictable, __builtin_expect, diff --git a/clang/test/CodeGen/cheri/assume-aligned.c b/clang/test/CodeGen/cheri/assume-aligned.c index 8aa1b62df43b4..bedd6feb1ccec 100644 --- a/clang/test/CodeGen/cheri/assume-aligned.c +++ b/clang/test/CodeGen/cheri/assume-aligned.c @@ -44,5 +44,5 @@ int* assume_aligned_ptr(void* ptr) { // PURECAP-NEXT: ret ptr addrspace(200) [[TMP0]] // int* __capability assume_aligned_cap(void* __capability ptr) { - return __builtin_assume_aligned_cap(ptr, 4); + return __builtin_assume_aligned(ptr, 4); } diff --git a/clang/test/CodeGen/cheri/csetbounds-stats-subobject.c b/clang/test/CodeGen/cheri/csetbounds-stats-subobject.c index ebc7ea37c7f98..5c636fa66047e 100644 --- a/clang/test/CodeGen/cheri/csetbounds-stats-subobject.c +++ b/clang/test/CodeGen/cheri/csetbounds-stats-subobject.c @@ -55,7 +55,7 @@ void test_subobject_addrof_global() { } void test_subobject_addrof_assume_aligned(struct Nested * __capability cap) { - struct Nested * __capability cap2 = __builtin_assume_aligned_cap(cap, 4096); + struct Nested * __capability cap2 = __builtin_assume_aligned(cap, 4096); do_stuff_with_int_capability(&cap2->a); // HYBRID-CSV-NEXT: 0,4,o,"{{.+}}/csetbounds-stats-subobject.c:[[@LINE-1]]:32","Add subobject bounds","addrof operator on int" // PURECAP-CSV-NEXT: 0,4,o,"{{.+}}/csetbounds-stats-subobject.c:[[@LINE-2]]:32","Add subobject bounds","addrof operator on int" From a068aa3f80c407ee9d80bb9bdfec07fc7c7ad6d8 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 13 Jan 2025 17:01:15 -0800 Subject: [PATCH 04/11] [libunwind] Fix baremetal build The header link.h might not exist for baremetal targets. Only include it when we actually have the c18n support. --- libunwind/src/CompartmentInfo.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libunwind/src/CompartmentInfo.hpp b/libunwind/src/CompartmentInfo.hpp index 39f3449c92926..2d050038aceee 100644 --- a/libunwind/src/CompartmentInfo.hpp +++ b/libunwind/src/CompartmentInfo.hpp @@ -13,7 +13,9 @@ #ifndef __COMPARTMENT_INFO_HPP__ #define __COMPARTMENT_INFO_HPP__ +#ifdef _LIBUNWIND_HAS_CHERI_LIB_C18N #include +#endif namespace libunwind { From 27b7a8754414d126635576b0235244115afa63c0 Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Thu, 9 Jan 2025 14:37:59 -0500 Subject: [PATCH 05/11] lld: Enable the --local-caprelocs=legacy command line argument --- lld/ELF/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index d53bf5ac82d5a..48431a55a2bee 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -829,7 +829,7 @@ static CapTableScopePolicy getCapTableScope(opt::InputArgList &args) { static CapRelocsMode getLocalCapRelocsMode(opt::InputArgList &args) { auto *arg = - args.getLastArg(OPT_local_caprelocs_cbuildcap, OPT_local_caprelocs_elf, + args.getLastArg(OPT_local_caprelocs_legacy, OPT_local_caprelocs_elf, OPT_local_caprelocs_cbuildcap); if (!arg) // TODO: change default to CBuildCap (at least for non-PIC) return CapRelocsMode::Legacy; From 68046e40aae19d291469134842c9951b2e5538ce Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 7 Feb 2025 17:32:02 -0800 Subject: [PATCH 06/11] [libunwind] Fix Morello build Can't use the MTE inline assembly when building for purecap Morello --- libunwind/src/DwarfInstructions.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp index 33db7c2facb16..b5d376225e945 100644 --- a/libunwind/src/DwarfInstructions.hpp +++ b/libunwind/src/DwarfInstructions.hpp @@ -288,7 +288,7 @@ int DwarfInstructions::stepWithDwarf(A &addressSpace, pc_t pc, // __unw_step_stage2 is not used for cross unwinding, so we use // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are // building for AArch64 natively. -#if defined(__aarch64__) +#if defined(__aarch64__) && !defined(__CHERI_PURE_CAPABILITY__) if (stage2 && cieInfo.mteTaggedFrame) { pint_t sp = registers.getSP(); pint_t p = sp; From fd15b52a46c935eb577a973a3f0863d815c75dd5 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 3 Feb 2025 08:51:16 -0800 Subject: [PATCH 07/11] [CHERI RISC-V] Use RISCVISAInfo::parseFeatures() instead of manual parsing No functional change intended. --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index 761279eb19683..6e1fbda1e2b73 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -167,7 +167,12 @@ static std::string computeDataLayout(const Triple &TT, StringRef FS, StringRef CapTypes = ""; StringRef PurecapOptions = ""; - if (llvm::is_contained(llvm::split(FS, ','), "+xcheri")) { + unsigned XLen = TT.isArch64Bit() ? 64 : 32; + std::vector Features; + if (!FS.empty()) + llvm::append_range(Features, llvm::split(FS, ',')); + auto ISAInfo = cantFail(llvm::RISCVISAInfo::parseFeatures(XLen, Features)); + if (ISAInfo->hasExtension("xcheri")) { if (TT.isArch64Bit()) CapTypes = "-pf200:128:128:128:64"; else From eb89624e08cafdc2734a462d7d0b9f3096cb5ad6 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 3 Feb 2025 08:52:08 -0800 Subject: [PATCH 08/11] [CHERI-RISC-V] Stop manually handling xcheri feature This may have been needed before ISAInfo handled custom extensions, but now we can just defer to ISAInfo. No functional change intended --- clang/lib/Basic/Targets/RISCV.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index a4068a44f3d03..078021af6f43a 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -437,7 +437,6 @@ bool RISCVTargetInfo::hasFeature(StringRef Feature) const { .Case("32bit", !Is64Bit) .Case("64bit", Is64Bit) .Case("experimental", HasExperimental) - .Case("xcheri", HasCheri) .Default(std::nullopt); if (Result) return *Result; From 6e8829dafa3de7c7021f7151cee3cf3cab823324 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 13 Feb 2023 13:08:09 +0000 Subject: [PATCH 09/11] [cheri_init_globals.h] Avoid using cgetaddr/cgetoffset in assembly The upcoming standard no longer includes cgetoffset (and cgetaddr has been removed in ISAv9). For now the assembly code still accepts cgetaddr and converts it to a move, but use an intrinsic call instead as that can be optimized to a subregister read on next use rather the requiring an explicit move. --- clang/lib/Headers/cheri_init_globals.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/clang/lib/Headers/cheri_init_globals.h b/clang/lib/Headers/cheri_init_globals.h index 630f2bd6abfd5..72b4f3a3f5591 100644 --- a/clang/lib/Headers/cheri_init_globals.h +++ b/clang/lib/Headers/cheri_init_globals.h @@ -76,13 +76,13 @@ __attribute__((weak)) extern void *__capability __cap_table_end; * position-dependent executables. */ #ifdef CHERI_INIT_GLOBALS_USE_OFFSET -#define cgetaddr_or_offset "cgetoffset" #define csetaddr_or_offset "csetoffset" +#define cheri_address_or_offset_get(_cap) __builtin_cheri_offset_get((_cap)) #define cheri_address_or_offset_set(_cap, _val) \ __builtin_cheri_offset_set((_cap), (_val)) #else -#define cgetaddr_or_offset "cgetaddr" #define csetaddr_or_offset "csetaddr" +#define cheri_address_or_offset_get(_cap) __builtin_cheri_address_get((_cap)) #define cheri_address_or_offset_set(_cap, _val) \ __builtin_cheri_address_set((_cap), (_val)) #endif @@ -219,13 +219,11 @@ cheri_init_globals_3(void *__capability data_cap, "lla %1, __stop___cap_relocs\n\t" : "=r"(start_addr), "=r"(stop_addr)); #else - void *__capability tmp; - __asm__ ( - "cllc %2, __start___cap_relocs\n\t" - cgetaddr_or_offset " %0, %2\n\t" - "cllc %2, __stop___cap_relocs\n\t" - cgetaddr_or_offset " %1, %2\n\t" - :"=r"(start_addr), "=r"(stop_addr), "=&C"(tmp)); + __asm__("cllc %0, __start___cap_relocs\n\t" + "cllc %1, __stop___cap_relocs\n\t" + : "=C"(start_relocs), "=C"(stop_relocs)); + start_addr = cheri_address_or_offset_get(start_relocs); + stop_addr = cheri_address_or_offset_get(stop_relocs); #endif #else #error Unknown architecture From 22bcd29d2a5c39aa8d9230eeafd3c4c4c6447f22 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Mon, 3 Feb 2025 09:18:24 -0800 Subject: [PATCH 10/11] [CHERI-RISC-V] Use RISCVIsaInfo to check for CHERI support in Driver This also handles implied features and therefore is more future-proof than a simple string comparison. --- clang/lib/Driver/ToolChains/Arch/RISCV.cpp | 53 ++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 42649e73f3423..2c9789ddb5217 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -165,12 +165,59 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, Features.push_back("-relax"); } + // If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or + // -mno-scalar-strict-align is passed, use it. Otherwise, the + // unaligned-scalar-mem is enabled if the CPU supports it or the target is + // Android. + if (const Arg *A = Args.getLastArg( + options::OPT_mno_strict_align, options::OPT_mscalar_strict_align, + options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) { + if (A->getOption().matches(options::OPT_mno_strict_align) || + A->getOption().matches(options::OPT_mno_scalar_strict_align)) { + Features.push_back("+unaligned-scalar-mem"); + } else { + Features.push_back("-unaligned-scalar-mem"); + } + } else if (CPUFastScalarUnaligned || Triple.isAndroid()) { + Features.push_back("+unaligned-scalar-mem"); + } + + // If -mstrict-align, -mno-strict-align, -mvector-strict-align, or + // -mno-vector-strict-align is passed, use it. Otherwise, the + // unaligned-vector-mem is enabled if the CPU supports it or the target is + // Android. + if (const Arg *A = Args.getLastArg( + options::OPT_mno_strict_align, options::OPT_mvector_strict_align, + options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) { + if (A->getOption().matches(options::OPT_mno_strict_align) || + A->getOption().matches(options::OPT_mno_vector_strict_align)) { + Features.push_back("+unaligned-vector-mem"); + } else { + Features.push_back("-unaligned-vector-mem"); + } + } else if (CPUFastVectorUnaligned || Triple.isAndroid()) { + Features.push_back("+unaligned-vector-mem"); + } + + // Now add any that the user explicitly requested on the command line, + // which may override the defaults. + handleTargetFeaturesGroup(D, Triple, Args, Features, + options::OPT_m_riscv_Features_Group); + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { bool IsPureCapability = isCheriPurecapABIName(A->getValue()); if (IsPureCapability) { - if (llvm::find(Features, "+xcheri") == Features.end()) { - D.Diag(diag::err_riscv_invalid_abi) << A->getValue() - << "pure capability ABI requires xcheri extension to be specified"; + auto ISAInfo = llvm::RISCVISAInfo::parseFeatures( + Triple.isArch32Bit() ? 32 : 64, + std::vector(Features.begin(), Features.end())); + if (!ISAInfo) { + handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) { + D.Diag(diag::err_invalid_feature_combination) << ErrMsg.getMessage(); + }); + } else if (!(*ISAInfo)->hasExtension("xcheri")) { + D.Diag(diag::err_riscv_invalid_abi) + << A->getValue() + << "pure capability ABI requires xcheri extension to be specified"; return; } Features.push_back("+cap-mode"); From b378633a0636bcd4e06efec7922b6813fbda82be Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Sun, 9 Feb 2025 16:59:49 -0800 Subject: [PATCH 11/11] [CHERI-RISC-V] Fix expanding CFromPtr for RV32 We have to use XLenVT for getting the intrinsic type otherwise we end up triggering an assertion in LegalizeDAG. --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index f3fc67b3dd72c..f3533652b945e 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -6008,15 +6008,15 @@ SDValue RISCVTargetLowering::lowerVPCttzElements(SDValue Op, /// `cfromptr(auth, addr)` is `addr ? csetaddr(auth, addr) : 0` which is /// semantic change but it is consistent with Morello when CCTLR.DDCBO==0. static SDValue emitCFromPtrReplacement(SelectionDAG &DAG, const SDLoc &DL, - SDValue Base, SDValue IntVal, - EVT CLenVT) { -SDValue AsCap = DAG.getNode( -ISD::INTRINSIC_WO_CHAIN, DL, CLenVT, -DAG.getConstant(Intrinsic::cheri_cap_address_set, DL, MVT::i64), Base, -IntVal); -return DAG.getSelectCC(DL, IntVal, -DAG.getConstant(0, DL, IntVal.getValueType()), AsCap, -DAG.getNullCapability(DL), ISD::SETNE); + SDValue Base, SDValue IntVal, EVT CLenVT, + EVT XLenVT) { + SDValue AsCap = + DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, CLenVT, + DAG.getConstant(Intrinsic::cheri_cap_address_set, DL, XLenVT), + Base, IntVal); + return DAG.getSelectCC(DL, IntVal, + DAG.getConstant(0, DL, IntVal.getValueType()), AsCap, + DAG.getNullCapability(DL), ISD::SETNE); } /// The CToPtr instruction is deprecated and will be removed. This function @@ -6919,7 +6919,8 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, } SDLoc DL(Op); EVT CLenVT = Op.getValueType(); - auto GetDDC = DAG.getConstant(Intrinsic::cheri_ddc_get, DL, MVT::i64); + MVT XLenVT = Subtarget.getXLenVT(); + auto GetDDC = DAG.getConstant(Intrinsic::cheri_ddc_get, DL, XLenVT); auto DDC = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, DL, CapType, GetDDC); // It would be nice if we could just use SetAddr on DDC, but for // consistency between constant inttoptr and non-constant inttoptr @@ -6928,7 +6929,7 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, // getting different values for inttoptr with a constant zero argument and // inttoptr with a variable that happens to be zero (the latter should not // result in a tagged value). - return emitCFromPtrReplacement(DAG, DL, DDC, Op0, CLenVT); + return emitCFromPtrReplacement(DAG, DL, DDC, Op0, CLenVT, XLenVT); } return Op; } @@ -10066,7 +10067,8 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, // Expand CFromPtr if the dedicated instruction has been removed. if (Subtarget.hasCheriISAv9Semantics()) { return emitCFromPtrReplacement(DAG, DL, Op.getOperand(1), - Op.getOperand(2), Op.getValueType()); + Op.getOperand(2), Op.getValueType(), + XLenVT); } break; case Intrinsic::cheri_cap_to_pointer: