5 changes: 4 additions & 1 deletion clang/lib/CodeGen/Targets/SystemZ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,16 @@ ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const {
}

ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const {
// Handle transparent union types.
Ty = useFirstFieldIfTransparentUnion(Ty);

// Handle the generic C++ ABI.
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory);

// Integers and enums are extended to full register width.
if (isPromotableIntegerTypeForABI(Ty))
return ABIArgInfo::getExtend(Ty);
return ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty));

// Handle vector types and vector-like structure types. Note that
// as opposed to float-like structure types, we do not allow any
Expand Down
18 changes: 16 additions & 2 deletions clang/lib/Driver/ToolChains/Hexagon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,14 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
options::OPT_t, options::OPT_u_Group});
AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);

ToolChain::UnwindLibType UNW = HTC.GetUnwindLibType(Args);

if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
if (NeedsSanitizerDeps) {
linkSanitizerRuntimeDeps(HTC, Args, CmdArgs);

CmdArgs.push_back("-lunwind");
if (UNW != ToolChain::UNW_None)
CmdArgs.push_back("-lunwind");
}
if (NeedsXRayDeps)
linkXRayRuntimeDeps(HTC, Args, CmdArgs);
Expand Down Expand Up @@ -618,13 +621,24 @@ HexagonToolChain::~HexagonToolChain() {}
void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
ToolChain::UnwindLibType UNW = GetUnwindLibType(Args);
if (UNW != ToolChain::UNW_None && UNW != ToolChain::UNW_CompilerRT) {
const Arg *A = Args.getLastArg(options::OPT_unwindlib_EQ);
if (A) {
getDriver().Diag(diag::err_drv_unsupported_unwind_for_platform)
<< A->getValue() << getTriple().normalize();
return;
}
}

switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back("-lc++");
if (Args.hasArg(options::OPT_fexperimental_library))
CmdArgs.push_back("-lc++experimental");
CmdArgs.push_back("-lc++abi");
CmdArgs.push_back("-lunwind");
if (UNW != ToolChain::UNW_None)
CmdArgs.push_back("-lunwind");
break;

case ToolChain::CST_Libstdcxx:
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
/* Authenticating a pointer that was not signed with the given key
and extra-data value will (likely) fail by trapping. */

/* The null function pointer is always the all-zero bit pattern.
Signing an all-zero bit pattern will embed a (likely) non-zero
signature in the result, and so the result will not seem to be
a null function pointer. Authenticating this value will yield
a null function pointer back. However, authenticating an
all-zero bit pattern will probably fail, because the
authentication will expect a (likely) non-zero signature to
embedded in the value.
Because of this, if a pointer may validly be null, you should
check for null before attempting to authenticate it with one
of these intrinsics. This is not necessary when using the
__ptrauth qualifier; the compiler will perform this check
automatically. */

#if __has_feature(ptrauth_intrinsics)

/* Strip the signature from a value without authenticating it.
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Lex/DependencyDirectivesScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,18 @@ bool Scanner::lexModule(const char *&First, const char *const End) {
// an import.

switch (*First) {
case ':':
case ':': {
// `module :` is never the start of a valid module declaration.
if (Id == "module") {
skipLine(First, End);
return false;
}
// `import:(type)name` is a valid ObjC method decl, so check one more token.
(void)lexToken(First, End);
if (!tryLexIdentifierOrSkipLine(First, End))
return false;
break;
}
case '<':
case '"':
break;
Expand Down
8 changes: 3 additions & 5 deletions clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,7 +1137,9 @@ Preprocessor::LookupEmbedFile(StringRef Filename, bool isAngled, bool OpenFile,
SeparateComponents(LookupPath, Entry, Filename, false);
llvm::Expected<FileEntryRef> ShouldBeEntry =
FM.getFileRef(LookupPath, OpenFile);
return llvm::expectedToOptional(std::move(ShouldBeEntry));
if (ShouldBeEntry)
return llvm::expectedToOptional(std::move(ShouldBeEntry));
llvm::consumeError(ShouldBeEntry.takeError());
}
return std::nullopt;
}
Expand Down Expand Up @@ -3624,12 +3626,10 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
LexEmbedParametersResult Result{};
SmallVector<Token, 2> ParameterTokens;
tok::TokenKind EndTokenKind = ForHasEmbed ? tok::r_paren : tok::eod;
Result.ParamRange = {CurTok.getLocation(), CurTok.getLocation()};

auto DiagMismatchedBracesAndSkipToEOD =
[&](tok::TokenKind Expected,
std::pair<tok::TokenKind, SourceLocation> Matches) {
Result.ParamRange.setEnd(CurTok.getEndLoc());
Diag(CurTok, diag::err_expected) << Expected;
Diag(Matches.second, diag::note_matching) << Matches.first;
if (CurTok.isNot(tok::eod))
Expand All @@ -3638,7 +3638,6 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {

auto ExpectOrDiagAndSkipToEOD = [&](tok::TokenKind Kind) {
if (CurTok.isNot(Kind)) {
Result.ParamRange.setEnd(CurTok.getEndLoc());
Diag(CurTok, diag::err_expected) << Kind;
if (CurTok.isNot(tok::eod))
DiscardUntilEndOfDirective(CurTok);
Expand Down Expand Up @@ -3872,7 +3871,6 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
}
}
}
Result.ParamRange.setEnd(CurTok.getLocation());
return Result;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Lex/Preprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -988,7 +988,7 @@ void Preprocessor::LexTokensUntilEOF(std::vector<Token> *Tokens) {
}

/// Lex a header-name token (including one formed from header-name-tokens if
/// \p AllowConcatenation is \c true).
/// \p AllowMacroExpansion is \c true).
///
/// \param FilenameTok Filled in with the next token. On success, this will
/// be either a header_name token. On failure, it will be whatever other
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2886,6 +2886,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
break;
}
case OMPD_reverse:
case OMPD_interchange:
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,9 @@ void Sema::Initialize() {
#include "clang/Basic/OpenCLExtensionTypes.def"
}

if (Context.getTargetInfo().hasAArch64SVETypes()) {
if (Context.getTargetInfo().hasAArch64SVETypes() ||
(Context.getAuxTargetInfo() &&
Context.getAuxTargetInfo()->hasAArch64SVETypes())) {
#define SVE_TYPE(Name, Id, SingletonId) \
addImplicitTypedef(Name, Context.SingletonId);
#include "clang/Basic/AArch64SVEACLETypes.def"
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7436,10 +7436,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
tryToFixVariablyModifiedVarType(TInfo, R, D.getIdentifierLoc(),
/*DiagID=*/0);

if (const AutoType *AutoT = R->getAs<AutoType>())
CheckConstrainedAuto(
AutoT,
TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc());
if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) {
const AutoType *AT = TL.getTypePtr();
CheckConstrainedAuto(AT, TL.getConceptNameLoc());
}

bool IsMemberSpecialization = false;
bool IsVariableTemplateSpecialization = false;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaExceptionSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::OMPTileDirectiveClass:
case Stmt::OMPUnrollDirectiveClass:
case Stmt::OMPReverseDirectiveClass:
case Stmt::OMPInterchangeDirectiveClass:
case Stmt::OMPSingleDirectiveClass:
case Stmt::OMPTargetDataDirectiveClass:
case Stmt::OMPTargetDirectiveClass:
Expand Down
160 changes: 160 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
Expand Down Expand Up @@ -4406,6 +4407,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
case OMPD_tile:
case OMPD_unroll:
case OMPD_reverse:
case OMPD_interchange:
break;
default:
processCapturedRegions(SemaRef, DKind, CurScope,
Expand Down Expand Up @@ -6290,6 +6292,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
"reverse directive does not support any clauses");
Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc);
break;
case OMPD_interchange:
Res = ActOnOpenMPInterchangeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
break;
case OMPD_for:
Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc,
VarsWithInheritedDSA);
Expand Down Expand Up @@ -14048,6 +14054,8 @@ bool SemaOpenMP::checkTransformableLoopNest(
DependentPreInits = Dir->getPreInits();
else if (auto *Dir = dyn_cast<OMPReverseDirective>(Transform))
DependentPreInits = Dir->getPreInits();
else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))
DependentPreInits = Dir->getPreInits();
else
llvm_unreachable("Unhandled loop transformation");

Expand Down Expand Up @@ -14853,6 +14861,158 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt,
buildPreInits(Context, PreInits));
}

StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
ASTContext &Context = getASTContext();
DeclContext *CurContext = SemaRef.CurContext;
Scope *CurScope = SemaRef.getCurScope();

// Empty statement should only be possible if there already was an error.
if (!AStmt)
return StmtError();

// interchange without permutation clause swaps two loops.
constexpr size_t NumLoops = 2;

// Verify and diagnose loop nest.
SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
Stmt *Body = nullptr;
SmallVector<SmallVector<Stmt *, 0>, 2> OriginalInits;
if (!checkTransformableLoopNest(OMPD_interchange, AStmt, NumLoops,
LoopHelpers, Body, OriginalInits))
return StmtError();

// Delay interchange to when template is completely instantiated.
if (CurContext->isDependentContext())
return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, nullptr, nullptr);

assert(LoopHelpers.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of "
"affected loops");
assert(OriginalInits.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of "
"affected loops");

// Decode the permutation clause.
constexpr uint64_t Permutation[] = {1, 0};

// Find the affected loops.
SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
collectLoopStmts(AStmt, LoopStmts);

// Collect pre-init statements on the order before the permuation.
SmallVector<Stmt *> PreInits;
for (auto I : llvm::seq<int>(NumLoops)) {
OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];

assert(LoopHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");
auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters.front());

std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
PreInits);
}

SmallVector<VarDecl *> PermutedIndVars(NumLoops);
CaptureVars CopyTransformer(SemaRef);

