[clang] [clang-tools-extra] [llvm] [NFC] Add implicit cast kinds for function pointer conversions (PR #110047)
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 25 14:49:12 PDT 2024
https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/110047
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e.
See https://github.com/llvm/llvm-project/pull/109056 for background.
>From 1113c14d7ea25baf6c328e69661f4b94e437a4b4 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Wed, 25 Sep 2024 14:30:22 -0700
Subject: [PATCH] [NFC] Add implicit cast kinds for function pointer
conversions
The new cast kinds are needed to distinguish between no-op conversions
and conversions from pointers to noexcept functions to pointers to
functions without noexcept as the latter can cause function pointers to
be re-signed on arm64e.
See https://github.com/llvm/llvm-project/pull/109056 for background.
---
.../bugprone/SwappedArgumentsCheck.cpp | 2 +
.../ProTypeCstyleCastCheck.cpp | 4 +-
.../google/AvoidCStyleCastsCheck.cpp | 7 +-
.../clang-tidy/modernize/LoopConvertCheck.cpp | 4 +-
.../ImplicitConversionInLoopCheck.cpp | 4 +-
.../MakeMemberFunctionConstCheck.cpp | 9 +-
.../clang-tidy/utils/DeclRefExprUtils.cpp | 2 +
clang-tools-extra/clangd/Hover.cpp | 2 +
clang/include/clang/AST/IgnoreExpr.h | 4 +-
clang/include/clang/AST/OperationKinds.def | 8 +
.../lib/ARCMigrate/TransBlockObjCVariable.cpp | 6 +-
clang/lib/AST/ByteCode/Compiler.cpp | 4 +
clang/lib/AST/Expr.cpp | 28 ++-
clang/lib/AST/ExprCXX.cpp | 6 +-
clang/lib/AST/ExprConstant.cpp | 17 +-
clang/lib/Analysis/CFG.cpp | 2 +
clang/lib/Analysis/ExprMutationAnalyzer.cpp | 12 +-
clang/lib/Analysis/FlowSensitive/Transfer.cpp | 8 +-
clang/lib/Analysis/ThreadSafety.cpp | 6 +-
clang/lib/Analysis/ThreadSafetyCommon.cpp | 2 +
clang/lib/CodeGen/CGDecl.cpp | 2 +
clang/lib/CodeGen/CGExpr.cpp | 6 +-
clang/lib/CodeGen/CGExprAgg.cpp | 4 +
clang/lib/CodeGen/CGExprComplex.cpp | 2 +
clang/lib/CodeGen/CGExprConstant.cpp | 2 +
clang/lib/CodeGen/CGExprScalar.cpp | 4 +-
clang/lib/CodeGen/CGHLSLRuntime.cpp | 1 -
clang/lib/CodeGen/CodeGenModule.cpp | 20 +-
clang/lib/Edit/RewriteObjCFoundationAPI.cpp | 2 +
clang/lib/Sema/CheckExprLifetime.cpp | 2 +
clang/lib/Sema/SemaChecking.cpp | 4 +
clang/lib/Sema/SemaDecl.cpp | 4 +-
clang/lib/Sema/SemaDeclCXX.cpp | 4 +-
clang/lib/Sema/SemaExpr.cpp | 2 +
clang/lib/Sema/SemaExprCXX.cpp | 6 +-
clang/lib/Sema/SemaInit.cpp | 4 +-
clang/lib/Sema/SemaOpenMP.cpp | 211 +++++++++---------
clang/lib/Sema/SemaOverload.cpp | 6 +-
clang/lib/Sema/SemaStmt.cpp | 2 +
clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 2 +
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 2 +
.../ast-dump-function-pointer-conversion.cpp | 30 +++
.../dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp | 4 +-
.../GlobalConstructorFunction.hlsl | 31 +--
.../CodeGenHLSL/GlobalConstructorLib.hlsl | 23 +-
clang/test/CodeGenHLSL/GlobalDestructors.hlsl | 51 ++---
.../builtins/RWBuffer-constructor.hlsl | 1 -
.../builtins/RWBuffer-subscript.hlsl | 5 +-
.../test/CodeGenHLSL/inline-constructors.hlsl | 76 -------
clang/test/CodeGenHLSL/inline-functions.hlsl | 116 ----------
llvm/include/llvm/CodeGen/VirtRegMap.h | 8 +-
llvm/include/llvm/SandboxIR/SandboxIR.h | 34 +++
llvm/lib/CodeGen/MachineVerifier.cpp | 2 +-
llvm/lib/SandboxIR/SandboxIR.cpp | 24 ++
.../test_g_insert_subvector.mir | 3 +
llvm/unittests/SandboxIR/SandboxIRTest.cpp | 66 ++++++
llvm/unittests/SandboxIR/TrackerTest.cpp | 31 +++
57 files changed, 506 insertions(+), 428 deletions(-)
create mode 100644 clang/test/AST/ast-dump-function-pointer-conversion.cpp
delete mode 100644 clang/test/CodeGenHLSL/inline-constructors.hlsl
delete mode 100644 clang/test/CodeGenHLSL/inline-functions.hlsl
diff --git a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
index 8989444dde1300..acb7112fa2abed 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SwappedArgumentsCheck.cpp
@@ -27,6 +27,8 @@ void SwappedArgumentsCheck::registerMatchers(MatchFinder *Finder) {
static const Expr *ignoreNoOpCasts(const Expr *E) {
if (auto *Cast = dyn_cast<CastExpr>(E))
if (Cast->getCastKind() == CK_LValueToRValue ||
+ Cast->getCastKind() == CK_FunctionPointerConversion ||
+ Cast->getCastKind() == CK_MemberFunctionPointerConversion ||
Cast->getCastKind() == CK_NoOp)
return ignoreNoOpCasts(Cast->getSubExpr());
return E;
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
index 5e255dcaacd262..bab08496e90e86 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeCstyleCastCheck.cpp
@@ -90,7 +90,9 @@ void ProTypeCstyleCastCheck::check(const MatchFinder::MatchResult &Result) {
return;
}
- if (MatchedCast->getCastKind() == CK_NoOp &&
+ if ((MatchedCast->getCastKind() == CK_NoOp ||
+ MatchedCast->getCastKind() == CK_FunctionPointerConversion ||
+ MatchedCast->getCastKind() == CK_MemberFunctionPointerConversion) &&
needsConstCast(SourceType, MatchedCast->getType())) {
diag(MatchedCast->getBeginLoc(),
"do not use C-style cast to cast away constness");
diff --git a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
index 3109bbb3724c79..888f7b122b82c3 100644
--- a/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/google/AvoidCStyleCastsCheck.cpp
@@ -123,7 +123,10 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
DestTypeAsWritten->isRecordType() &&
!DestTypeAsWritten->isElaboratedTypeSpecifier();
- if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
+ if ((CastExpr->getCastKind() == CK_NoOp ||
+ CastExpr->getCastKind() == CK_FunctionPointerConversion ||
+ CastExpr->getCastKind() == CK_MemberFunctionPointerConversion) &&
+ !FnToFnCast) {
// Function pointer/reference casts may be needed to resolve ambiguities in
// case of overloaded functions, so detection of redundant casts is trickier
// in this case. Don't emit "redundant cast" warnings for function
@@ -201,6 +204,8 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
}
return;
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
if (FnToFnCast) {
ReplaceWithNamedCast("static_cast");
return;
diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index a1786ba5acfdf5..658f134faa0b9f 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -500,7 +500,9 @@ static bool canBeModified(ASTContext *Context, const Expr *E) {
if (Parents.size() != 1)
return true;
if (const auto *Cast = Parents[0].get<ImplicitCastExpr>()) {
- if ((Cast->getCastKind() == CK_NoOp &&
+ if (((Cast->getCastKind() == CK_NoOp ||
+ Cast->getCastKind() == CK_FunctionPointerConversion ||
+ Cast->getCastKind() == CK_MemberFunctionPointerConversion) &&
Context->hasSameType(Cast->getType(), E->getType().withConst())) ||
(Cast->getCastKind() == CK_LValueToRValue &&
!Cast->getType().isNull() && Cast->getType()->isFundamentalType()))
diff --git a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
index 86fca0722dcd82..4fc32e1d1572eb 100644
--- a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp
@@ -24,7 +24,9 @@ namespace clang::tidy::performance {
// case we skip the first cast expr.
static bool isNonTrivialImplicitCast(const Stmt *ST) {
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(ST)) {
- return (ICE->getCastKind() != CK_NoOp) ||
+ return (ICE->getCastKind() != CK_NoOp &&
+ ICE->getCastKind() != CK_FunctionPointerConversion &&
+ ICE->getCastKind() != CK_MemberFunctionPointerConversion) ||
isNonTrivialImplicitCast(ICE->getSubExpr());
}
return false;
diff --git a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
index d42fcba70e81b4..751cd637a02334 100644
--- a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp
@@ -97,7 +97,9 @@ class FindUsageOfThis : public RecursiveASTVisitor<FindUsageOfThis> {
// (possibly `-UnaryOperator Deref)
// `-CXXThisExpr 'S *' this
bool visitUser(const ImplicitCastExpr *Cast) {
- if (Cast->getCastKind() != CK_NoOp)
+ if (Cast->getCastKind() != CK_NoOp &&
+ Cast->getCastKind() != CK_FunctionPointerConversion &&
+ Cast->getCastKind() != CK_MemberFunctionPointerConversion)
return false; // Stop traversal.
// Only allow NoOp cast to 'const S' or 'const S *'.
@@ -159,7 +161,10 @@ class FindUsageOfThis : public RecursiveASTVisitor<FindUsageOfThis> {
if (Cast->getCastKind() == CK_LValueToRValue)
return true;
- if (Cast->getCastKind() == CK_NoOp && Cast->getType().isConstQualified())
+ if ((Cast->getCastKind() == CK_NoOp ||
+ Cast->getCastKind() == CK_FunctionPointerConversion ||
+ Cast->getCastKind() == CK_MemberFunctionPointerConversion) &&
+ Cast->getType().isConstQualified())
return true;
}
diff --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 106feb7fb41720..87e523eaaa7718 100644
--- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -240,6 +240,8 @@ AST_MATCHER_P(DeclRefExpr, doesNotMutateObject, int, Indirections) {
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_Dynamic:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index de103e011c7085..d5c609d100d4e4 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1122,6 +1122,8 @@ void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI,
if (const auto *ImplicitCast = CastNode->ASTNode.get<ImplicitCastExpr>()) {
switch (ImplicitCast->getCastKind()) {
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
// If it was a reference before, it's still a reference.
diff --git a/clang/include/clang/AST/IgnoreExpr.h b/clang/include/clang/AST/IgnoreExpr.h
index 917bada61fa6fd..967c381dfa9dc5 100644
--- a/clang/include/clang/AST/IgnoreExpr.h
+++ b/clang/include/clang/AST/IgnoreExpr.h
@@ -102,7 +102,9 @@ inline Expr *IgnoreBaseCastsSingleStep(Expr *E) {
if (auto *CE = dyn_cast<CastExpr>(E))
if (CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
- CE->getCastKind() == CK_NoOp)
+ CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_FunctionPointerConversion ||
+ CE->getCastKind() == CK_MemberFunctionPointerConversion)
return CE->getSubExpr();
return E;
diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def
index 8788b8ff0ef0a4..25cd0dbb5e3a3b 100644
--- a/clang/include/clang/AST/OperationKinds.def
+++ b/clang/include/clang/AST/OperationKinds.def
@@ -84,6 +84,14 @@ CAST_OPERATION(LValueToRValue)
/// void () noexcept -> void ()
CAST_OPERATION(NoOp)
+/// CK_FunctionPointerConversion - A conversion from pointer/reference to
+/// noexcept function to pointer/reference to function.
+CAST_OPERATION(FunctionPointerConversion)
+
+/// CK_MemberFunctionPointerConversion - A conversion from pointer to noexcept
+/// member function to pointer to member function.
+CAST_OPERATION(MemberFunctionPointerConversion)
+
/// CK_BaseToDerived - A conversion from a C++ class pointer/reference
/// to a derived class pointer/reference.
/// B *b = static_cast<B*>(a);
diff --git a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 1e4db33135b6a1..7295f064849ea6 100644
--- a/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/clang/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -53,8 +53,10 @@ class RootBlockObjCVarRewriter :
if (ref->getDecl() == Var) {
if (castE->getCastKind() == CK_LValueToRValue)
return true; // Using the value of the variable.
- if (castE->getCastKind() == CK_NoOp && castE->isLValue() &&
- Var->getASTContext().getLangOpts().CPlusPlus)
+ if ((castE->getCastKind() == CK_NoOp ||
+ castE->getCastKind() == CK_FunctionPointerConversion ||
+ castE->getCastKind() == CK_MemberFunctionPointerConversion) &&
+ castE->isLValue() && Var->getASTContext().getLangOpts().CPlusPlus)
return true; // Binding to const C++ reference.
}
}
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 7e0775a51aee61..394aa9a7d363b2 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -429,6 +429,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_FunctionToPointerDecay:
case CK_NonAtomicToAtomic:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
case CK_AddressSpaceConversion:
return this->delegate(SubExpr);
@@ -3067,6 +3069,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
if (ICE->getCastKind() != CK_NoOp &&
+ ICE->getCastKind() != CK_FunctionPointerConversion &&
+ ICE->getCastKind() != CK_MemberFunctionPointerConversion &&
ICE->getCastKind() != CK_IntegralCast)
break;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 2e463fc00c6b68..c62ffa9bf7df59 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -98,7 +98,9 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
continue;
}
- if (CE->getCastKind() == CK_NoOp) {
+ if (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_FunctionPointerConversion ||
+ CE->getCastKind() == CK_MemberFunctionPointerConversion) {
E = CE->getSubExpr();
continue;
}
@@ -1926,6 +1928,8 @@ bool CastExpr::CastConsistency() const {
case CK_Dependent:
case CK_LValueToRValue:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_PointerToBoolean:
@@ -3188,7 +3192,9 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
E = M->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)
E = ICE->getSubExpr();
else
break;
@@ -3198,7 +3204,9 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
E = BE->getSubExpr();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)
E = ICE->getSubExpr();
else
break;
@@ -3263,6 +3271,8 @@ bool Expr::isImplicitCXXThis() const {
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion ||
ICE->getCastKind() == CK_LValueToRValue ||
ICE->getCastKind() == CK_DerivedToBase ||
ICE->getCastKind() == CK_UncheckedDerivedToBase) {
@@ -3478,6 +3488,8 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
// Handle misc casts we want to ignore.
if (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_FunctionPointerConversion ||
+ CE->getCastKind() == CK_MemberFunctionPointerConversion ||
CE->getCastKind() == CK_LValueToRValue ||
CE->getCastKind() == CK_ToUnion ||
CE->getCastKind() == CK_ConstructorConversion ||
@@ -4113,7 +4125,10 @@ FieldDecl *Expr::getSourceBitField() {
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_LValueToRValue ||
- (ICE->isGLValue() && ICE->getCastKind() == CK_NoOp))
+ (ICE->isGLValue() &&
+ (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)))
E = ICE->getSubExpr()->IgnoreParens();
else
break;
@@ -4167,7 +4182,10 @@ bool Expr::refersToVectorElement() const {
const Expr *E = this->IgnoreParens();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->isGLValue() && ICE->getCastKind() == CK_NoOp)
+ if (ICE->isGLValue() &&
+ (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion))
E = ICE->getSubExpr()->IgnoreParens();
else
break;
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 83ce404add5f50..a3f09786960b1f 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -344,8 +344,12 @@ QualType CXXDeleteExpr::getDestroyedType() const {
while (const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
if (ICE->getCastKind() == CK_DerivedToBase ||
ICE->getCastKind() == CK_UncheckedDerivedToBase ||
- ICE->getCastKind() == CK_NoOp) {
+ ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion) {
assert((ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion ||
getOperatorDelete()->isDestroyingOperatorDelete()) &&
"only a destroying operator delete can have a converted arg");
Arg = ICE->getSubExpr();
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6387e375dda79c..28f829e612be47 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -6247,7 +6247,9 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
} else if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
// Step over a derived-to-base conversion.
E = ICE->getSubExpr();
- if (ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)
continue;
if (ICE->getCastKind() != CK_DerivedToBase &&
ICE->getCastKind() != CK_UncheckedDerivedToBase)
@@ -8301,6 +8303,8 @@ class ExprEvaluatorBase
}
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -10074,6 +10078,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
if (ICE->getCastKind() != CK_NoOp &&
+ ICE->getCastKind() != CK_FunctionPointerConversion &&
+ ICE->getCastKind() != CK_MemberFunctionPointerConversion &&
ICE->getCastKind() != CK_IntegralCast)
break;
@@ -12210,8 +12216,9 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
// We only conservatively allow a few kinds of casts, because this code is
// inherently a simple solution that seeks to support the common case.
auto CastKind = Cast->getCastKind();
- if (CastKind != CK_NoOp && CastKind != CK_BitCast &&
- CastKind != CK_AddressSpaceConversion)
+ if (CastKind != CK_NoOp && CastKind != CK_FunctionPointerConversion &&
+ CastKind != CK_MemberFunctionPointerConversion &&
+ CastKind != CK_BitCast && CastKind != CK_AddressSpaceConversion)
return NoParens;
const auto *SubExpr = Cast->getSubExpr();
@@ -14448,6 +14455,8 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
QualType SrcType = SubExpr->getType();
switch (E->getCastKind()) {
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
@@ -15288,6 +15297,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_Dynamic:
case CK_ToUnion:
case CK_ArrayToPointerDecay:
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index f678ac6f2ff36a..baa5f96f8cbdbe 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1491,6 +1491,8 @@ void CFGBuilder::findConstructionContexts(
// Should we support other implicit cast kinds?
switch (Cast->getCastKind()) {
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_ConstructorConversion:
findConstructionContexts(Layer, Cast->getSubExpr());
break;
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
index 6d726ae44104ed..8f19bd7e918706 100644
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -377,11 +377,13 @@ ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) {
// We're assuming 'Exp' is mutated as soon as its address is taken, though in
// theory we can follow the pointer and see whether it escaped `Stm` or is
// dereferenced and then mutated. This is left for future improvements.
- const auto AsAmpersandOperand =
- unaryOperator(hasOperatorName("&"),
- // A NoOp implicit cast is adding const.
- unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))),
- hasUnaryOperand(canResolveToExpr(Exp)));
+ const auto AsAmpersandOperand = unaryOperator(
+ hasOperatorName("&"),
+ // A NoOp implicit cast is adding const.
+ unless(hasParent(implicitCastExpr(
+ anyOf(hasCastKind(CK_NoOp), hasCastKind(CK_FunctionPointerConversion),
+ hasCastKind(CK_MemberFunctionPointerConversion))))),
+ hasUnaryOperand(canResolveToExpr(Exp)));
const auto AsPointerFromArrayDecay = castExpr(
hasCastKind(CK_ArrayToPointerDecay),
unless(hasParent(arraySubscriptExpr())), has(canResolveToExpr(Exp)));
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 9c54eb16d22246..b58d40df7f07fc 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -322,7 +322,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
case CK_UserDefinedConversion:
// FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
// CK_ConstructorConversion, and CK_UserDefinedConversion.
- case CK_NoOp: {
+ case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion: {
// FIXME: Consider making `Environment::getStorageLocation` skip noop
// expressions (this and other similar expressions in the file) instead
// of assigning them storage locations.
@@ -679,7 +681,9 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
}
void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
- if (S->getCastKind() == CK_NoOp) {
+ if (S->getCastKind() == CK_NoOp ||
+ S->getCastKind() == CK_FunctionPointerConversion ||
+ S->getCastKind() == CK_MemberFunctionPointerConversion) {
const Expr *SubExpr = S->getSubExpr();
assert(SubExpr != nullptr);
diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp
index 5577f45aa5217f..49883e01f77d60 100644
--- a/clang/lib/Analysis/ThreadSafety.cpp
+++ b/clang/lib/Analysis/ThreadSafety.cpp
@@ -2103,8 +2103,10 @@ void BuildLockset::VisitCXXConstructExpr(const CXXConstructExpr *Exp) {
static const Expr *UnpackConstruction(const Expr *E) {
if (auto *CE = dyn_cast<CastExpr>(E))
- if (CE->getCastKind() == CK_NoOp)
- E = CE->getSubExpr()->IgnoreParens();
+ if (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_FunctionPointerConversion ||
+ CE->getCastKind() == CK_MemberFunctionPointerConversion)
+ E = CE->getSubExpr()->IgnoreParens();
if (auto *CE = dyn_cast<CastExpr>(E))
if (CE->getCastKind() == CK_ConstructorConversion ||
CE->getCastKind() == CK_UserDefinedConversion)
diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp
index cbcfefdc525490..aa54fe4ea66d5b 100644
--- a/clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -620,6 +620,8 @@ til::SExpr *SExprBuilder::translateCastExpr(const CastExpr *CE,
// return new (Arena) til::Load(E0);
}
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
case CK_ArrayToPointerDecay:
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 563f728e29d781..e035ae819eecc7 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -697,6 +697,8 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF,
switch (castExpr->getCastKind()) {
// Look through casts that don't require representation changes.
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BitCast:
case CK_BlockPointerToObjCPointerCast:
needsCast = true;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 35b5daaf6d4b55..95d0a764fdfb84 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1297,6 +1297,8 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo,
// Non-converting casts (but not C's implicit conversion from void*).
case CK_BitCast:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_AddressSpaceConversion:
if (auto PtrTy = CE->getSubExpr()->getType()->getAs<PointerType>()) {
if (PtrTy->getPointeeType()->isVoidType())
@@ -5292,6 +5294,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_IntegralComplexToBoolean:
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
+ case CK_MemberFunctionPointerConversion:
case CK_DerivedToBaseMemberPointer:
case CK_BaseToDerivedMemberPointer:
case CK_MemberPointerToBoolean:
@@ -5339,7 +5342,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
case CK_LValueToRValue:
return EmitLValue(E->getSubExpr());
- case CK_NoOp: {
+ case CK_NoOp:
+ case CK_FunctionPointerConversion: {
// CK_NoOp can model a qualification conversion, which can remove an array
// bound and change the IR type.
// FIXME: Once pointee types are removed from IR, remove this.
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index bbfc6672ecc25a..b30410da255e12 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -905,6 +905,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_FunctionToPointerDecay:
case CK_NullToPointer:
case CK_NullToMemberPointer:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BaseToDerivedMemberPointer:
case CK_DerivedToBaseMemberPointer:
case CK_MemberPointerToBoolean:
@@ -1424,6 +1426,8 @@ static bool castPreservesZero(const CastExpr *CE) {
switch (CE->getCastKind()) {
// No-ops.
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
case CK_BitCast:
diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp
index fef26e7b4ccdbd..794b06ebf29935 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -560,6 +560,8 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op,
}
case CK_BitCast:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BaseToDerived:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase:
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index f22321f0e738a1..386ca154618473 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1163,6 +1163,8 @@ class ConstExprEmitter
case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_ConstructorConversion:
return Visit(subExpr, destType);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 82caf65ac68d6b..5dd97c5a4b7b46 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2418,7 +2418,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
case CK_UserDefinedConversion:
return Visit(const_cast<Expr*>(E));
- case CK_NoOp: {
+ case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion: {
return CE->changesVolatileQualification() ? EmitLoadOfLValue(CE)
: Visit(const_cast<Expr *>(E));
}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index bec0a29e34fcb5..b6e6555e63fca1 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -338,7 +338,6 @@ void clang::CodeGen::CGHLSLRuntime::setHLSLEntryAttributes(
NumThreadsAttr->getZ());
Fn->addFnAttr(NumThreadsKindStr, NumThreadsStr);
}
- Fn->addFnAttr(llvm::Attribute::NoInline);
}
static Value *buildVectorInput(IRBuilder<> &B, Function *F, llvm::Type *Ty) {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 17b82b205063d4..ba2d6588900a11 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2473,14 +2473,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::StackProtectReq);
if (!D) {
- // Non-entry HLSL functions must always be inlined.
- if (getLangOpts().HLSL && !F->hasFnAttribute(llvm::Attribute::NoInline))
- B.addAttribute(llvm::Attribute::AlwaysInline);
// If we don't have a declaration to control inlining, the function isn't
// explicitly marked as alwaysinline for semantic reasons, and inlining is
// disabled, mark the function as noinline.
- else if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
- CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
+ if (!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
+ CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining)
B.addAttribute(llvm::Attribute::NoInline);
F->addFnAttrs(B);
@@ -2507,13 +2504,9 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();
- // Non-entry HLSL functions must always be inlined.
- if (getLangOpts().HLSL && !F->hasFnAttribute(llvm::Attribute::NoInline) &&
- !D->hasAttr<NoInlineAttr>()) {
- B.addAttribute(llvm::Attribute::AlwaysInline);
- } else if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) &&
- !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
- // Add optnone, but do so only if the function isn't always_inline.
+ // Add optnone, but do so only if the function isn't always_inline.
+ if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) &&
+ !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
B.addAttribute(llvm::Attribute::OptimizeNone);
// OptimizeNone implies noinline; we should not be inlining such functions.
@@ -2533,8 +2526,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<NoDuplicateAttr>()) {
B.addAttribute(llvm::Attribute::NoDuplicate);
- } else if (D->hasAttr<NoInlineAttr>() &&
- !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
+ } else if (D->hasAttr<NoInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
// Add noinline if the function isn't always_inline.
B.addAttribute(llvm::Attribute::NoInline);
} else if (D->hasAttr<AlwaysInlineAttr>() &&
diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
index 81797c8c4dc75a..8443f47c2199b6 100644
--- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -999,6 +999,8 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
switch (ICE->getCastKind()) {
case CK_LValueToRValue:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_UserDefinedConversion:
case CK_HLSLArrayRValue:
break;
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index c98fbca849faba..8089dd7fd50095 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -673,6 +673,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
// We assume that casts to 'bool' do not preserve enough information to
// retain a local object.
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BitCast:
case CK_BaseToDerived:
case CK_DerivedToBase:
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 99500daca295c9..eb46743782cd7e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -12976,6 +12976,8 @@ std::optional<std::pair<
default:
break;
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
case CK_UncheckedDerivedToBase:
case CK_DerivedToBase: {
@@ -13071,6 +13073,8 @@ std::optional<std::pair<
default:
break;
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
return getBaseAlignmentAndOffsetFromPtr(From, Ctx);
case CK_ArrayToPointerDecay:
return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 8557c25b93a8da..7970b80a70d39a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12733,7 +12733,9 @@ namespace {
if (ILE->getNumInits() == 1)
ArgExpr = ILE->getInit(0);
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr))
- if (ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)
ArgExpr = ICE->getSubExpr();
HandleValue(ArgExpr);
return;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index d8cdfcf8c6ec05..59f4d5511b19e3 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -3878,7 +3878,9 @@ namespace {
if (ILE->getNumInits() == 1)
ArgExpr = ILE->getInit(0);
if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr))
- if (ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_NoOp ||
+ ICE->getCastKind() == CK_FunctionPointerConversion ||
+ ICE->getCastKind() == CK_MemberFunctionPointerConversion)
ArgExpr = ICE->getSubExpr();
HandleValue(ArgExpr, false /*AddressOf*/);
return;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 80c252c79e4d7a..8e490a7e1a3565 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -19444,6 +19444,8 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// can be found.
switch (ICE->getCastKind()) {
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_DerivedToBase:
case CK_UncheckedDerivedToBase: {
ExprResult Sub = Rebuild(ICE->getSubExpr());
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index ac3fe6ab8f9bd0..db0cfce7f3f177 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4871,7 +4871,11 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, CK_NoOp, VK_PRValue,
+ From = ImpCastExprToType(From, ToType,
+ ToType->isMemberFunctionPointerType()
+ ? CK_MemberFunctionPointerConversion
+ : CK_FunctionPointerConversion,
+ VK_PRValue,
/*BasePath=*/nullptr, CCK)
.get();
break;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 4d11f2a43fcc6b..dc28b66f35f900 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -8016,8 +8016,8 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_FunctionReferenceConversion:
assert(CurInit.get()->isLValue() &&
"function reference should be lvalue");
- CurInit =
- S.ImpCastExprToType(CurInit.get(), Step->Type, CK_NoOp, VK_LValue);
+ CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type,
+ CK_FunctionPointerConversion, VK_LValue);
break;
case SK_AtomicConversion: {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index b952ffbd69f5d5..9afb8cea26fe78 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -2861,113 +2861,120 @@ void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) {
// clause requires an accessible, unambiguous default constructor for the
// class type, unless the list item is also specified in a firstprivate
// clause.
- if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
- for (OMPClause *C : D->clauses()) {
- if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
- SmallVector<Expr *, 8> PrivateCopies;
- for (Expr *DE : Clause->varlist()) {
- if (DE->isValueDependent() || DE->isTypeDependent()) {
- PrivateCopies.push_back(nullptr);
- continue;
- }
- auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens());
- auto *VD = cast<VarDecl>(DRE->getDecl());
- QualType Type = VD->getType().getNonReferenceType();
- const DSAStackTy::DSAVarData DVar =
- DSAStack->getTopDSA(VD, /*FromParent=*/false);
- if (DVar.CKind == OMPC_lastprivate) {
- // Generate helper private variable and initialize it with the
- // default value. The address of the original variable is replaced
- // by the address of the new private variable in CodeGen. This new
- // variable is not added to IdResolver, so the code in the OpenMP
- // region uses original variable for proper diagnostics.
- VarDecl *VDPrivate = buildVarDecl(
- SemaRef, DE->getExprLoc(), Type.getUnqualifiedType(),
- VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE);
- SemaRef.ActOnUninitializedDecl(VDPrivate);
- if (VDPrivate->isInvalidDecl()) {
- PrivateCopies.push_back(nullptr);
- continue;
- }
- PrivateCopies.push_back(buildDeclRefExpr(
- SemaRef, VDPrivate, DE->getType(), DE->getExprLoc()));
- } else {
- // The variable is also a firstprivate, so initialization sequence
- // for private copy is generated already.
- PrivateCopies.push_back(nullptr);
- }
- }
- Clause->setPrivateCopies(PrivateCopies);
+
+ auto FinalizeLastprivate = [&](OMPLastprivateClause *Clause) {
+ SmallVector<Expr *, 8> PrivateCopies;
+ for (Expr *DE : Clause->varlist()) {
+ if (DE->isValueDependent() || DE->isTypeDependent()) {
+ PrivateCopies.push_back(nullptr);
continue;
}
- // Finalize nontemporal clause by handling private copies, if any.
- if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
- SmallVector<Expr *, 8> PrivateRefs;
- for (Expr *RefExpr : Clause->varlist()) {
- assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
- SourceLocation ELoc;
- SourceRange ERange;
- Expr *SimpleRefExpr = RefExpr;
- auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange);
- if (Res.second)
- // It will be analyzed later.
- PrivateRefs.push_back(RefExpr);
- ValueDecl *D = Res.first;
- if (!D)
- continue;
-
- const DSAStackTy::DSAVarData DVar =
- DSAStack->getTopDSA(D, /*FromParent=*/false);
- PrivateRefs.push_back(DVar.PrivateCopy ? DVar.PrivateCopy
- : SimpleRefExpr);
- }
- Clause->setPrivateRefs(PrivateRefs);
+ auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens());
+ auto *VD = cast<VarDecl>(DRE->getDecl());
+ QualType Type = VD->getType().getNonReferenceType();
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ if (DVar.CKind != OMPC_lastprivate) {
+ // The variable is also a firstprivate, so initialization sequence
+ // for private copy is generated already.
+ PrivateCopies.push_back(nullptr);
continue;
}
- if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
- for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) {
- OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I);
- auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts());
- if (!DRE)
- continue;
- ValueDecl *VD = DRE->getDecl();
- if (!VD || !isa<VarDecl>(VD))
- continue;
- DSAStackTy::DSAVarData DVar =
- DSAStack->getTopDSA(VD, /*FromParent=*/false);
- // OpenMP [2.12.5, target Construct]
- // Memory allocators that appear in a uses_allocators clause cannot
- // appear in other data-sharing attribute clauses or data-mapping
- // attribute clauses in the same construct.
- Expr *MapExpr = nullptr;
- if (DVar.RefExpr ||
- DSAStack->checkMappableExprComponentListsForDecl(
- VD, /*CurrentRegionOnly=*/true,
- [VD, &MapExpr](
- OMPClauseMappableExprCommon::MappableExprComponentListRef
- MapExprComponents,
- OpenMPClauseKind C) {
- auto MI = MapExprComponents.rbegin();
- auto ME = MapExprComponents.rend();
- if (MI != ME &&
- MI->getAssociatedDeclaration()->getCanonicalDecl() ==
- VD->getCanonicalDecl()) {
- MapExpr = MI->getAssociatedExpression();
- return true;
- }
- return false;
- })) {
- Diag(D.Allocator->getExprLoc(),
- diag::err_omp_allocator_used_in_clauses)
- << D.Allocator->getSourceRange();
- if (DVar.RefExpr)
- reportOriginalDsa(SemaRef, DSAStack, VD, DVar);
- else
- Diag(MapExpr->getExprLoc(), diag::note_used_here)
- << MapExpr->getSourceRange();
- }
- }
+ // Generate helper private variable and initialize it with the
+ // default value. The address of the original variable is replaced
+ // by the address of the new private variable in CodeGen. This new
+ // variable is not added to IdResolver, so the code in the OpenMP
+ // region uses original variable for proper diagnostics.
+ VarDecl *VDPrivate = buildVarDecl(
+ SemaRef, DE->getExprLoc(), Type.getUnqualifiedType(), VD->getName(),
+ VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE);
+ SemaRef.ActOnUninitializedDecl(VDPrivate);
+ if (VDPrivate->isInvalidDecl()) {
+ PrivateCopies.push_back(nullptr);
+ continue;
+ }
+ PrivateCopies.push_back(buildDeclRefExpr(
+ SemaRef, VDPrivate, DE->getType(), DE->getExprLoc()));
+ }
+ Clause->setPrivateCopies(PrivateCopies);
+ };
+
+ auto FinalizeNontemporal = [&](OMPNontemporalClause *Clause) {
+ // Finalize nontemporal clause by handling private copies, if any.
+ SmallVector<Expr *, 8> PrivateRefs;
+ for (Expr *RefExpr : Clause->varlist()) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange);
+ if (Res.second)
+ // It will be analyzed later.
+ PrivateRefs.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
+
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ PrivateRefs.push_back(DVar.PrivateCopy ? DVar.PrivateCopy
+ : SimpleRefExpr);
+ }
+ Clause->setPrivateRefs(PrivateRefs);
+ };
+
+ auto FinalizeAllocators = [&](OMPUsesAllocatorsClause *Clause) {
+ for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I);
+ auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts());
+ if (!DRE)
+ continue;
+ ValueDecl *VD = DRE->getDecl();
+ if (!VD || !isa<VarDecl>(VD))
+ continue;
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ // OpenMP [2.12.5, target Construct]
+ // Memory allocators that appear in a uses_allocators clause cannot
+ // appear in other data-sharing attribute clauses or data-mapping
+ // attribute clauses in the same construct.
+ Expr *MapExpr = nullptr;
+ if (DVar.RefExpr ||
+ DSAStack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [VD, &MapExpr](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents,
+ OpenMPClauseKind C) {
+ auto MI = MapExprComponents.rbegin();
+ auto ME = MapExprComponents.rend();
+ if (MI != ME &&
+ MI->getAssociatedDeclaration()->getCanonicalDecl() ==
+ VD->getCanonicalDecl()) {
+ MapExpr = MI->getAssociatedExpression();
+ return true;
+ }
+ return false;
+ })) {
+ Diag(D.Allocator->getExprLoc(), diag::err_omp_allocator_used_in_clauses)
+ << D.Allocator->getSourceRange();
+ if (DVar.RefExpr)
+ reportOriginalDsa(SemaRef, DSAStack, VD, DVar);
+ else
+ Diag(MapExpr->getExprLoc(), diag::note_used_here)
+ << MapExpr->getSourceRange();
+ }
+ }
+ };
+
+ if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
+ for (OMPClause *C : D->clauses()) {
+ if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
+ FinalizeLastprivate(Clause);
+ } else if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
+ FinalizeNontemporal(Clause);
+ } else if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ FinalizeAllocators(Clause);
}
}
// Check allocate clauses.
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index d304f322aced64..2e36f652baa5df 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -330,6 +330,8 @@ static const Expr *IgnoreNarrowingConversion(ASTContext &Ctx,
while (auto *ICE = dyn_cast<ImplicitCastExpr>(Converted)) {
switch (ICE->getCastKind()) {
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_IntegralCast:
case CK_IntegralToBoolean:
case CK_IntegralToFloating:
@@ -14206,7 +14208,9 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
// was a LambdaExpr.
Expr *SubE = E;
auto *CE = dyn_cast<CastExpr>(SubE);
- if (CE && CE->getCastKind() == CK_NoOp)
+ if (CE && (CE->getCastKind() == CK_NoOp ||
+ CE->getCastKind() == CK_FunctionPointerConversion ||
+ CE->getCastKind() == CK_MemberFunctionPointerConversion))
SubE = CE->getSubExpr();
SubE = SubE->IgnoreParens();
if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(SubE))
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 9664287b9a3fe9..b8c36eee7ce066 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -281,6 +281,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
E = WarnExpr;
if (const auto *Cast = dyn_cast<CastExpr>(E))
if (Cast->getCastKind() == CK_NoOp ||
+ Cast->getCastKind() == CK_FunctionPointerConversion ||
+ Cast->getCastKind() == CK_MemberFunctionPointerConversion ||
Cast->getCastKind() == CK_ConstructorConversion ||
Cast->getCastKind() == CK_IntegralCast)
E = Cast->getSubExpr()->IgnoreImpCasts();
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 7a900780384a91..ad021d12a7fd43 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -327,6 +327,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_NonAtomicToAtomic:
// True no-ops.
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_ConstructorConversion:
case CK_UserDefinedConversion:
case CK_FunctionToPointerDecay:
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 7eca0579143f44..341d794aabdcc2 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -397,6 +397,8 @@ std::optional<SVal> SValBuilder::getConstantVal(const Expr *E) {
case CK_ArrayToPointerDecay:
case CK_IntegralToPointer:
case CK_NoOp:
+ case CK_FunctionPointerConversion:
+ case CK_MemberFunctionPointerConversion:
case CK_BitCast: {
const Expr *SE = CE->getSubExpr();
std::optional<SVal> Val = getConstantVal(SE);
diff --git a/clang/test/AST/ast-dump-function-pointer-conversion.cpp b/clang/test/AST/ast-dump-function-pointer-conversion.cpp
new file mode 100644
index 00000000000000..4c545e5bc40524
--- /dev/null
+++ b/clang/test/AST/ast-dump-function-pointer-conversion.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++17 -ast-dump %s | FileCheck --check-prefixes=CHECK,CXX17 %s
+// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s
+
+void f() noexcept;
+
+struct S {
+ void m() noexcept;
+};
+
+// CHECK: FunctionDecl {{.*}} testFunctionPointerConversion 'void ()'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} fp 'void (*)()' cinit
+// CXX17-NEXT: ImplicitCastExpr {{.*}} 'void (*)()' <FunctionPointerConversion>
+// CHECK-NEXT: UnaryOperator {{.*}} 'void (*)() noexcept' prefix '&'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'void () noexcept' lvalue Function {{.*}} 'f' 'void () noexcept'
+void testFunctionPointerConversion() {
+ void (*fp)() = &f;
+}
+
+// CHECK: FunctionDecl {{.*}} testMemberFunctionPointerConversion 'void ()'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} mfp 'void (S::*)()' cinit
+// CXX17-NEXT: ImplicitCastExpr {{.*}} 'void (S::*)()' <MemberFunctionPointerConversion>
+// CHECK-NEXT: UnaryOperator {{.*}} 'void (S::*)() noexcept' prefix '&'
+// CHECK-NEXT: DeclRefExpr {{.*}} 'void () noexcept' CXXMethod {{.*}} 'm' 'void () noexcept'
+void testMemberFunctionPointerConversion() {
+ void (S::*mfp)() = &S::m;
+}
diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp
index 32c4ddd921bba1..a6209337a08864 100644
--- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p4-ast.cpp
@@ -3,7 +3,7 @@
void f() noexcept;
// CHECK: VarDecl {{.*}} ref 'void (&)()' cinit
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()' lvalue <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()' lvalue <FunctionPointerConversion>
// CHECK-NEXT: DeclRefExpr {{.*}} 'void () noexcept' lvalue Function {{.*}} 'f' 'void () noexcept'
void (&ref)() = f;
@@ -13,6 +13,6 @@ struct X {
} x;
// CHECK: VarDecl {{.*}} xp 'void (&)()' cinit
-// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()' lvalue <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void ()' lvalue <FunctionPointerConversion>
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'void () noexcept' lvalue <UserDefinedConversion>
void (&xp)() = x;
diff --git a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
index b39311ad67cd62..f954c9d2f029f2 100644
--- a/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
+++ b/clang/test/CodeGenHLSL/GlobalConstructorFunction.hlsl
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -O0 %s -o - | FileCheck %s --check-prefixes=CHECK,INLINE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
int i;
@@ -8,7 +7,7 @@ __attribute__((constructor)) void call_me_first(void) {
}
__attribute__((constructor)) void then_call_me(void) {
- i = 13;
+ i = 12;
}
__attribute__((destructor)) void call_me_last(void) {
@@ -22,21 +21,11 @@ void main(unsigned GI : SV_GroupIndex) {}
// CHECK-NOT:@llvm.global_ctors
// CHECK-NOT:@llvm.global_dtors
-// CHECK: define void @main()
-// CHECK-NEXT: entry:
-// Verify function constructors are emitted
-// NOINLINE-NEXT: call void @"?call_me_first@@YAXXZ"()
-// NOINLINE-NEXT: call void @"?then_call_me@@YAXXZ"()
-// NOINLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
-// NOINLINE-NEXT: call void @"?main@@YAXI at Z"(i32 %0)
-// NOINLINE-NEXT: call void @"?call_me_last@@YAXXZ"(
-// NOINLINE-NEXT: ret void
-
-// Verify constructor calls are inlined when AlwaysInline is run
-// INLINE-NEXT: alloca
-// INLINE-NEXT: store i32 12
-// INLINE-NEXT: store i32 13
-// INLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
-// INLINE-NEXT: store i32 %
-// INLINE-NEXT: store i32 0
-// INLINE: ret void
+//CHECK: define void @main()
+//CHECK-NEXT: entry:
+//CHECK-NEXT: call void @"?call_me_first@@YAXXZ"()
+//CHECK-NEXT: call void @"?then_call_me@@YAXXZ"()
+//CHECK-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
+//CHECK-NEXT: call void @"?main@@YAXI at Z"(i32 %0)
+//CHECK-NEXT: call void @"?call_me_last@@YAXXZ"(
+//CHECK-NEXT: ret void
diff --git a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl
index 78f6475462bc47..2c5c4e19c3296d 100644
--- a/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl
+++ b/clang/test/CodeGenHLSL/GlobalConstructorLib.hlsl
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -O0 %s -o - | FileCheck %s --check-prefixes=CHECK,INLINE
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s
// Make sure global variable for ctors exist for lib profile.
// CHECK:@llvm.global_ctors
@@ -12,11 +11,7 @@ void FirstEntry() {}
// CHECK: define void @FirstEntry()
// CHECK-NEXT: entry:
-// NOINLINE-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl()
-// NOINLINE-NEXT: call void @"?FirstEntry@@YAXXZ"()
-// Verify inlining leaves only calls to "llvm." intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
+// CHECK-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl()
[shader("compute")]
[numthreads(1,1,1)]
@@ -24,15 +19,5 @@ void SecondEntry() {}
// CHECK: define void @SecondEntry()
// CHECK-NEXT: entry:
-// NOINLINE-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl()
-// NOINLINE-NEXT: call void @"?SecondEntry@@YAXXZ"()
-// Verify inlining leaves only calls to "llvm." intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
-
-
-// Verify the constructor is alwaysinline
-// NOINLINE: ; Function Attrs: {{.*}}alwaysinline
-// NOINLINE-NEXT: define internal void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl() [[IntAttr:\#[0-9]+]]
-
-// NOINLINE: attributes [[IntAttr]] = {{.*}} alwaysinline
+// CHECK-NEXT: call void @_GLOBAL__sub_I_GlobalConstructorLib.hlsl()
+// CHECK-NEXT: call void @"?SecondEntry@@YAXXZ"()
diff --git a/clang/test/CodeGenHLSL/GlobalDestructors.hlsl b/clang/test/CodeGenHLSL/GlobalDestructors.hlsl
index ea28354222f885..24c3c039fc6192 100644
--- a/clang/test/CodeGenHLSL/GlobalDestructors.hlsl
+++ b/clang/test/CodeGenHLSL/GlobalDestructors.hlsl
@@ -1,18 +1,10 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CS,NOINLINE,CHECK
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=LIB,NOINLINE,CHECK
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -O0 %s -o - | FileCheck %s --check-prefixes=INLINE,CHECK
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -O0 %s -o - | FileCheck %s --check-prefixes=INLINE,CHECK
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=CS,CHECK
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -disable-llvm-passes %s -o - | FileCheck %s --check-prefixes=LIB,CHECK
-// Tests that constructors and destructors are appropriately generated for globals
-// and that their calls are inlined when AlwaysInline is run
-// but global variables are retained for the library profiles
-
-// Make sure global variable for ctors/dtors exist for lib profile.
-// LIB:@llvm.global_ctors
+// Make sure global variable for dtors exist for lib profile.
// LIB:@llvm.global_dtors
-// Make sure global variable for ctors/dtors removed for compute profile.
-// CS-NOT:@llvm.global_ctors
-// CS-NOT:@llvm.global_dtors
+// Make sure global variable for dtors removed for compute profile.
+// CS-NOT:llvm.global_dtors
struct Tail {
Tail() {
@@ -54,25 +46,22 @@ void main(unsigned GI : SV_GroupIndex) {
Wag();
}
-// CHECK: define void @main()
-// CHECK-NEXT: entry:
-// Verify destructor is emitted
-// NOINLINE-NEXT: call void @_GLOBAL__sub_I_GlobalDestructors.hlsl()
-// NOINLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
-// NOINLINE-NEXT: call void @"?main@@YAXI at Z"(i32 %0)
-// NOINLINE-NEXT: call void @_GLOBAL__D_a()
-// NOINLINE-NEXT: ret void
-// Verify inlining leaves only calls to "llvm." intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// INLINE: ret void
+// Make sure global variable for ctors/dtors removed.
+// CHECK-NOT:@llvm.global_ctors
+// CHECK-NOT:@llvm.global_dtors
+//CHECK: define void @main()
+//CHECK-NEXT: entry:
+//CHECK-NEXT: call void @_GLOBAL__sub_I_GlobalDestructors.hlsl()
+//CHECK-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
+//CHECK-NEXT: call void @"?main@@YAXI at Z"(i32 %0)
+//CHECK-NEXT: call void @_GLOBAL__D_a()
+//CHECK-NEXT: ret void
// This is really just a sanity check I needed for myself to verify that
// function scope static variables also get destroyed properly.
-// NOINLINE: define internal void @_GLOBAL__D_a() [[IntAttr:\#[0-9]+]]
-// NOINLINE-NEXT: entry:
-// NOINLINE-NEXT: call void @"??1Tail@@QAA at XZ"(ptr @"?T@?1??Wag@@YAXXZ at 4UTail@@A")
-// NOINLINE-NEXT: call void @"??1Pupper@@QAA at XZ"(ptr @"?GlobalPup@@3UPupper@@A")
-// NOINLINE-NEXT: ret void
-
-// NOINLINE: attributes [[IntAttr]] = {{.*}} alwaysinline
+//CHECK: define internal void @_GLOBAL__D_a()
+//CHECK-NEXT: entry:
+//CHECK-NEXT: call void @"??1Tail@@QAA at XZ"(ptr @"?T@?1??Wag@@YAXXZ at 4UTail@@A")
+//CHECK-NEXT: call void @"??1Pupper@@QAA at XZ"(ptr @"?GlobalPup@@3UPupper@@A")
+//CHECK-NEXT: ret void
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
index 174f4c3eaaad26..baddfcf2cf1d52 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl
@@ -1,4 +1,3 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --check-prefix=CHECK-SPIRV
RWBuffer<float> Buf;
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl
index 2a350c1619bd6e..da8a1e538ec5e7 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-subscript.hlsl
@@ -11,7 +11,6 @@ void main(unsigned GI : SV_GroupIndex) {
// Even at -O0 the subscript operators get inlined. The -O0 IR is a bit messy
// and confusing to follow so the match here is pretty weak.
-// CHECK: define void @main()
-// Verify inlining leaves only calls to "llvm." intrinsics
-// CHECK-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
+// CHECK: define internal void @"?main@@YAXI at Z"
+// CHECK-NOT: call
// CHECK: ret void
diff --git a/clang/test/CodeGenHLSL/inline-constructors.hlsl b/clang/test/CodeGenHLSL/inline-constructors.hlsl
deleted file mode 100644
index 995878a9c0f798..00000000000000
--- a/clang/test/CodeGenHLSL/inline-constructors.hlsl
+++ /dev/null
@@ -1,76 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -o - -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -o - -disable-llvm-passes %s | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -o - -O0 %s | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -o - -O0 %s | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -std=hlsl202x -emit-llvm -o - -O1 %s | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -std=hlsl202x -emit-llvm -o - -O1 %s | FileCheck %s --check-prefixes=CHECK,INLINE
-
-// Tests that implicit constructor calls for user classes will always be inlined.
-
-struct Weed {
- Weed() {Count += 1;}
- [[maybe_unused]] void pull() {Count--;}
- static int weedCount() { return Count; }
-private:
- static int Count;
-
-} YardWeeds;
-
-int Weed::Count = 1; // It begins. . .
-
-struct Kitty {
- unsigned burrsInFur;
-
- Kitty() {
- burrsInFur = 0;
- }
-
- void wanderInYard(int hours) {
- burrsInFur = hours*Weed::weedCount()/8;
- }
-
- void lick() {
- if(burrsInFur) {
- burrsInFur--;
- Weed w;
- }
- }
-
-} Nion;
-
-void NionsDay(int hours) {
- static Kitty Nion;
- Nion.wanderInYard(hours);
- while(Nion.burrsInFur) Nion.lick();
-}
-
-// CHECK: define void @main()
-// CHECK-NEXT: entry:
-// Verify constructor is emitted
-// NOINLINE-NEXT: call void @_GLOBAL__sub_I_inline_constructors.hlsl()
-// NOINLINE-NEXT: %0 = call i32 @llvm.dx.flattened.thread.id.in.group()
-// NOINLINE-NEXT: call void @"?main@@YAXI at Z"(i32 %0)
-// Verify inlining leaves only calls to "llvm." intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
-[shader("compute")]
-[numthreads(1,1,1)]
-void main(unsigned GI : SV_GroupIndex) {
- NionsDay(10);
-}
-
-
-// CHECK: define void @rainyMain()
-// CHECK-NEXT: entry:
-// Verify constructor is emitted
-// NOINLINE-NEXT: call void @_GLOBAL__sub_I_inline_constructors.hlsl()
-// NOINLINE-NEXT: call void @"?rainyMain@@YAXXZ"()
-// Verify inlining leaves only calls to "llvm." intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
-[shader("compute")]
-[numthreads(1,1,1)]
-void rainyMain() {
- NionsDay(1);
-}
-
diff --git a/clang/test/CodeGenHLSL/inline-functions.hlsl b/clang/test/CodeGenHLSL/inline-functions.hlsl
deleted file mode 100644
index 7dd905e966e069..00000000000000
--- a/clang/test/CodeGenHLSL/inline-functions.hlsl
+++ /dev/null
@@ -1,116 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,NOINLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O0 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute %s -emit-llvm -O1 -o - | FileCheck %s --check-prefixes=CHECK,INLINE
-
-// Tests that user functions will always be inlined.
-// This includes exported functions and mangled entry point implementation functions.
-// The unmangled entry functions must not be alwaysinlined.
-
-#define MAX 100
-
-float nums[MAX];
-
-// Verify that all functions have the alwaysinline attribute
-// NOINLINE: Function Attrs: alwaysinline
-// NOINLINE: define void @"?swap@@YAXY0GE at III@Z"(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %ix1, i32 noundef %ix2) [[IntAttr:\#[0-9]+]]
-// NOINLINE: ret void
-// Swap the values of Buf at indices ix1 and ix2
-void swap(unsigned Buf[MAX], unsigned ix1, unsigned ix2) {
- float tmp = Buf[ix1];
- Buf[ix1] = Buf[ix2];
- Buf[ix2] = tmp;
-}
-
-// NOINLINE: Function Attrs: alwaysinline
-// NOINLINE: define void @"?BubbleSort@@YAXY0GE at II@Z"(ptr noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) [[IntAttr]]
-// NOINLINE: ret void
-// Inefficiently sort Buf in place
-void BubbleSort(unsigned Buf[MAX], unsigned size) {
- bool swapped = true;
- while (swapped) {
- swapped = false;
- for (unsigned i = 1; i < size; i++) {
- if (Buf[i] < Buf[i-1]) {
- swap(Buf, i, i-1);
- swapped = true;
- }
- }
- }
-}
-
-// Note ExtAttr is the inlined export set of attribs
-// CHECK: Function Attrs: alwaysinline
-// CHECK: define noundef i32 @"?RemoveDupes@@YAIY0GE at II@Z"(ptr {{[a-z_ ]*}}noundef byval([100 x i32]) align 4 %Buf, i32 noundef %size) {{[a-z_ ]*}}[[ExtAttr:\#[0-9]+]]
-// CHECK: ret i32
-// Sort Buf and remove any duplicate values
-// returns the number of values left
-export
-unsigned RemoveDupes(unsigned Buf[MAX], unsigned size) {
- BubbleSort(Buf, size);
- unsigned insertPt = 0;
- for (unsigned i = 1; i < size; i++) {
- if (Buf[i] == Buf[i-1])
- insertPt++;
- else
- Buf[insertPt] = Buf[i];
- }
- return insertPt;
-}
-
-
-RWBuffer<unsigned> Indices;
-
-// The mangled version of main only remains without inlining
-// because it has internal linkage from the start
-// Note main functions get the norecurse attrib, which IntAttr reflects
-// NOINLINE: Function Attrs: alwaysinline
-// NOINLINE: define internal void @"?main@@YAXI at Z"(i32 noundef %GI) [[IntAttr]]
-// NOINLINE: ret void
-
-// The unmangled version is not inlined, EntryAttr reflects that
-// CHECK: Function Attrs: {{.*}}noinline
-// CHECK: define void @main() {{[a-z_ ]*}}[[EntryAttr:\#[0-9]+]]
-// Make sure function calls are inlined when AlwaysInline is run
-// This only leaves calls to llvm. intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
-
-[numthreads(1,1,1)]
-[shader("compute")]
-void main(unsigned int GI : SV_GroupIndex) {
- unsigned tmpIndices[MAX];
- if (GI > MAX) return;
- for (unsigned i = 1; i < GI; i++)
- tmpIndices[i] = Indices[i];
- RemoveDupes(tmpIndices, GI);
- for (unsigned i = 1; i < GI; i++)
- tmpIndices[i] = Indices[i];
-}
-
-// The mangled version of main only remains without inlining
-// because it has internal linkage from the start
-// Note main functions get the norecurse attrib, which IntAttr reflects
-// NOINLINE: Function Attrs: alwaysinline
-// NOINLINE: define internal void @"?main10@@YAXXZ"() [[IntAttr]]
-// NOINLINE: ret void
-
-// The unmangled version is not inlined, EntryAttr reflects that
-// CHECK: Function Attrs: {{.*}}noinline
-// CHECK: define void @main10() {{[a-z_ ]*}}[[EntryAttr]]
-// Make sure function calls are inlined when AlwaysInline is run
-// This only leaves calls to llvm. intrinsics
-// INLINE-NOT: call {{[^@]*}} @{{[^l][^l][^v][^m][^\.]}}
-// CHECK: ret void
-
-[numthreads(1,1,1)]
-[shader("compute")]
-void main10() {
- main(10);
-}
-
-// NOINLINE: attributes [[IntAttr]] = {{.*}} alwaysinline
-// CHECK: attributes [[ExtAttr]] = {{.*}} alwaysinline
-// CHECK: attributes [[EntryAttr]] = {{.*}} noinline
diff --git a/llvm/include/llvm/CodeGen/VirtRegMap.h b/llvm/include/llvm/CodeGen/VirtRegMap.h
index dee462255b0b28..52221762fed5d0 100644
--- a/llvm/include/llvm/CodeGen/VirtRegMap.h
+++ b/llvm/include/llvm/CodeGen/VirtRegMap.h
@@ -31,12 +31,6 @@ class raw_ostream;
class TargetInstrInfo;
class VirtRegMap : public MachineFunctionPass {
- public:
- enum {
- NO_STACK_SLOT = (1L << 30)-1,
- };
-
- private:
MachineRegisterInfo *MRI = nullptr;
const TargetInstrInfo *TII = nullptr;
const TargetRegisterInfo *TRI = nullptr;
@@ -69,6 +63,8 @@ class TargetInstrInfo;
public:
static char ID;
+ static constexpr int NO_STACK_SLOT = INT_MAX;
+
VirtRegMap() : MachineFunctionPass(ID), Virt2StackSlotMap(NO_STACK_SLOT) {}
VirtRegMap(const VirtRegMap &) = delete;
VirtRegMap &operator=(const VirtRegMap &) = delete;
diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 22b46bd8d7da14..b276c06033596d 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -130,6 +130,7 @@ class GlobalValue;
class GlobalObject;
class GlobalIFunc;
class GlobalVariable;
+class GlobalAlias;
class Context;
class Function;
class Instruction;
@@ -336,6 +337,7 @@ class Value {
friend class GlobalObject; // For `Val`.
friend class GlobalIFunc; // For `Val`.
friend class GlobalVariable; // For `Val`.
+ friend class GlobalAlias; // For `Val`.
/// All values point to the context.
Context &Ctx;
@@ -1528,6 +1530,38 @@ class GlobalVariable final
#endif
};
+class GlobalAlias final
+ : public GlobalWithNodeAPI<GlobalAlias, llvm::GlobalAlias, GlobalValue,
+ llvm::GlobalValue> {
+ GlobalAlias(llvm::GlobalAlias *C, Context &Ctx)
+ : GlobalWithNodeAPI(ClassID::GlobalAlias, C, Ctx) {}
+ friend class Context; // For constructor.
+
+public:
+ /// For isa/dyn_cast.
+ static bool classof(const sandboxir::Value *From) {
+ return From->getSubclassID() == ClassID::GlobalAlias;
+ }
+
+ // TODO: Missing create() due to unimplemented sandboxir::Module.
+
+ // TODO: Missing copyAttributresFrom().
+ // TODO: Missing removeFromParent(), eraseFromParent().
+
+ void setAliasee(Constant *Aliasee);
+ Constant *getAliasee() const;
+
+ const GlobalObject *getAliaseeObject() const;
+ GlobalObject *getAliaseeObject() {
+ return const_cast<GlobalObject *>(
+ static_cast<const GlobalAlias *>(this)->getAliaseeObject());
+ }
+
+ static bool isValidLinkage(LinkageTypes L) {
+ return llvm::GlobalAlias::isValidLinkage(L);
+ }
+};
+
class BlockAddress final : public Constant {
BlockAddress(llvm::BlockAddress *C, Context &Ctx)
: Constant(ClassID::BlockAddress, C, Ctx) {}
diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp
index 6eed73c15f091d..1fcbeeec6f64cc 100644
--- a/llvm/lib/CodeGen/MachineVerifier.cpp
+++ b/llvm/lib/CodeGen/MachineVerifier.cpp
@@ -1739,7 +1739,7 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
}
if (IndexOp.getImm() != 0 &&
- Src1Ty.getElementCount().getKnownMinValue() % IndexOp.getImm() != 0) {
+ IndexOp.getImm() % Src1Ty.getElementCount().getKnownMinValue() != 0) {
report("Index must be a multiple of the second source vector's "
"minimum vector length",
MI);
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index c26ba1983db91e..d047a53b4752ee 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -2534,6 +2534,8 @@ template class GlobalWithNodeAPI<Function, llvm::Function, GlobalObject,
llvm::GlobalObject>;
template class GlobalWithNodeAPI<GlobalVariable, llvm::GlobalVariable,
GlobalObject, llvm::GlobalObject>;
+template class GlobalWithNodeAPI<GlobalAlias, llvm::GlobalAlias, GlobalValue,
+ llvm::GlobalValue>;
} // namespace llvm::sandboxir
void GlobalIFunc::setResolver(Constant *Resolver) {
@@ -2587,6 +2589,24 @@ void GlobalVariable::setExternallyInitialized(bool V) {
cast<llvm::GlobalVariable>(Val)->setExternallyInitialized(V);
}
+void GlobalAlias::setAliasee(Constant *Aliasee) {
+ Ctx.getTracker()
+ .emplaceIfTracking<
+ GenericSetter<&GlobalAlias::getAliasee, &GlobalAlias::setAliasee>>(
+ this);
+ cast<llvm::GlobalAlias>(Val)->setAliasee(cast<llvm::Constant>(Aliasee->Val));
+}
+
+Constant *GlobalAlias::getAliasee() const {
+ return cast<Constant>(
+ Ctx.getOrCreateConstant(cast<llvm::GlobalAlias>(Val)->getAliasee()));
+}
+
+const GlobalObject *GlobalAlias::getAliaseeObject() const {
+ return cast<GlobalObject>(Ctx.getOrCreateConstant(
+ cast<llvm::GlobalAlias>(Val)->getAliaseeObject()));
+}
+
void GlobalValue::setUnnamedAddr(UnnamedAddr V) {
Ctx.getTracker()
.emplaceIfTracking<GenericSetter<&GlobalValue::getUnnamedAddr,
@@ -2803,6 +2823,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
It->second = std::unique_ptr<GlobalVariable>(
new GlobalVariable(cast<llvm::GlobalVariable>(C), *this));
break;
+ case llvm::Value::GlobalAliasVal:
+ It->second = std::unique_ptr<GlobalAlias>(
+ new GlobalAlias(cast<llvm::GlobalAlias>(C), *this));
+ break;
default:
It->second = std::unique_ptr<Constant>(new Constant(C, *this));
break;
diff --git a/llvm/test/MachineVerifier/test_g_insert_subvector.mir b/llvm/test/MachineVerifier/test_g_insert_subvector.mir
index 9fce3c3e842d40..62ddd28919b205 100644
--- a/llvm/test/MachineVerifier/test_g_insert_subvector.mir
+++ b/llvm/test/MachineVerifier/test_g_insert_subvector.mir
@@ -41,4 +41,7 @@ body: |
; CHECK: Index must be a multiple of the second source vector's minimum vector length
%13:_(<vscale x 4 x s32>) = G_INSERT_SUBVECTOR %12, %1, 3
+
+ ; CHECK: Index must be a multiple of the second source vector's minimum vector length
+ %13:_(<vscale x 4 x s32>) = G_INSERT_SUBVECTOR %12, %1, 1
...
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 5ded063ef6f735..b998091f6d7a97 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -1051,6 +1051,72 @@ define void @foo() {
EXPECT_EQ(GV0->getCodeModel(), LLVMGV0->getCodeModel());
}
+TEST_F(SandboxIRTest, GlobalAlias) {
+ parseIR(C, R"IR(
+ at alias0 = dso_local alias void(), ptr @foo
+ at alias1 = dso_local alias void(), ptr @foo
+declare void @bar();
+define void @foo() {
+ call void @alias0()
+ call void @alias1()
+ call void @bar()
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ auto *LLVMBB = &*LLVMF.begin();
+ auto LLVMIt = LLVMBB->begin();
+ auto *LLVMCall0 = cast<llvm::CallInst>(&*LLVMIt++);
+ auto *LLVMAlias0 = cast<llvm::GlobalAlias>(LLVMCall0->getCalledOperand());
+ sandboxir::Context Ctx(C);
+
+ auto &F = *Ctx.createFunction(&LLVMF);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *Call0 = cast<sandboxir::CallInst>(&*It++);
+ auto *Call1 = cast<sandboxir::CallInst>(&*It++);
+ auto *CallBar = cast<sandboxir::CallInst>(&*It++);
+ auto *CalleeBar = cast<sandboxir::Constant>(CallBar->getCalledOperand());
+ // Check classof(), creation.
+ auto *Alias0 = cast<sandboxir::GlobalAlias>(Call0->getCalledOperand());
+ auto *Alias1 = cast<sandboxir::GlobalAlias>(Call1->getCalledOperand());
+ // Check getIterator().
+ {
+ auto It0 = Alias0->getIterator();
+ auto It1 = Alias1->getIterator();
+ EXPECT_EQ(&*It0, Alias0);
+ EXPECT_EQ(&*It1, Alias1);
+ EXPECT_EQ(std::next(It0), It1);
+ EXPECT_EQ(std::prev(It1), It0);
+ EXPECT_EQ(&*std::next(It0), Alias1);
+ EXPECT_EQ(&*std::prev(It1), Alias0);
+ }
+ // Check getReverseIterator().
+ {
+ auto RevIt0 = Alias0->getReverseIterator();
+ auto RevIt1 = Alias1->getReverseIterator();
+ EXPECT_EQ(&*RevIt0, Alias0);
+ EXPECT_EQ(&*RevIt1, Alias1);
+ EXPECT_EQ(std::prev(RevIt0), RevIt1);
+ EXPECT_EQ(std::next(RevIt1), RevIt0);
+ EXPECT_EQ(&*std::prev(RevIt0), Alias1);
+ EXPECT_EQ(&*std::next(RevIt1), Alias0);
+ }
+ // Check getAliasee().
+ EXPECT_EQ(Alias0->getAliasee(), Ctx.getValue(LLVMAlias0->getAliasee()));
+ // Check setAliasee().
+ auto *OrigAliasee = Alias0->getAliasee();
+ auto *NewAliasee = CalleeBar;
+ EXPECT_NE(NewAliasee, OrigAliasee);
+ Alias0->setAliasee(NewAliasee);
+ EXPECT_EQ(Alias0->getAliasee(), NewAliasee);
+ Alias0->setAliasee(OrigAliasee);
+ EXPECT_EQ(Alias0->getAliasee(), OrigAliasee);
+ // Check getAliaseeObject().
+ EXPECT_EQ(Alias0->getAliaseeObject(),
+ Ctx.getValue(LLVMAlias0->getAliaseeObject()));
+}
+
TEST_F(SandboxIRTest, BlockAddress) {
parseIR(C, R"IR(
define void @foo(ptr %ptr) {
diff --git a/llvm/unittests/SandboxIR/TrackerTest.cpp b/llvm/unittests/SandboxIR/TrackerTest.cpp
index f46e16e626baf0..da5416395ec42f 100644
--- a/llvm/unittests/SandboxIR/TrackerTest.cpp
+++ b/llvm/unittests/SandboxIR/TrackerTest.cpp
@@ -1638,6 +1638,37 @@ define void @foo() {
EXPECT_EQ(GV0->isExternallyInitialized(), OrigIsExtInit);
}
+TEST_F(TrackerTest, GlobalAliasSetters) {
+ parseIR(C, R"IR(
+ at alias = dso_local alias void(), ptr @foo
+declare void @bar();
+define void @foo() {
+ call void @alias()
+ call void @bar()
+ ret void
+}
+)IR");
+ Function &LLVMF = *M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+
+ auto &F = *Ctx.createFunction(&LLVMF);
+ auto *BB = &*F.begin();
+ auto It = BB->begin();
+ auto *Call0 = cast<sandboxir::CallInst>(&*It++);
+ auto *Call1 = cast<sandboxir::CallInst>(&*It++);
+ auto *Callee1 = cast<sandboxir::Constant>(Call1->getCalledOperand());
+ auto *Alias = cast<sandboxir::GlobalAlias>(Call0->getCalledOperand());
+ // Check setAliasee().
+ auto *OrigAliasee = Alias->getAliasee();
+ auto *NewAliasee = Callee1;
+ EXPECT_NE(NewAliasee, OrigAliasee);
+ Ctx.save();
+ Alias->setAliasee(NewAliasee);
+ EXPECT_EQ(Alias->getAliasee(), NewAliasee);
+ Ctx.revert();
+ EXPECT_EQ(Alias->getAliasee(), OrigAliasee);
+}
+
TEST_F(TrackerTest, SetVolatile) {
parseIR(C, R"IR(
define void @foo(ptr %arg0, i8 %val) {
More information about the cfe-commits
mailing list