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/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; 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/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/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"); 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 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/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(); -} 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" 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 { 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; 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; 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: 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 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);