// Create the permuted loops from the inside to the outside of the
// interchanged loop nest. Body of the innermost new loop is the original
// innermost body.
Stmt *Inner = Body;
for (auto TargetIdx : llvm::reverse(llvm::seq<int>(NumLoops))) {
// Get the original loop that belongs to this new position.
uint64_t SourceIdx = Permutation[TargetIdx];
OMPLoopBasedDirective::HelperExprs &SourceHelper = LoopHelpers[SourceIdx];
Stmt *SourceLoopStmt = LoopStmts[SourceIdx];
assert(SourceHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");
auto *OrigCntVar = cast<DeclRefExpr>(SourceHelper.Counters.front());

// Normalized loop counter variable: From 0 to n-1, always an integer type.
DeclRefExpr *IterVarRef = cast<DeclRefExpr>(SourceHelper.IterationVarRef);
QualType IVTy = IterVarRef->getType();
assert(IVTy->isIntegerType() &&
"Expected the logical iteration counter to be an integer");

std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
SourceLocation OrigVarLoc = IterVarRef->getExprLoc();

// Make a copy of the NumIterations expression for each use: By the AST
// constraints, every expression object in a DeclContext must be unique.
auto MakeNumIterations = [&CopyTransformer, &SourceHelper]() -> Expr * {
return AssertSuccess(
CopyTransformer.TransformExpr(SourceHelper.NumIterations));
};

// Iteration variable for the permuted loop. Reuse the one from
// checkOpenMPLoop which will also be used to update the original loop
// variable.
SmallString<64> PermutedCntName(".permuted_");
PermutedCntName.append({llvm::utostr(TargetIdx), ".iv.", OrigVarName});
auto *PermutedCntDecl = cast<VarDecl>(IterVarRef->getDecl());
PermutedCntDecl->setDeclName(
&SemaRef.PP.getIdentifierTable().get(PermutedCntName));
PermutedIndVars[TargetIdx] = PermutedCntDecl;
auto MakePermutedRef = [this, PermutedCntDecl, IVTy, OrigVarLoc]() {
return buildDeclRefExpr(SemaRef, PermutedCntDecl, IVTy, OrigVarLoc);
};

// For init-statement:
// \code
// auto .permuted_{target}.iv = 0
// \endcode
ExprResult Zero = SemaRef.ActOnIntegerConstant(OrigVarLoc, 0);
if (!Zero.isUsable())
return StmtError();
SemaRef.AddInitializerToDecl(PermutedCntDecl, Zero.get(),
/*DirectInit=*/false);
StmtResult InitStmt = new (Context)
DeclStmt(DeclGroupRef(PermutedCntDecl), OrigCntVar->getBeginLoc(),
OrigCntVar->getEndLoc());
if (!InitStmt.isUsable())
return StmtError();

// For cond-expression:
// \code
// .permuted_{target}.iv < MakeNumIterations()
// \endcode
ExprResult CondExpr =
SemaRef.BuildBinOp(CurScope, SourceHelper.Cond->getExprLoc(), BO_LT,
MakePermutedRef(), MakeNumIterations());
if (!CondExpr.isUsable())
return StmtError();

// For incr-statement:
// \code
// ++.tile.iv
// \endcode
ExprResult IncrStmt = SemaRef.BuildUnaryOp(
CurScope, SourceHelper.Inc->getExprLoc(), UO_PreInc, MakePermutedRef());
if (!IncrStmt.isUsable())
return StmtError();

SmallVector<Stmt *, 4> BodyParts(SourceHelper.Updates.begin(),
SourceHelper.Updates.end());
if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(SourceLoopStmt))
BodyParts.push_back(SourceCXXFor->getLoopVarStmt());
BodyParts.push_back(Inner);
Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(),
Inner->getBeginLoc(), Inner->getEndLoc());
Inner = new (Context) ForStmt(
Context, InitStmt.get(), CondExpr.get(), nullptr, IncrStmt.get(), Inner,
SourceHelper.Init->getBeginLoc(), SourceHelper.Init->getBeginLoc(),
SourceHelper.Inc->getEndLoc());
}

return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, Inner,
buildPreInits(Context, PreInits));
}

OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
SourceLocation StartLoc,
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6229,7 +6229,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
getTrivialTemplateArgumentLoc(UnpackedArg, QualType(), Loc));
}
QualType T = CheckTemplateIdType(TemplateName(TD), Loc, Args);
if (T.isNull())
// We may get a non-null type with errors, in which case
// `getAsCXXRecordDecl` will return `nullptr`. For instance, this
// happens when one of the template arguments is an invalid
// expression. We return early to avoid triggering the assertion
// about the `CodeSynthesisContext`.
if (T.isNull() || T->containsErrors())
return nullptr;
CXXRecordDecl *SubstRecord = T->getAsCXXRecordDecl();

Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6363,11 +6363,10 @@ TypeResult Sema::ActOnTypeName(Declarator &D) {
CheckExtraCXXDefaultArguments(D);
}

if (const AutoType *AutoT = T->getAs<AutoType>())
CheckConstrainedAuto(
AutoT,
TInfo->getTypeLoc().getContainedAutoTypeLoc().getConceptNameLoc());

if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) {
const AutoType *AT = TL.getTypePtr();
CheckConstrainedAuto(AT, TL.getConceptNameLoc());
}
return CreateParsedType(T, TInfo);
}

Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9250,6 +9250,17 @@ TreeTransform<Derived>::TransformOMPReverseDirective(OMPReverseDirective *D) {
return Res;
}

template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPInterchangeDirective(
OMPInterchangeDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().OpenMP().StartOpenMPDSABlock(
D->getDirectiveKind(), DirName, nullptr, D->getBeginLoc());
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
getDerived().getSema().OpenMP().EndOpenMPDSABlock(Res.get());
return Res;
}

template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9875,6 +9875,7 @@ void ASTReader::finishPendingActions() {
// We only perform ODR checks for decls not in the explicit
// global module fragment.
!shouldSkipCheckingODR(FD) &&
!shouldSkipCheckingODR(NonConstDefn) &&
FD->getODRHash() != NonConstDefn->getODRHash()) {
if (!isa<CXXMethodDecl>(FD)) {
PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
Reader.mergeDefinitionVisibility(OldDef, ED);
// We don't want to check the ODR hash value for declarations from global
// module fragment.
if (!shouldSkipCheckingODR(ED) &&
if (!shouldSkipCheckingODR(ED) && !shouldSkipCheckingODR(OldDef) &&
OldDef->getODRHash() != ED->getODRHash())
Reader.PendingEnumOdrMergeFailures[OldDef].push_back(ED);
} else {
Expand Down Expand Up @@ -2134,7 +2134,7 @@ void ASTDeclReader::MergeDefinitionData(
}

// We don't want to check ODR for decls in the global module fragment.
if (shouldSkipCheckingODR(MergeDD.Definition))
if (shouldSkipCheckingODR(MergeDD.Definition) || shouldSkipCheckingODR(D))
return;

if (D->getODRHash() != MergeDD.ODRHash) {
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,10 @@ void ASTStmtReader::VisitOMPReverseDirective(OMPReverseDirective *D) {
VisitOMPLoopTransformationDirective(D);
}

void ASTStmtReader::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
VisitOMPLoopTransformationDirective(D);
}

void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) {
VisitOMPLoopDirective(D);
D->setHasCancel(Record.readBool());
Expand Down Expand Up @@ -3477,6 +3481,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}

case STMT_OMP_INTERCHANGE_DIRECTIVE: {
unsigned NumLoops = Record[ASTStmtReader::NumStmtFields];
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
S = OMPInterchangeDirective::CreateEmpty(Context, NumClauses, NumLoops);
break;
}

case STMT_OMP_FOR_DIRECTIVE: {
unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields];
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2442,6 +2442,11 @@ void ASTStmtWriter::VisitOMPReverseDirective(OMPReverseDirective *D) {
Code = serialization::STMT_OMP_REVERSE_DIRECTIVE;
}

void ASTStmtWriter::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
VisitOMPLoopTransformationDirective(D);
Code = serialization::STMT_OMP_INTERCHANGE_DIRECTIVE;
}

void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) {
VisitOMPLoopDirective(D);
Record.writeBool(D->hasCancel());
Expand Down
1 change: 1 addition & 0 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1813,6 +1813,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
case Stmt::OMPReverseDirectiveClass:
case Stmt::OMPTileDirectiveClass:
case Stmt::OMPInterchangeDirectiveClass:
case Stmt::OMPInteropDirectiveClass:
case Stmt::OMPDispatchDirectiveClass:
case Stmt::OMPMaskedDirectiveClass:
Expand Down
94 changes: 92 additions & 2 deletions clang/test/AST/Interp/cxx11.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s
// RUN: %clang_cc1 -verify=both,ref -std=c++11 %s
// RUN: %clang_cc1 -triple x86_64-linux -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s
// RUN: %clang_cc1 -triple x86_64-linux -verify=both,ref -std=c++11 %s

namespace IntOrEnum {
const int k = 0;
Expand Down Expand Up @@ -62,3 +62,93 @@ namespace ReferenceToConst {
}
};
}



