[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