Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
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
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/unittests/SourceCodeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,10 @@ TEST(SourceCodeTests, isKeywords) {
LangOpts.Coroutines = true;
EXPECT_TRUE(isKeyword("int", LangOpts));
EXPECT_TRUE(isKeyword("return", LangOpts));
// CHERI-TODO: COROUTINES_KEYWORD is not included in CXX20_KEYWORD until
// https://github.com/CTSRD-CHERI/llvm-project/issues/717 has been fixed.
EXPECT_FALSE(isKeyword("co_await", LangOpts));
LangOpts.Coroutines = true;
EXPECT_TRUE(isKeyword("co_await", LangOpts));

// these are identifiers (not keywords!) with special meaning in some
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ FEATURE(experimental_library, LangOpts.ExperimentalLibrary)

// CHERI features:
FEATURE(capabilities, PP.getTargetInfo().SupportsCapabilities())
FEATURE(cheri, PP.getTargetInfo().SupportsCapabilities())
FEATURE(pointer_interpretation, PP.getTargetInfo().SupportsCapabilities())
FEATURE(cheri_casts, PP.getTargetInfo().SupportsCapabilities())
// CHERI typed sealed pointers
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,9 @@ class Sema final : public SemaBase {
bool CheckCHERIAssignCompatible(QualType LHS, QualType RHS, Expr *&RHSExpr,
bool InsertBitCast = true);

void DiagnoseAmbiguousProvenance(Expr *LHS, Expr *RHS, SourceLocation Loc,
bool IsCompAssign);

/// ActOnPragmaClangSection - Called on well formed \#pragma clang section
void ActOnPragmaClangSection(SourceLocation PragmaLoc,
PragmaClangSectionAction Action,
Expand Down
136 changes: 121 additions & 15 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
Expand Down Expand Up @@ -2321,14 +2324,40 @@ static RValue EmitCheckedUnsignedMultiplySignedResult(
CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info,
const clang::Expr *Op2, WidthAndSignedness Op2Info,
const clang::Expr *ResultArg, QualType ResultQTy,
WidthAndSignedness ResultInfo) {
WidthAndSignedness ResultInfo, SourceLocation Loc) {
assert(isSpecialUnsignedMultiplySignedResult(
Builtin::BI__builtin_mul_overflow, Op1Info, Op2Info, ResultInfo) &&
"Cannot specialize this multiply");

clang::QualType Op1QTy = Op1->getType();
clang::QualType Op2QTy = Op2->getType();
bool Op1IsCap = Op1QTy->isCHERICapabilityType(CGF.getContext());
bool Op2IsCap = Op2QTy->isCHERICapabilityType(CGF.getContext());
bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGF.getContext());

llvm::Value *V1 = CGF.EmitScalarExpr(Op1);
llvm::Value *V2 = CGF.EmitScalarExpr(Op2);

llvm::Value *ProvenanceCap = nullptr;
if (ResultIsCap) {
bool Op1NoProvenance =
!Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance);
bool Op2NoProvenance =
!Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance);
if (Op1NoProvenance && Op2NoProvenance)
ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy);
else if (Op1NoProvenance)
ProvenanceCap = V2;
else
ProvenanceCap = V1;
}

if (Op1IsCap)
V1 = CGF.getCapabilityIntegerValue(V1);

if (Op2IsCap)
V2 = CGF.getCapabilityIntegerValue(V2);

llvm::Value *HasOverflow;
llvm::Value *Result = EmitOverflowIntrinsic(
CGF, Intrinsic::umul_with_overflow, V1, V2, HasOverflow);
Expand All @@ -2342,6 +2371,9 @@ static RValue EmitCheckedUnsignedMultiplySignedResult(
llvm::Value *IntMaxOverflow = CGF.Builder.CreateICmpUGT(Result, IntMaxValue);
HasOverflow = CGF.Builder.CreateOr(HasOverflow, IntMaxOverflow);

if (ResultIsCap)
Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc);