namespace GH50055 {
// Enums without fixed underlying type
enum E1 {e11=-4, e12=4};
enum E2 {e21=0, e22=4};
enum E3 {e31=-4, e32=1024};
enum E4 {e41=0};
// Empty but as-if it had a single enumerator with value 0
enum EEmpty {};

// Enum with fixed underlying type because the underlying type is explicitly specified
enum EFixed : int {efixed1=-4, efixed2=4};
// Enum with fixed underlying type because it is scoped
enum class EScoped {escoped1=-4, escoped2=4};

enum EMaxInt {emaxint1=-1, emaxint2=__INT_MAX__};

enum NumberType {};

E2 testDefaultArgForParam(E2 e2Param = (E2)-1) { // ok, not a constant expression context
E2 e2LocalInit = e2Param; // ok, not a constant expression context
return e2LocalInit;
}

// #include <enum-constexpr-conversion-system-header.h>

void testValueInRangeOfEnumerationValues() {
constexpr E1 x1 = static_cast<E1>(-8);
constexpr E1 x2 = static_cast<E1>(8);
// both-error@-1 {{integer value 8 is outside the valid range of values [-8, 7] for the enumeration type 'E1'}}
E1 x2b = static_cast<E1>(8); // ok, not a constant expression context

constexpr E2 x3 = static_cast<E2>(-8);
// both-error@-1 {{integer value -8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
constexpr E2 x4 = static_cast<E2>(0);
constexpr E2 x5 = static_cast<E2>(8);
// both-error@-1 {{integer value 8 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}

constexpr E3 x6 = static_cast<E3>(-2048);
constexpr E3 x7 = static_cast<E3>(-8);
constexpr E3 x8 = static_cast<E3>(0);
constexpr E3 x9 = static_cast<E3>(8);
constexpr E3 x10 = static_cast<E3>(2048);
// both-error@-1 {{integer value 2048 is outside the valid range of values [-2048, 2047] for the enumeration type 'E3'}}

constexpr E4 x11 = static_cast<E4>(0);
constexpr E4 x12 = static_cast<E4>(1);
constexpr E4 x13 = static_cast<E4>(2);
// both-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'E4'}}

constexpr EEmpty x14 = static_cast<EEmpty>(0);
constexpr EEmpty x15 = static_cast<EEmpty>(1);
constexpr EEmpty x16 = static_cast<EEmpty>(2);
// both-error@-1 {{integer value 2 is outside the valid range of values [0, 1] for the enumeration type 'EEmpty'}}

constexpr EFixed x17 = static_cast<EFixed>(100);
constexpr EScoped x18 = static_cast<EScoped>(100);

constexpr EMaxInt x19 = static_cast<EMaxInt>(__INT_MAX__-1);
constexpr EMaxInt x20 = static_cast<EMaxInt>((long)__INT_MAX__+1);
// both-error@-1 {{integer value 2147483648 is outside the valid range of values [-2147483648, 2147483647] for the enumeration type 'EMaxInt'}}

const NumberType neg_one = (NumberType) ((NumberType) 0 - (NumberType) 1); // ok, not a constant expression context
}

template<class T, unsigned size> struct Bitfield {
static constexpr T max = static_cast<T>((1 << size) - 1); // #enum
};

void testValueInRangeOfEnumerationValuesViaTemplate() {
Bitfield<E2, 3> good;
Bitfield<E2, 4> bad; // both-error@#enum {{integer value 15 is outside the valid range of values [0, 7] for the enumeration type 'E2'}}
}

enum SortOrder {
AscendingOrder,
DescendingOrder
};

class A {
static void f(SortOrder order);
};

void A::f(SortOrder order) {
if (order == SortOrder(-1)) // ok, not a constant expression context
return;
}
}
15 changes: 15 additions & 0 deletions clang/test/AST/Interp/cxx2a.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=ref,both %s
// RUN: %clang_cc1 -std=c++2a -fsyntax-only -fcxx-exceptions -verify=expected,both %s -fexperimental-new-constant-interpreter

template <unsigned N>
struct S {
S() requires (N==1) = default;
S() requires (N==2) {} // both-note {{declared here}}
consteval S() requires (N==3) = default;
};

consteval int aConstevalFunction() { // both-error {{consteval function never produces a constant expression}}
S<2> s4; // both-note {{non-constexpr constructor 'S' cannot be used in a constant expression}}
return 0;
}
/// We're NOT calling the above function. The diagnostics should appear anyway.
73 changes: 73 additions & 0 deletions clang/test/AST/Interp/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,80 @@ constexpr Sp ss[] = {Sp{new int{154}}}; // both-error {{must be initialized by a
// both-note {{pointer to heap-allocated object}} \
// both-note {{allocation performed here}}

namespace DeleteRunsDtors {
struct InnerFoo {
int *mem;
constexpr ~InnerFoo() {
delete mem;
}
};

struct Foo {
int *a;
InnerFoo IF;

constexpr Foo() {
a = new int(13);
IF.mem = new int(100);
}
constexpr ~Foo() { delete a; }
};

constexpr int abc() {
Foo *F = new Foo();
int n = *F->a;
delete F;

return n;
}
static_assert(abc() == 13);

constexpr int abc2() {
Foo *f = new Foo[3];

delete[] f;

return 1;
}
static_assert(abc2() == 1);
}

/// FIXME: There is a slight difference in diagnostics here, because we don't
/// create a new frame when we delete record fields or bases at all.
namespace FaultyDtorCalledByDelete {
struct InnerFoo {
int *mem;
constexpr ~InnerFoo() {
if (mem) {
(void)(1/0); // both-warning {{division by zero is undefined}} \
// both-note {{division by zero}}
}
delete mem;
}
};

struct Foo {
int *a;
InnerFoo IF;

constexpr Foo() {
a = new int(13);
IF.mem = new int(100);
}
constexpr ~Foo() { delete a; }
};

constexpr int abc() {
Foo *F = new Foo();
int n = *F->a;
delete F; // both-note {{in call to}} \
// ref-note {{in call to}}

return n;
}
static_assert(abc() == 13); // both-error {{not an integral constant expression}} \
// both-note {{in call to 'abc()'}}
}


#else
Expand Down
9 changes: 9 additions & 0 deletions clang/test/CXX/drs/cwg24xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ auto h() -> C auto {
C auto foo = T();
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
C auto *bar = T();
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
C auto &baz = T();
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
C auto &&quux = T();
// expected-warning@-1 {{'C' is deprecated}}
// expected-note@#cwg2428-C {{'C' has been explicitly marked deprecated here}}
return foo;
}
#endif
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CodeGen/SystemZ/systemz-abi.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,29 @@ union union_double pass_union_double(union union_double arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_union_double(ptr dead_on_unwind noalias writable sret(%union.union_double) align 8 %{{.*}}, i64 %{{.*}})


// Verify that transparent unions are passed like their first member (but returned like a union)

union tu_char { char a; } __attribute__((transparent_union));
union tu_char pass_tu_char(union tu_char arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_tu_char(ptr dead_on_unwind noalias writable sret(%union.tu_char) align 1 %{{.*}}, i8 signext %{{.*}})

union tu_short { short a; } __attribute__((transparent_union));
union tu_short pass_tu_short(union tu_short arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_tu_short(ptr dead_on_unwind noalias writable sret(%union.tu_short) align 2 %{{.*}}, i16 signext %{{.*}})

union tu_int { int a; } __attribute__((transparent_union));
union tu_int pass_tu_int(union tu_int arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_tu_int(ptr dead_on_unwind noalias writable sret(%union.tu_int) align 4 %{{.*}}, i32 signext %{{.*}})

union tu_long { long a; } __attribute__((transparent_union));
union tu_long pass_tu_long(union tu_long arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_tu_long(ptr dead_on_unwind noalias writable sret(%union.tu_long) align 8 %{{.*}}, i64 %{{.*}})

union tu_ptr { void *a; } __attribute__((transparent_union));
union tu_ptr pass_tu_ptr(union tu_ptr arg) { return arg; }
// CHECK-LABEL: define{{.*}} void @pass_tu_ptr(ptr dead_on_unwind noalias writable sret(%union.tu_ptr) align 8 %{{.*}}, ptr %{{.*}})


// Accessing variable argument lists

int va_int(__builtin_va_list l) { return __builtin_va_arg(l, int); }
Expand Down
111 changes: 111 additions & 0 deletions clang/test/CodeGen/aarch64-fmv-resolver-emission.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s

// CHECK: @used_before_default_def = weak_odr ifunc void (), ptr @used_before_default_def.resolver
// CHECK: @used_after_default_def = weak_odr ifunc void (), ptr @used_after_default_def.resolver
// CHECK-NOT: @used_before_default_decl = weak_odr ifunc void (), ptr @used_before_default_decl.resolver
// CHECK-NOT: @used_after_default_decl = weak_odr ifunc void (), ptr @used_after_default_decl.resolver
// CHECK-NOT: @used_no_default = weak_odr ifunc void (), ptr @used_no_default.resolver
// CHECK-NOT: @not_used_no_default = weak_odr ifunc void (), ptr @not_used_no_default.resolver
// CHECK: @not_used_with_default = weak_odr ifunc void (), ptr @not_used_with_default.resolver


// Test that an ifunc is generated and used when the default
// version is defined after the first use of the function.
//
__attribute__((target_version("aes"))) void used_before_default_def(void) {}
// CHECK-LABEL: define dso_local void @used_before_default_def._Maes(
//
void call_before_def(void) { used_before_default_def(); }
// CHECK-LABEL: define dso_local void @call_before_def(
// CHECK: call void @used_before_default_def()
//
__attribute__((target_version("default"))) void used_before_default_def(void) {}
// CHECK-LABEL: define dso_local void @used_before_default_def.default(
//
// CHECK-NOT: declare void @used_before_default_def(


// Test that an ifunc is generated and used when the default
// version is defined before the first use of the function.
//
__attribute__((target_version("aes"))) void used_after_default_def(void) {}
// CHECK-LABEL: define dso_local void @used_after_default_def._Maes(
//
__attribute__((target_version("default"))) void used_after_default_def(void) {}
// CHECK-LABEL: define dso_local void @used_after_default_def.default(
//
void call_after_def(void) { used_after_default_def(); }
// CHECK-LABEL: define dso_local void @call_after_def(
// CHECK: call void @used_after_default_def()
//
// CHECK-NOT: declare void @used_after_default_def(


// Test that an unmagled declaration is generated and used when the
// default version is declared after the first use of the function.
//
__attribute__((target_version("aes"))) void used_before_default_decl(void) {}
// CHECK-LABEL: define dso_local void @used_before_default_decl._Maes(
//
void call_before_decl(void) { used_before_default_decl(); }
// CHECK-LABEL: define dso_local void @call_before_decl(
// CHECK: call void @used_before_default_decl()
//
__attribute__((target_version("default"))) void used_before_default_decl(void);
// CHECK: declare void @used_before_default_decl()


// Test that an unmagled declaration is generated and used when the
// default version is declared before the first use of the function.
//
__attribute__((target_version("aes"))) void used_after_default_decl(void) {}
// CHECK-LABEL: define dso_local void @used_after_default_decl._Maes(
//
__attribute__((target_version("default"))) void used_after_default_decl(void);
// CHECK: declare void @used_after_default_decl()
//
void call_after_decl(void) { used_after_default_decl(); }
// CHECK-LABEL: define dso_local void @call_after_decl(
// CHECK: call void @used_after_default_decl()


// Test that an unmagled declaration is generated and used when
// the default version is not present.
//
__attribute__((target_version("aes"))) void used_no_default(void) {}
// CHECK-LABEL: define dso_local void @used_no_default._Maes(
//
void call_no_default(void) { used_no_default(); }
// CHECK-LABEL: define dso_local void @call_no_default(
// CHECK: call void @used_no_default()
//
// CHECK: declare void @used_no_default()


// Test that neither an ifunc nor a declaration is generated if the default
// definition is missing since the versioned function is not used.
//
__attribute__((target_version("aes"))) void not_used_no_default(void) {}
// CHECK-LABEL: define dso_local void @not_used_no_default._Maes(
//
// CHECK-NOT: declare void @not_used_no_default(


// Test that an ifunc is generated if the default version is defined but not used.
//
__attribute__((target_version("aes"))) void not_used_with_default(void) {}
// CHECK-LABEL: define dso_local void @not_used_with_default._Maes(
//
__attribute__((target_version("default"))) void not_used_with_default(void) {}
// CHECK-LABEL: define dso_local void @not_used_with_default.default(
//
// CHECK-NOT: declare void @not_used_with_default(


// CHECK: define weak_odr ptr @used_before_default_def.resolver()
// CHECK: define weak_odr ptr @used_after_default_def.resolver()
// CHECK-NOT: define weak_odr ptr @used_before_default_decl.resolver(
// CHECK-NOT: define weak_odr ptr @used_after_default_decl.resolver(
// CHECK-NOT: define weak_odr ptr @used_no_default.resolver(
// CHECK-NOT: define weak_odr ptr @not_used_no_default.resolver(
// CHECK: define weak_odr ptr @not_used_with_default.resolver()
6 changes: 3 additions & 3 deletions clang/test/CodeGen/aarch64-mixed-target-attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,9 @@ __attribute__((target_version("jscvt"))) int default_def_with_version_decls(void
// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+rdm,-v9.5a" }
// CHECK: attributes #[[ATTR5:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod,+fp-armv8,+neon,-v9.5a" }
// CHECK: attributes #[[ATTR6:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" }
// CHECK: attributes #[[ATTR7:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" }
// CHECK: attributes #[[ATTR8:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
// CHECK: attributes #[[ATTR6:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" }
// CHECK: attributes #[[ATTR7:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" }
// CHECK: attributes #[[ATTR8:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" }
//.
// CHECK-NOFMV: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" }
//.
Expand Down
54 changes: 54 additions & 0 deletions clang/test/CodeGen/attr-counted-by.c
Original file line number Diff line number Diff line change
Expand Up @@ -1852,3 +1852,57 @@ struct annotated_struct_array {
void test29(struct annotated_struct_array *ann, int idx1, int idx2) {
ann->ann_array[idx1]->array[idx2] = __builtin_dynamic_object_size(ann->ann_array[idx1]->array, 1);
}

typedef struct {
char __padding[0];
} test30_spinlock_t;

struct test30_struct {
struct test30_decl *name_node;
int priv_len;
test30_spinlock_t pcpu_refcnt;
char priv[] __counted_by(priv_len);
};

// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] {
// SANITIZE-WITH-ATTR-NEXT: entry:
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB39:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]]
// SANITIZE-WITH-ATTR-NEXT: unreachable, !nosanitize [[META2]]
//
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 8
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 4)
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], 12
// NO-SANITIZE-WITH-ATTR-NEXT: [[CONV:%.*]] = select i1 [[DOTINV]], i8 0, i8 [[TMP2]]
// NO-SANITIZE-WITH-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 12
// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
// NO-SANITIZE-WITH-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[PCPU_REFCNT]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITH-ATTR-NEXT: store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
// NO-SANITIZE-WITH-ATTR-NEXT: ret void
//
// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
// SANITIZE-WITHOUT-ATTR-NEXT: entry:
// SANITIZE-WITHOUT-ATTR-NEXT: [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP0]]) #[[ATTR8]], !nosanitize [[META9]]
// SANITIZE-WITHOUT-ATTR-NEXT: unreachable, !nosanitize [[META9]]
//
// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry:
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[PCPU_REFCNT:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 12
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
// NO-SANITIZE-WITHOUT-ATTR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[PCPU_REFCNT]], i64 0, i64 [[IDXPROM]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret void
//
void test30(struct test30_struct *ptr, int idx) {
ptr->pcpu_refcnt.__padding[idx] = __builtin_dynamic_object_size(ptr, 1);
}
348 changes: 174 additions & 174 deletions clang/test/CodeGen/attr-target-clones-aarch64.c

Large diffs are not rendered by default.

818 changes: 407 additions & 411 deletions clang/test/CodeGen/attr-target-version.c

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions clang/test/CodeGen/math-libcalls-tbaa.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ extern "C" float expf(float);
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]]
// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
// CHECK-NEXT: [[MUL:%.*]] = fmul float [[CALL]], [[TMP1]]
// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA6:![0-9]+]]
// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]]
// CHECK-NEXT: ret float [[MUL]]
//
extern "C" float foo (float num[], float r2inv, int n) {
Expand All @@ -27,11 +26,15 @@ extern "C" float foo (float num[], float r2inv, int n) {
// NoNewStructPathTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0}
// NoNewStructPathTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
// NoNewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"}
// NoNewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0}
// NoNewStructPathTBAA: [[META7]] = !{!"int", [[META4]], i64 0}
//.
// NewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4}
// NewStructPathTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"}
// NewStructPathTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"}
// NewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"}
// NewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4}
// NewStructPathTBAA: [[META7]] = !{[[META4]], i64 4, !"int"}
//.
//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
// NewStructPathTBAA: {{.*}}
Expand Down
70 changes: 70 additions & 0 deletions clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- -fptrauth-function-pointer-type-discrimination | FileCheck -check-prefixes CHECK,TYPE %s
// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- -fptrauth-function-pointer-type-discrimination | FileCheck -check-prefixes CHECK,TYPE %s
// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck -check-prefixes CHECK,ZERO %s
// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck -check-prefixes CHECK,ZERO %s

typedef void (*fptr_t)(void);

char *cptr;
void (*fptr)(void);

// CHECK-LABEL: define{{.*}} void @test1
void test1() {
// TYPE: [[LOAD:%.*]] = load ptr, ptr @cptr
// TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64
// TYPE: call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 0, i32 0, i64 18983)
// TYPE: call void {{.*}}() [ "ptrauth"(i32 0, i64 18983) ]
// ZERO-NOT: @llvm.ptrauth.resign

(*(fptr_t)cptr)();
}

// CHECK-LABEL: define{{.*}} i8 @test2
char test2() {
return *(char *)fptr;

// TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
// TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
// TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]]

// TYPE: [[NONNULL]]:
// TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64
// TYPE: [[CALL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 18983, i32 0, i64 0)
// TYPE: [[TOPTR:%.*]] = inttoptr i64 [[CALL]] to ptr

// TYPE: [[CONT]]:
// TYPE: phi ptr [ null, {{.*}} ], [ [[TOPTR]], %[[NONNULL]] ]
// ZERO-NOT: @llvm.ptrauth.resign
}

// CHECK-LABEL: define{{.*}} void @test4
void test4() {
(*((fptr_t)(&*((char *)(&*(fptr_t)cptr)))))();

// CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr
// TYPE-NEXT: [[CAST4:%.*]] = ptrtoint ptr [[LOAD]] to i64
// TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 0, i64 0, i32 0, i64 18983)
// TYPE-NEXT: [[CAST5:%.*]] = inttoptr i64 [[RESIGN]] to ptr
// TYPE-NEXT: call void [[CAST5]]() [ "ptrauth"(i32 0, i64 18983) ]
// ZERO-NOT: @llvm.ptrauth.resign
// ZERO: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ]
}

void *vptr;
// CHECK-LABEL: define{{.*}} void @test5
void test5() {
vptr = &*(char *)fptr;

// TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
// TYPE-NEXT: [[CMP]] = icmp ne ptr [[LOAD]], null
// TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]]

// TYPE: [[NONNULL]]:
// TYPE: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 0)
// TYPE: [[CAST:%.*]] = inttoptr i64 [[RESIGN]] to ptr

// TYPE: [[CONT]]:
// TYPE: [[PHI:%.*]] = phi ptr [ null, {{.*}} ], [ [[CAST]], %[[NONNULL]] ]
// TYPE: store ptr [[PHI]], ptr @vptr
// ZERO-NOT: @llvm.ptrauth.resign
}
108 changes: 108 additions & 0 deletions clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,TYPE

// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,TYPE

// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,ZERO

// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,ZERO

// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -xc++ -o- | FileCheck %s --check-prefixes=CHECK,CHECKCXX,TYPE,TYPECXX

// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -xc++ -o- | FileCheck %s --check-prefixes=CHECK,CHECKCXX,TYPE,TYPECXX

#ifdef __cplusplus
extern "C" {
#endif

void f(void);
void f2(int);
void (*fptr)(void);
void *opaque;
unsigned long uintptr;

#ifdef __cplusplus
struct ptr_member {
void (*fptr_)(int) = 0;
};
ptr_member pm;
void (*test_member)() = (void (*)())pm.fptr_;

// CHECKCXX-LABEL: define{{.*}} internal void @__cxx_global_var_init
// TYPECXX: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 2712, i32 0, i64 18983)
#endif


// CHECK-LABEL: define{{.*}} void @test_cast_to_opaque
void test_cast_to_opaque() {
opaque = (void *)f;

// TYPE: [[RESIGN_VAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 0)
// TYPE: [[RESIGN_PTR:%.*]] = inttoptr i64 [[RESIGN_VAL]] to ptr
// ZERO-NOT: @llvm.ptrauth.resign
}

// CHECK-LABEL: define{{.*}} void @test_cast_from_opaque
void test_cast_from_opaque() {
fptr = (void (*)(void))opaque;

// TYPE: [[LOAD:%.*]] = load ptr, ptr @opaque
// TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
// TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label

// TYPE: [[RESIGN_LAB]]:
// TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64
// TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 0, i32 0, i64 18983)

// ZERO-NOT: @llvm.ptrauth.resign
}

// CHECK-LABEL: define{{.*}} void @test_cast_to_intptr
void test_cast_to_intptr() {
uintptr = (unsigned long)fptr;

// TYPE: [[ENTRY:.*]]:
// TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr
// TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null
// TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label %[[RESIGN_CONT:.*]]

// TYPE: [[RESIGN_LAB]]:
// TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64
// TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 18983, i32 0, i64 0)
// TYPE: [[RESIGN:%.*]] = inttoptr i64 [[RESIGN_INT]] to ptr
// TYPE: br label %[[RESIGN_CONT]]

// TYPE: [[RESIGN_CONT]]:
// TYPE: phi ptr [ null, %[[ENTRY]] ], [ [[RESIGN]], %[[RESIGN_LAB]] ]

// ZERO-NOT: @llvm.ptrauth.resign
}

// CHECK-LABEL: define{{.*}} void @test_function_to_function_cast
void test_function_to_function_cast() {
void (*fptr2)(int) = (void (*)(int))fptr;
// TYPE: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 2712)
// ZERO-NOT: @llvm.ptrauth.resign
}

// CHECK-LABEL: define{{.*}} void @test_call_lvalue_cast
void test_call_lvalue_cast() {
(*(void (*)(int))f)(42);

// TYPE: entry:
// TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 2712)
// TYPE-NEXT: [[RESIGN_INT:%.*]] = inttoptr i64 [[RESIGN]] to ptr
// TYPE-NEXT: call void [[RESIGN_INT]](i32 noundef 42) [ "ptrauth"(i32 0, i64 2712) ]
// ZERO-NOT: @llvm.ptrauth.resign
// ZERO: call void ptrauth (ptr @f, i32 0)(i32 noundef 42) [ "ptrauth"(i32 0, i64 0) ]
}


#ifdef __cplusplus
}
#endif
33 changes: 22 additions & 11 deletions clang/test/CodeGen/ptrauth-function-type-discriminator.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefix=CHECK --check-prefix=CHECKC
// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefix=CHECK
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -x ast -o - %t.ast | FileCheck -check-prefix=CHECK --check-prefix=CHECKC %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s

// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm %s -o- | FileCheck --check-prefixes=CHECK,CHECKC %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -disable-llvm-passes -emit-llvm -xc++ %s -o- | FileCheck --check-prefix=CHECK %s
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-pch %s -o %t.ast
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -emit-llvm -x ast -o - %t.ast | FileCheck --check-prefixes=CHECK,CHECKC %s

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -47,29 +58,29 @@ void (*fptr3)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, 26)
// CHECK: @fptr4 = global ptr ptrauth (ptr @external_function, i32 2, i64 26, ptr @fptr4)
void (*fptr4)(void) = __builtin_ptrauth_sign_constant(&external_function, 2, __builtin_ptrauth_blend_discriminator(&fptr4, 26));

// CHECK-LABEL: define void @test_call()
// CHECK-LABEL: define{{.*}} void @test_call()
void test_call() {
// CHECK: [[T0:%.*]] = load ptr, ptr @fnptr,
// CHECK-NEXT: call void [[T0]]() [ "ptrauth"(i32 0, i64 18983) ]
fnptr();
}

// CHECK-LABEL: define ptr @test_function_pointer()
// CHECK-LABEL: define{{.*}} ptr @test_function_pointer()
// CHECK: ret ptr ptrauth (ptr @external_function, i32 0, i64 18983)
void (*test_function_pointer())(void) {
return external_function;
}

struct InitiallyIncomplete;
extern struct InitiallyIncomplete returns_initially_incomplete(void);
// CHECK-LABEL: define void @use_while_incomplete()
// CHECK-LABEL: define{{.*}} void @use_while_incomplete()
void use_while_incomplete() {
// CHECK: [[VAR:%.*]] = alloca ptr,
// CHECK-NEXT: store ptr ptrauth (ptr @returns_initially_incomplete, i32 0, i64 25106), ptr [[VAR]]
struct InitiallyIncomplete (*fnptr)(void) = &returns_initially_incomplete;
}
struct InitiallyIncomplete { int x; };
// CHECK-LABEL: define void @use_while_complete()
// CHECK-LABEL: define{{.*}} void @use_while_complete()
void use_while_complete() {
// CHECK: [[VAR:%.*]] = alloca ptr,
// CHECK-NEXT: store ptr ptrauth (ptr @returns_initially_incomplete, i32 0, i64 25106), ptr [[VAR]]
Expand All @@ -83,7 +94,7 @@ void knr(param)
int param;
{}

// CHECKC-LABEL: define void @test_knr
// CHECKC-LABEL: define{{.*}} void @test_knr
void test_knr() {
void (*p)() = knr;
p(0);
Expand All @@ -94,7 +105,7 @@ void test_knr() {
// CHECKC: call void [[LOAD]](i32 noundef 0) [ "ptrauth"(i32 0, i64 18983) ]
}

// CHECKC-LABEL: define void @test_redeclaration
// CHECKC-LABEL: define{{.*}} void @test_redeclaration
void test_redeclaration() {
void redecl();
void (*ptr)() = redecl;
Expand All @@ -113,7 +124,7 @@ void knr2(param)
int param;
{}

// CHECKC-LABEL: define void @test_redecl_knr
// CHECKC-LABEL: define{{.*}} void @test_redecl_knr
void test_redecl_knr() {
void (*p)() = knr2;
p();
Expand Down
3 changes: 3 additions & 0 deletions clang/test/CodeGen/ptrauth-ubsan-vptr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -triple arm64e-apple-ios15 -fsanitize=vptr -O0 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple arm64e-apple-ios15 -fsanitize=vptr -O2 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s

// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsanitize=vptr -O0 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsanitize=vptr -O2 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s

struct S {
S() {}
~S() {}
Expand Down
111 changes: 111 additions & 0 deletions clang/test/CodeGenCXX/aarch64-fmv-resolver-emission.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s

// CHECK: @_Z23used_before_default_defv = weak_odr ifunc void (), ptr @_Z23used_before_default_defv.resolver
// CHECK: @_Z22used_after_default_defv = weak_odr ifunc void (), ptr @_Z22used_after_default_defv.resolver
// CHECK-NOT: @_Z24used_before_default_declv = weak_odr ifunc void (), ptr @_Z24used_before_default_declv.resolver
// CHECK-NOT: @_Z23used_after_default_declv = weak_odr ifunc void (), ptr @_Z23used_after_default_declv.resolver
// CHECK-NOT: @_Z15used_no_defaultv = weak_odr ifunc void (), ptr @_Z15used_no_defaultv.resolver
// CHECK-NOT: @_Z19not_used_no_defaultv = weak_odr ifunc void (), ptr @_Z19not_used_no_defaultv.resolver
// CHECK: @_Z21not_used_with_defaultv = weak_odr ifunc void (), ptr @_Z21not_used_with_defaultv.resolver


// Test that an ifunc is generated and used when the default
// version is defined after the first use of the function.
//
__attribute__((target_version("aes"))) void used_before_default_def(void) {}
// CHECK-LABEL: define dso_local void @_Z23used_before_default_defv._Maes(
//
void call_before_def(void) { used_before_default_def(); }
// CHECK-LABEL: define dso_local void @_Z15call_before_defv(
// CHECK: call void @_Z23used_before_default_defv()
//
__attribute__((target_version("default"))) void used_before_default_def(void) {}
// CHECK-LABEL: define dso_local void @_Z23used_before_default_defv.default(
//
// CHECK-NOT: declare void @_Z23used_before_default_defv(


// Test that an ifunc is generated and used when the default
// version is defined before the first use of the function.
//
__attribute__((target_version("aes"))) void used_after_default_def(void) {}
// CHECK-LABEL: define dso_local void @_Z22used_after_default_defv._Maes(
//
__attribute__((target_version("default"))) void used_after_default_def(void) {}
// CHECK-LABEL: define dso_local void @_Z22used_after_default_defv.default(
//
void call_after_def(void) { used_after_default_def(); }
// CHECK-LABEL: define dso_local void @_Z14call_after_defv(
// CHECK: call void @_Z22used_after_default_defv()
//
// CHECK-NOT: declare void @_Z22used_after_default_defv(


// Test that an unmagled declaration is generated and used when the
// default version is declared after the first use of the function.
//
__attribute__((target_version("aes"))) void used_before_default_decl(void) {}
// CHECK-LABEL: define dso_local void @_Z24used_before_default_declv._Maes(
//
void call_before_decl(void) { used_before_default_decl(); }
// CHECK-LABEL: define dso_local void @_Z16call_before_declv(
// CHECK: call void @_Z24used_before_default_declv()
//
__attribute__((target_version("default"))) void used_before_default_decl(void);
// CHECK: declare void @_Z24used_before_default_declv()


// Test that an unmagled declaration is generated and used when the
// default version is declared before the first use of the function.
//
__attribute__((target_version("aes"))) void used_after_default_decl(void) {}
// CHECK-LABEL: define dso_local void @_Z23used_after_default_declv._Maes(
//
__attribute__((target_version("default"))) void used_after_default_decl(void);
// CHECK: declare void @_Z23used_after_default_declv()
//
void call_after_decl(void) { used_after_default_decl(); }
// CHECK-LABEL: define dso_local void @_Z15call_after_declv(
// CHECK: call void @_Z23used_after_default_declv()


// Test that an unmagled declaration is generated and used when
// the default version is not present.
//
__attribute__((target_version("aes"))) void used_no_default(void) {}
// CHECK-LABEL: define dso_local void @_Z15used_no_defaultv._Maes(
//
void call_no_default(void) { used_no_default(); }
// CHECK-LABEL: define dso_local void @_Z15call_no_defaultv(
// CHECK: call void @_Z15used_no_defaultv()
//
// CHECK: declare void @_Z15used_no_defaultv()


// Test that neither an ifunc nor a declaration is generated if the default
// definition is missing since the versioned function is not used.
//
__attribute__((target_version("aes"))) void not_used_no_default(void) {}
// CHECK-LABEL: define dso_local void @_Z19not_used_no_defaultv._Maes(
//
// CHECK-NOT: declare void @_Z19not_used_no_defaultv(


// Test that an ifunc is generated if the default version is defined but not used.
//
__attribute__((target_version("aes"))) void not_used_with_default(void) {}
// CHECK-LABEL: define dso_local void @_Z21not_used_with_defaultv._Maes(
//
__attribute__((target_version("default"))) void not_used_with_default(void) {}
// CHECK-LABEL: define dso_local void @_Z21not_used_with_defaultv.default(
//
// CHECK-NOT: declare void @_Z21not_used_with_defaultv(


// CHECK: define weak_odr ptr @_Z23used_before_default_defv.resolver()
// CHECK: define weak_odr ptr @_Z22used_after_default_defv.resolver()
// CHECK-NOT: define weak_odr ptr @_Z24used_before_default_declv.resolver(
// CHECK-NOT: define weak_odr ptr @_Z23used_after_default_declv.resolver(
// CHECK-NOT: define weak_odr ptr @_Z15used_no_defaultv.resolver(
// CHECK-NOT: define weak_odr ptr @_Z19not_used_no_defaultv.resolver(
// CHECK: define weak_odr ptr @_Z21not_used_with_defaultv.resolver()
210 changes: 112 additions & 98 deletions clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp

Large diffs are not rendered by default.

247 changes: 132 additions & 115 deletions clang/test/CodeGenCXX/attr-target-version.cpp

Large diffs are not rendered by default.

49 changes: 17 additions & 32 deletions clang/test/CodeGenCXX/fmv-namespace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ __attribute((target_version("mops"))) int bar() { return 1; }
//.
// CHECK: @__aarch64_cpu_features = external dso_local global { i64 }
// CHECK: @_ZN4Name3fooEv = weak_odr ifunc i32 (), ptr @_ZN4Name3fooEv.resolver
// CHECK: @_ZN9OtherName3fooEv = weak_odr ifunc i32 (), ptr @_ZN9OtherName3fooEv.resolver
// CHECK: @_ZN3Foo3barEv = weak_odr ifunc i32 (), ptr @_ZN3Foo3barEv.resolver
//.
// CHECK-LABEL: define dso_local noundef i32 @_ZN4Name3fooEv._Msve(
Expand All @@ -42,20 +41,6 @@ __attribute((target_version("mops"))) int bar() { return 1; }
// CHECK-NEXT: ret i32 [[CALL]]
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN4Name3fooEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
// CHECK: [[RESOLVER_RETURN]]:
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv._Msve
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv.default
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN9OtherName3fooEv._Msve(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
Expand All @@ -69,28 +54,14 @@ __attribute((target_version("mops"))) int bar() { return 1; }
// CHECK-NEXT: ret i32 [[CALL]]
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN9OtherName3fooEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
// CHECK: [[RESOLVER_RETURN]]:
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv._Msve
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN9OtherName3fooEv.default
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv.default(
// CHECK-SAME: ) #[[ATTR1]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define dso_local noundef i32 @_ZN3Foo3barEv._Mmops(
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: ret i32 1
//
Expand All @@ -101,6 +72,20 @@ __attribute((target_version("mops"))) int bar() { return 1; }
// CHECK-NEXT: ret i32 0
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN4Name3fooEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1073741824
// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1073741824
// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
// CHECK-NEXT: br i1 [[TMP3]], label %[[RESOLVER_RETURN:.*]], label %[[RESOLVER_ELSE:.*]]
// CHECK: [[RESOLVER_RETURN]]:
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv._Msve
// CHECK: [[RESOLVER_ELSE]]:
// CHECK-NEXT: ret ptr @_ZN4Name3fooEv.default
//
//
// CHECK-LABEL: define weak_odr ptr @_ZN3Foo3barEv.resolver() comdat {
// CHECK-NEXT: [[RESOLVER_ENTRY:.*:]]
// CHECK-NEXT: call void @__init_cpu_features_resolver()
Expand All @@ -117,8 +102,8 @@ __attribute((target_version("mops"))) int bar() { return 1; }
//.
// CHECK: attributes #[[ATTR0]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR1]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR2]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mops" }
// CHECK: attributes #[[ATTR3:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
// CHECK: attributes #[[ATTR2:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
// CHECK: attributes #[[ATTR3]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mops" }
//.
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
Expand Down
62 changes: 39 additions & 23 deletions clang/test/CodeGenCXX/ptrauth-explicit-vtable-pointer-control.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,NODISC %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,TYPE %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,ADDR %s

// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -emit-llvm -o - | FileCheck --check-prefixes=CHECK,BOTH %s
Expand Down Expand Up @@ -111,7 +127,7 @@ int TVDisc_ExplicitNoExtraDiscrimination = ptrauth_string_discriminator("_ZTVN5t
int TVDisc_ExplicitTypeDiscrimination = ptrauth_string_discriminator("_ZTVN5test126ExplicitTypeDiscriminationE");


// CHECK-LABEL: define void @test_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -133,15 +149,15 @@ void test_default(NoExplicitAuth *a) {
a->f();
}

// CHECK-LABEL: define void @test_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
// CHECK-NOT: call i64 @llvm.ptrauth.auth
void test_disabled(ExplicitlyDisableAuth *a) {
a->f();
}

// CHECK-LABEL: define void @test_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -166,7 +182,7 @@ void test_addr_disc(ExplicitAddressDiscrimination *a) {
a->f();
}

// CHECK-LABEL: define void @test_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -185,7 +201,7 @@ void test_no_addr_disc(ExplicitNoAddressDiscrimination *a) {
a->f();
}

// CHECK-LABEL: define void @test_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -206,7 +222,7 @@ void test_no_extra_disc(ExplicitNoExtraDiscrimination *a) {
a->f();
}

// CHECK-LABEL: define void @test_type_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_type_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -229,7 +245,7 @@ void test_type_disc(ExplicitTypeDiscrimination *a) {
a->f();
}

// CHECK-LABEL: define void @test_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = load ptr, ptr {{%.*}}, align 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand Down Expand Up @@ -257,7 +273,7 @@ void test_custom_disc(ExplicitCustomDiscrimination *a) {
// Codegen should be the same as the simple cases above once we have a vtable.
//

// CHECK-LABEL: define void @test_subclass_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -279,15 +295,15 @@ void test_subclass_default(NoExplicitAuth *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
// CHECK-NOT: call i64 @llvm.ptrauth.auth
void test_subclass_disabled(ExplicitlyDisableAuth *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -312,7 +328,7 @@ void test_subclass_addr_disc(ExplicitAddressDiscrimination *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_no_addr_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -331,7 +347,7 @@ void test_subclass_no_addr_disc(ExplicitNoAddressDiscrimination *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_no_extra_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -352,7 +368,7 @@ void test_subclass_no_extra_disc(ExplicitNoExtraDiscrimination *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_type_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_type_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand All @@ -375,7 +391,7 @@ void test_subclass_type_disc(ExplicitTypeDiscrimination *a) {
make_subclass(a)->f();
}

// CHECK-LABEL: define void @test_subclass_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_subclass_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTADDR:%.*]] = call noundef ptr @_ZN5test113make_subclass
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
//
Expand Down Expand Up @@ -404,7 +420,7 @@ void test_subclass_custom_disc(ExplicitCustomDiscrimination *a) {
// Codegen should be the same as the simple cases above once we have a vtable.
//

// CHECK-LABEL: define void @test_multiple_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_multiple_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary
// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
Expand All @@ -427,7 +443,7 @@ void test_multiple_default(NoExplicitAuth *a) {
make_multiple_primary(a)->f();
}

// CHECK-LABEL: define void @test_multiple_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_multiple_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary
// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
Expand All @@ -436,7 +452,7 @@ void test_multiple_disabled(ExplicitlyDisableAuth *a) {
make_multiple_primary(a)->f();
}

// CHECK-LABEL: define void @test_multiple_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_multiple_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[CALL:%.*]] = call noundef ptr @_ZN5test121make_multiple_primary
// CHECK: [[VTADDR:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 8
// CHECK: [[VTABLE:%.*]] = load ptr, ptr [[VTADDR]], align 8
Expand Down Expand Up @@ -466,7 +482,7 @@ void test_multiple_custom_disc(ExplicitCustomDiscrimination *a) {
// but twice for vtt/vtable. The names in the vtt version have "VTT" prefixes.
//

// CHECK-LABEL: define void @test_virtual_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_virtual_default(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTTADDR:%.*]] = call noundef ptr @_ZN5test120make_virtual_primary
// CHECK: [[VTTABLE:%.*]] = load ptr, ptr [[VTTADDR]], align 8
//
Expand Down Expand Up @@ -509,13 +525,13 @@ void test_virtual_default(NoExplicitAuth *a) {
make_virtual_primary(a)->f();
}

// CHECK-LABEL: define void @test_virtual_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_virtual_disabled(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-NOT: call i64 @llvm.ptrauth.auth
void test_virtual_disabled(ExplicitlyDisableAuth *a) {
make_virtual_primary(a)->f();
}

// CHECK-LABEL: define void @test_virtual_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK-LABEL: define{{.*}} void @test_virtual_custom_disc(ptr noundef {{%.*}}) {{#.*}} {
// CHECK: [[VTTADDR:%.*]] = call noundef ptr @_ZN5test120make_virtual_primary
// CHECK: [[VTTABLE:%.*]] = load ptr, ptr [[VTTADDR]], align 8
//
Expand Down
14 changes: 10 additions & 4 deletions clang/test/CodeGenCXX/ptrauth-rtti-layout.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// RUN: %clang_cc1 %s -I%S -triple=arm64-apple-ios -fptrauth-calls -std=c++11 -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -I%S -triple=arm64-apple-ios -fptrauth-calls -std=c++11 -emit-llvm -o - | FileCheck --check-prefix=DARWIN %s
// RUN: %clang_cc1 %s -I%S -triple=aarch64-linux-gnu -fptrauth-calls -std=c++11 -emit-llvm -o - | FileCheck --check-prefix=ELF %s

#include <typeinfo>

struct A { int a; };

// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
// CHECK: @_ZTS1A = linkonce_odr hidden constant [3 x i8] c"1A\00"
// CHECK: @_ZTI1A = linkonce_odr hidden constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1A to i64), i64 -9223372036854775808) to ptr) }
// DARWIN: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
// DARWIN: @_ZTS1A = linkonce_odr hidden constant [3 x i8] c"1A\00"
// DARWIN: @_ZTI1A = linkonce_odr hidden constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1A to i64), i64 -9223372036854775808) to ptr) }

// ELF: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
// ELF: @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00"
// ELF: @_ZTI1A = linkonce_odr constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS1A }

auto ATI = typeid(A);
15 changes: 11 additions & 4 deletions clang/test/CodeGenCXX/ptrauth-static-destructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
// RUN: | FileCheck %s --check-prefix=CXAATEXIT

// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
// RUN: -fno-use-cxa-atexit \
// RUN: | FileCheck %s --check-prefix=ATEXIT
// RUN: -fno-use-cxa-atexit | FileCheck %s --check-prefixes=ATEXIT,DARWIN

// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
// RUN: | FileCheck %s --check-prefix=CXAATEXIT

// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
// RUN: -fno-use-cxa-atexit | FileCheck %s --check-prefixes=ATEXIT,ELF

class Foo {
public:
Expand All @@ -20,5 +25,7 @@ Foo global;
// ATEXIT: define internal void @__cxx_global_var_init()
// ATEXIT: %{{.*}} = call i32 @atexit(ptr ptrauth (ptr @__dtor_global, i32 0))

// ATEXIT: define internal void @__dtor_global() {{.*}} section "__TEXT,__StaticInit,regular,pure_instructions" {
// ATEXIT: %{{.*}} = call ptr @_ZN3FooD1Ev(ptr @global)
// DARWIN: define internal void @__dtor_global() {{.*}} section "__TEXT,__StaticInit,regular,pure_instructions" {
// ELF: define internal void @__dtor_global() {{.*}} section ".text.startup" {
// DARWIN: %{{.*}} = call ptr @_ZN3FooD1Ev(ptr @global)
// ELF: call void @_ZN3FooD1Ev(ptr @global)
15 changes: 9 additions & 6 deletions clang/test/CodeGenCXX/ptrauth-throw.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECKDISC
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECKDISC

// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple aarch64-linux-gnu -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECKDISC

class Foo {
public:
~Foo() {
}
};

// CHECK-LABEL: define void @_Z1fv()
// CHECK-LABEL: define{{.*}} void @_Z1fv()
// CHECK: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0))

// CHECKDISC-LABEL: define void @_Z1fv()
// CHECKDISC-LABEL: define{{.*}} void @_Z1fv()
// CHECKDISC: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0, i64 10942))

void f() {
throw Foo();
}

// __cxa_throw is defined to take its destructor as "void (*)(void *)" in the ABI.
// CHECK-LABEL: define void @__cxa_throw({{.*}})
// CHECK-LABEL: define{{.*}} void @__cxa_throw({{.*}})
// CHECK: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 0) ]

// CHECKDISC-LABEL: define void @__cxa_throw({{.*}})
// CHECKDISC-LABEL: define{{.*}} void @__cxa_throw({{.*}})
// CHECKDISC: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 10942) ]

extern "C" void __cxa_throw(void *exception, void *, void (*dtor)(void *)) {
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CodeGenCXX/ptrauth-thunks.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s

namespace Test1 {
struct B1 {
Expand Down
69 changes: 39 additions & 30 deletions clang/test/CodeGenCXX/ptrauth-virtual-function.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck --check-prefixes=CHECK,DARWIN %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 %s -o - | FileCheck --check-prefixes=CHECK,ELF %s

// Check virtual function pointers in vtables are signed.

Expand Down Expand Up @@ -182,7 +183,8 @@ V1::~V1() {
// Check sign/authentication of vtable pointers and authentication of virtual
// functions.

// CHECK-LABEL: define noundef ptr @_ZN2V1D2Ev(
// DARWIN-LABEL: define noundef ptr @_ZN2V1D2Ev(
// ELF-LABEL: define dso_local void @_ZN2V1D2Ev(
// CHECK: %[[THIS1:.*]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T1:[0-9]+]] = ptrtoint ptr %[[T0]] to i64
Expand All @@ -193,7 +195,7 @@ V1::~V1() {
// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T7]] to ptr
// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS1]]

// CHECK-LABEL: define void @_Z8testB0m0P2B0(
// CHECK-LABEL: define{{.*}} void @_Z8testB0m0P2B0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -208,7 +210,7 @@ void testB0m0(B0 *a) {
a->m0();
}

// CHECK-LABEL: define void @_Z8testB0m1P2B0(
// CHECK-LABEL: define{{.*}} void @_Z8testB0m1P2B0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -223,7 +225,7 @@ void testB0m1(B0 *a) {
a->m1();
}

// CHECK-LABEL: define void @_Z8testB0m2P2B0(
// CHECK-LABEL: define{{.*}} void @_Z8testB0m2P2B0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -238,7 +240,7 @@ void testB0m2(B0 *a) {
a->m2();
}

// CHECK-LABEL: define void @_Z8testD0m0P2D0(
// CHECK-LABEL: define{{.*}} void @_Z8testD0m0P2D0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -253,7 +255,7 @@ void testD0m0(D0 *a) {
a->m0();
}

// CHECK-LABEL: define void @_Z8testD0m1P2D0(
// CHECK-LABEL: define{{.*}} void @_Z8testD0m1P2D0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -268,7 +270,7 @@ void testD0m1(D0 *a) {
a->m1();
}

// CHECK-LABEL: define void @_Z8testD0m2P2D0(
// CHECK-LABEL: define{{.*}} void @_Z8testD0m2P2D0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -283,7 +285,7 @@ void testD0m2(D0 *a) {
a->m2();
}

// CHECK-LABEL: define void @_Z8testD0m3P2D0(
// CHECK-LABEL: define{{.*}} void @_Z8testD0m3P2D0(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -299,7 +301,7 @@ void testD0m3(D0 *a) {
}


// CHECK-LABEL: define void @_Z8testD1m0P2D1(
// CHECK-LABEL: define{{.*}} void @_Z8testD1m0P2D1(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -314,7 +316,7 @@ void testD1m0(D1 *a) {
a->m0();
}

// CHECK-LABEL: define void @_Z8testD1m1P2D1(
// CHECK-LABEL: define{{.*}} void @_Z8testD1m1P2D1(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -329,7 +331,7 @@ void testD1m1(D1 *a) {
a->m1();
}

// CHECK-LABEL: define void @_Z8testD1m2P2D1(
// CHECK-LABEL: define{{.*}} void @_Z8testD1m2P2D1(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -345,7 +347,7 @@ void testD1m2(D1 *a) {
}


// CHECK-LABEL: define void @_Z8testD2m0P2D2(
// CHECK-LABEL: define{{.*}} void @_Z8testD2m0P2D2(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -360,7 +362,7 @@ void testD2m0(D2 *a) {
a->m0();
}

// CHECK-LABEL: define void @_Z8testD2m1P2D2(
// CHECK-LABEL: define{{.*}} void @_Z8testD2m1P2D2(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -375,21 +377,21 @@ void testD2m1(D2 *a) {
a->m1();
}

// CHECK-LABEL: define void @_Z10testD2m2D0P2D2(
// CHECK-LABEL: define{{.*}} void @_Z10testD2m2D0P2D2(
// CHECK: call void @_ZN2B02m2Ev(ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}){{$}}

void testD2m2D0(D2 *a) {
a->D0::m2();
}

// CHECK-LABEL: define void @_Z10testD2m2D1P2D2(
// CHECK-LABEL: define{{.*}} void @_Z10testD2m2D1P2D2(
// CHECK: call void @_ZN2B02m2Ev(ptr noundef nonnull align {{[0-9]+}} dereferenceable(12) %{{.*}}){{$}}

void testD2m2D1(D2 *a) {
a->D1::m2();
}

// CHECK-LABEL: define void @_Z8testD2m3P2D2(
// CHECK-LABEL: define{{.*}} void @_Z8testD2m3P2D2(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -404,7 +406,7 @@ void testD2m3(D2 *a) {
a->m3();
}

// CHECK-LABEL: define void @_Z8testD3m0P2D3(
// CHECK-LABEL: define{{.*}} void @_Z8testD3m0P2D3(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -419,7 +421,7 @@ void testD3m0(D3 *a) {
a->m0();
}

// CHECK-LABEL: define void @_Z8testD3m1P2D3(
// CHECK-LABEL: define{{.*}} void @_Z8testD3m1P2D3(
// CHECK: %[[VTABLE:[a-z]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
// CHECK: %[[T3:[0-9]+]] = call i64 @llvm.ptrauth.auth(i64 %[[T0]], i32 2, i64 0)
Expand All @@ -434,7 +436,7 @@ void testD3m1(D3 *a) {
a->m1();
}

// CHECK: define void @_Z8testD3m2P2D3(ptr noundef %[[A:.*]])
// CHECK: define{{.*}} void @_Z8testD3m2P2D3(ptr noundef %[[A:.*]])
// CHECK: %[[A_ADDR:.*]] = alloca ptr, align 8
// CHECK: store ptr %[[A]], ptr %[[A_ADDR]], align 8
// CHECK: %[[V0:.*]] = load ptr, ptr %[[A_ADDR]], align 8
Expand All @@ -459,7 +461,7 @@ void testD3m2(D3 *a) {
a->m2();
}

// CHECK-LABEL: define void @_Z17testD3Destructor0P2D3(
// CHECK-LABEL: define{{.*}} void @_Z17testD3Destructor0P2D3(
// CHECK: load ptr, ptr
// CHECK: %[[VTABLE:.*]] = load ptr, ptr %{{.*}}
// CHECK: %[[T2:[0-9]+]] = ptrtoint ptr %[[VTABLE]] to i64
Expand All @@ -475,7 +477,7 @@ void testD3Destructor0(D3 *a) {
delete a;
}

// CHECK-LABEL: define void @_Z17testD3Destructor1P2D3(
// CHECK-LABEL: define{{.*}} void @_Z17testD3Destructor1P2D3(
// CHECK: %[[T6:.*]] = load ptr, ptr %
// CHECK: %[[VTABLE0:[a-z0-9]+]] = load ptr, ptr %
// CHECK: %[[T2:[0-9]+]] = ptrtoint ptr %[[VTABLE0]] to i64
Expand All @@ -492,14 +494,15 @@ void testD3Destructor0(D3 *a) {
// CHECK: %[[T12:[0-9]+]] = load ptr, ptr %[[VFN]]
// CHECK: %[[T13:[0-9]+]] = ptrtoint ptr %[[VFN]] to i64
// CHECK: %[[T14:[0-9]+]] = call i64 @llvm.ptrauth.blend(i64 %[[T13]], i64 57279)
// CHECK: %call = call noundef ptr %[[T12]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T14]]) ]
// DARWIN: %call = call noundef ptr %[[T12]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T14]]) ]
// ELF: call void %[[T12]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T14]]) ]
// CHECK: call void @_ZdlPv(ptr noundef %[[T7]])

void testD3Destructor1(D3 *a) {
::delete a;
}

// CHECK-LABEL: define void @_Z17testD3Destructor2P2D3(
// CHECK-LABEL: define{{.*}} void @_Z17testD3Destructor2P2D3(
// CHECK: load ptr, ptr
// CHECK: %[[VTABLE:.*]] = load ptr, ptr %
// CHECK: %[[T2:.*]] = ptrtoint ptr %[[VTABLE]] to i64
Expand All @@ -509,7 +512,8 @@ void testD3Destructor1(D3 *a) {
// CHECK: %[[T5:.*]] = load ptr, ptr %[[VFN]]
// CHECK: %[[T6:.*]] = ptrtoint ptr %[[VFN]] to i64
// CHECK: %[[T7:.*]] = call i64 @llvm.ptrauth.blend(i64 %[[T6]], i64 57279)
// CHECK: %call = call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T7]]) ]
// DARWIN: %call = call noundef ptr %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T7]]) ]
// ELF: call void %[[T5]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(32) %{{.*}}) #{{.*}} [ "ptrauth"(i32 0, i64 %[[T7]]) ]

void testD3Destructor2(D3 *a) {
a->~D3();
Expand All @@ -526,23 +530,27 @@ void materializeConstructors() {
V1 V1;
}

// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2B0C2Ev(
// DARWIN-LABEL: define linkonce_odr noundef ptr @_ZN2B0C2Ev(
// ELF-LABEL: define linkonce_odr void @_ZN2B0C2Ev(
// CHECK: %[[THIS:.*]] = load ptr, ptr %
// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 40) ({ [7 x ptr] }, ptr @_ZTV2B0, i32 0, i32 0, i32 2) to i64), i32 2, i64 0)
// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr
// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]]

// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D0C2Ev(
// DARWIN-LABEL: define linkonce_odr noundef ptr @_ZN2D0C2Ev(
// ELF-LABEL: define linkonce_odr void @_ZN2D0C2Ev(
// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 56) ({ [9 x ptr] }, ptr @_ZTV2D0, i32 0, i32 0, i32 2) to i64), i32 2, i64 0)
// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr
// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]]

// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D1C2Ev(
// DARWIN-LABEL: define linkonce_odr noundef ptr @_ZN2D1C2Ev(
// ELF-LABEL: define linkonce_odr void @_ZN2D1C2Ev(
// CHECK: %[[T0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 48) ({ [8 x ptr] }, ptr @_ZTV2D1, i32 0, i32 0, i32 2) to i64), i32 2, i64 0)
// CHECK: %[[SIGNED_VTADDR:[0-9]+]] = inttoptr i64 %[[T0]] to ptr
// CHECK: store ptr %[[SIGNED_VTADDR]], ptr %[[THIS]]

// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2D2C2Ev(
// DARWIN-LABEL: define linkonce_odr noundef ptr @_ZN2D2C2Ev(
// ELF-LABEL: define linkonce_odr void @_ZN2D2C2Ev(
// CHECK: %[[SLOT0:.*]] = load ptr, ptr
// CHECK: %[[SIGN_VTADDR0:[0-9]+]] = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr inbounds inrange(-16, 56) ({ [9 x ptr], [8 x ptr] }, ptr @_ZTV2D2, i32 0, i32 0, i32 2) to i64), i32 2, i64 0)
// CHECK: %[[T1:[0-9]+]] = inttoptr i64 %[[SIGN_VTADDR0]] to ptr
Expand All @@ -552,7 +560,8 @@ void materializeConstructors() {
// CHECK: %[[T5:[0-9]+]] = inttoptr i64 %[[SIGN_VTADDR1]] to ptr
// CHECK: store ptr %[[T5]], ptr %[[T3]]

// CHECK-LABEL: define linkonce_odr noundef ptr @_ZN2V0C2Ev(
// DARWIN-LABEL: define linkonce_odr noundef ptr @_ZN2V0C2Ev(
// ELF-LABEL: define linkonce_odr void @_ZN2V0C2Ev(
// CHECK: %[[THIS1]] = load ptr, ptr %
// CHECK: %[[VTT:[a-z0-9]+]] = load ptr, ptr %{{.*}}
// CHECK: %[[T0:[0-9]+]] = load ptr, ptr %[[VTT]]
Expand Down
20 changes: 14 additions & 6 deletions clang/test/CodeGenCXX/ptrauth-vtable-virtual-inheritance-thunk.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -fptrauth-intrinsics -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -emit-llvm -O0 -disable-llvm-passes -o - | FileCheck --check-prefix=CHECK %s
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple arm64-apple-ios -disable-llvm-passes -fptrauth-intrinsics -fptrauth-calls \
// RUN: -fptrauth-vtable-pointer-type-discrimination -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,DARWIN %s
// RUN: %clang_cc1 %s -x c++ -std=c++11 -triple aarch64-linux-gnu -disable-llvm-passes -fptrauth-intrinsics -fptrauth-calls \
// RUN: -fptrauth-vtable-pointer-type-discrimination -emit-llvm -O0 -o - | FileCheck --check-prefixes=CHECK,ELF %s

// The actual vtable construction

Expand Down Expand Up @@ -103,9 +106,11 @@

// CHECK: @_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]

// CHECK: @_ZTS1B = linkonce_odr hidden constant [3 x i8] c"1B\00", align 1
// DARWIN: @_ZTS1B = linkonce_odr hidden constant [3 x i8] c"1B\00", align 1
// ELF: @_ZTS1B = linkonce_odr constant [3 x i8] c"1B\00", comdat, align 1

// CHECK: @_ZTI1B = linkonce_odr hidden constant { ptr, ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1B to i64), i64 -9223372036854775808) to ptr), ptr @_ZTI1A }, align 8
// DARWIN: @_ZTI1B = linkonce_odr hidden constant { ptr, ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), i32 2), ptr inttoptr (i64 add (i64 ptrtoint (ptr @_ZTS1B to i64), i64 -9223372036854775808) to ptr), ptr @_ZTI1A }, align 8
// ELF: @_ZTI1B = linkonce_odr constant { ptr, ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), i32 2), ptr @_ZTS1B, ptr @_ZTI1A }, comdat, align 8

// CHECK: @_ZTI1C = constant { ptr, ptr, i32, i32, ptr, i64 } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), i32 2), ptr @_ZTS1C, i32 0, i32 1, ptr @_ZTI1B, i64 -6141 }, align 8

Expand Down Expand Up @@ -177,7 +182,8 @@
// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1gEv, i32 0, i64 19402, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 3)),
// CHECK-SAME: ptr ptrauth (ptr @_ZN1A1hEz, i32 0, i64 31735, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 4)),
// CHECK-SAME: ptr ptrauth (ptr @_ZN1BD1Ev, i32 0, i64 2043, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 5)),
// CHECK-SAME: ptr ptrauth (ptr @_ZN1BD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 6))] }, align 8
// DARWIN-SAME: ptr ptrauth (ptr @_ZN1BD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 6))] }, align 8
// ELF-SAME: ptr ptrauth (ptr @_ZN1BD0Ev, i32 0, i64 63674, ptr getelementptr inbounds ({ [7 x ptr] }, ptr @_ZTV1B, i32 0, i32 0, i32 6))] }, comdat, align 8

extern "C" int printf(const char *format, ...);

Expand Down Expand Up @@ -284,13 +290,15 @@ int main() {
}

// And check the thunks
// CHECK: ptr @_ZTv0_n48_N1CD1Ev(ptr noundef %this)
// DARWIN: ptr @_ZTv0_n48_N1CD1Ev(ptr noundef %this)
// ELF: void @_ZTv0_n48_N1CD1Ev(ptr noundef %this)
// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866)

// CHECK: void @_ZTv0_n48_N1CD0Ev(ptr noundef %this)
// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866)

// CHECK: ptr @_ZTv0_n48_N1DD1Ev(ptr noundef %this)
// DARWIN: ptr @_ZTv0_n48_N1DD1Ev(ptr noundef %this)
// ELF: void @_ZTv0_n48_N1DD1Ev(ptr noundef %this)
// CHECK: [[TEMP:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TEMP:%.*]], i32 2, i64 62866)

// CHECK: void @_ZTv0_n48_N1DD0Ev(ptr noundef %this)
Expand Down
4 changes: 3 additions & 1 deletion clang/test/CodeGenCXX/ubsan-vtable-checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-linux -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=MSABI --check-prefix=CHECK-VPTR-MS
// RUN: %clang_cc1 -std=c++11 -triple arm64e-ios-13 -emit-llvm -fptrauth-intrinsics -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-address-discrimination -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM --check-prefix=CHECK-PTRAUTH
// RUN: %clang_cc1 -std=c++11 -triple aarch64-unknown-linux -emit-llvm -fptrauth-intrinsics -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-address-discrimination -fsanitize=null,vptr %s -o - | FileCheck %s --check-prefix=CHECK-VPTR --check-prefix=ITANIUM --check-prefix=CHECK-PTRAUTH

struct T {
virtual ~T() {}
virtual int v() { return 1; }
Expand All @@ -29,7 +31,7 @@ int get_v(T* t) {
// CHECK-NULL: load ptr, ptr {{.*}}

// CHECK-PTRAUTH: [[CAST_VTABLE:%.*]] = ptrtoint ptr %vtable to i64
// CHECK-PTRAUTH: [[STRIPPED_VTABLE:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[CAST_VTABLE]], i32 0), !nosanitize !2
// CHECK-PTRAUTH: [[STRIPPED_VTABLE:%.*]] = call i64 @llvm.ptrauth.strip(i64 [[CAST_VTABLE]], i32 0), !nosanitize
// CHECK-PTRAUTH: [[STRIPPED_PTR:%.*]] = inttoptr i64 [[STRIPPED_VTABLE]] to ptr
// CHECK-PTRAUTH: [[STRIPPED_INT:%.*]] = ptrtoint ptr [[STRIPPED_PTR]] to i64
// Make sure authed vtable pointer feeds into hashing
Expand Down
Loading