bool isVolatile =
ResultArg->getType()->getPointeeType().isVolatileQualified();
Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
Expand All @@ -2362,23 +2394,50 @@ static bool isSpecialMixedSignMultiply(unsigned BuiltinID,

/// Emit a checked mixed-sign multiply. This is a cheaper specialization of
/// the generic checked-binop irgen.
static RValue
EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
WidthAndSignedness Op1Info, const clang::Expr *Op2,
WidthAndSignedness Op2Info,
const clang::Expr *ResultArg, QualType ResultQTy,
WidthAndSignedness ResultInfo) {
static RValue EmitCheckedMixedSignMultiply(
CodeGenFunction &CGF, const clang::Expr *Op1, WidthAndSignedness Op1Info,
const clang::Expr *Op2, WidthAndSignedness Op2Info,
const clang::Expr *ResultArg, QualType ResultQTy,
WidthAndSignedness ResultInfo, SourceLocation Loc) {
assert(isSpecialMixedSignMultiply(Builtin::BI__builtin_mul_overflow, Op1Info,
Op2Info, ResultInfo) &&
"Not a mixed-sign multipliction we can specialize");

QualType Op1QTy = Op1->getType();
QualType Op2QTy = Op2->getType();
bool Op1IsCap = Op1QTy->isCHERICapabilityType(CGF.getContext());
bool Op2IsCap = Op2QTy->isCHERICapabilityType(CGF.getContext());
bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGF.getContext());

// Emit the signed and unsigned operands.
const clang::Expr *SignedOp = Op1Info.Signed ? Op1 : Op2;
const clang::Expr *UnsignedOp = Op1Info.Signed ? Op2 : Op1;
llvm::Value *Signed = CGF.EmitScalarExpr(SignedOp);
llvm::Value *Unsigned = CGF.EmitScalarExpr(UnsignedOp);
unsigned SignedOpWidth = Op1Info.Signed ? Op1Info.Width : Op2Info.Width;
unsigned UnsignedOpWidth = Op1Info.Signed ? Op2Info.Width : Op1Info.Width;
bool SignedIsCap = Op1Info.Signed ? Op1IsCap : Op2IsCap;
bool UnsignedIsCap = Op1Info.Signed ? Op2IsCap : Op1IsCap;

llvm::Value *ProvenanceCap = nullptr;
if (ResultIsCap) {
bool Op1NoProvenance =
!Op1IsCap || Op1QTy->hasAttr(attr::CHERINoProvenance);
bool Op2NoProvenance =
!Op2IsCap || Op2QTy->hasAttr(attr::CHERINoProvenance);
if (Op1NoProvenance && Op2NoProvenance)
ProvenanceCap = llvm::ConstantPointerNull::get(CGF.Int8CheriCapTy);
else if (Op1NoProvenance)
ProvenanceCap = Op1Info.Signed ? Unsigned : Signed;
else
ProvenanceCap = Op1Info.Signed ? Signed : Unsigned;
}

if (SignedIsCap)
Signed = CGF.getCapabilityIntegerValue(Signed);

if (UnsignedIsCap)
Unsigned = CGF.getCapabilityIntegerValue(Unsigned);

// One of the operands may be smaller than the other. If so, [s|z]ext it.
if (SignedOpWidth < UnsignedOpWidth)
Expand All @@ -2389,7 +2448,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
llvm::Type *OpTy = Signed->getType();
llvm::Value *Zero = llvm::Constant::getNullValue(OpTy);
Address ResultPtr = CGF.EmitPointerWithAlignment(ResultArg);
llvm::Type *ResTy = CGF.getTypes().ConvertType(ResultQTy);
llvm::Type *ResTy = ResultIsCap ? llvm::IntegerType::get(CGF.getLLVMContext(),
ResultInfo.Width)
: CGF.getTypes().ConvertType(ResultQTy);
unsigned OpWidth = std::max(Op1Info.Width, Op2Info.Width);

// Take the absolute value of the signed operand.
Expand Down Expand Up @@ -2428,8 +2489,7 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
IsNegative, CGF.Builder.CreateIsNotNull(UnsignedResult));
Overflow = CGF.Builder.CreateOr(UnsignedOverflow, Underflow);
if (ResultInfo.Width < OpWidth) {
auto IntMax =
llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
auto IntMax = llvm::APInt::getMaxValue(ResultInfo.Width).zext(OpWidth);
llvm::Value *TruncOverflow = CGF.Builder.CreateICmpUGT(
UnsignedResult, llvm::ConstantInt::get(OpTy, IntMax));
Overflow = CGF.Builder.CreateOr(Overflow, TruncOverflow);
Expand All @@ -2443,6 +2503,9 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
}
assert(Overflow && Result && "Missing overflow or result");

if (ResultIsCap)
Result = CGF.setCapabilityIntegerValue(ProvenanceCap, Result, Loc);

bool isVolatile =
ResultArg->getType()->getPointeeType().isVolatileQualified();
CGF.Builder.CreateStore(CGF.EmitToMemory(Result, ResultQTy), ResultPtr,
Expand Down Expand Up @@ -5495,13 +5558,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
const clang::Expr *RightArg = E->getArg(1);
const clang::Expr *ResultArg = E->getArg(2);

clang::QualType LeftQTy = LeftArg->getType();
clang::QualType RightQTy = RightArg->getType();
clang::QualType ResultQTy =
ResultArg->getType()->castAs<PointerType>()->getPointeeType();

bool LeftIsCap = LeftQTy->isCHERICapabilityType(CGM.getContext());
bool RightIsCap = RightQTy->isCHERICapabilityType(CGM.getContext());
bool ResultIsCap = ResultQTy->isCHERICapabilityType(CGM.getContext());
WidthAndSignedness LeftInfo =
getIntegerWidthAndSignedness(CGM.getContext(), LeftArg->getType());
getIntegerWidthAndSignedness(CGM.getContext(), LeftQTy);
WidthAndSignedness RightInfo =
getIntegerWidthAndSignedness(CGM.getContext(), RightArg->getType());
getIntegerWidthAndSignedness(CGM.getContext(), RightQTy);
WidthAndSignedness ResultInfo =
getIntegerWidthAndSignedness(CGM.getContext(), ResultQTy);

Expand All @@ -5510,44 +5578,78 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (isSpecialMixedSignMultiply(BuiltinID, LeftInfo, RightInfo, ResultInfo))
return EmitCheckedMixedSignMultiply(*this, LeftArg, LeftInfo, RightArg,
RightInfo, ResultArg, ResultQTy,
ResultInfo);
ResultInfo, E->getExprLoc());

if (isSpecialUnsignedMultiplySignedResult(BuiltinID, LeftInfo, RightInfo,
ResultInfo))
return EmitCheckedUnsignedMultiplySignedResult(
*this, LeftArg, LeftInfo, RightArg, RightInfo, ResultArg, ResultQTy,
ResultInfo);
ResultInfo, E->getExprLoc());

WidthAndSignedness EncompassingInfo =
EncompassingIntegerType({LeftInfo, RightInfo, ResultInfo});

llvm::Type *EncompassingLLVMTy =
llvm::IntegerType::get(CGM.getLLVMContext(), EncompassingInfo.Width);

llvm::Type *ResultLLVMTy = CGM.getTypes().ConvertType(ResultQTy);
llvm::Type *ResultLLVMTy =
ResultIsCap
? llvm::IntegerType::get(CGM.getLLVMContext(), ResultInfo.Width)
: CGM.getTypes().ConvertType(ResultQTy);

Intrinsic::ID IntrinsicId;
bool Commutative;
switch (BuiltinID) {
default:
llvm_unreachable("Unknown overflow builtin id.");
case Builtin::BI__builtin_add_overflow:
IntrinsicId = EncompassingInfo.Signed ? Intrinsic::sadd_with_overflow
: Intrinsic::uadd_with_overflow;
Commutative = true;
break;
case Builtin::BI__builtin_sub_overflow:
IntrinsicId = EncompassingInfo.Signed ? Intrinsic::ssub_with_overflow
: Intrinsic::usub_with_overflow;
Commutative = false;
break;
case Builtin::BI__builtin_mul_overflow:
IntrinsicId = EncompassingInfo.Signed ? Intrinsic::smul_with_overflow
: Intrinsic::umul_with_overflow;
Commutative = true;
break;
}

llvm::Value *Left = EmitScalarExpr(LeftArg);
llvm::Value *Right = EmitScalarExpr(RightArg);
Address ResultPtr = EmitPointerWithAlignment(ResultArg);

llvm::Value *ProvenanceCap = nullptr;
if (ResultIsCap) {
if (!Commutative) {
if (LeftIsCap)
ProvenanceCap = Left;
else
ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy);
} else {
bool LeftNoProvenance =
!LeftIsCap || LeftQTy->hasAttr(attr::CHERINoProvenance);
bool RightNoProvenance =
!RightIsCap || RightQTy->hasAttr(attr::CHERINoProvenance);
if (LeftNoProvenance && RightNoProvenance)
ProvenanceCap = llvm::ConstantPointerNull::get(Int8CheriCapTy);
else if (LeftNoProvenance)
ProvenanceCap = Right;
else
ProvenanceCap = Left;
}
}

if (LeftIsCap)
Left = getCapabilityIntegerValue(Left);

if (RightIsCap)
Right = getCapabilityIntegerValue(Right);

// Extend each operand to the encompassing type.
Left = Builder.CreateIntCast(Left, EncompassingLLVMTy, LeftInfo.Signed);
Right = Builder.CreateIntCast(Right, EncompassingLLVMTy, RightInfo.Signed);
Expand All @@ -5572,6 +5674,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Result = ResultTrunc;
}

if (ResultIsCap)
Result =
setCapabilityIntegerValue(ProvenanceCap, Result, E->getExprLoc());

// Finally, store the result using the pointer.
bool isVolatile =
ResultArg->getType()->getPointeeType().isVolatileQualified();
Expand Down
16 changes: 6 additions & 10 deletions clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ using namespace llvm::opt;
// Returns false if an error is diagnosed.
static bool getArchFeatures(const Driver &D, StringRef Arch,
std::vector<StringRef> &Features,
const ArgList &Args) {
const ArgList &Args,
std::unique_ptr<llvm::RISCVISAInfo> &ISAInfoOut) {
bool EnableExperimentalExtensions =
Args.hasArg(options::OPT_menable_experimental_extensions);
auto ISAInfo =
Expand All @@ -48,6 +49,7 @@ static bool getArchFeatures(const Driver &D, StringRef Arch,
if (EnableExperimentalExtensions)
Features.push_back(Args.MakeArgString("+experimental"));

ISAInfoOut = std::move(*ISAInfo);
return true;
}

Expand Down Expand Up @@ -92,8 +94,9 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
std::string MArch = getRISCVArch(Args, Triple);
std::unique_ptr<llvm::RISCVISAInfo> ISAInfo;

if (!getArchFeatures(D, MArch, Features, Args))
if (!getArchFeatures(D, MArch, Features, Args, ISAInfo))
return;

bool CPUFastScalarUnaligned = false;
Expand Down Expand Up @@ -210,14 +213,7 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// +xcheriot implies both +xcheri and +xcheripurecap
Features.push_back("+xcheriot");
} else if (IsPureCapability) {
auto ISAInfo = llvm::RISCVISAInfo::parseFeatures(
Triple.isArch32Bit() ? 32 : 64,
std::vector<std::string>(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")) {
if (!ISAInfo->hasExtension("xcheri")) {
D.Diag(diag::err_riscv_invalid_abi)
<< A->getValue()
<< "pure capability ABI requires xcheri extension to be specified";
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (TI.SupportsCapabilities()) {
const uint64_t CapWidth = TI.getCHERICapabilityWidth();
const uint64_t CapRange = TI.getPointerRangeForCHERICapability();
Builder.defineMacro("__CHERI__", "1"); // TODO: or define __CHERI__ to 128/256?
Builder.defineMacro("__CHERI_CAPABILITY_WIDTH__", Twine(CapWidth));
DefineTypeSizeof("__SIZEOF_CHERI_CAPABILITY__", CapWidth, TI, Builder);
Builder.defineMacro("__CHERI_ADDRESS_BITS__", Twine(CapRange));
Expand All @@ -1137,6 +1136,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__UINTCAP_MAX__", TI.getIntTypeByWidth(CapRange, false), TI, Builder);

if (TI.areAllPointersCapabilities()) {
Builder.defineMacro("__CHERI__");

// XXXAR is there a reason we use two instead of just defining it?
// I don't think we have any checks that rely on the value
Builder.defineMacro("__CHERI_PURE_CAPABILITY__", "2");
Expand All @@ -1148,6 +1149,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.getCheriBounds() > LangOptions::CBM_Conservative)
Builder.defineMacro("__CHERI_SUBOBJECT_BOUNDS__",
Twine(LangOpts.getCheriBounds()));
} else {
Builder.defineMacro("__CHERI_HYBRID__");
}
}

Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
Expand Down Expand Up @@ -569,6 +572,18 @@ static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) {
}
}

// ScalarExprEmitter::EmitSub's diagnostics aren't included here since
// they're generally unhelpful, grouped under pedantic warnings, and would be
// confusing without also taking into account the type of the result.
if (BuiltinID != Builtin::BI__builtin_sub_overflow) {
assert((BuiltinID == Builtin::BI__builtin_add_overflow ||
BuiltinID == Builtin::BI__builtin_mul_overflow) &&
"Unexpected overflow builtin");

S.DiagnoseAmbiguousProvenance(TheCall->getArg(0), TheCall->getArg(1),
TheCall->getExprLoc(), false);
}

return false;
}

Expand Down
Loading