summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2024-03-16 14:24:50 -0700
committerFangrui Song <i@maskray.me>2024-03-16 14:24:50 -0700
commit3aa7d5b9726ba51fc943ad80c11369264806fcce (patch)
tree32beb24493d323a3264e32ae5733011dd7530f1a
parent0fd3675447f41b033472f9269648e8e735bc543a (diff)
parent84b5178124e47f6019b56c04abcfb978a94b1c3c (diff)
Created using spr 1.3.5-bogner
-rw-r--r--.github/workflows/pr-code-format.yml2
-rw-r--r--clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp16
-rw-r--r--clang/cmake/caches/Fuchsia-stage2.cmake1
-rw-r--r--clang/docs/ReleaseNotes.rst14
-rw-r--r--clang/include/clang/AST/Availability.h3
-rw-r--r--clang/include/clang/Basic/AllDiagnostics.h1
-rw-r--r--clang/include/clang/Basic/Builtins.td6
-rw-r--r--clang/include/clang/Basic/CMakeLists.txt1
-rw-r--r--clang/include/clang/Basic/Diagnostic.td1
-rw-r--r--clang/include/clang/Basic/DiagnosticIDs.h4
-rw-r--r--clang/include/clang/Basic/DiagnosticInstallAPI.h26
-rw-r--r--clang/include/clang/Basic/DiagnosticInstallAPIKinds.td20
-rw-r--r--clang/include/clang/Driver/Driver.h9
-rw-r--r--clang/include/clang/Format/.clang-format7
-rw-r--r--clang/include/clang/InstallAPI/Context.h4
-rw-r--r--clang/include/clang/InstallAPI/DylibVerifier.h104
-rw-r--r--clang/include/clang/InstallAPI/Frontend.h1
-rw-r--r--clang/include/clang/InstallAPI/FrontendRecords.h49
-rw-r--r--clang/include/clang/InstallAPI/InstallAPIDiagnostic.h14
-rw-r--r--clang/include/clang/InstallAPI/MachO.h3
-rw-r--r--clang/lib/AST/DeclCXX.cpp7
-rw-r--r--clang/lib/AST/Expr.cpp13
-rw-r--r--clang/lib/AST/ExprConstant.cpp3
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp8
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.h1
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp5
-rw-r--r--clang/lib/Basic/DiagnosticIDs.cpp10
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp15
-rw-r--r--clang/lib/Driver/Driver.cpp129
-rw-r--r--clang/lib/Format/.clang-format7
-rw-r--r--clang/lib/Format/BreakableToken.h3
-rw-r--r--clang/lib/Format/ContinuationIndenter.h5
-rw-r--r--clang/lib/Format/Encoding.h1
-rw-r--r--clang/lib/Format/Format.cpp28
-rw-r--r--clang/lib/Format/FormatInternal.h3
-rw-r--r--clang/lib/Format/FormatToken.h2
-rw-r--r--clang/lib/Format/FormatTokenLexer.h5
-rw-r--r--clang/lib/Format/FormatTokenSource.h3
-rw-r--r--clang/lib/Format/Macros.h6
-rw-r--r--clang/lib/Format/SortJavaScriptImports.h3
-rw-r--r--clang/lib/Format/TokenAnalyzer.h11
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp22
-rw-r--r--clang/lib/Format/TokenAnnotator.h1
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.h2
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp15
-rw-r--r--clang/lib/Format/UnwrappedLineParser.h9
-rw-r--r--clang/lib/Format/WhitespaceManager.h5
-rw-r--r--clang/lib/Headers/hlsl/hlsl_intrinsics.h110
-rw-r--r--clang/lib/InstallAPI/CMakeLists.txt2
-rw-r--r--clang/lib/InstallAPI/DylibVerifier.cpp212
-rw-r--r--clang/lib/InstallAPI/Frontend.cpp49
-rw-r--r--clang/lib/InstallAPI/Visitor.cpp101
-rw-r--r--clang/lib/Sema/SemaChecking.cpp15
-rw-r--r--clang/lib/Sema/SemaConcept.cpp6
-rw-r--r--clang/test/AST/Interp/builtin-functions.cpp2
-rw-r--r--clang/test/AST/Interp/literals.cpp12
-rw-r--r--clang/test/CodeGenCXX/mangle-ms-back-references.cpp17
-rw-r--r--clang/test/CodeGenHLSL/builtins/clamp-builtin.hlsl8
-rw-r--r--clang/test/CodeGenHLSL/builtins/clamp.hlsl134
-rw-r--r--clang/test/InstallAPI/asm.test90
-rw-r--r--clang/test/InstallAPI/driver-invalid-options.test7
-rw-r--r--clang/test/InstallAPI/functions.test2
-rw-r--r--clang/test/SemaCXX/cxx23-assume.cpp10
-rw-r--r--clang/test/SemaCXX/lambda-expressions.cpp21
-rw-r--r--clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl91
-rw-r--r--clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl6
-rw-r--r--clang/test/SemaTemplate/concepts.cpp29
-rw-r--r--clang/tools/clang-format/.clang-format7
-rw-r--r--clang/tools/clang-installapi/CMakeLists.txt8
-rw-r--r--clang/tools/clang-installapi/ClangInstallAPI.cpp35
-rw-r--r--clang/tools/clang-installapi/InstallAPIOpts.td31
-rw-r--r--clang/tools/clang-installapi/Options.cpp197
-rw-r--r--clang/tools/clang-installapi/Options.h25
-rw-r--r--clang/tools/driver/driver.cpp141
-rw-r--r--clang/unittests/Format/.clang-format7
-rw-r--r--clang/unittests/Format/FormatTest.cpp21
-rw-r--r--clang/unittests/Format/TokenAnnotatorTest.cpp5
-rw-r--r--compiler-rt/test/tsan/signal_reset.cpp8
-rw-r--r--libc/config/baremetal/api.td2
-rw-r--r--libc/docs/gpu/building.rst6
-rw-r--r--libc/docs/gpu/testing.rst144
-rw-r--r--libc/docs/gpu/using.rst14
-rw-r--r--libcxx/docs/Status/Cxx23Papers.csv2
-rw-r--r--libcxx/include/__compare/partial_order.h2
-rw-r--r--libcxx/include/__compare/strong_order.h2
-rw-r--r--libcxx/include/__compare/weak_order.h2
-rw-r--r--libcxx/include/__format/format_context.h2
-rw-r--r--libcxx/include/__format/format_functions.h2
-rw-r--r--libcxx/include/__format/formatter_floating_point.h2
-rw-r--r--libcxx/include/__iterator/iter_move.h2
-rw-r--r--libcxx/include/__ranges/access.h6
-rw-r--r--libcxx/include/__ranges/rbegin.h3
-rw-r--r--libcxx/include/__ranges/rend.h3
-rw-r--r--libcxx/include/__ranges/size.h3
-rw-r--r--libcxx/include/chrono1
-rw-r--r--libcxx/include/complex7
-rw-r--r--libcxx/include/format4
-rw-r--r--libcxx/include/mutex20
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx03.csv5
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx11.csv5
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx14.csv5
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx17.csv5
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx20.csv10
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx23.csv16
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx26.csv16
-rw-r--r--libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp19
-rw-r--r--libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp19
-rw-r--r--libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp7
-rw-r--r--libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp51
-rw-r--r--libcxx/test/std/ranges/range.access/begin.pass.cpp10
-rw-r--r--libcxx/test/std/ranges/range.access/end.pass.cpp12
-rw-r--r--libcxx/test/std/ranges/range.access/rbegin.pass.cpp11
-rw-r--r--libcxx/test/std/ranges/range.access/rend.pass.cpp12
-rw-r--r--libcxx/test/std/ranges/range.access/size.pass.cpp3
-rw-r--r--libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp102
-rw-r--r--lldb/source/Commands/CommandObjectDWIMPrint.cpp13
-rw-r--r--lldb/source/Host/common/Alarm.cpp10
-rw-r--r--lldb/test/API/commands/dwim-print/TestDWIMPrint.py12
-rw-r--r--lldb/unittests/Host/AlarmTest.cpp8
-rw-r--r--lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp2
-rw-r--r--llvm/cmake/modules/AddLLVM.cmake10
-rw-r--r--llvm/cmake/modules/HandleLLVMOptions.cmake9
-rw-r--r--llvm/include/llvm/IR/IntrinsicsDirectX.td3
-rw-r--r--llvm/include/llvm/Passes/PassBuilder.h46
-rw-r--r--llvm/include/llvm/TextAPI/Record.h7
-rw-r--r--llvm/lib/Passes/PassBuilder.cpp57
-rw-r--r--llvm/lib/Target/DirectX/DXIL.td10
-rw-r--r--llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp49
-rw-r--r--llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp22
-rw-r--r--llvm/lib/TextAPI/TextStub.cpp8
-rw-r--r--llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp41
-rw-r--r--llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp61
-rw-r--r--llvm/test/CodeGen/DirectX/clamp-vec.ll74
-rw-r--r--llvm/test/CodeGen/DirectX/clamp.ll94
-rw-r--r--llvm/test/CodeGen/DirectX/fmax.ll31
-rw-r--r--llvm/test/CodeGen/DirectX/fmin.ll31
-rw-r--r--llvm/test/CodeGen/DirectX/smax.ll31
-rw-r--r--llvm/test/CodeGen/DirectX/smin.ll31
-rw-r--r--llvm/test/CodeGen/DirectX/umax.ll29
-rw-r--r--llvm/test/CodeGen/DirectX/umin.ll31
-rw-r--r--llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll2
-rw-r--r--llvm/test/Transforms/DFAJumpThreading/unpredictable-heuristic.ll124
-rw-r--r--llvm/test/Transforms/LowerMatrixIntrinsics/multiply-fused-lifetime-ends.ll484
-rwxr-xr-xllvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylibbin0 -> 3206 bytes
-rwxr-xr-xllvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylibbin0 -> 2716 bytes
-rw-r--r--llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test86
-rw-r--r--llvm/tools/llvm-objdump/MachODump.cpp112
-rw-r--r--mlir/lib/Dialect/Affine/IR/AffineOps.cpp3
-rw-r--r--mlir/lib/Dialect/Arith/IR/ArithDialect.cpp9
-rw-r--r--mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp10
-rw-r--r--mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp6
-rw-r--r--mlir/lib/Dialect/Func/IR/FuncOps.cpp3
-rw-r--r--mlir/lib/Dialect/GPU/IR/GPUDialect.cpp3
-rw-r--r--mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp20
-rw-r--r--mlir/lib/Dialect/MLProgram/IR/CMakeLists.txt1
-rw-r--r--mlir/lib/Dialect/MLProgram/IR/MLProgramDialect.cpp15
-rw-r--r--mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp12
-rw-r--r--mlir/lib/Dialect/SCF/IR/SCF.cpp9
-rw-r--r--mlir/lib/Dialect/Shape/IR/Shape.cpp3
-rw-r--r--mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp5
-rw-r--r--mlir/lib/Dialect/SparseTensor/Transforms/StageSparseOperations.cpp34
-rw-r--r--mlir/lib/Dialect/Tensor/IR/TensorDialect.cpp21
-rw-r--r--mlir/lib/Dialect/Tosa/CMakeLists.txt1
-rw-r--r--mlir/lib/Dialect/Tosa/IR/TosaOps.cpp9
-rw-r--r--mlir/lib/Dialect/Vector/IR/VectorOps.cpp12
-rw-r--r--mlir/lib/Target/LLVMIR/DebugTranslation.cpp4
-rw-r--r--mlir/test/Dialect/Bufferization/invalid.mlir23
-rw-r--r--mlir/test/Dialect/MLProgram/inlining.mlir19
-rw-r--r--mlir/test/Dialect/SparseTensor/invalid.mlir10
-rw-r--r--mlir/test/Dialect/Vector/canonicalize.mlir12
-rw-r--r--mlir/test/Integration/Dialect/Linalg/CPU/mmt4d.mlir2
-rw-r--r--mlir/test/Integration/Dialect/Linalg/CPU/test-matmul-masked-vec.mlir2
-rw-r--r--mlir/test/Integration/Dialect/Memref/reinterpret-cast-runtime-verification.mlir9
-rw-r--r--mlir/test/Integration/Dialect/Memref/subview-runtime-verification.mlir13
-rwxr-xr-xmlir/test/Integration/Dialect/SparseTensor/CPU/sparse_empty.mlir144
-rw-r--r--mlir/test/Integration/Dialect/Tosa/CPU/test-fully-connected.mlir2
-rw-r--r--openmp/libomptarget/plugins-nextgen/common/include/PluginInterface.h2
-rw-r--r--openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp2
-rw-r--r--openmp/runtime/src/kmp.h10
-rw-r--r--utils/bazel/llvm-project-overlay/libc/BUILD.bazel1
-rw-r--r--utils/bazel/llvm-project-overlay/mlir/BUILD.bazel59
-rw-r--r--utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel24
182 files changed, 3788 insertions, 808 deletions
diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 3d0c23917bd4..1d1fa2483b65 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -53,7 +53,7 @@ jobs:
- name: Install clang-format
uses: aminya/setup-cpp@v1
with:
- clangformat: 17.0.1
+ clangformat: 18.1.1
- name: Setup Python env
uses: actions/setup-python@v4
diff --git a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
index 42dd612eeeec..656b62c9a1f4 100644
--- a/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
+++ b/clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
@@ -72,6 +72,22 @@ TEST_F(ExtractVariableTest, Test) {
)cpp";
EXPECT_UNAVAILABLE(NoCrashCasesC);
+ ExtraArgs = {"-xc"};
+ const char *NoCrashDesignator = R"cpp(
+ struct A {
+ struct {
+ int x;
+ };
+ };
+ struct B {
+ int y;
+ };
+ void foo(struct B *b) {
+ struct A a = {.x=b[[->]]y};
+ }
+ )cpp";
+ EXPECT_AVAILABLE(NoCrashDesignator);
+
ExtraArgs = {"-xobjective-c"};
const char *AvailableObjC = R"cpp(
__attribute__((objc_root_class))
diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake
index db7430b3344c..d5546e20873b 100644
--- a/clang/cmake/caches/Fuchsia-stage2.cmake
+++ b/clang/cmake/caches/Fuchsia-stage2.cmake
@@ -11,6 +11,7 @@ set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "")
+set(LLVM_ENABLE_FATLTO ON CACHE BOOL "")
set(LLVM_ENABLE_HTTPLIB ON CACHE BOOL "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "")
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 623a4b3c18bb..0982a18e4629 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -47,6 +47,12 @@ C++ Specific Potentially Breaking Changes
ABI Changes in This Version
---------------------------
+- Fixed Microsoft name mangling of implicitly defined variables used for thread
+ safe static initialization of static local variables. This change resolves
+ incompatibilities with code compiled by MSVC but might introduce
+ incompatibilities with code compiled by earlier versions of Clang when an
+ inline member function that contains a static local variable with a dynamic
+ initializer is declared with ``__declspec(dllimport)``. (#GH83616).
AST Dumping Potentially Breaking Changes
----------------------------------------
@@ -244,6 +250,9 @@ Improvements to Clang's diagnostics
such as attempting to call ``free`` on an unallocated object. Fixes
`#79443 <https://github.com/llvm/llvm-project/issues/79443>`_.
+- The ``XXX parameter of 'main' must be of type`` error can now be disabled via ``-Wno-main``.
+ `#85494 <https://github.com/llvm/llvm-project/pull/85494>`_.
+
Improvements to Clang's time-trace
----------------------------------
@@ -288,6 +297,9 @@ Bug Fixes in This Version
by the C standard. This significantly improves codegen of `*` and `/` especially.
Fixes (`#31205 <https://github.com/llvm/llvm-project/issues/31205>`_).
+- Fixes an assertion failure on invalid code when trying to define member
+ functions in lambdas.
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -381,6 +393,8 @@ Bug Fixes to C++ Support
Fixes (#GH80997)
- Fix an issue where missing set friend declaration in template class instantiation.
Fixes (#GH84368).
+- Fixed a crash while checking constraints of a trailing requires-expression of a lambda, that the
+ expression references to an entity declared outside of the lambda. (#GH64808)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/AST/Availability.h b/clang/include/clang/AST/Availability.h
index ae3acbeffe7f..5cfbaf0cdfbd 100644
--- a/clang/include/clang/AST/Availability.h
+++ b/clang/include/clang/AST/Availability.h
@@ -75,6 +75,9 @@ struct AvailabilityInfo {
/// Determine if this AvailabilityInfo represents the default availability.
bool isDefault() const { return *this == AvailabilityInfo(); }
+ /// Check if the symbol has been obsoleted.
+ bool isObsoleted() const { return !Obsoleted.empty(); }
+
/// Check if the symbol is unconditionally deprecated.
///
/// i.e. \code __attribute__((deprecated)) \endcode
diff --git a/clang/include/clang/Basic/AllDiagnostics.h b/clang/include/clang/Basic/AllDiagnostics.h
index cc6aa631534a..e64634cc138f 100644
--- a/clang/include/clang/Basic/AllDiagnostics.h
+++ b/clang/include/clang/Basic/AllDiagnostics.h
@@ -20,6 +20,7 @@
#include "clang/Basic/DiagnosticCrossTU.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/DiagnosticInstallAPI.h"
#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index eae41b5505a4..491c9d895413 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4591,6 +4591,12 @@ def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> {
let Prototype = "unsigned int(bool)";
}
+def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_elementwise_clamp"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
+
def HLSLCreateHandle : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_create_handle"];
let Attributes = [NoThrow, Const];
diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt
index 7785fb430c06..7d53c751c13a 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -12,6 +12,7 @@ clang_diag_gen(Common)
clang_diag_gen(CrossTU)
clang_diag_gen(Driver)
clang_diag_gen(Frontend)
+clang_diag_gen(InstallAPI)
clang_diag_gen(Lex)
clang_diag_gen(Parse)
clang_diag_gen(Refactoring)
diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td
index 8d66e265fbae..0b8b3af939ba 100644
--- a/clang/include/clang/Basic/Diagnostic.td
+++ b/clang/include/clang/Basic/Diagnostic.td
@@ -162,6 +162,7 @@ include "DiagnosticCommonKinds.td"
include "DiagnosticCrossTUKinds.td"
include "DiagnosticDriverKinds.td"
include "DiagnosticFrontendKinds.td"
+include "DiagnosticInstallAPIKinds.td"
include "DiagnosticLexKinds.td"
include "DiagnosticParseKinds.td"
include "DiagnosticRefactoringKinds.td"
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h
index 0cdda42793f6..95b502b1e97a 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -42,6 +42,7 @@ namespace clang {
DIAG_SIZE_SEMA = 4500,
DIAG_SIZE_ANALYSIS = 100,
DIAG_SIZE_REFACTORING = 1000,
+ DIAG_SIZE_INSTALLAPI = 100,
};
// Start position for diagnostics.
enum {
@@ -57,7 +58,8 @@ namespace clang {
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
- DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING)
+ DIAG_START_INSTALLAPI = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING),
+ DIAG_UPPER_LIMIT = DIAG_START_INSTALLAPI + static_cast<int>(DIAG_SIZE_INSTALLAPI)
};
class CustomDiagInfo;
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPI.h b/clang/include/clang/Basic/DiagnosticInstallAPI.h
new file mode 100644
index 000000000000..a76f6e087a2b
--- /dev/null
+++ b/clang/include/clang/Basic/DiagnosticInstallAPI.h
@@ -0,0 +1,26 @@
+//===--- DiagnosticInstallAPI.h - Diagnostics for InstallAPI-----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTICINSTALLAPI_H
+#define LLVM_CLANG_BASIC_DIAGNOSTICINSTALLAPI_H
+
+#include "clang/Basic/Diagnostic.h"
+namespace clang {
+namespace diag {
+enum {
+#define DIAG(ENUM, FLAGS, DEFAULT_MAPPING, DESC, GROUP, SFINAE, NOWERROR, \
+ SHOWINSYSHEADER, SHOWINSYSMACRO, DEFERRABLE, CATEGORY) \
+ ENUM,
+#define INSTALLAPISTART
+#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
+#undef DIAG
+ NUM_BUILTIN_INSTALLAPI_DIAGNOSTICS
+};
+} // namespace diag
+} // namespace clang
+#endif // LLVM_CLANG_BASIC_DIAGNOSTICINSTALLAPI_H
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
new file mode 100644
index 000000000000..31be4f09cf3a
--- /dev/null
+++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
@@ -0,0 +1,20 @@
+//==--- DiagnosticInstallAPIKinds.td - installapi diagnostics -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// InstallAPI Diagnostics
+//===----------------------------------------------------------------------===//
+
+let Component = "InstallAPI" in {
+let CategoryName = "Command line" in {
+def err_cannot_write_file : Error<"cannot write file '%0': %1">;
+def err_no_install_name : Error<"no install name specified: add -install_name <path>">;
+def err_no_output_file: Error<"no output file specified">;
+} // end of command line category.
+
+} // end of InstallAPI component
diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h
index c4cab360bab3..8e27f75012ee 100644
--- a/clang/include/clang/Driver/Driver.h
+++ b/clang/include/clang/Driver/Driver.h
@@ -28,8 +28,8 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Support/StringSaver.h"
-#include <list>
#include <map>
+#include <set>
#include <string>
#include <vector>
@@ -839,6 +839,13 @@ llvm::Error expandResponseFiles(SmallVectorImpl<const char *> &Args,
bool ClangCLMode, llvm::BumpPtrAllocator &Alloc,
llvm::vfs::FileSystem *FS = nullptr);
+/// Apply a space separated list of edits to the input argument lists.
+/// See applyOneOverrideOption.
+void applyOverrideOptions(SmallVectorImpl<const char *> &Args,
+ const char *OverrideOpts,
+ llvm::StringSet<> &SavedStrings,
+ raw_ostream *OS = nullptr);
+
} // end namespace driver
} // end namespace clang
diff --git a/clang/include/clang/Format/.clang-format b/clang/include/clang/Format/.clang-format
index f95602cab0f7..d7331b3c8cf0 100644
--- a/clang/include/clang/Format/.clang-format
+++ b/clang/include/clang/Format/.clang-format
@@ -1,6 +1 @@
-BasedOnStyle: LLVM
-InsertBraces: true
-InsertNewlineAtEOF: true
-LineEnding: LF
-RemoveBracesLLVM: true
-RemoveParentheses: ReturnStatement
+BasedOnStyle: clang-format
diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h
index bdb576d7d85f..54e517544b8e 100644
--- a/clang/include/clang/InstallAPI/Context.h
+++ b/clang/include/clang/InstallAPI/Context.h
@@ -11,6 +11,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/HeaderFile.h"
#include "clang/InstallAPI/MachO.h"
#include "llvm/ADT/DenseMap.h"
@@ -45,6 +46,9 @@ struct InstallAPIContext {
/// DiagnosticsEngine for all error reporting.
DiagnosticsEngine *Diags = nullptr;
+ /// Verifier when binary dylib is passed as input.
+ std::unique_ptr<DylibVerifier> Verifier = nullptr;
+
/// File Path of output location.
llvm::StringRef OutputLoc{};
diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h
new file mode 100644
index 000000000000..72c4743fdf65
--- /dev/null
+++ b/clang/include/clang/InstallAPI/DylibVerifier.h
@@ -0,0 +1,104 @@
+//===- InstallAPI/DylibVerifier.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
+#define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/InstallAPI/MachO.h"
+
+namespace clang {
+namespace installapi {
+struct FrontendAttrs;
+
+/// A list of InstallAPI verification modes.
+enum class VerificationMode {
+ Invalid,
+ ErrorsOnly,
+ ErrorsAndWarnings,
+ Pedantic,
+};
+
+/// Service responsible to tracking state of verification across the
+/// lifetime of InstallAPI.
+/// As declarations are collected during AST traversal, they are
+/// compared as symbols against what is available in the binary dylib.
+class DylibVerifier {
+private:
+ struct SymbolContext;
+
+public:
+ enum class Result { NoVerify, Ignore, Valid, Invalid };
+ struct VerifierContext {
+ // Current target being verified against the AST.
+ llvm::MachO::Target Target;
+
+ // Query state of verification after AST has been traversed.
+ Result FrontendState;
+
+ // First error for AST traversal, which is tied to the target triple.
+ bool DiscoveredFirstError;
+ };
+
+ DylibVerifier() = default;
+
+ DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag,
+ VerificationMode Mode, bool Demangle)
+ : Dylib(std::move(Dylib)), Diag(Diag), Mode(Mode), Demangle(Demangle),
+ Exports(std::make_unique<SymbolSet>()) {}
+
+ Result verify(GlobalRecord *R, const FrontendAttrs *FA);
+ Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
+ Result verify(ObjCIVarRecord *R, const FrontendAttrs *FA,
+ const StringRef SuperClass);
+
+ /// Initialize target for verification.
+ void setTarget(const Target &T);
+
+ /// Release ownership over exports.
+ std::unique_ptr<SymbolSet> getExports() { return std::move(Exports); }
+
+ /// Get result of verification.
+ Result getState() const { return Ctx.FrontendState; }
+
+private:
+ /// Determine whether to compare declaration to symbol in binary.
+ bool canVerify();
+
+ /// Shared implementation for verifying exported symbols.
+ Result verifyImpl(Record *R, SymbolContext &SymCtx);
+
+ /// Update result state on each call to `verify`.
+ void updateState(Result State);
+
+ /// Add verified exported symbol.
+ void addSymbol(const Record *R, SymbolContext &SymCtx,
+ TargetList &&Targets = {});
+
+ // Symbols in dylib.
+ llvm::MachO::Records Dylib;
+
+ // Engine for reporting violations.
+ [[maybe_unused]] DiagnosticsEngine *Diag = nullptr;
+
+ // Controls what class of violations to report.
+ [[maybe_unused]] VerificationMode Mode = VerificationMode::Invalid;
+
+ // Attempt to demangle when reporting violations.
+ bool Demangle = false;
+
+ // Valid symbols in final text file.
+ std::unique_ptr<SymbolSet> Exports = std::make_unique<SymbolSet>();
+
+ // Track current state of verification while traversing AST.
+ VerifierContext Ctx;
+};
+
+} // namespace installapi
+} // namespace clang
+#endif // LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
diff --git a/clang/include/clang/InstallAPI/Frontend.h b/clang/include/clang/InstallAPI/Frontend.h
index 873cb50d60a5..660fc8cd69a5 100644
--- a/clang/include/clang/InstallAPI/Frontend.h
+++ b/clang/include/clang/InstallAPI/Frontend.h
@@ -14,7 +14,6 @@
#define LLVM_CLANG_INSTALLAPI_FRONTEND_H
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/Availability.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/InstallAPI/Context.h"
diff --git a/clang/include/clang/InstallAPI/FrontendRecords.h b/clang/include/clang/InstallAPI/FrontendRecords.h
index 1f5bc37798be..59271e81e230 100644
--- a/clang/include/clang/InstallAPI/FrontendRecords.h
+++ b/clang/include/clang/InstallAPI/FrontendRecords.h
@@ -43,13 +43,13 @@ public:
/// \param Flags The flags that describe attributes of the symbol.
/// \param Inlined Whether declaration is inlined, only applicable to
/// functions.
- /// \return The non-owning pointer to added record in slice.
- GlobalRecord *addGlobal(StringRef Name, RecordLinkage Linkage,
- GlobalRecord::Kind GV,
- const clang::AvailabilityInfo Avail, const Decl *D,
- const HeaderType Access,
- SymbolFlags Flags = SymbolFlags::None,
- bool Inlined = false);
+ /// \return The non-owning pointer to added record in slice with it's frontend
+ /// attributes.
+ std::pair<GlobalRecord *, FrontendAttrs *>
+ addGlobal(StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
+ const clang::AvailabilityInfo Avail, const Decl *D,
+ const HeaderType Access, SymbolFlags Flags = SymbolFlags::None,
+ bool Inlined = false);
/// Add ObjC Class record with attributes from AST.
///
@@ -60,11 +60,12 @@ public:
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param IsEHType Whether declaration has an exception attribute.
- /// \return The non-owning pointer to added record in slice.
- ObjCInterfaceRecord *addObjCInterface(StringRef Name, RecordLinkage Linkage,
- const clang::AvailabilityInfo Avail,
- const Decl *D, HeaderType Access,
- bool IsEHType);
+ /// \return The non-owning pointer to added record in slice with it's frontend
+ /// attributes.
+ std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
+ addObjCInterface(StringRef Name, RecordLinkage Linkage,
+ const clang::AvailabilityInfo Avail, const Decl *D,
+ HeaderType Access, bool IsEHType);
/// Add ObjC Category record with attributes from AST.
///
@@ -75,11 +76,12 @@ public:
/// to the active target triple.
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
- /// \return The non-owning pointer to added record in slice.
- ObjCCategoryRecord *addObjCCategory(StringRef ClassToExtend,
- StringRef CategoryName,
- const clang::AvailabilityInfo Avail,
- const Decl *D, HeaderType Access);
+ /// \return The non-owning pointer to added record in slice with it's frontend
+ /// attributes.
+ std::pair<ObjCCategoryRecord *, FrontendAttrs *>
+ addObjCCategory(StringRef ClassToExtend, StringRef CategoryName,
+ const clang::AvailabilityInfo Avail, const Decl *D,
+ HeaderType Access);
/// Add ObjC IVar record with attributes from AST.
///
@@ -91,12 +93,13 @@ public:
/// \param D The pointer to the declaration from traversing AST.
/// \param Access The intended access level of symbol.
/// \param AC The access control tied to the ivar declaration.
- /// \return The non-owning pointer to added record in slice.
- ObjCIVarRecord *addObjCIVar(ObjCContainerRecord *Container,
- StringRef IvarName, RecordLinkage Linkage,
- const clang::AvailabilityInfo Avail,
- const Decl *D, HeaderType Access,
- const clang::ObjCIvarDecl::AccessControl AC);
+ /// \return The non-owning pointer to added record in slice with it's frontend
+ /// attributes.
+ std::pair<ObjCIVarRecord *, FrontendAttrs *>
+ addObjCIVar(ObjCContainerRecord *Container, StringRef IvarName,
+ RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
+ const Decl *D, HeaderType Access,
+ const clang::ObjCIvarDecl::AccessControl AC);
private:
/// Mapping of records stored in slice to their frontend attributes.
diff --git a/clang/include/clang/InstallAPI/InstallAPIDiagnostic.h b/clang/include/clang/InstallAPI/InstallAPIDiagnostic.h
new file mode 100644
index 000000000000..547fb0bcf9a8
--- /dev/null
+++ b/clang/include/clang/InstallAPI/InstallAPIDiagnostic.h
@@ -0,0 +1,14 @@
+//===--- InstallAPIDiagnostic.h - Diagnostics for InstallAPI ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INSTALLAPI_INSTALLAPIDIAGNOSTIC_H
+#define LLVM_CLANG_INSTALLAPI_INSTALLAPIDIAGNOSTIC_H
+
+#include "clang/Basic/DiagnosticInstallAPI.h"
+
+#endif
diff --git a/clang/include/clang/InstallAPI/MachO.h b/clang/include/clang/InstallAPI/MachO.h
index 55e5591389ce..6dee6f224203 100644
--- a/clang/include/clang/InstallAPI/MachO.h
+++ b/clang/include/clang/InstallAPI/MachO.h
@@ -18,6 +18,7 @@
#include "llvm/TextAPI/PackedVersion.h"
#include "llvm/TextAPI/Platform.h"
#include "llvm/TextAPI/RecordVisitor.h"
+#include "llvm/TextAPI/Symbol.h"
#include "llvm/TextAPI/Target.h"
#include "llvm/TextAPI/TextAPIWriter.h"
#include "llvm/TextAPI/Utils.h"
@@ -33,8 +34,10 @@ using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord;
using Records = llvm::MachO::Records;
using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs;
using SymbolSet = llvm::MachO::SymbolSet;
+using SimpleSymbol = llvm::MachO::SimpleSymbol;
using FileType = llvm::MachO::FileType;
using PackedVersion = llvm::MachO::PackedVersion;
using Target = llvm::MachO::Target;
+using TargetList = llvm::MachO::TargetList;
#endif // LLVM_CLANG_INSTALLAPI_MACHO_H
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1c3dcf63465c..645ec2f7563b 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1567,10 +1567,9 @@ bool CXXRecordDecl::isGenericLambda() const {
#ifndef NDEBUG
static bool allLookupResultsAreTheSame(const DeclContext::lookup_result &R) {
- for (auto *D : R)
- if (!declaresSameEntity(D, R.front()))
- return false;
- return true;
+ return llvm::all_of(R, [&](NamedDecl *D) {
+ return D->isInvalidDecl() || declaresSameEntity(D, R.front());
+ });
}
#endif
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index f5ad402e3bd7..131dace77f9c 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -4604,8 +4604,17 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
SourceLocation DesignatedInitExpr::getBeginLoc() const {
auto *DIE = const_cast<DesignatedInitExpr *>(this);
Designator &First = *DIE->getDesignator(0);
- if (First.isFieldDesignator())
- return GNUSyntax ? First.getFieldLoc() : First.getDotLoc();
+ if (First.isFieldDesignator()) {
+ // Skip past implicit designators for anonymous structs/unions, since
+ // these do not have valid source locations.
+ for (unsigned int i = 0; i < DIE->size(); i++) {
+ Designator &Des = *DIE->getDesignator(i);
+ SourceLocation retval = GNUSyntax ? Des.getFieldLoc() : Des.getDotLoc();
+ if (!retval.isValid())
+ continue;
+ return retval;
+ }
+ }
return First.getLBracketLoc();
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7137efb7876d..fa9e8ecf6543 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -5594,6 +5594,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
if (Assumption->isValueDependent())
return ESR_Failed;
+ if (Assumption->HasSideEffects(Info.getCtx()))
+ continue;
+
bool Value;
if (!EvaluateAsBooleanCondition(Assumption, Value, Info))
return ESR_Failed;
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index f07e430e279d..2e48ec2c5087 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1756,6 +1756,14 @@ bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
}
template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayTypeTraitExpr(
+ const ArrayTypeTraitExpr *E) {
+ if (DiscardResult)
+ return true;
+ return this->emitConst(E->getValue(), E);
+}
+
+template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
if (DiscardResult)
return true;
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 969598c97805..db0d73ce23f7 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -99,6 +99,7 @@ public:
bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
bool VisitTypeTraitExpr(const TypeTraitExpr *E);
+ bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
bool VisitLambdaExpr(const LambdaExpr *E);
bool VisitPredefinedExpr(const PredefinedExpr *E);
bool VisitCXXThrowExpr(const CXXThrowExpr *E);
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index b272a546573a..aa26bb7ed46f 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -390,6 +390,7 @@ public:
const FunctionDecl *D = nullptr,
bool ForceThisQuals = false,
bool MangleExceptionSpec = true);
+ void mangleSourceName(StringRef Name);
void mangleNestedName(GlobalDecl GD);
private:
@@ -408,7 +409,6 @@ private:
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName());
}
void mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name);
- void mangleSourceName(StringRef Name);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
@@ -3920,7 +3920,8 @@ void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable(
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
- Mangler.getStream() << "?$TSS" << GuardNum << '@';
+ Mangler.getStream() << "?";
+ Mangler.mangleSourceName("$TSS" + llvm::utostr(GuardNum));
Mangler.mangleNestedName(VD);
Mangler.getStream() << "@4HA";
}
diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp
index b353a6627f29..4138b4ee4b0e 100644
--- a/clang/lib/Basic/DiagnosticIDs.cpp
+++ b/clang/lib/Basic/DiagnosticIDs.cpp
@@ -49,6 +49,7 @@ struct StaticDiagInfoDescriptionStringTable {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
+#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};
@@ -70,7 +71,8 @@ const StaticDiagInfoDescriptionStringTable StaticDiagInfoDescriptions = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
- // clang-format on
+#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
+// clang-format on
#undef DIAG
};
@@ -95,7 +97,8 @@ const uint32_t StaticDiagInfoDescriptionOffsets[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
- // clang-format on
+#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
+// clang-format on
#undef DIAG
};
@@ -173,6 +176,7 @@ VALIDATE_DIAG_SIZE(CROSSTU)
VALIDATE_DIAG_SIZE(SEMA)
VALIDATE_DIAG_SIZE(ANALYSIS)
VALIDATE_DIAG_SIZE(REFACTORING)
+VALIDATE_DIAG_SIZE(INSTALLAPI)
#undef VALIDATE_DIAG_SIZE
#undef STRINGIFY_NAME
@@ -204,6 +208,7 @@ const StaticDiagInfoRec StaticDiagInfo[] = {
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#include "clang/Basic/DiagnosticRefactoringKinds.inc"
+#include "clang/Basic/DiagnosticInstallAPIKinds.inc"
// clang-format on
#undef DIAG
};
@@ -246,6 +251,7 @@ CATEGORY(CROSSTU, COMMENT)
CATEGORY(SEMA, CROSSTU)
CATEGORY(ANALYSIS, SEMA)
CATEGORY(REFACTORING, ANALYSIS)
+CATEGORY(INSTALLAPI, REFACTORING)
#undef CATEGORY
// Avoid out of bounds reads.
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e708bf3d6df1..e965df810add 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18048,6 +18048,21 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
/*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
Intrinsic::dx_any, ArrayRef<Value *>{Op0}, nullptr, "dx.any");
}
+ case Builtin::BI__builtin_hlsl_elementwise_clamp: {
+ Value *OpX = EmitScalarExpr(E->getArg(0));
+ Value *OpMin = EmitScalarExpr(E->getArg(1));
+ Value *OpMax = EmitScalarExpr(E->getArg(2));
+
+ QualType Ty = E->getArg(0)->getType();
+ bool IsUnsigned = false;
+ if (auto *VecTy = Ty->getAs<VectorType>())
+ Ty = VecTy->getElementType();
+ IsUnsigned = Ty->isUnsignedIntegerType();
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/OpX->getType(),
+ IsUnsigned ? Intrinsic::dx_uclamp : Intrinsic::dx_clamp,
+ ArrayRef<Value *>{OpX, OpMin, OpMax}, nullptr, "dx.clamp");
+ }
case Builtin::BI__builtin_hlsl_dot: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 190782a79a24..e3f5f5905a72 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -87,6 +87,7 @@
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/RISCVISAInfo.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
@@ -6677,3 +6678,131 @@ llvm::Error driver::expandResponseFiles(SmallVectorImpl<const char *> &Args,
return llvm::Error::success();
}
+
+static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
+ return SavedStrings.insert(S).first->getKeyData();
+}
+
+/// Apply a list of edits to the input argument lists.
+///
+/// The input string is a space separated list of edits to perform,
+/// they are applied in order to the input argument lists. Edits
+/// should be one of the following forms:
+///
+/// '#': Silence information about the changes to the command line arguments.
+///
+/// '^': Add FOO as a new argument at the beginning of the command line.
+///
+/// '+': Add FOO as a new argument at the end of the command line.
+///
+/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
+/// line.
+///
+/// 'xOPTION': Removes all instances of the literal argument OPTION.
+///
+/// 'XOPTION': Removes all instances of the literal argument OPTION,
+/// and the following argument.
+///
+/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
+/// at the end of the command line.
+///
+/// \param OS - The stream to write edit information to.
+/// \param Args - The vector of command line arguments.
+/// \param Edit - The override command to perform.
+/// \param SavedStrings - Set to use for storing string representations.
+static void applyOneOverrideOption(raw_ostream &OS,
+ SmallVectorImpl<const char *> &Args,
+ StringRef Edit,
+ llvm::StringSet<> &SavedStrings) {
+ // This does not need to be efficient.
+
+ if (Edit[0] == '^') {
+ const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at beginning\n";
+ Args.insert(Args.begin() + 1, Str);
+ } else if (Edit[0] == '+') {
+ const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
+ OS << "### Adding argument " << Str << " at end\n";
+ Args.push_back(Str);
+ } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
+ Edit.slice(2, Edit.size() - 1).contains('/')) {
+ StringRef MatchPattern = Edit.substr(2).split('/').first;
+ StringRef ReplPattern = Edit.substr(2).split('/').second;
+ ReplPattern = ReplPattern.slice(0, ReplPattern.size() - 1);
+
+ for (unsigned i = 1, e = Args.size(); i != e; ++i) {
+ // Ignore end-of-line response file markers
+ if (Args[i] == nullptr)
+ continue;
+ std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
+
+ if (Repl != Args[i]) {
+ OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
+ Args[i] = GetStableCStr(SavedStrings, Repl);
+ }
+ }
+ } else if (Edit[0] == 'x' || Edit[0] == 'X') {
+ auto Option = Edit.substr(1);
+ for (unsigned i = 1; i < Args.size();) {
+ if (Option == Args[i]) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ if (Edit[0] == 'X') {
+ if (i < Args.size()) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ OS << "### Invalid X edit, end of command line!\n";
+ }
+ } else
+ ++i;
+ }
+ } else if (Edit[0] == 'O') {
+ for (unsigned i = 1; i < Args.size();) {
+ const char *A = Args[i];
+ // Ignore end-of-line response file markers
+ if (A == nullptr)
+ continue;
+ if (A[0] == '-' && A[1] == 'O' &&
+ (A[2] == '\0' || (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
+ ('0' <= A[2] && A[2] <= '9'))))) {
+ OS << "### Deleting argument " << Args[i] << '\n';
+ Args.erase(Args.begin() + i);
+ } else
+ ++i;
+ }
+ OS << "### Adding argument " << Edit << " at end\n";
+ Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
+ } else {
+ OS << "### Unrecognized edit: " << Edit << "\n";
+ }
+}
+
+void driver::applyOverrideOptions(SmallVectorImpl<const char *> &Args,
+ const char *OverrideStr,
+ llvm::StringSet<> &SavedStrings,
+ raw_ostream *OS) {
+ if (!OS)
+ OS = &llvm::nulls();
+
+ if (OverrideStr[0] == '#') {
+ ++OverrideStr;
+ OS = &llvm::nulls();
+ }
+
+ *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
+
+ // This does not need to be efficient.
+
+ const char *S = OverrideStr;
+ while (*S) {
+ const char *End = ::strchr(S, ' ');
+ if (!End)
+ End = S + strlen(S);
+ if (End != S)
+ applyOneOverrideOption(*OS, Args, std::string(S, End), SavedStrings);
+ S = End;
+ if (*S != '\0')
+ ++S;
+ }
+}
diff --git a/clang/lib/Format/.clang-format b/clang/lib/Format/.clang-format
index f95602cab0f7..d7331b3c8cf0 100644
--- a/clang/lib/Format/.clang-format
+++ b/clang/lib/Format/.clang-format
@@ -1,6 +1 @@
-BasedOnStyle: LLVM
-InsertBraces: true
-InsertNewlineAtEOF: true
-LineEnding: LF
-RemoveBracesLLVM: true
-RemoveParentheses: ReturnStatement
+BasedOnStyle: clang-format
diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h
index e7c0680641e2..8b9360a3335e 100644
--- a/clang/lib/Format/BreakableToken.h
+++ b/clang/lib/Format/BreakableToken.h
@@ -18,11 +18,8 @@
#define LLVM_CLANG_LIB_FORMAT_BREAKABLETOKEN_H
#include "Encoding.h"
-#include "TokenAnnotator.h"
#include "WhitespaceManager.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Regex.h"
-#include <utility>
namespace clang {
namespace format {
diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h
index 2598947bb624..18441e10a124 100644
--- a/clang/lib/Format/ContinuationIndenter.h
+++ b/clang/lib/Format/ContinuationIndenter.h
@@ -17,11 +17,6 @@
#include "Encoding.h"
#include "FormatToken.h"
-#include "clang/Format/Format.h"
-#include "llvm/Support/Regex.h"
-#include <map>
-#include <optional>
-#include <tuple>
namespace clang {
class SourceManager;
diff --git a/clang/lib/Format/Encoding.h b/clang/lib/Format/Encoding.h
index a0d664121b2b..12f9043bb95a 100644
--- a/clang/lib/Format/Encoding.h
+++ b/clang/lib/Format/Encoding.h
@@ -16,7 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_ENCODING_H
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Unicode.h"
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index faf65c619b23..d5d115a3c8db 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -13,44 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Format/Format.h"
-#include "AffectedRangeManager.h"
-#include "BreakableToken.h"
-#include "ContinuationIndenter.h"
#include "DefinitionBlockSeparator.h"
-#include "FormatInternal.h"
-#include "FormatToken.h"
-#include "FormatTokenLexer.h"
#include "IntegerLiteralSeparatorFixer.h"
#include "NamespaceEndCommentsFixer.h"
#include "ObjCPropertyAttributeOrderFixer.h"
#include "QualifierAlignmentFixer.h"
#include "SortJavaScriptImports.h"
-#include "TokenAnalyzer.h"
-#include "TokenAnnotator.h"
#include "UnwrappedLineFormatter.h"
-#include "UnwrappedLineParser.h"
#include "UsingDeclarationsSorter.h"
-#include "WhitespaceManager.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Tooling/Inclusions/HeaderIncludes.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Regex.h"
-#include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/Support/YAMLTraits.h"
-#include <algorithm>
-#include <memory>
-#include <mutex>
-#include <optional>
-#include <string>
-#include <unordered_map>
#define DEBUG_TYPE "format-formatter"
diff --git a/clang/lib/Format/FormatInternal.h b/clang/lib/Format/FormatInternal.h
index 9043ce32e9e3..87974a853365 100644
--- a/clang/lib/Format/FormatInternal.h
+++ b/clang/lib/Format/FormatInternal.h
@@ -15,9 +15,6 @@
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
#define LLVM_CLANG_LIB_FORMAT_FORMATINTERNAL_H
-#include "BreakableToken.h"
-#include <utility>
-
namespace clang {
namespace format {
namespace internal {
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index ee96d072b120..c9022aba2871 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -19,8 +19,6 @@
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
-#include <memory>
-#include <optional>
#include <unordered_set>
namespace clang {
diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h
index 65dd733bd533..277cc0a2dfde 100644
--- a/clang/lib/Format/FormatTokenLexer.h
+++ b/clang/lib/Format/FormatTokenLexer.h
@@ -17,14 +17,9 @@
#include "Encoding.h"
#include "FormatToken.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Format/Format.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/Support/Regex.h"
#include <stack>
diff --git a/clang/lib/Format/FormatTokenSource.h b/clang/lib/Format/FormatTokenSource.h
index 7819244eb7d1..cce19f527a92 100644
--- a/clang/lib/Format/FormatTokenSource.h
+++ b/clang/lib/Format/FormatTokenSource.h
@@ -15,10 +15,7 @@
#ifndef LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H
#define LLVM_CLANG_LIB_FORMAT_FORMATTOKENSOURCE_H
-#include "FormatToken.h"
#include "UnwrappedLineParser.h"
-#include "llvm/ADT/DenseMap.h"
-#include <cstddef>
#define DEBUG_TYPE "format-token-source"
diff --git a/clang/lib/Format/Macros.h b/clang/lib/Format/Macros.h
index d2f7fe502364..fb12d22299de 100644
--- a/clang/lib/Format/Macros.h
+++ b/clang/lib/Format/Macros.h
@@ -39,15 +39,9 @@
#define CLANG_LIB_FORMAT_MACROS_H
#include <list>
-#include <map>
-#include <string>
-#include <vector>
#include "FormatToken.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
namespace clang {
namespace format {
diff --git a/clang/lib/Format/SortJavaScriptImports.h b/clang/lib/Format/SortJavaScriptImports.h
index 7336db9537b0..b55b149aab4c 100644
--- a/clang/lib/Format/SortJavaScriptImports.h
+++ b/clang/lib/Format/SortJavaScriptImports.h
@@ -14,10 +14,7 @@
#ifndef LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H
#define LLVM_CLANG_LIB_FORMAT_SORTJAVASCRIPTIMPORTS_H
-#include "clang/Basic/LLVM.h"
#include "clang/Format/Format.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
namespace clang {
namespace format {
diff --git a/clang/lib/Format/TokenAnalyzer.h b/clang/lib/Format/TokenAnalyzer.h
index 4086dab1c94c..b7494c395c8a 100644
--- a/clang/lib/Format/TokenAnalyzer.h
+++ b/clang/lib/Format/TokenAnalyzer.h
@@ -17,19 +17,8 @@
#define LLVM_CLANG_LIB_FORMAT_TOKENANALYZER_H
#include "AffectedRangeManager.h"
-#include "Encoding.h"
-#include "FormatToken.h"
#include "FormatTokenLexer.h"
#include "TokenAnnotator.h"
-#include "UnwrappedLineParser.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Format/Format.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Support/Debug.h"
-#include <memory>
namespace clang {
namespace format {
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index e464c2b5731a..1342d37a1479 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -3595,6 +3595,13 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
if (!Current.Tok.getIdentifierInfo())
return false;
+ const auto &Previous = *Current.Previous;
+
+ if (const auto *PrevPrev = Previous.Previous;
+ PrevPrev && PrevPrev->is(TT_ObjCDecl)) {
+ return false;
+ }
+
auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * {
for (; Next; Next = Next->Next) {
if (Next->is(TT_OverloadedOperatorLParen))
@@ -3633,18 +3640,17 @@ static bool isFunctionDeclarationName(const FormatToken &Current,
// Find parentheses of parameter list.
const FormatToken *Next = Current.Next;
if (Current.is(tok::kw_operator)) {
- const auto *Previous = Current.Previous;
- if (Previous->Tok.getIdentifierInfo() &&
- !Previous->isOneOf(tok::kw_return, tok::kw_co_return)) {
+ if (Previous.Tok.getIdentifierInfo() &&
+ !Previous.isOneOf(tok::kw_return, tok::kw_co_return)) {
return true;
}
- if (Previous->is(tok::r_paren) && Previous->is(TT_TypeDeclarationParen)) {
- assert(Previous->MatchingParen);
- assert(Previous->MatchingParen->is(tok::l_paren));
- assert(Previous->MatchingParen->is(TT_TypeDeclarationParen));
+ if (Previous.is(tok::r_paren) && Previous.is(TT_TypeDeclarationParen)) {
+ assert(Previous.MatchingParen);
+ assert(Previous.MatchingParen->is(tok::l_paren));
+ assert(Previous.MatchingParen->is(TT_TypeDeclarationParen));
return true;
}
- if (!Previous->isPointerOrReference() && Previous->isNot(TT_TemplateCloser))
+ if (!Previous.isPointerOrReference() && Previous.isNot(TT_TemplateCloser))
return false;
Next = skipOperatorName(Next);
} else {
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index b0931e85c16c..aa44b31e0fce 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -16,7 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
#include "UnwrappedLineParser.h"
-#include "clang/Format/Format.h"
namespace clang {
namespace format {
diff --git a/clang/lib/Format/UnwrappedLineFormatter.h b/clang/lib/Format/UnwrappedLineFormatter.h
index ee6d31de8c42..9b8acf427a2a 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.h
+++ b/clang/lib/Format/UnwrappedLineFormatter.h
@@ -16,8 +16,6 @@
#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEFORMATTER_H
#include "ContinuationIndenter.h"
-#include "clang/Format/Format.h"
-#include <map>
namespace clang {
namespace format {
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index a1f6ce05e45e..2b893f7abe40 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1224,7 +1224,6 @@ void UnwrappedLineParser::parsePPUnknown() {
static bool tokenCanStartNewLine(const FormatToken &Tok) {
// Semicolon can be a null-statement, l_square can be a start of a macro or
// a C++11 attribute, but this doesn't seem to be common.
- assert(Tok.isNot(TT_AttributeSquare));
return !Tok.isOneOf(tok::semi, tok::l_brace,
// Tokens that can only be used as binary operators and a
// part of overloaded operator names.
@@ -3712,14 +3711,19 @@ bool UnwrappedLineParser::parseEnum() {
if (Style.Language == FormatStyle::LK_Proto && FormatTok->is(tok::equal))
return false;
- // Eat up enum class ...
- if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct))
- nextToken();
+ if (IsCpp) {
+ // Eat up enum class ...
+ if (FormatTok->isOneOf(tok::kw_class, tok::kw_struct))
+ nextToken();
+ while (FormatTok->is(tok::l_square))
+ if (!handleCppAttributes())
+ return false;
+ }
while (FormatTok->Tok.getIdentifierInfo() ||
FormatTok->isOneOf(tok::colon, tok::coloncolon, tok::less,
tok::greater, tok::comma, tok::question,
- tok::l_square, tok::r_square)) {
+ tok::l_square)) {
if (Style.isVerilog()) {
FormatTok->setFinalizedType(TT_VerilogDimensionedTypeName);
nextToken();
@@ -3732,7 +3736,6 @@ bool UnwrappedLineParser::parseEnum() {
// We can have macros or attributes in between 'enum' and the enum name.
if (FormatTok->is(tok::l_paren))
parseParens();
- assert(FormatTok->isNot(TT_AttributeSquare));
if (FormatTok->is(tok::identifier)) {
nextToken();
// If there are two identifiers in a row, this is likely an elaborate
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
index 1403533a2d0e..da3188ed240c 100644
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -15,17 +15,8 @@
#ifndef LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H
#define LLVM_CLANG_LIB_FORMAT_UNWRAPPEDLINEPARSER_H
-#include "Encoding.h"
-#include "FormatToken.h"
#include "Macros.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Format/Format.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/Support/Regex.h"
-#include <list>
#include <stack>
-#include <vector>
namespace clang {
namespace format {
diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h
index 9942e0f35738..0ebc6cf8377c 100644
--- a/clang/lib/Format/WhitespaceManager.h
+++ b/clang/lib/Format/WhitespaceManager.h
@@ -17,11 +17,6 @@
#include "TokenAnnotator.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Format/Format.h"
-#include "llvm/ADT/SmallVector.h"
-#include <algorithm>
-#include <string>
-#include <tuple>
namespace clang {
namespace format {
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 718fb9a9b35c..5e703772b7ee 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -253,6 +253,116 @@ _HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil)
double4 ceil(double4);
//===----------------------------------------------------------------------===//
+// clamp builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T clamp(T X, T Min, T Max)
+/// \brief Clamps the specified value \a X to the specified
+/// minimum ( \a Min) and maximum ( \a Max) range.
+/// \param X A value to clamp.
+/// \param Min The specified minimum range.
+/// \param Max The specified maximum range.
+///
+/// Returns The clamped value for the \a X parameter.
+/// For values of -INF or INF, clamp will behave as expected.
+/// However for values of NaN, the results are undefined.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+half clamp(half, half, half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+half2 clamp(half2, half2, half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+half3 clamp(half3, half3, half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+half4 clamp(half4, half4, half4);
+
+#ifdef __HLSL_ENABLE_16_BIT
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int16_t clamp(int16_t, int16_t, int16_t);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int16_t2 clamp(int16_t2, int16_t2, int16_t2);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int16_t3 clamp(int16_t3, int16_t3, int16_t3);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int16_t4 clamp(int16_t4, int16_t4, int16_t4);
+
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint16_t clamp(uint16_t, uint16_t, uint16_t);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint16_t2 clamp(uint16_t2, uint16_t2, uint16_t2);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint16_t3 clamp(uint16_t3, uint16_t3, uint16_t3);
+_HLSL_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint16_t4 clamp(uint16_t4, uint16_t4, uint16_t4);
+#endif
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int clamp(int, int, int);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int2 clamp(int2, int2, int2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int3 clamp(int3, int3, int3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int4 clamp(int4, int4, int4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint clamp(uint, uint, uint);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint2 clamp(uint2, uint2, uint2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint3 clamp(uint3, uint3, uint3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint4 clamp(uint4, uint4, uint4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int64_t clamp(int64_t, int64_t, int64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int64_t2 clamp(int64_t2, int64_t2, int64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int64_t3 clamp(int64_t3, int64_t3, int64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+int64_t4 clamp(int64_t4, int64_t4, int64_t4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint64_t clamp(uint64_t, uint64_t, uint64_t);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint64_t2 clamp(uint64_t2, uint64_t2, uint64_t2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint64_t3 clamp(uint64_t3, uint64_t3, uint64_t3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+uint64_t4 clamp(uint64_t4, uint64_t4, uint64_t4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+float clamp(float, float, float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+float2 clamp(float2, float2, float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+float3 clamp(float3, float3, float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+float4 clamp(float4, float4, float4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+double clamp(double, double, double);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+double2 clamp(double2, double2, double2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+double3 clamp(double3, double3, double3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_clamp)
+double4 clamp(double4, double4, double4);
+
+//===----------------------------------------------------------------------===//
// cos builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/InstallAPI/CMakeLists.txt b/clang/lib/InstallAPI/CMakeLists.txt
index dc90d6370de4..894db699578f 100644
--- a/clang/lib/InstallAPI/CMakeLists.txt
+++ b/clang/lib/InstallAPI/CMakeLists.txt
@@ -1,10 +1,12 @@
set(LLVM_LINK_COMPONENTS
Support
TextAPI
+ Demangle
Core
)
add_clang_library(clangInstallAPI
+ DylibVerifier.cpp
FileList.cpp
Frontend.cpp
HeaderFile.cpp
diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp
new file mode 100644
index 000000000000..b7dd85d63fa1
--- /dev/null
+++ b/clang/lib/InstallAPI/DylibVerifier.cpp
@@ -0,0 +1,212 @@
+#include "clang/InstallAPI/DylibVerifier.h"
+#include "clang/InstallAPI/FrontendRecords.h"
+#include "llvm/Demangle/Demangle.h"
+
+using namespace llvm::MachO;
+
+namespace clang {
+namespace installapi {
+
+/// Metadata stored about a mapping of a declaration to a symbol.
+struct DylibVerifier::SymbolContext {
+ // Name to use for printing in diagnostics.
+ std::string PrettyPrintName{""};
+
+ // Name to use for all querying and verification
+ // purposes.
+ std::string SymbolName{""};
+
+ // Kind to map symbol type against record.
+ EncodeKind Kind = EncodeKind::GlobalSymbol;
+
+ // Frontend Attributes tied to the AST.
+ const FrontendAttrs *FA = nullptr;
+
+ // The ObjCInterface symbol type, if applicable.
+ ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None;
+};
+
+static std::string
+getAnnotatedName(const Record *R, EncodeKind Kind, StringRef Name,
+ bool ValidSourceLoc = true,
+ ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) {
+ assert(!Name.empty() && "Need symbol name for printing");
+
+ std::string Annotation;
+ if (R->isWeakDefined())
+ Annotation += "(weak-def) ";
+ if (R->isWeakReferenced())
+ Annotation += "(weak-ref) ";
+ if (R->isThreadLocalValue())
+ Annotation += "(tlv) ";
+
+ // Check if symbol represents only part of a @interface declaration.
+ const bool IsAnnotatedObjCClass = ((ObjCIF != ObjCIFSymbolKind::None) &&
+ (ObjCIF <= ObjCIFSymbolKind::EHType));
+
+ if (IsAnnotatedObjCClass) {
+ if (ObjCIF == ObjCIFSymbolKind::EHType)
+ Annotation += "Exception Type of ";
+ if (ObjCIF == ObjCIFSymbolKind::MetaClass)
+ Annotation += "Metaclass of ";
+ if (ObjCIF == ObjCIFSymbolKind::Class)
+ Annotation += "Class of ";
+ }
+
+ // Only print symbol type prefix or leading "_" if there is no source location
+ // tied to it. This can only ever happen when the location has to come from
+ // debug info.
+ if (ValidSourceLoc) {
+ if ((Kind == EncodeKind::GlobalSymbol) && Name.starts_with("_"))
+ return Annotation + Name.drop_front(1).str();
+ return Annotation + Name.str();
+ }
+
+ if (IsAnnotatedObjCClass)
+ return Annotation + Name.str();
+
+ switch (Kind) {
+ case EncodeKind::GlobalSymbol:
+ return Annotation + Name.str();
+ case EncodeKind::ObjectiveCInstanceVariable:
+ return Annotation + "(ObjC IVar) " + Name.str();
+ case EncodeKind::ObjectiveCClass:
+ return Annotation + "(ObjC Class) " + Name.str();
+ case EncodeKind::ObjectiveCClassEHType:
+ return Annotation + "(ObjC Class EH) " + Name.str();
+ }
+
+ llvm_unreachable("unexpected case for EncodeKind");
+}
+
+static std::string demangle(StringRef Name) {
+ // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
+ if (!(Name.starts_with("_Z") || Name.starts_with("___Z")))
+ return Name.str();
+ char *Result = llvm::itaniumDemangle(Name.data());
+ if (!Result)
+ return Name.str();
+
+ std::string Demangled(Result);
+ free(Result);
+ return Demangled;
+}
+
+static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev,
+ const DylibVerifier::Result Curr) {
+ if (Prev == Curr)
+ return Prev;
+
+ // Never update from invalid or noverify state.
+ if ((Prev == DylibVerifier::Result::Invalid) ||
+ (Prev == DylibVerifier::Result::NoVerify))
+ return Prev;
+
+ // Don't let an ignored verification remove a valid one.
+ if (Prev == DylibVerifier::Result::Valid &&
+ Curr == DylibVerifier::Result::Ignore)
+ return Prev;
+
+ return Curr;
+}
+
+void DylibVerifier::updateState(Result State) {
+ Ctx.FrontendState = updateResult(Ctx.FrontendState, State);
+}
+
+void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx,
+ TargetList &&Targets) {
+ if (Targets.empty())
+ Targets = {Ctx.Target};
+
+ Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets);
+}
+
+DylibVerifier::Result DylibVerifier::verifyImpl(Record *R,
+ SymbolContext &SymCtx) {
+ R->setVerify();
+ if (!canVerify()) {
+ // Accumulate symbols when not in verifying against dylib.
+ if (R->isExported() && !SymCtx.FA->Avail.isUnconditionallyUnavailable() &&
+ !SymCtx.FA->Avail.isObsoleted()) {
+ addSymbol(R, SymCtx);
+ }
+ return Ctx.FrontendState;
+ }
+ return Ctx.FrontendState;
+}
+
+bool DylibVerifier::canVerify() {
+ return Ctx.FrontendState != Result::NoVerify;
+}
+
+void DylibVerifier::setTarget(const Target &T) {
+ Ctx.Target = T;
+ Ctx.DiscoveredFirstError = false;
+ updateState(Dylib.empty() ? Result::NoVerify : Result::Ignore);
+}
+
+DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R,
+ const FrontendAttrs *FA,
+ const StringRef SuperClass) {
+ if (R->isVerified())
+ return getState();
+
+ std::string FullName =
+ ObjCIVarRecord::createScopedName(SuperClass, R->getName());
+ SymbolContext SymCtx{
+ getAnnotatedName(R, EncodeKind::ObjectiveCInstanceVariable,
+ Demangle ? demangle(FullName) : FullName),
+ FullName, EncodeKind::ObjectiveCInstanceVariable, FA};
+ return verifyImpl(R, SymCtx);
+}
+
+static ObjCIFSymbolKind assignObjCIFSymbolKind(const ObjCInterfaceRecord *R) {
+ ObjCIFSymbolKind Result = ObjCIFSymbolKind::None;
+ if (R->getLinkageForSymbol(ObjCIFSymbolKind::Class) != RecordLinkage::Unknown)
+ Result |= ObjCIFSymbolKind::Class;
+ if (R->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass) !=
+ RecordLinkage::Unknown)
+ Result |= ObjCIFSymbolKind::MetaClass;
+ if (R->getLinkageForSymbol(ObjCIFSymbolKind::EHType) !=
+ RecordLinkage::Unknown)
+ Result |= ObjCIFSymbolKind::EHType;
+ return Result;
+}
+
+DylibVerifier::Result DylibVerifier::verify(ObjCInterfaceRecord *R,
+ const FrontendAttrs *FA) {
+ if (R->isVerified())
+ return getState();
+ SymbolContext SymCtx;
+ SymCtx.SymbolName = R->getName();
+ SymCtx.ObjCIFKind = assignObjCIFSymbolKind(R);
+
+ std::string DisplayName =
+ Demangle ? demangle(SymCtx.SymbolName) : SymCtx.SymbolName;
+ SymCtx.Kind = R->hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType
+ : EncodeKind::ObjectiveCClass;
+ SymCtx.PrettyPrintName = getAnnotatedName(R, SymCtx.Kind, DisplayName);
+ SymCtx.FA = FA;
+
+ return verifyImpl(R, SymCtx);
+}
+
+DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R,
+ const FrontendAttrs *FA) {
+ if (R->isVerified())
+ return getState();
+
+ // Global classifications could be obfusciated with `asm`.
+ SimpleSymbol Sym = parseSymbol(R->getName());
+ SymbolContext SymCtx;
+ SymCtx.SymbolName = Sym.Name;
+ SymCtx.PrettyPrintName =
+ getAnnotatedName(R, Sym.Kind, Demangle ? demangle(Sym.Name) : Sym.Name);
+ SymCtx.Kind = Sym.Kind;
+ SymCtx.FA = FA;
+ return verifyImpl(R, SymCtx);
+}
+
+} // namespace installapi
+} // namespace clang
diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp
index 707aeb17dc89..12cd5fcbc22b 100644
--- a/clang/lib/InstallAPI/Frontend.cpp
+++ b/clang/lib/InstallAPI/Frontend.cpp
@@ -16,41 +16,47 @@ using namespace llvm;
using namespace llvm::MachO;
namespace clang::installapi {
-
-GlobalRecord *FrontendRecordsSlice::addGlobal(
+std::pair<GlobalRecord *, FrontendAttrs *> FrontendRecordsSlice::addGlobal(
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
SymbolFlags Flags, bool Inlined) {
- auto *GR =
+ GlobalRecord *GR =
llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
- FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
- return GR;
+ auto Result = FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
+ return {GR, &(Result.first->second)};
}
-ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface(
- StringRef Name, RecordLinkage Linkage, const clang::AvailabilityInfo Avail,
- const Decl *D, HeaderType Access, bool IsEHType) {
+std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
+FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage,
+ const clang::AvailabilityInfo Avail,
+ const Decl *D, HeaderType Access,
+ bool IsEHType) {
ObjCIFSymbolKind SymType =
ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;
if (IsEHType)
SymType |= ObjCIFSymbolKind::EHType;
- auto *ObjCR =
+
+ ObjCInterfaceRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
- FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
- return ObjCR;
+ auto Result =
+ FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
+ return {ObjCR, &(Result.first->second)};
}
-ObjCCategoryRecord *FrontendRecordsSlice::addObjCCategory(
- StringRef ClassToExtend, StringRef CategoryName,
- const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access) {
- auto *ObjCR =
+std::pair<ObjCCategoryRecord *, FrontendAttrs *>
+FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend,
+ StringRef CategoryName,
+ const clang::AvailabilityInfo Avail,
+ const Decl *D, HeaderType Access) {
+ ObjCCategoryRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
- FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
- return ObjCR;
+ auto Result =
+ FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
+ return {ObjCR, &(Result.first->second)};
}
-ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
+std::pair<ObjCIVarRecord *, FrontendAttrs *> FrontendRecordsSlice::addObjCIVar(
ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
const clang::ObjCIvarDecl::AccessControl AC) {
@@ -59,11 +65,12 @@ ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar(
if ((Linkage == RecordLinkage::Exported) &&
((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
Linkage = RecordLinkage::Internal;
- auto *ObjCR =
+ ObjCIVarRecord *ObjCR =
llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
- FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
+ auto Result =
+ FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
- return nullptr;
+ return {ObjCR, &(Result.first->second)};
}
std::optional<HeaderType>
diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp
index b4ed5974a057..187afe59309d 100644
--- a/clang/lib/InstallAPI/Visitor.cpp
+++ b/clang/lib/InstallAPI/Visitor.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/VTableBuilder.h"
#include "clang/Basic/Linkage.h"
+#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/FrontendRecords.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
@@ -156,7 +157,9 @@ void InstallAPIVisitor::recordObjCInstanceVariables(
StringRef Name = IV->getName();
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
auto AC = IV->getCanonicalAccessControl();
- Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
+ auto [ObjCIVR, FA] =
+ Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
+ Ctx.Verifier->verify(ObjCIVR, FA, SuperClass);
}
}
@@ -178,15 +181,16 @@ bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
hasObjCExceptionAttribute(D));
- ObjCInterfaceRecord *Class =
+ auto [Class, FA] =
Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
+ Ctx.Verifier->verify(Class, FA);
// Get base class.
StringRef SuperClassName;
if (const auto *SuperClass = D->getSuperClass())
SuperClassName = SuperClass->getObjCRuntimeNameAsString();
- recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName,
+ recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(),
D->ivars());
return true;
}
@@ -201,8 +205,8 @@ bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
const StringRef InterfaceName = InterfaceD->getName();
- ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory(
- InterfaceName, CategoryName, Avail, D, *Access);
+ auto [Category, FA] = Ctx.Slice->addObjCCategory(InterfaceName, CategoryName,
+ Avail, D, *Access);
recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName,
D->ivars());
return true;
@@ -236,8 +240,10 @@ bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
const bool WeakDef = D->hasAttr<WeakAttr>();
const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
- Ctx.Slice->addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
- Avail, D, *Access, getFlags(WeakDef, ThreadLocal));
+ auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage,
+ GlobalRecord::Kind::Variable, Avail, D,
+ *Access, getFlags(WeakDef, ThreadLocal));
+ Ctx.Verifier->verify(GR, FA);
return true;
}
@@ -287,8 +293,10 @@ bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
const RecordLinkage Linkage = (Inlined || !isExported(D))
? RecordLinkage::Internal
: RecordLinkage::Exported;
- Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D,
- *Access, getFlags(WeakDef), Inlined);
+ auto [GR, FA] =
+ Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail,
+ D, *Access, getFlags(WeakDef), Inlined);
+ Ctx.Verifier->verify(GR, FA);
return true;
}
@@ -478,9 +486,10 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
VTableLinkage == CXXLinkage::WeakODRLinkage) {
const std::string Name = getMangledCXXVTableName(D);
const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Variable, Avail, D, Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Variable, Avail,
+ D, Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {
VTableContextBase *VTable = D->getASTContext().getVTableContext();
auto AddThunk = [&](GlobalDecl GD) {
@@ -491,9 +500,10 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
for (const auto &Thunk : *Thunks) {
const std::string Name = getMangledCXXThunk(GD, Thunk);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail,
- GD.getDecl(), Access);
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Function,
+ Avail, GD.getDecl(), Access);
+ Ctx.Verifier->verify(GR, FA);
}
};
@@ -519,12 +529,16 @@ void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
if (hasRTTI(D)) {
std::string Name = getMangledCXXRTTI(D);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Variable, Avail, D, Access);
+ auto [GR, FA] =
+ Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Variable, Avail, D, Access);
+ Ctx.Verifier->verify(GR, FA);
Name = getMangledCXXRTTIName(D);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Variable, Avail, D, Access);
+ auto [NamedGR, NamedFA] =
+ Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Variable, Avail, D, Access);
+ Ctx.Verifier->verify(NamedGR, NamedFA);
}
for (const auto &It : D->bases()) {
@@ -615,15 +629,17 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;
std::string Name = getMangledCtorDtor(M, Ctor_Base);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Function, Avail,
+ D, *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
if (!D->isAbstract()) {
std::string Name = getMangledCtorDtor(M, Ctor_Complete);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(
+ Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
+ D, *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
}
continue;
@@ -635,20 +651,23 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;
std::string Name = getMangledCtorDtor(M, Dtor_Base);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Function, Avail,
+ D, *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
Name = getMangledCtorDtor(M, Dtor_Complete);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(
+ Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,
+ *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(CompleteGR, CompleteFA);
if (Dtor->isVirtual()) {
Name = getMangledCtorDtor(M, Dtor_Deleting);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(
+ Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
+ D, *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(VirtualGR, VirtualFA);
}
continue;
@@ -661,9 +680,10 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
continue;
std::string Name = getMangledName(M);
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Function, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Function, Avail, D,
+ *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
}
if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
@@ -694,9 +714,10 @@ bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);
const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;
- Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
- GlobalRecord::Kind::Variable, Avail, D, *Access,
- getFlags(WeakDef));
+ auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
+ GlobalRecord::Kind::Variable, Avail, D,
+ *Access, getFlags(WeakDef));
+ Ctx.Verifier->verify(GR, FA);
}
return true;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e303a7c6511c..46b783862e4e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5499,6 +5499,17 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
+ case Builtin::BI__builtin_hlsl_elementwise_clamp: {
+ if (checkArgCount(*this, TheCall, 3))
+ return true;
+ if (CheckVectorElementCallArgs(this, TheCall))
+ return true;
+ if (SemaBuiltinElementwiseTernaryMath(
+ TheCall, /*CheckForFloatArgs*/
+ TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
+ return true;
+ break;
+ }
case Builtin::BI__builtin_hlsl_dot: {
if (checkArgCount(*this, TheCall, 2))
return true;
@@ -5547,7 +5558,9 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
- if (SemaBuiltinElementwiseTernaryMath(TheCall, /*CheckForFloatArgs*/ false))
+ if (SemaBuiltinElementwiseTernaryMath(
+ TheCall, /*CheckForFloatArgs*/
+ TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
return true;
}
}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index a8e387e35fb4..1c546e9f5894 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -692,11 +692,15 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
// A lambda conversion operator has the same constraints as the call operator
// and constraints checking relies on whether we are in a lambda call operator
// (and may refer to its parameters), so check the call operator instead.
+ // Note that the declarations outside of the lambda should also be
+ // considered. Turning on the 'ForOverloadResolution' flag results in the
+ // LocalInstantiationScope not looking into its parents, but we can still
+ // access Decls from the parents while building a lambda RAII scope later.
if (const auto *MD = dyn_cast<CXXConversionDecl>(FD);
MD && isLambdaConversionOperator(const_cast<CXXConversionDecl *>(MD)))
return CheckFunctionConstraints(MD->getParent()->getLambdaCallOperator(),
Satisfaction, UsageLoc,
- ForOverloadResolution);
+ /*ShouldAddDeclsFromParentScope=*/true);
DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD);
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 6c8df99a1597..a09c6d3acca5 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -514,7 +514,9 @@ namespace bswap {
#define CFSTR __builtin___CFStringMakeConstantString
void test7(void) {
const void *X;
+#if !defined(_AIX)
X = CFSTR("\242"); // both-warning {{input conversion stopped}}
+#endif
X = CFSTR("\0"); // no-warning
X = CFSTR(242); // both-error {{cannot initialize a parameter of type 'const char *' with an rvalue of type 'int'}}
X = CFSTR("foo", "bar"); // both-error {{too many arguments to function call}}
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 0a9580b6f664..277438d2e631 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -910,6 +910,18 @@ namespace TypeTraits {
struct U {};
static_assert(S3<U>{}.foo(), "");
static_assert(!S3<T>{}.foo(), "");
+
+ typedef int Int;
+ typedef Int IntAr[10];
+ typedef const IntAr ConstIntAr;
+ typedef ConstIntAr ConstIntArAr[4];
+
+ static_assert(__array_rank(IntAr) == 1, "");
+ static_assert(__array_rank(ConstIntArAr) == 2, "");
+
+ static_assert(__array_extent(IntAr, 0) == 10, "");
+ static_assert(__array_extent(ConstIntArAr, 0) == 4, "");
+ static_assert(__array_extent(ConstIntArAr, 1) == 10, "");
}
#if __cplusplus >= 201402L
diff --git a/clang/test/CodeGenCXX/mangle-ms-back-references.cpp b/clang/test/CodeGenCXX/mangle-ms-back-references.cpp
index cb95c100b3d2..b27a9c5acacb 100644
--- a/clang/test/CodeGenCXX/mangle-ms-back-references.cpp
+++ b/clang/test/CodeGenCXX/mangle-ms-back-references.cpp
@@ -83,3 +83,20 @@ class H;
void ManyParams(T01 &, T02 &, T03 &, T04 &, T05 &, T06 &, T07 &, T08 &, T09 &, T10 &, H<T11> &, H<T11> &) {}
// CHECK: "?ManyParams@@YAXAAVT01@@AAVT02@@AAVT03@@AAVT04@@AAVT05@@AAVT06@@AAVT07@@AAVT08@@AAVT09@@AAVT10@@AAV?$H@VT11@@@@AAV?$H@VT11@@@@@Z"
+
+namespace NS {
+// The name "TSS0" for the name of the class below has been specifically
+// chosen to ensure that back reference lookup does not match against the
+// implicitly generated "$TSS0" name of the thread safe static initialization
+// variable.
+struct __declspec(dllexport) TSS0 {
+ static TSS0& get();
+ __forceinline static TSS0& singleton() {
+ static TSS0& lsv = get();
+ return lsv;
+ }
+};
+}
+// CHECK: "?singleton@TSS0@NS@@SAAAU12@XZ"
+// CHECK: "?lsv@?1??singleton@TSS0@NS@@SAAAU23@XZ@4AAU23@A"
+// CHECK: "?$TSS0@?1??singleton@TSS0@NS@@SAAAU23@XZ@4HA"
diff --git a/clang/test/CodeGenHLSL/builtins/clamp-builtin.hlsl b/clang/test/CodeGenHLSL/builtins/clamp-builtin.hlsl
new file mode 100644
index 000000000000..e3ef26429e7e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/clamp-builtin.hlsl
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK-LABEL: builtin_test_clamp_int4
+// CHECK: %dx.clamp = call <4 x i32> @llvm.dx.clamp.v4i32(<4 x i32> %0, <4 x i32> %1, <4 x i32> %2)
+// CHECK: ret <4 x i32> %dx.clamp
+int4 builtin_test_clamp_int4(int4 p0, int4 p1, int4 p2) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p2);
+}
diff --git a/clang/test/CodeGenHLSL/builtins/clamp.hlsl b/clang/test/CodeGenHLSL/builtins/clamp.hlsl
new file mode 100644
index 000000000000..029e48ffe258
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/clamp.hlsl
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -fnative-half-type \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN: --check-prefixes=CHECK,NATIVE_HALF
+// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF
+
+#ifdef __HLSL_ENABLE_16_BIT
+// NATIVE_HALF: define noundef i16 @
+// NATIVE_HALF: call i16 @llvm.dx.clamp.i16(
+int16_t test_clamp_short(int16_t p0, int16_t p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <2 x i16> @
+// NATIVE_HALF: call <2 x i16> @llvm.dx.clamp.v2i16(
+int16_t2 test_clamp_short2(int16_t2 p0, int16_t2 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <3 x i16> @
+// NATIVE_HALF: call <3 x i16> @llvm.dx.clamp.v3i16
+int16_t3 test_clamp_short3(int16_t3 p0, int16_t3 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <4 x i16> @
+// NATIVE_HALF: call <4 x i16> @llvm.dx.clamp.v4i16
+int16_t4 test_clamp_short4(int16_t4 p0, int16_t4 p1) { return clamp(p0, p1,p1); }
+
+// NATIVE_HALF: define noundef i16 @
+// NATIVE_HALF: call i16 @llvm.dx.uclamp.i16(
+uint16_t test_clamp_ushort(uint16_t p0, uint16_t p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <2 x i16> @
+// NATIVE_HALF: call <2 x i16> @llvm.dx.uclamp.v2i16
+uint16_t2 test_clamp_ushort2(uint16_t2 p0, uint16_t2 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <3 x i16> @
+// NATIVE_HALF: call <3 x i16> @llvm.dx.uclamp.v3i16
+uint16_t3 test_clamp_ushort3(uint16_t3 p0, uint16_t3 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <4 x i16> @
+// NATIVE_HALF: call <4 x i16> @llvm.dx.uclamp.v4i16
+uint16_t4 test_clamp_ushort4(uint16_t4 p0, uint16_t4 p1) { return clamp(p0, p1,p1); }
+#endif
+
+// CHECK: define noundef i32 @
+// CHECK: call i32 @llvm.dx.clamp.i32(
+int test_clamp_int(int p0, int p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x i32> @
+// CHECK: call <2 x i32> @llvm.dx.clamp.v2i32
+int2 test_clamp_int2(int2 p0, int2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x i32> @
+// CHECK: call <3 x i32> @llvm.dx.clamp.v3i32
+int3 test_clamp_int3(int3 p0, int3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x i32> @
+// CHECK: call <4 x i32> @llvm.dx.clamp.v4i32
+int4 test_clamp_int4(int4 p0, int4 p1) { return clamp(p0, p1,p1); }
+
+// CHECK: define noundef i32 @
+// CHECK: call i32 @llvm.dx.uclamp.i32(
+int test_clamp_uint(uint p0, uint p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x i32> @
+// CHECK: call <2 x i32> @llvm.dx.uclamp.v2i32
+uint2 test_clamp_uint2(uint2 p0, uint2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x i32> @
+// CHECK: call <3 x i32> @llvm.dx.uclamp.v3i32
+uint3 test_clamp_uint3(uint3 p0, uint3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x i32> @
+// CHECK: call <4 x i32> @llvm.dx.uclamp.v4i32
+uint4 test_clamp_uint4(uint4 p0, uint4 p1) { return clamp(p0, p1,p1); }
+
+// CHECK: define noundef i64 @
+// CHECK: call i64 @llvm.dx.clamp.i64(
+int64_t test_clamp_long(int64_t p0, int64_t p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x i64> @
+// CHECK: call <2 x i64> @llvm.dx.clamp.v2i64
+int64_t2 test_clamp_long2(int64_t2 p0, int64_t2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x i64> @
+// CHECK: call <3 x i64> @llvm.dx.clamp.v3i64
+int64_t3 test_clamp_long3(int64_t3 p0, int64_t3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x i64> @
+// CHECK: call <4 x i64> @llvm.dx.clamp.v4i64
+int64_t4 test_clamp_long4(int64_t4 p0, int64_t4 p1) { return clamp(p0, p1,p1); }
+
+// CHECK: define noundef i64 @
+// CHECK: call i64 @llvm.dx.uclamp.i64(
+uint64_t test_clamp_long(uint64_t p0, uint64_t p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x i64> @
+// CHECK: call <2 x i64> @llvm.dx.uclamp.v2i64
+uint64_t2 test_clamp_long2(uint64_t2 p0, uint64_t2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x i64> @
+// CHECK: call <3 x i64> @llvm.dx.uclamp.v3i64
+uint64_t3 test_clamp_long3(uint64_t3 p0, uint64_t3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x i64> @
+// CHECK: call <4 x i64> @llvm.dx.uclamp.v4i64
+uint64_t4 test_clamp_long4(uint64_t4 p0, uint64_t4 p1) { return clamp(p0, p1,p1); }
+
+// NATIVE_HALF: define noundef half @
+// NATIVE_HALF: call half @llvm.dx.clamp.f16(
+// NO_HALF: define noundef float @"?test_clamp_half
+// NO_HALF: call float @llvm.dx.clamp.f32(
+half test_clamp_half(half p0, half p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <2 x half> @
+// NATIVE_HALF: call <2 x half> @llvm.dx.clamp.v2f16
+// NO_HALF: define noundef <2 x float> @"?test_clamp_half2
+// NO_HALF: call <2 x float> @llvm.dx.clamp.v2f32(
+half2 test_clamp_half2(half2 p0, half2 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <3 x half> @
+// NATIVE_HALF: call <3 x half> @llvm.dx.clamp.v3f16
+// NO_HALF: define noundef <3 x float> @"?test_clamp_half3
+// NO_HALF: call <3 x float> @llvm.dx.clamp.v3f32(
+half3 test_clamp_half3(half3 p0, half3 p1) { return clamp(p0, p1,p1); }
+// NATIVE_HALF: define noundef <4 x half> @
+// NATIVE_HALF: call <4 x half> @llvm.dx.clamp.v4f16
+// NO_HALF: define noundef <4 x float> @"?test_clamp_half4
+// NO_HALF: call <4 x float> @llvm.dx.clamp.v4f32(
+half4 test_clamp_half4(half4 p0, half4 p1) { return clamp(p0, p1,p1); }
+
+// CHECK: define noundef float @"?test_clamp_float
+// CHECK: call float @llvm.dx.clamp.f32(
+float test_clamp_float(float p0, float p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x float> @"?test_clamp_float2
+// CHECK: call <2 x float> @llvm.dx.clamp.v2f32
+float2 test_clamp_float2(float2 p0, float2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x float> @"?test_clamp_float3
+// CHECK: call <3 x float> @llvm.dx.clamp.v3f32
+float3 test_clamp_float3(float3 p0, float3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x float> @"?test_clamp_float4
+// CHECK: call <4 x float> @llvm.dx.clamp.v4f32
+float4 test_clamp_float4(float4 p0, float4 p1) { return clamp(p0, p1,p1); }
+
+// CHECK: define noundef double @
+// CHECK: call double @llvm.dx.clamp.f64(
+double test_clamp_double(double p0, double p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <2 x double> @
+// CHECK: call <2 x double> @llvm.dx.clamp.v2f64
+double2 test_clamp_double2(double2 p0, double2 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <3 x double> @
+// CHECK: call <3 x double> @llvm.dx.clamp.v3f64
+double3 test_clamp_double3(double3 p0, double3 p1) { return clamp(p0, p1,p1); }
+// CHECK: define noundef <4 x double> @
+// CHECK: call <4 x double> @llvm.dx.clamp.v4f64
+double4 test_clamp_double4(double4 p0, double4 p1) { return clamp(p0, p1,p1); }
diff --git a/clang/test/InstallAPI/asm.test b/clang/test/InstallAPI/asm.test
new file mode 100644
index 000000000000..b6af7f643d72
--- /dev/null
+++ b/clang/test/InstallAPI/asm.test
@@ -0,0 +1,90 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s|DSTROOT|%/t|g" %t/inputs.json.in > %t/inputs.json
+
+// RUN: clang-installapi -target arm64-apple-macos13.1 \
+// RUN: -I%t/usr/include \
+// RUN: -install_name @rpath/lib/libasm.dylib \
+// RUN: %t/inputs.json -o %t/output.tbd 2>&1 | FileCheck %s --allow-empty
+// RUN: llvm-readtapi -compare %t/output.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty
+
+// CHECK-NOT: error:
+// CHECK-NOT: warning:
+
+//--- usr/include/asm.h
+#ifndef ASM_H
+#define ASM_H
+
+extern int ivar __asm("_OBJC_IVAR_$_SomeClass._ivar1");
+extern int objcClass1 __asm("_OBJC_CLASS_$_SomeClass");
+extern int objcClass2 __asm("_OBJC_METACLASS_$_SomeClass");
+extern int objcClass3 __asm("_OBJC_EHTYPE_$_SomeClass");
+extern int objcClass4 __asm(".objc_class_name_SomeClass");
+
+__attribute__((visibility("hidden")))
+@interface NSString {
+}
+@end
+
+extern int ivarExtra __asm("_OBJC_IVAR_$_NSString._ivar1");
+#endif // ASM_H
+
+//--- inputs.json.in
+{
+ "headers": [ {
+ "path" : "DSTROOT/usr/include/asm.h",
+ "type" : "public"
+ }],
+ "version": "3"
+}
+
+//--- expected.tbd
+{
+ "main_library": {
+ "compatibility_versions": [
+ {
+ "version": "0"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "0"
+ }
+ ],
+ "exported_symbols": [
+ {
+ "data": {
+ "objc_class": [
+ "SomeClass"
+ ],
+ "objc_eh_type": [
+ "SomeClass"
+ ],
+ "objc_ivar": [
+ "NSString._ivar1",
+ "SomeClass._ivar1"
+ ]
+ }
+ }
+ ],
+ "flags": [
+ {
+ "attributes": [
+ "not_app_extension_safe"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "@rpath/lib/libasm.dylib"
+ }
+ ],
+ "target_info": [
+ {
+ "min_deployment": "13.1",
+ "target": "arm64-macos"
+ }
+ ]
+ },
+ "tapi_tbd_version": 5
+}
diff --git a/clang/test/InstallAPI/driver-invalid-options.test b/clang/test/InstallAPI/driver-invalid-options.test
index a2e008e1eb03..69f3b2d66ab8 100644
--- a/clang/test/InstallAPI/driver-invalid-options.test
+++ b/clang/test/InstallAPI/driver-invalid-options.test
@@ -1,4 +1,9 @@
/// Check non-darwin triple is rejected.
-// RUN: not clang-installapi -target x86_64-unknown-unknown %s 2> %t
+// RUN: not clang-installapi -target x86_64-unknown-unknown %s -o tmp.tbd 2> %t
// RUN: FileCheck --check-prefix INVALID_INSTALLAPI -input-file %t %s
// INVALID_INSTALLAPI: error: unsupported option 'installapi' for target 'x86_64-unknown-unknown'
+
+/// Check that missing install_name is reported.
+// RUN: not clang-installapi -target x86_64-apple-ios-simulator %s -o tmp.tbd 2> %t
+// RUN: FileCheck --check-prefix INVALID_INSTALL_NAME -input-file %t %s
+// INVALID_INSTALL_NAME: error: no install name specified: add -install_name <path>
diff --git a/clang/test/InstallAPI/functions.test b/clang/test/InstallAPI/functions.test
index 527965303cb3..5b5fd1308842 100644
--- a/clang/test/InstallAPI/functions.test
+++ b/clang/test/InstallAPI/functions.test
@@ -4,7 +4,7 @@
// RUN: clang-installapi -target arm64-apple-macos13.1 \
// RUN: -I%t/usr/include -I%t/usr/local/include \
-// RUN: -install_name @rpath/lib/libfunctions.dylib \
+// RUN: -install_name @rpath/lib/libfunctions.dylib --filetype=tbd-v4 \
// RUN: %t/inputs.json -o %t/outputs.tbd 2>&1 | FileCheck %s --allow-empty
// RUN: llvm-readtapi -compare %t/outputs.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 2d7c9b174d90..478da092471a 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -126,3 +126,13 @@ static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint sati
static_assert(f5<double>() == 2);
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
+
+// Do not validate assumptions whose evaluation would have side-effects.
+constexpr int foo() {
+ int a = 0;
+ [[assume(a++)]] [[assume(++a)]]; // expected-warning 2 {{has side effects that will be discarded}} ext-warning 2 {{C++23 extension}}
+ [[assume((a+=1))]]; // expected-warning {{has side effects that will be discarded}} ext-warning {{C++23 extension}}
+ return a;
+}
+
+static_assert(foo() == 0);
diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index 0516a5da31ae..389002ab0e34 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -std=c++11 -Wno-unused-value -fsyntax-only -verify=expected,expected-cxx14,cxx11 -fblocks %s
// RUN: %clang_cc1 -std=c++14 -Wno-unused-value -fsyntax-only -verify -verify=expected-cxx14 -fblocks %s
// RUN: %clang_cc1 -std=c++17 -Wno-unused-value -verify -ast-dump -fblocks %s | FileCheck %s
@@ -558,8 +559,8 @@ struct B {
int x;
A a = [&] { int y = x; };
A b = [&] { [&] { [&] { int y = x; }; }; };
- A d = [&](auto param) { int y = x; };
- A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; };
+ A d = [&](auto param) { int y = x; }; // cxx11-error {{'auto' not allowed in lambda parameter}}
+ A e = [&](auto param) { [&] { [&](auto param2) { int y = x; }; }; }; // cxx11-error 2 {{'auto' not allowed in lambda parameter}}
};
B<int> b;
@@ -589,6 +590,7 @@ struct S1 {
void foo1() {
auto s0 = S1{[name=]() {}}; // expected-error 2 {{expected expression}}
auto s1 = S1{[name=name]() {}}; // expected-error {{use of undeclared identifier 'name'; did you mean 'name1'?}}
+ // cxx11-warning@-1 {{initialized lambda captures are a C++14 extension}}
}
}
@@ -604,7 +606,7 @@ namespace PR25627_dont_odr_use_local_consts {
namespace ConversionOperatorDoesNotHaveDeducedReturnType {
auto x = [](int){};
- auto y = [](auto &v) -> void { v.n = 0; };
+ auto y = [](auto &v) -> void { v.n = 0; }; // cxx11-error {{'auto' not allowed in lambda parameter}} cxx11-note {{candidate function not viable}} cxx11-note {{conversion candidate}}
using T = decltype(x);
using U = decltype(y);
using ExpectedTypeT = void (*)(int);
@@ -624,22 +626,22 @@ namespace ConversionOperatorDoesNotHaveDeducedReturnType {
template<typename T>
friend constexpr U::operator ExpectedTypeU<T>() const noexcept;
#else
- friend auto T::operator()(int) const;
+ friend auto T::operator()(int) const; // cxx11-error {{'auto' return without trailing return type; deduced return types are a C++14 extension}}
friend T::operator ExpectedTypeT() const;
template<typename T>
- friend void U::operator()(T&) const;
+ friend void U::operator()(T&) const; // cxx11-error {{friend declaration of 'operator()' does not match any declaration}}
// FIXME: This should not match, as above.
template<typename T>
- friend U::operator ExpectedTypeU<T>() const;
+ friend U::operator ExpectedTypeU<T>() const; // cxx11-error {{friend declaration of 'operator void (*)(type-parameter-0-0 &)' does not match any declaration}}
#endif
private:
int n;
};
- // Should be OK: lambda's call operator is a friend.
- void use(X &x) { y(x); }
+ // Should be OK in C++14 and later: lambda's call operator is a friend.
+ void use(X &x) { y(x); } // cxx11-error {{no matching function for call to object}}
// This used to crash in return type deduction for the conversion opreator.
struct A { int n; void f() { +[](decltype(n)) {}; } };
@@ -733,6 +735,8 @@ void GH67492() {
auto lambda = (test, []() noexcept(true) {});
}
+// FIXME: This currently causes clang to crash in C++11 mode.
+#if __cplusplus >= 201402L
namespace GH83267 {
auto l = [](auto a) { return 1; };
using type = decltype(l);
@@ -747,3 +751,4 @@ using t = decltype(ll);
template auto t::operator()<int>(int a) const; // expected-note {{in instantiation}}
}
+#endif
diff --git a/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
new file mode 100644
index 000000000000..4c0e5315ce53
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/clamp-errors.hlsl
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm -disable-llvm-passes -verify -verify-ignore-unexpected
+
+float2 test_no_second_arg(float2 p0) {
+ return __builtin_hlsl_elementwise_clamp(p0);
+ // expected-error@-1 {{too few arguments to function call, expected 3, have 1}}
+}
+
+float2 test_no_third_arg(float2 p0) {
+ return __builtin_hlsl_elementwise_clamp(p0, p0);
+ // expected-error@-1 {{too few arguments to function call, expected 3, have 2}}
+}
+
+float2 test_too_many_arg(float2 p0) {
+ return __builtin_hlsl_elementwise_clamp(p0, p0, p0, p0);
+ // expected-error@-1 {{too many arguments to function call, expected 3, have 4}}
+}
+
+float2 test_clamp_no_second_arg(float2 p0) {
+ return clamp(p0);
+ // expected-error@-1 {{no matching function for call to 'clamp'}}
+}
+
+float2 test_clamp_vector_size_mismatch(float3 p0, float2 p1) {
+ return clamp(p0, p0, p1);
+ // expected-warning@-1 {{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'float __attribute__((ext_vector_type(2)))' (vector of 2 'float' values)}}
+}
+
+float2 test_clamp_builtin_vector_size_mismatch(float3 p0, float2 p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must have the same type}}
+}
+
+float test_clamp_scalar_mismatch(float p0, half p1) {
+ return clamp(p1, p0, p1);
+ // expected-error@-1 {{call to 'clamp' is ambiguous}}
+}
+
+float2 test_clamp_element_type_mismatch(half2 p0, float2 p1) {
+ return clamp(p1, p0, p1);
+ // expected-error@-1 {{call to 'clamp' is ambiguous}}
+}
+
+float2 test_builtin_clamp_float2_splat(float p0, float2 p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float3 test_builtin_clamp_float3_splat(float p0, float3 p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float4 test_builtin_clamp_float4_splat(float p0, float4 p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float2 test_clamp_float2_int_splat(float2 p0, int p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float3 test_clamp_float3_int_splat(float3 p0, int p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float2 test_builtin_clamp_int_vect_to_float_vec_promotion(int2 p0, float p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p1, p1);
+ // expected-error@-1 {{all arguments to '__builtin_hlsl_elementwise_clamp' must be vectors}}
+}
+
+float test_builtin_clamp_bool_type_promotion(bool p0) {
+ return __builtin_hlsl_elementwise_clamp(p0, p0, p0);
+ // expected-error@-1 {{1st argument must be a vector, integer or floating point type (was 'bool')}}
+}
+
+float builtin_bool_to_float_type_promotion(float p0, bool p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p0, p1);
+ // expected-error@-1 {{3rd argument must be a floating point type (was 'bool')}}
+}
+
+float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
+ return __builtin_hlsl_elementwise_clamp(p1, p0, p1);
+ // expected-error@-1 {{2nd argument must be a floating point type (was 'bool')}}
+}
+
+float builtin_clamp_int_to_float_promotion(float p0, int p1) {
+ return __builtin_hlsl_elementwise_clamp(p0, p0, p1);
+ // expected-error@-1 {{3rd argument must be a floating point type (was 'int')}}
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
index 0b6843591455..97ce931bf1b5 100644
--- a/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/mad-errors.hlsl
@@ -72,15 +72,15 @@ float2 test_builtin_mad_int_vect_to_float_vec_promotion(int2 p0, float p1) {
float builtin_bool_to_float_type_promotion(float p0, bool p1) {
return __builtin_hlsl_mad(p0, p0, p1);
- // expected-error@-1 {{3rd argument must be a vector, integer or floating point type (was 'bool')}}
+ // expected-error@-1 {{3rd argument must be a floating point type (was 'bool')}}
}
float builtin_bool_to_float_type_promotion2(bool p0, float p1) {
return __builtin_hlsl_mad(p1, p0, p1);
- // expected-error@-1 {{2nd argument must be a vector, integer or floating point type (was 'bool')}}
+ // expected-error@-1 {{2nd argument must be a floating point type (was 'bool')}}
}
float builtin_mad_int_to_float_promotion(float p0, int p1) {
return __builtin_hlsl_mad(p0, p0, p1);
- // expected-error@-1 {{arguments are of different types ('double' vs 'int')}}
+ // expected-error@-1 {{3rd argument must be a floating point type (was 'int')}}
}
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index bac209a28da9..b7ea0d003a52 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1085,3 +1085,32 @@ template void Struct<void>::bar<>();
template int Struct<void>::field<1, 2>;
}
+
+namespace GH64808 {
+
+template <class T> struct basic_sender {
+ T func;
+ basic_sender(T) : func(T()) {}
+};
+
+auto a = basic_sender{[](auto... __captures) {
+ return []() // #note-a-1
+ requires((__captures, ...), false) // #note-a-2
+ {};
+}()};
+
+auto b = basic_sender{[](auto... __captures) {
+ return []()
+ requires([](int, double) { return true; }(decltype(__captures)()...))
+ {};
+}(1, 2.33)};
+
+void foo() {
+ a.func();
+ // expected-error@-1{{no matching function for call}}
+ // expected-note@#note-a-1{{constraints not satisfied}}
+ // expected-note@#note-a-2{{evaluated to false}}
+ b.func();
+}
+
+} // namespace GH64808
diff --git a/clang/tools/clang-format/.clang-format b/clang/tools/clang-format/.clang-format
index f95602cab0f7..d7331b3c8cf0 100644
--- a/clang/tools/clang-format/.clang-format
+++ b/clang/tools/clang-format/.clang-format
@@ -1,6 +1 @@
-BasedOnStyle: LLVM
-InsertBraces: true
-InsertNewlineAtEOF: true
-LineEnding: LF
-RemoveBracesLLVM: true
-RemoveParentheses: ReturnStatement
+BasedOnStyle: clang-format
diff --git a/clang/tools/clang-installapi/CMakeLists.txt b/clang/tools/clang-installapi/CMakeLists.txt
index e05f4eac3ad1..b90ffc847b15 100644
--- a/clang/tools/clang-installapi/CMakeLists.txt
+++ b/clang/tools/clang-installapi/CMakeLists.txt
@@ -2,13 +2,20 @@ set(LLVM_LINK_COMPONENTS
Support
TargetParser
TextAPI
+ TextAPIBinaryReader
Option
)
+set(LLVM_TARGET_DEFINITIONS InstallAPIOpts.td)
+tablegen(LLVM InstallAPIOpts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(InstallAPIDriverOptions)
+
add_clang_tool(clang-installapi
ClangInstallAPI.cpp
Options.cpp
+ DEPENDS
+ InstallAPIDriverOptions
GENERATE_DRIVER
)
@@ -22,3 +29,4 @@ clang_target_link_libraries(clang-installapi
clangTooling
clangSerialization
)
+
diff --git a/clang/tools/clang-installapi/ClangInstallAPI.cpp b/clang/tools/clang-installapi/ClangInstallAPI.cpp
index 15b0baee88bc..d758f7311790 100644
--- a/clang/tools/clang-installapi/ClangInstallAPI.cpp
+++ b/clang/tools/clang-installapi/ClangInstallAPI.cpp
@@ -14,12 +14,12 @@
#include "Options.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticFrontend.h"
-#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/InstallAPI/Frontend.h"
#include "clang/InstallAPI/FrontendRecords.h"
+#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "clang/InstallAPI/MachO.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/ArrayRef.h"
@@ -92,22 +92,8 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
IntrusiveRefCntPtr<clang::FileManager> FM(
new FileManager(clang::FileSystemOptions(), OverlayFileSystem));
- // Set up driver to parse input arguments.
- auto DriverArgs = llvm::ArrayRef(Args).slice(1);
- clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
- *Diag, "clang installapi tool");
- auto TargetAndMode =
- clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
- Driver.setTargetAndMode(TargetAndMode);
- bool HasError = false;
- llvm::opt::InputArgList ArgList =
- Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
- if (HasError)
- return EXIT_FAILURE;
- Driver.setCheckInputsExist(false);
-
- // Capture InstallAPI specific options and diagnose any option errors.
- Options Opts(*Diag, FM.get(), ArgList);
+ // Capture all options and diagnose any errors.
+ Options Opts(*Diag, FM.get(), Args, ProgName);
if (Diag->hasErrorOccurred())
return EXIT_FAILURE;
@@ -130,6 +116,7 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
for (const HeaderType Type :
{HeaderType::Public, HeaderType::Private, HeaderType::Project}) {
Ctx.Slice = std::make_shared<FrontendRecordsSlice>(Trip);
+ Ctx.Verifier->setTarget(Targ);
Ctx.Type = Type;
if (!runFrontend(ProgName, Opts.DriverOpts.Verbose, Ctx,
InMemoryFileSystem.get(), Opts.getClangFrontendArgs()))
@@ -138,6 +125,9 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
}
}
+ if (Ctx.Verifier->getState() == DylibVerifier::Result::Invalid)
+ return EXIT_FAILURE;
+
// After symbols have been collected, prepare to write output.
auto Out = CI->createOutputFile(Ctx.OutputLoc, /*Binary=*/false,
/*RemoveFileOnSignal=*/false,
@@ -147,13 +137,7 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
return EXIT_FAILURE;
// Assign attributes for serialization.
- auto Symbols = std::make_unique<SymbolSet>();
- for (const auto &FR : FrontendResults) {
- SymbolConverter Converter(Symbols.get(), FR->getTarget());
- FR->visit(Converter);
- }
-
- InterfaceFile IF(std::move(Symbols));
+ InterfaceFile IF(Ctx.Verifier->getExports());
for (const auto &TargetInfo : Opts.DriverOpts.Targets) {
IF.addTarget(TargetInfo.first);
IF.setFromBinaryAttrs(Ctx.BA, TargetInfo.first);
@@ -161,7 +145,8 @@ static bool run(ArrayRef<const char *> Args, const char *ProgName) {
// Write output file and perform CI cleanup.
if (auto Err = TextAPIWriter::writeToStream(*Out, IF, Ctx.FT)) {
- Diag->Report(diag::err_cannot_open_file) << Ctx.OutputLoc;
+ Diag->Report(diag::err_cannot_write_file)
+ << Ctx.OutputLoc << std::move(Err);
CI->clearOutputFiles(/*EraseFiles=*/true);
return EXIT_FAILURE;
}
diff --git a/clang/tools/clang-installapi/InstallAPIOpts.td b/clang/tools/clang-installapi/InstallAPIOpts.td
new file mode 100644
index 000000000000..87f4c3327e84
--- /dev/null
+++ b/clang/tools/clang-installapi/InstallAPIOpts.td
@@ -0,0 +1,31 @@
+//===--- InstallAPIOpts.td ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the specific options for InstallAPI.
+//
+//===----------------------------------------------------------------------===//
+
+// Include the common option parsing interfaces.
+include "llvm/Option/OptParser.td"
+
+
+/////////
+// Options
+
+// TextAPI options.
+def filetype : Joined<["--"], "filetype=">,
+ HelpText<"Specify the output file type (tbd-v4 or tbd-v5)">;
+
+// Verification options.
+def verify_against : Separate<["-"], "verify-against">,
+ HelpText<"Verify the specified dynamic library/framework against the headers">;
+def verify_against_EQ : Joined<["--"], "verify-against=">, Alias<verify_against>;
+def verify_mode_EQ : Joined<["--"], "verify-mode=">,
+ HelpText<"Specify the severity and extend of the validation. Valid modes are ErrorsOnly, ErrorsAndWarnings, and Pedantic.">;
+def demangle : Flag<["--", "-"], "demangle">,
+ HelpText<"Demangle symbols when printing warnings and errors">;
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index 70cb80f0fdb3..e5ff8a1aaa4f 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -10,35 +10,85 @@
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/InstallAPI/FileList.h"
+#include "clang/InstallAPI/InstallAPIDiagnostic.h"
#include "llvm/Support/Program.h"
#include "llvm/TargetParser/Host.h"
+#include "llvm/TextAPI/DylibReader.h"
+#include "llvm/TextAPI/TextAPIWriter.h"
-using namespace clang::driver;
-using namespace clang::driver::options;
+using namespace llvm;
using namespace llvm::opt;
using namespace llvm::MachO;
+namespace drv = clang::driver::options;
+
namespace clang {
namespace installapi {
+/// Create prefix string literals used in InstallAPIOpts.td.
+#define PREFIX(NAME, VALUE) \
+ static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
+ static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
+ NAME##_init, std::size(NAME##_init) - 1);
+#include "InstallAPIOpts.inc"
+#undef PREFIX
+
+static constexpr const llvm::StringLiteral PrefixTable_init[] =
+#define PREFIX_UNION(VALUES) VALUES
+#include "InstallAPIOpts.inc"
+#undef PREFIX_UNION
+ ;
+static constexpr const ArrayRef<StringLiteral>
+ PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
+
+/// Create table mapping all options defined in InstallAPIOpts.td.
+static constexpr OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
+ VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
+ {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
+ PARAM, FLAGS, VISIBILITY, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \
+ VALUES},
+#include "InstallAPIOpts.inc"
+#undef OPTION
+};
+
+namespace {
+
+/// \brief Create OptTable class for parsing actual command line arguments.
+class DriverOptTable : public opt::PrecomputedOptTable {
+public:
+ DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
+};
+
+} // end anonymous namespace.
+
+static llvm::opt::OptTable *createDriverOptTable() {
+ return new DriverOptTable();
+}
+
bool Options::processDriverOptions(InputArgList &Args) {
// Handle inputs.
- llvm::append_range(DriverOpts.FileLists, Args.getAllArgValues(OPT_INPUT));
+ llvm::append_range(DriverOpts.FileLists,
+ Args.getAllArgValues(drv::OPT_INPUT));
// Handle output.
SmallString<PATH_MAX> OutputPath;
- if (auto *Arg = Args.getLastArg(OPT_o)) {
+ if (auto *Arg = Args.getLastArg(drv::OPT_o)) {
OutputPath = Arg->getValue();
if (OutputPath != "-")
FM->makeAbsolutePath(OutputPath);
DriverOpts.OutputPath = std::string(OutputPath);
}
+ if (DriverOpts.OutputPath.empty()) {
+ Diags->Report(diag::err_no_output_file);
+ return false;
+ }
// Do basic error checking first for mixing -target and -arch options.
- auto *ArgArch = Args.getLastArgNoClaim(OPT_arch);
- auto *ArgTarget = Args.getLastArgNoClaim(OPT_target);
+ auto *ArgArch = Args.getLastArgNoClaim(drv::OPT_arch);
+ auto *ArgTarget = Args.getLastArgNoClaim(drv::OPT_target);
auto *ArgTargetVariant =
- Args.getLastArgNoClaim(OPT_darwin_target_variant_triple);
+ Args.getLastArgNoClaim(drv::OPT_darwin_target_variant_triple);
if (ArgArch && (ArgTarget || ArgTargetVariant)) {
Diags->Report(clang::diag::err_drv_argument_not_allowed_with)
<< ArgArch->getAsString(Args)
@@ -46,7 +96,7 @@ bool Options::processDriverOptions(InputArgList &Args) {
return false;
}
- auto *ArgMinTargetOS = Args.getLastArgNoClaim(OPT_mtargetos_EQ);
+ auto *ArgMinTargetOS = Args.getLastArgNoClaim(drv::OPT_mtargetos_EQ);
if ((ArgTarget || ArgTargetVariant) && ArgMinTargetOS) {
Diags->Report(clang::diag::err_drv_cannot_mix_options)
<< ArgTarget->getAsString(Args) << ArgMinTargetOS->getAsString(Args);
@@ -55,7 +105,7 @@ bool Options::processDriverOptions(InputArgList &Args) {
// Capture target triples first.
if (ArgTarget) {
- for (const Arg *A : Args.filtered(OPT_target)) {
+ for (const Arg *A : Args.filtered(drv::OPT_target)) {
A->claim();
llvm::Triple TargetTriple(A->getValue());
Target TAPITarget = Target(TargetTriple);
@@ -69,30 +119,32 @@ bool Options::processDriverOptions(InputArgList &Args) {
}
}
- DriverOpts.Verbose = Args.hasArgNoClaim(OPT_v);
+ DriverOpts.Verbose = Args.hasArgNoClaim(drv::OPT_v);
return true;
}
bool Options::processLinkerOptions(InputArgList &Args) {
- // TODO: add error handling.
-
- // Required arguments.
- if (const Arg *A = Args.getLastArg(options::OPT_install__name))
+ // Handle required arguments.
+ if (const Arg *A = Args.getLastArg(drv::OPT_install__name))
LinkerOpts.InstallName = A->getValue();
+ if (LinkerOpts.InstallName.empty()) {
+ Diags->Report(diag::err_no_install_name);
+ return false;
+ }
// Defaulted or optional arguments.
- if (auto *Arg = Args.getLastArg(OPT_current__version))
+ if (auto *Arg = Args.getLastArg(drv::OPT_current__version))
LinkerOpts.CurrentVersion.parse64(Arg->getValue());
- if (auto *Arg = Args.getLastArg(OPT_compatibility__version))
+ if (auto *Arg = Args.getLastArg(drv::OPT_compatibility__version))
LinkerOpts.CompatVersion.parse64(Arg->getValue());
- LinkerOpts.IsDylib = Args.hasArg(OPT_dynamiclib);
+ LinkerOpts.IsDylib = Args.hasArg(drv::OPT_dynamiclib);
- LinkerOpts.AppExtensionSafe =
- Args.hasFlag(OPT_fapplication_extension, OPT_fno_application_extension,
- /*Default=*/LinkerOpts.AppExtensionSafe);
+ LinkerOpts.AppExtensionSafe = Args.hasFlag(
+ drv::OPT_fapplication_extension, drv::OPT_fno_application_extension,
+ /*Default=*/LinkerOpts.AppExtensionSafe);
if (::getenv("LD_NO_ENCRYPT") != nullptr)
LinkerOpts.AppExtensionSafe = true;
@@ -105,7 +157,7 @@ bool Options::processLinkerOptions(InputArgList &Args) {
bool Options::processFrontendOptions(InputArgList &Args) {
// Do not claim any arguments, as they will be passed along for CC1
// invocations.
- if (auto *A = Args.getLastArgNoClaim(OPT_x)) {
+ if (auto *A = Args.getLastArgNoClaim(drv::OPT_x)) {
FEOpts.LangMode = llvm::StringSwitch<clang::Language>(A->getValue())
.Case("c", clang::Language::C)
.Case("c++", clang::Language::CXX)
@@ -119,8 +171,8 @@ bool Options::processFrontendOptions(InputArgList &Args) {
return false;
}
}
- for (auto *A : Args.filtered(OPT_ObjC, OPT_ObjCXX)) {
- if (A->getOption().matches(OPT_ObjC))
+ for (auto *A : Args.filtered(drv::OPT_ObjC, drv::OPT_ObjCXX)) {
+ if (A->getOption().matches(drv::OPT_ObjC))
FEOpts.LangMode = clang::Language::ObjC;
else
FEOpts.LangMode = clang::Language::ObjCXX;
@@ -129,9 +181,77 @@ bool Options::processFrontendOptions(InputArgList &Args) {
return true;
}
+std::vector<const char *>
+Options::processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args) {
+ std::unique_ptr<llvm::opt::OptTable> Table;
+ Table.reset(createDriverOptTable());
+
+ unsigned MissingArgIndex, MissingArgCount;
+ auto ParsedArgs = Table->ParseArgs(Args.slice(1), MissingArgIndex,
+ MissingArgCount, Visibility());
+
+ // Capture InstallAPI only driver options.
+ DriverOpts.Demangle = ParsedArgs.hasArg(OPT_demangle);
+
+ if (auto *A = ParsedArgs.getLastArg(OPT_filetype)) {
+ DriverOpts.OutFT = TextAPIWriter::parseFileType(A->getValue());
+ if (DriverOpts.OutFT == FileType::Invalid) {
+ Diags->Report(clang::diag::err_drv_invalid_value)
+ << A->getAsString(ParsedArgs) << A->getValue();
+ return {};
+ }
+ }
+
+ if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_mode_EQ)) {
+ DriverOpts.VerifyMode =
+ StringSwitch<VerificationMode>(A->getValue())
+ .Case("ErrorsOnly", VerificationMode::ErrorsOnly)
+ .Case("ErrorsAndWarnings", VerificationMode::ErrorsAndWarnings)
+ .Case("Pedantic", VerificationMode::Pedantic)
+ .Default(VerificationMode::Invalid);
+
+ if (DriverOpts.VerifyMode == VerificationMode::Invalid) {
+ Diags->Report(clang::diag::err_drv_invalid_value)
+ << A->getAsString(ParsedArgs) << A->getValue();
+ return {};
+ }
+ }
+
+ if (const Arg *A = ParsedArgs.getLastArg(OPT_verify_against))
+ DriverOpts.DylibToVerify = A->getValue();
+
+ /// Any unclaimed arguments should be forwarded to the clang driver.
+ std::vector<const char *> ClangDriverArgs(ParsedArgs.size());
+ for (const Arg *A : ParsedArgs) {
+ if (A->isClaimed())
+ continue;
+ llvm::copy(A->getValues(), std::back_inserter(ClangDriverArgs));
+ }
+ return ClangDriverArgs;
+}
+
Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
- InputArgList &ArgList)
+ ArrayRef<const char *> Args, const StringRef ProgName)
: Diags(&Diag), FM(FM) {
+
+ // First process InstallAPI specific options.
+ auto DriverArgs = processAndFilterOutInstallAPIOptions(Args);
+ if (Diags->hasErrorOccurred())
+ return;
+
+ // Set up driver to parse remaining input arguments.
+ clang::driver::Driver Driver(ProgName, llvm::sys::getDefaultTargetTriple(),
+ *Diags, "clang installapi tool");
+ auto TargetAndMode =
+ clang::driver::ToolChain::getTargetAndModeFromProgramName(ProgName);
+ Driver.setTargetAndMode(TargetAndMode);
+ bool HasError = false;
+ llvm::opt::InputArgList ArgList =
+ Driver.ParseArgStrings(DriverArgs, /*UseDriverMode=*/true, HasError);
+ if (HasError)
+ return;
+ Driver.setCheckInputsExist(false);
+
if (!processDriverOptions(ArgList))
return;
@@ -145,7 +265,6 @@ Options::Options(DiagnosticsEngine &Diag, FileManager *FM,
for (const Arg *A : ArgList) {
if (A->isClaimed())
continue;
-
FrontendArgs.emplace_back(A->getSpelling());
llvm::copy(A->getValues(), std::back_inserter(FrontendArgs));
}
@@ -172,16 +291,40 @@ InstallAPIContext Options::createContext() {
for (const std::string &ListPath : DriverOpts.FileLists) {
auto Buffer = FM->getBufferForFile(ListPath);
if (auto Err = Buffer.getError()) {
- Diags->Report(diag::err_cannot_open_file) << ListPath;
+ Diags->Report(diag::err_cannot_open_file) << ListPath << Err.message();
return Ctx;
}
if (auto Err = FileListReader::loadHeaders(std::move(Buffer.get()),
Ctx.InputHeaders)) {
- Diags->Report(diag::err_cannot_open_file) << ListPath;
+ Diags->Report(diag::err_cannot_open_file) << ListPath << std::move(Err);
return Ctx;
}
}
+ // Parse binary dylib and initialize verifier.
+ if (DriverOpts.DylibToVerify.empty()) {
+ Ctx.Verifier = std::make_unique<DylibVerifier>();
+ return Ctx;
+ }
+
+ auto Buffer = FM->getBufferForFile(DriverOpts.DylibToVerify);
+ if (auto Err = Buffer.getError()) {
+ Diags->Report(diag::err_cannot_open_file)
+ << DriverOpts.DylibToVerify << Err.message();
+ return Ctx;
+ }
+
+ DylibReader::ParseOption PO;
+ PO.Undefineds = false;
+ Expected<Records> Slices =
+ DylibReader::readFile((*Buffer)->getMemBufferRef(), PO);
+ if (auto Err = Slices.takeError()) {
+ Diags->Report(diag::err_cannot_open_file) << DriverOpts.DylibToVerify;
+ return Ctx;
+ }
+
+ Ctx.Verifier = std::make_unique<DylibVerifier>(
+ std::move(*Slices), Diags, DriverOpts.VerifyMode, DriverOpts.Demangle);
return Ctx;
}
diff --git a/clang/tools/clang-installapi/Options.h b/clang/tools/clang-installapi/Options.h
index e218d57b3051..2beeafc86bb0 100644
--- a/clang/tools/clang-installapi/Options.h
+++ b/clang/tools/clang-installapi/Options.h
@@ -11,8 +11,10 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/InstallAPI/Context.h"
+#include "clang/InstallAPI/DylibVerifier.h"
#include "clang/InstallAPI/MachO.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -32,12 +34,21 @@ struct DriverOptions {
/// \brief Mappings of target triples & tapi targets to build for.
std::map<llvm::MachO::Target, llvm::Triple> Targets;
+ /// \brief Path to binary dylib for comparing.
+ std::string DylibToVerify;
+
/// \brief Output path.
std::string OutputPath;
/// \brief File encoding to print.
FileType OutFT = FileType::TBD_V5;
+ /// \brief Verification mode for comparing symbols.
+ VerificationMode VerifyMode = VerificationMode::Pedantic;
+
+ /// \brief Print demangled symbols when reporting errors.
+ bool Demangle = false;
+
/// \brief Print verbose output.
bool Verbose = false;
};
@@ -69,6 +80,8 @@ private:
bool processDriverOptions(llvm::opt::InputArgList &Args);
bool processLinkerOptions(llvm::opt::InputArgList &Args);
bool processFrontendOptions(llvm::opt::InputArgList &Args);
+ std::vector<const char *>
+ processAndFilterOutInstallAPIOptions(ArrayRef<const char *> Args);
public:
/// The various options grouped together.
@@ -83,7 +96,7 @@ public:
/// \brief Constructor for options.
Options(clang::DiagnosticsEngine &Diag, FileManager *FM,
- llvm::opt::InputArgList &Args);
+ ArrayRef<const char *> Args, const StringRef ProgName);
/// \brief Get CC1 arguments after extracting out the irrelevant
/// ones.
@@ -95,6 +108,16 @@ private:
std::vector<std::string> FrontendArgs;
};
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
+ VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "InstallAPIOpts.inc"
+ LastOption
+#undef OPTION
+};
+
} // namespace installapi
} // namespace clang
#endif
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 376025e3605b..83b5bbb71f52 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -28,6 +28,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
@@ -41,7 +42,6 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
-#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/TargetSelect.h"
@@ -73,136 +73,8 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
return llvm::sys::fs::getMainExecutable(Argv0, P);
}
-static const char *GetStableCStr(std::set<std::string> &SavedStrings,
- StringRef S) {
- return SavedStrings.insert(std::string(S)).first->c_str();
-}
-
-/// ApplyOneQAOverride - Apply a list of edits to the input argument lists.
-///
-/// The input string is a space separated list of edits to perform,
-/// they are applied in order to the input argument lists. Edits
-/// should be one of the following forms:
-///
-/// '#': Silence information about the changes to the command line arguments.
-///
-/// '^': Add FOO as a new argument at the beginning of the command line.
-///
-/// '+': Add FOO as a new argument at the end of the command line.
-///
-/// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
-/// line.
-///
-/// 'xOPTION': Removes all instances of the literal argument OPTION.
-///
-/// 'XOPTION': Removes all instances of the literal argument OPTION,
-/// and the following argument.
-///
-/// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
-/// at the end of the command line.
-///
-/// \param OS - The stream to write edit information to.
-/// \param Args - The vector of command line arguments.
-/// \param Edit - The override command to perform.
-/// \param SavedStrings - Set to use for storing string representations.
-static void ApplyOneQAOverride(raw_ostream &OS,
- SmallVectorImpl<const char*> &Args,
- StringRef Edit,
- std::set<std::string> &SavedStrings) {
- // This does not need to be efficient.
-
- if (Edit[0] == '^') {
- const char *Str =
- GetStableCStr(SavedStrings, Edit.substr(1));
- OS << "### Adding argument " << Str << " at beginning\n";
- Args.insert(Args.begin() + 1, Str);
- } else if (Edit[0] == '+') {
- const char *Str =
- GetStableCStr(SavedStrings, Edit.substr(1));
- OS << "### Adding argument " << Str << " at end\n";
- Args.push_back(Str);
- } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.ends_with("/") &&
- Edit.slice(2, Edit.size() - 1).contains('/')) {
- StringRef MatchPattern = Edit.substr(2).split('/').first;
- StringRef ReplPattern = Edit.substr(2).split('/').second;
- ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
-
- for (unsigned i = 1, e = Args.size(); i != e; ++i) {
- // Ignore end-of-line response file markers
- if (Args[i] == nullptr)
- continue;
- std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
-
- if (Repl != Args[i]) {
- OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
- Args[i] = GetStableCStr(SavedStrings, Repl);
- }
- }
- } else if (Edit[0] == 'x' || Edit[0] == 'X') {
- auto Option = Edit.substr(1);
- for (unsigned i = 1; i < Args.size();) {
- if (Option == Args[i]) {
- OS << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- if (Edit[0] == 'X') {
- if (i < Args.size()) {
- OS << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- } else
- OS << "### Invalid X edit, end of command line!\n";
- }
- } else
- ++i;
- }
- } else if (Edit[0] == 'O') {
- for (unsigned i = 1; i < Args.size();) {
- const char *A = Args[i];
- // Ignore end-of-line response file markers
- if (A == nullptr)
- continue;
- if (A[0] == '-' && A[1] == 'O' &&
- (A[2] == '\0' ||
- (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
- ('0' <= A[2] && A[2] <= '9'))))) {
- OS << "### Deleting argument " << Args[i] << '\n';
- Args.erase(Args.begin() + i);
- } else
- ++i;
- }
- OS << "### Adding argument " << Edit << " at end\n";
- Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
- } else {
- OS << "### Unrecognized edit: " << Edit << "\n";
- }
-}
-
-/// ApplyQAOverride - Apply a space separated list of edits to the
-/// input argument lists. See ApplyOneQAOverride.
-static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
- const char *OverrideStr,
- std::set<std::string> &SavedStrings) {
- raw_ostream *OS = &llvm::errs();
-
- if (OverrideStr[0] == '#') {
- ++OverrideStr;
- OS = &llvm::nulls();
- }
-
- *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
-
- // This does not need to be efficient.
-
- const char *S = OverrideStr;
- while (*S) {
- const char *End = ::strchr(S, ' ');
- if (!End)
- End = S + strlen(S);
- if (End != S)
- ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
- S = End;
- if (*S != '\0')
- ++S;
- }
+static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
+ return SavedStrings.insert(S).first->getKeyData();
}
extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
@@ -215,7 +87,7 @@ extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
SmallVectorImpl<const char *> &ArgVector,
- std::set<std::string> &SavedStrings) {
+ llvm::StringSet<> &SavedStrings) {
// Put target and mode arguments at the start of argument list so that
// arguments specified in command line could override them. Avoid putting
// them at index 0, as an option like '-cc1' must remain the first.
@@ -419,12 +291,13 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
}
- std::set<std::string> SavedStrings;
+ llvm::StringSet<> SavedStrings;
// Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
// scenes.
if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
// FIXME: Driver shouldn't take extra initial argument.
- ApplyQAOverride(Args, OverrideStr, SavedStrings);
+ driver::applyOverrideOptions(Args, OverrideStr, SavedStrings,
+ &llvm::errs());
}
std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);
diff --git a/clang/unittests/Format/.clang-format b/clang/unittests/Format/.clang-format
index f95602cab0f7..d7331b3c8cf0 100644
--- a/clang/unittests/Format/.clang-format
+++ b/clang/unittests/Format/.clang-format
@@ -1,6 +1 @@
-BasedOnStyle: LLVM
-InsertBraces: true
-InsertNewlineAtEOF: true
-LineEnding: LF
-RemoveBracesLLVM: true
-RemoveParentheses: ReturnStatement
+BasedOnStyle: clang-format
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index fc367a7a5a89..add92d3e1110 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -3802,6 +3802,27 @@ TEST_F(FormatTest, FormatsEnum) {
" // Comment 2\n"
" TWO,\n"
"};");
+ verifyFormat("enum [[clang::enum_extensibility(open)]] E {\n"
+ " // Comment 1\n"
+ " ONE,\n"
+ " // Comment 2\n"
+ " TWO\n"
+ "};");
+ verifyFormat("enum [[nodiscard]] [[clang::enum_extensibility(open)]] E {\n"
+ " // Comment 1\n"
+ " ONE,\n"
+ " // Comment 2\n"
+ " TWO\n"
+ "};");
+ verifyFormat("enum [[clang::enum_extensibility(open)]] E { // foo\n"
+ " A,\n"
+ " // bar\n"
+ " B\n"
+ "};",
+ "enum [[clang::enum_extensibility(open)]] E{// foo\n"
+ " A,\n"
+ " // bar\n"
+ " B};");
// Not enums.
verifyFormat("enum X f() {\n"
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 21c18a03a4fc..b30ea64201bf 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -2645,6 +2645,11 @@ TEST_F(TokenAnnotatorTest, StartOfName) {
EXPECT_TOKEN(Tokens[2], tok::identifier, TT_Unknown);
EXPECT_TOKEN(Tokens[3], tok::identifier, TT_Unknown);
EXPECT_TOKEN(Tokens[4], tok::identifier, TT_StartOfName);
+
+ Tokens = annotate("@interface NSCoder (TestCoder)");
+ ASSERT_EQ(Tokens.size(), 7u) << Tokens;
+ EXPECT_TOKEN(Tokens[0], tok::at, TT_ObjCDecl);
+ EXPECT_TOKEN(Tokens[2], tok::identifier, TT_StartOfName);
}
TEST_F(TokenAnnotatorTest, BraceKind) {
diff --git a/compiler-rt/test/tsan/signal_reset.cpp b/compiler-rt/test/tsan/signal_reset.cpp
index 82758d882382..d76b7e5f3b5f 100644
--- a/compiler-rt/test/tsan/signal_reset.cpp
+++ b/compiler-rt/test/tsan/signal_reset.cpp
@@ -28,12 +28,12 @@ static void* reset(void *p) {
struct sigaction act = {};
for (int i = 0; i < 1000000; i++) {
act.sa_handler = &handler;
- if (sigaction(SIGPROF, &act, 0)) {
+ if (sigaction(SIGALRM, &act, 0)) {
perror("sigaction");
exit(1);
}
act.sa_handler = SIG_IGN;
- if (sigaction(SIGPROF, &act, 0)) {
+ if (sigaction(SIGALRM, &act, 0)) {
perror("sigaction");
exit(1);
}
@@ -44,7 +44,7 @@ static void* reset(void *p) {
int main() {
struct sigaction act = {};
act.sa_handler = SIG_IGN;
- if (sigaction(SIGPROF, &act, 0)) {
+ if (sigaction(SIGALRM, &act, 0)) {
perror("sigaction");
exit(1);
}
@@ -53,7 +53,7 @@ int main() {
t.it_value.tv_sec = 0;
t.it_value.tv_usec = 10;
t.it_interval = t.it_value;
- if (setitimer(ITIMER_PROF, &t, 0)) {
+ if (setitimer(ITIMER_REAL, &t, 0)) {
perror("setitimer");
exit(1);
}
diff --git a/libc/config/baremetal/api.td b/libc/config/baremetal/api.td
index d24c92e9e590..283647260779 100644
--- a/libc/config/baremetal/api.td
+++ b/libc/config/baremetal/api.td
@@ -68,7 +68,7 @@ def StdlibAPI : PublicAPI<"stdlib.h"> {
"size_t",
"__bsearchcompare_t",
"__qsortcompare_t",
- "__qsortrcompare_t",
+ "__atexithandler_t",
];
}
diff --git a/libc/docs/gpu/building.rst b/libc/docs/gpu/building.rst
index dab21e1324d2..6d94134a407d 100644
--- a/libc/docs/gpu/building.rst
+++ b/libc/docs/gpu/building.rst
@@ -220,11 +220,15 @@ targets. This section will briefly describe their purpose.
be used to enable host services for anyone looking to interface with the
:ref:`RPC client<libc_gpu_rpc>`.
+.. _gpu_cmake_options:
+
CMake options
=============
This section briefly lists a few of the CMake variables that specifically
-control the GPU build of the C library.
+control the GPU build of the C library. These options can be passed individually
+to each target using ``-DRUNTIMES_<target>_<variable>=<value>`` when using a
+standard runtime build.
**LLVM_LIBC_FULL_BUILD**:BOOL
This flag controls whether or not the libc build will generate its own
diff --git a/libc/docs/gpu/testing.rst b/libc/docs/gpu/testing.rst
index 9842a6752836..9f17159fb6d5 100644
--- a/libc/docs/gpu/testing.rst
+++ b/libc/docs/gpu/testing.rst
@@ -1,9 +1,9 @@
.. _libc_gpu_testing:
-============================
-Testing the GPU libc library
-============================
+=========================
+Testing the GPU C library
+=========================
.. note::
Running GPU tests with high parallelism is likely to cause spurious failures,
@@ -14,24 +14,134 @@ Testing the GPU libc library
:depth: 4
:local:
-Testing Infrastructure
+Testing infrastructure
======================
-The testing support in LLVM's libc implementation for GPUs is designed to mimic
-the standard unit tests as much as possible. We use the :ref:`libc_gpu_rpc`
-support to provide the necessary utilities like printing from the GPU. Execution
-is performed by emitting a ``_start`` kernel from the GPU
-that is then called by an external loader utility. This is an example of how
-this can be done manually:
+The LLVM C library supports different kinds of :ref:`tests <build_and_test>`
+depending on the build configuration. The GPU target is considered a full build
+and therefore provides all of its own utilities to build and run the generated
+tests. Currently the GPU supports two kinds of tests.
+
+#. **Hermetic tests** - These are unit tests built with a test suite similar to
+ Google's ``gtest`` infrastructure. These use the same infrastructure as unit
+ tests except that the entire environment is self-hosted. This allows us to
+ run them on the GPU using our custom utilities. These are used to test the
+ majority of functional implementations.
+
+#. **Integration tests** - These are lightweight tests that simply call a
+ ``main`` function and checks if it returns non-zero. These are primarily used
+ to test interfaces that are sensitive to threading.
+
+The GPU uses the same testing infrastructure as the other supported ``libc``
+targets. We do this by treating the GPU as a standard hosted environment capable
+of launching a ``main`` function. Effectively, this means building our own
+startup libraries and loader.
+
+Testing utilities
+=================
+
+We provide two utilities to execute arbitrary programs on the GPU. That is the
+``loader`` and the ``start`` object.
+
+Startup object
+--------------
+
+This object mimics the standard object used by existing C library
+implementations. Its job is to perform the necessary setup prior to calling the
+``main`` function. In the GPU case, this means exporting GPU kernels that will
+perform the necessary operations. Here we use ``_begin`` and ``_end`` to handle
+calling global constructors and destructors while ``_start`` begins the standard
+execution. The following code block shows the implementation for AMDGPU
+architectures.
+
+.. code-block:: c++
+
+ extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
+ _begin(int argc, char **argv, char **env) {
+ LIBC_NAMESPACE::atexit(&LIBC_NAMESPACE::call_fini_array_callbacks);
+ LIBC_NAMESPACE::call_init_array_callbacks(argc, argv, env);
+ }
+
+ extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
+ _start(int argc, char **argv, char **envp, int *ret) {
+ __atomic_fetch_or(ret, main(argc, argv, envp), __ATOMIC_RELAXED);
+ }
+
+ extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
+ _end(int retval) {
+ LIBC_NAMESPACE::exit(retval);
+ }
+
+Loader runtime
+--------------
+
+The startup object provides a GPU executable with callable kernels for the
+respective runtime. We can then define a minimal runtime that will launch these
+kernels on the given device. Currently we provide the ``amdhsa-loader`` and
+``nvptx-loader`` targeting the AMD HSA runtime and CUDA driver runtime
+respectively. By default these will launch with a single thread on the GPU.
.. code-block:: sh
- $> clang++ crt1.o test.cpp --target=amdgcn-amd-amdhsa -mcpu=gfx90a -flto
- $> ./amdhsa_loader --threads 1 --blocks 1 a.out
+ $> clang++ crt1.o test.cpp --target=amdgcn-amd-amdhsa -mcpu=native -flto
+ $> amdhsa_loader --threads 1 --blocks 1 ./a.out
Test Passed!
-Unlike the exported ``libcgpu.a``, the testing architecture can only support a
-single architecture at a time. This is either detected automatically, or set
-manually by the user using ``LIBC_GPU_TEST_ARCHITECTURE``. The latter is useful
-in cases where the user does not build LLVM's libc on machine with the GPU to
-use for testing.
+The loader utility will forward any arguments passed after the executable image
+to the program on the GPU as well as any set environment variables. The number
+of threads and blocks to be set can be controlled with ``--threads`` and
+``--blocks``. These also accept additional ``x``, ``y``, ``z`` variants for
+multidimensional grids.
+
+Running tests
+=============
+
+Tests will only be built and run if a GPU target architecture is set and the
+corresponding loader utility was built. These can be overridden with the
+``LIBC_GPU_TEST_ARCHITECTURE`` and ``LIBC_GPU_LOADER_EXECUTABLE`` :ref:`CMake
+options <gpu_cmake_options>`. Once built, they can be run like any other tests.
+The CMake target depends on how the library was built.
+
+#. **Cross build** - If the C library was built using ``LLVM_ENABLE_PROJECTS``
+ or a runtimes cross build, then the standard targets will be present in the
+ base CMake build directory.
+
+ #. All tests - You can run all supported tests with the command:
+
+ .. code-block:: sh
+
+ $> ninja check-libc
+
+ #. Hermetic tests - You can run hermetic with tests the command:
+
+ .. code-block:: sh
+
+ $> ninja libc-hermetic-tests
+
+ #. Integration tests - You can run integration tests by the command:
+
+ .. code-block:: sh
+
+ $> ninja libc-integration-tests
+
+#. **Runtimes build** - If the library was built using ``LLVM_ENABLE_RUNTIMES``
+ then the actual ``libc`` build will be in a separate directory.
+
+ #. All tests - You can run all supported tests with the command:
+
+ .. code-block:: sh
+
+ $> ninja check-libc-amdgcn-amd-amdhsa
+ $> ninja check-libc-nvptx64-nvidia-cuda
+
+ #. Specific tests - You can use the same targets as above by entering the
+ runtimes build directory.
+
+ .. code-block:: sh
+
+ $> ninja -C runtimes/runtimes-amdgcn-amd-amdhsa-bins check-libc
+ $> ninja -C runtimes/runtimes-nvptx64-nvidia-cuda-bins check-libc
+ $> cd runtimes/runtimes-amdgcn-amd-amdhsa-bins && ninja check-libc
+ $> cd runtimes/runtimes-nvptx64-nvidia-cuda-bins && ninja check-libc
+
+Tests can also be built and run manually using the respective loader utility.
diff --git a/libc/docs/gpu/using.rst b/libc/docs/gpu/using.rst
index 11a00cd620d8..1a9446eeb113 100644
--- a/libc/docs/gpu/using.rst
+++ b/libc/docs/gpu/using.rst
@@ -159,17 +159,21 @@ GPUs.
}
We can then compile this for both NVPTX and AMDGPU into LLVM-IR using the
-following commands.
+following commands. This will yield valid LLVM-IR for the given target just like
+if we were using CUDA, OpenCL, or OpenMP.
.. code-block:: sh
$> clang id.c --target=amdgcn-amd-amdhsa -mcpu=native -nogpulib -flto -c
$> clang id.c --target=nvptx64-nvidia-cuda -march=native -nogpulib -flto -c
-We use this support to treat the GPU as a hosted environment by providing a C
-library and startup object just like a standard C library running on the host
-machine. Then, in order to execute these programs, we provide a loader utility
-to launch the executable on the GPU similar to a cross-compiling emulator.
+We can also use this support to treat the GPU as a hosted environment by
+providing a C library and startup object just like a standard C library running
+on the host machine. Then, in order to execute these programs, we provide a
+loader utility to launch the executable on the GPU similar to a cross-compiling
+emulator. This is how we run :ref:`unit tests <libc_gpu_testing>` targeting the
+GPU. This is clearly not the most efficient way to use a GPU, but it provides a
+simple method to test execution on a GPU for debugging or development.
Building for AMDGPU targets
^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 56e1468b4ca1..80547c5c1f3f 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -100,7 +100,7 @@
"`P2396R1 <https://wg21.link/P2396R1>`__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|"
"`P2505R5 <https://wg21.link/P2505R5>`__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0",""
"`P2539R4 <https://wg21.link/P2539R4>`__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|Complete|","18.0","|format|"
-"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|"
+"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","|Complete|","19.0","|ranges|"
"`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
"","","","","","",""
"`P0290R4 <https://wg21.link/P0290R4>`__","LWG", "``apply()`` for ``synchronized_value<T>``","February 2023","","","|concurrency TS|"
diff --git a/libcxx/include/__compare/partial_order.h b/libcxx/include/__compare/partial_order.h
index f3ed4900fbff..1d2fae63e5f2 100644
--- a/libcxx/include/__compare/partial_order.h
+++ b/libcxx/include/__compare/partial_order.h
@@ -28,6 +28,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// [cmp.alg]
namespace __partial_order {
+void partial_order() = delete;
+
struct __fn {
// NOLINTBEGIN(libcpp-robust-against-adl) partial_order should use ADL, but only here
template <class _Tp, class _Up>
diff --git a/libcxx/include/__compare/strong_order.h b/libcxx/include/__compare/strong_order.h
index 3dc819e64251..8c363b563822 100644
--- a/libcxx/include/__compare/strong_order.h
+++ b/libcxx/include/__compare/strong_order.h
@@ -37,6 +37,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// [cmp.alg]
namespace __strong_order {
+void strong_order() = delete;
+
struct __fn {
// NOLINTBEGIN(libcpp-robust-against-adl) strong_order should use ADL, but only here
template <class _Tp, class _Up>
diff --git a/libcxx/include/__compare/weak_order.h b/libcxx/include/__compare/weak_order.h
index b82a708c29a1..1a3e85feb233 100644
--- a/libcxx/include/__compare/weak_order.h
+++ b/libcxx/include/__compare/weak_order.h
@@ -30,6 +30,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// [cmp.alg]
namespace __weak_order {
+void weak_order() = delete;
+
struct __fn {
// NOLINTBEGIN(libcpp-robust-against-adl) weak_order should use ADL, but only here
template <class _Tp, class _Up>
diff --git a/libcxx/include/__format/format_context.h b/libcxx/include/__format/format_context.h
index d131e942aca6..bf603c5c62d9 100644
--- a/libcxx/include/__format/format_context.h
+++ b/libcxx/include/__format/format_context.h
@@ -27,7 +27,7 @@
#include <cstddef>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
-# include <locale>
+# include <__locale>
# include <optional>
#endif
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 3ee53539f4ee..c7810140105a 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -41,7 +41,7 @@
#include <string_view>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
-# include <locale>
+# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index f01d323efff5..1d94cc349c0d 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -39,7 +39,7 @@
#include <cstddef>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
-# include <locale>
+# include <__locale>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__iterator/iter_move.h b/libcxx/include/__iterator/iter_move.h
index 202b94cccc5a..ba8aed3c0ffb 100644
--- a/libcxx/include/__iterator/iter_move.h
+++ b/libcxx/include/__iterator/iter_move.h
@@ -35,7 +35,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
namespace __iter_move {
-void iter_move();
+void iter_move() = delete;
template <class _Tp>
concept __unqualified_iter_move = __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) {
diff --git a/libcxx/include/__ranges/access.h b/libcxx/include/__ranges/access.h
index 263fdd637fd9..218b3928ecdc 100644
--- a/libcxx/include/__ranges/access.h
+++ b/libcxx/include/__ranges/access.h
@@ -45,8 +45,7 @@ concept __member_begin = __can_borrow<_Tp> && __workaround_52970<_Tp> && require
{ _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
};
-void begin(auto&) = delete;
-void begin(const auto&) = delete;
+void begin() = delete;
template <class _Tp>
concept __unqualified_begin =
@@ -109,8 +108,7 @@ concept __member_end = __can_borrow<_Tp> && __workaround_52970<_Tp> && requires(
{ _LIBCPP_AUTO_CAST(__t.end()) } -> sentinel_for<iterator_t<_Tp>>;
};
-void end(auto&) = delete;
-void end(const auto&) = delete;
+void end() = delete;
template <class _Tp>
concept __unqualified_end =
diff --git a/libcxx/include/__ranges/rbegin.h b/libcxx/include/__ranges/rbegin.h
index 7111201ae7d6..947e428f00cd 100644
--- a/libcxx/include/__ranges/rbegin.h
+++ b/libcxx/include/__ranges/rbegin.h
@@ -40,8 +40,7 @@ concept __member_rbegin = __can_borrow<_Tp> && __workaround_52970<_Tp> && requir
{ _LIBCPP_AUTO_CAST(__t.rbegin()) } -> input_or_output_iterator;
};
-void rbegin(auto&) = delete;
-void rbegin(const auto&) = delete;
+void rbegin() = delete;
template <class _Tp>
concept __unqualified_rbegin =
diff --git a/libcxx/include/__ranges/rend.h b/libcxx/include/__ranges/rend.h
index 58d98aafd264..1b6be58fea24 100644
--- a/libcxx/include/__ranges/rend.h
+++ b/libcxx/include/__ranges/rend.h
@@ -42,8 +42,7 @@ concept __member_rend = __can_borrow<_Tp> && __workaround_52970<_Tp> && requires
{ _LIBCPP_AUTO_CAST(__t.rend()) } -> sentinel_for<decltype(ranges::rbegin(__t))>;
};
-void rend(auto&) = delete;
-void rend(const auto&) = delete;
+void rend() = delete;
template <class _Tp>
concept __unqualified_rend =
diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h
index 14e21aae6bf1..59ca2b11ee38 100644
--- a/libcxx/include/__ranges/size.h
+++ b/libcxx/include/__ranges/size.h
@@ -41,8 +41,7 @@ inline constexpr bool disable_sized_range = false;
namespace ranges {
namespace __size {
-void size(auto&) = delete;
-void size(const auto&) = delete;
+void size() = delete;
template <class _Tp>
concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>;
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 0320c1dc4c2f..5bab3f8ad5cf 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -883,6 +883,7 @@ constexpr chrono::year operator ""y(unsigned lo
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER == 20
# include <charconv>
+# include <locale>
#endif
#endif // _LIBCPP_CHRONO
diff --git a/libcxx/include/complex b/libcxx/include/complex
index e996485a38ae..a81f968143c4 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -258,6 +258,7 @@ template<class T> complex<T> tanh (const complex<T>&);
#include <__config>
#include <__fwd/complex.h>
+#include <__fwd/tuple.h>
#include <__tuple/tuple_element.h>
#include <__tuple/tuple_size.h>
#include <__utility/move.h>
@@ -1444,15 +1445,9 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) {
// [complex.tuple], tuple interface
template <class _Tp>
-struct tuple_size;
-
-template <class _Tp>
struct tuple_size<complex<_Tp>> : integral_constant<size_t, 2> {};
template <size_t _Ip, class _Tp>
-struct tuple_element;
-
-template <size_t _Ip, class _Tp>
struct tuple_element<_Ip, complex<_Tp>> {
static_assert(_Ip < 2, "Index value is out of range.");
using type = _Tp;
diff --git a/libcxx/include/format b/libcxx/include/format
index c0485c5a1035..146613464534 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -221,4 +221,8 @@ namespace std {
# pragma GCC system_header
#endif
+#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
+# include <locale>
+#endif
+
#endif // _LIBCPP_FORMAT
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index ea56e3051908..12fae9a88b9d 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -418,24 +418,6 @@ inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&...
std::__lock_first(0, __l0, __l1, __l2, __l3...);
}
-template <class _L0>
-inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0) {
- __l0.unlock();
-}
-
-template <class _L0, class _L1>
-inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1) {
- __l0.unlock();
- __l1.unlock();
-}
-
-template <class _L0, class _L1, class _L2, class... _L3>
-inline _LIBCPP_HIDE_FROM_ABI void __unlock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&... __l3) {
- __l0.unlock();
- __l1.unlock();
- std::__unlock(__l2, __l3...);
-}
-
# endif // _LIBCPP_CXX03_LANG
# if _LIBCPP_STD_VER >= 17
@@ -498,7 +480,7 @@ public:
private:
template <size_t... _Indx>
_LIBCPP_HIDE_FROM_ABI static void __unlock_unpack(__tuple_indices<_Indx...>, _MutexTuple& __mt) {
- std::__unlock(std::get<_Indx>(__mt)...);
+ (std::get<_Indx>(__mt).unlock(), ...);
}
_MutexTuple __t_;
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 678a986e522a..c65b9b9d705e 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -266,9 +266,14 @@ filesystem system_error
filesystem type_traits
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
format locale
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index c3875fa2cfc0..b3d9e327fc7a 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -267,9 +267,14 @@ filesystem system_error
filesystem type_traits
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
format locale
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index e28e0cd44fed..d723409422a3 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -269,9 +269,14 @@ filesystem system_error
filesystem type_traits
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
format locale
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index e28e0cd44fed..d723409422a3 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -269,9 +269,14 @@ filesystem system_error
filesystem type_traits
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
format locale
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index eec71f4fc628..03b4eda8b4d8 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -113,14 +113,19 @@ charconv type_traits
charconv version
chrono array
chrono bit
+chrono cctype
+chrono cerrno
chrono charconv
+chrono clocale
chrono cmath
chrono compare
chrono concepts
chrono cstddef
chrono cstdint
+chrono cstdlib
chrono cstring
chrono ctime
+chrono cwchar
chrono forward_list
chrono limits
chrono locale
@@ -275,9 +280,14 @@ filesystem system_error
filesystem type_traits
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
format locale
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index ccba100af20e..8150f0935900 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -68,15 +68,20 @@ charconv limits
charconv new
charconv version
chrono array
+chrono cctype
+chrono cerrno
+chrono clocale
chrono cmath
chrono compare
chrono cstddef
chrono cstdint
+chrono cstdlib
+chrono cstring
chrono ctime
+chrono cwchar
chrono forward_list
chrono initializer_list
chrono limits
-chrono locale
chrono new
chrono optional
chrono ostream
@@ -85,6 +90,8 @@ chrono sstream
chrono stdexcept
chrono string
chrono string_view
+chrono tuple
+chrono typeinfo
chrono vector
chrono version
cinttypes cstdint
@@ -184,12 +191,16 @@ filesystem string
filesystem string_view
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
-format locale
format new
format optional
format queue
@@ -198,6 +209,7 @@ format stdexcept
format string
format string_view
format tuple
+format typeinfo
format version
forward_list compare
forward_list cstddef
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index ccba100af20e..8150f0935900 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -68,15 +68,20 @@ charconv limits
charconv new
charconv version
chrono array
+chrono cctype
+chrono cerrno
+chrono clocale
chrono cmath
chrono compare
chrono cstddef
chrono cstdint
+chrono cstdlib
+chrono cstring
chrono ctime
+chrono cwchar
chrono forward_list
chrono initializer_list
chrono limits
-chrono locale
chrono new
chrono optional
chrono ostream
@@ -85,6 +90,8 @@ chrono sstream
chrono stdexcept
chrono string
chrono string_view
+chrono tuple
+chrono typeinfo
chrono vector
chrono version
cinttypes cstdint
@@ -184,12 +191,16 @@ filesystem string
filesystem string_view
filesystem version
format array
+format cctype
+format clocale
format cmath
format cstddef
format cstdint
+format cstdlib
+format cstring
+format cwchar
format initializer_list
format limits
-format locale
format new
format optional
format queue
@@ -198,6 +209,7 @@ format stdexcept
format string
format string_view
format tuple
+format typeinfo
format version
forward_list compare
forward_list cstddef
diff --git a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp
index d4bbde75ae88..068202c6e415 100644
--- a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp
+++ b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/generic_category.pass.cpp
@@ -44,19 +44,14 @@ int main(int, char**)
errno = E2BIG; // something that message will never generate
const std::error_category& e_cat1 = std::generic_category();
const std::string msg = e_cat1.message(-1);
- // Exact message format varies by platform. We can't detect
- // some of these (Musl in particular) using the preprocessor,
- // so accept a few sensible messages. Newlib unfortunately
- // responds with an empty message, which we probably want to
- // treat as a failure code otherwise, but we can detect that
- // with the preprocessor.
- LIBCPP_ASSERT(msg.rfind("Error -1 occurred", 0) == 0 // AIX
- || msg.rfind("No error information", 0) == 0 // Musl
- || msg.rfind("Unknown error", 0) == 0 // Glibc
-#if defined(_NEWLIB_VERSION)
- || msg.empty()
+ // Exact message format varies by platform.
+#if defined(_AIX)
+ LIBCPP_ASSERT(msg.rfind("Error -1 occurred", 0) == 0);
+#elif defined(_NEWLIB_VERSION)
+ LIBCPP_ASSERT(msg.empty());
+#else
+ LIBCPP_ASSERT(msg.rfind("Unknown error", 0) == 0);
#endif
- );
assert(errno == E2BIG);
}
diff --git a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp
index eefbddd27a7f..42fdd1cb3b91 100644
--- a/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp
+++ b/libcxx/test/std/diagnostics/syserr/syserr.errcat/syserr.errcat.objects/system_category.pass.cpp
@@ -50,19 +50,14 @@ int main(int, char**) {
errno = E2BIG; // something that message will never generate
const std::error_category& e_cat1 = std::system_category();
const std::string msg = e_cat1.message(-1);
- // Exact message format varies by platform. We can't detect
- // some of these (Musl in particular) using the preprocessor,
- // so accept a few sensible messages. Newlib unfortunately
- // responds with an empty message, which we probably want to
- // treat as a failure code otherwise, but we can detect that
- // with the preprocessor.
- LIBCPP_ASSERT(msg.rfind("Error -1 occurred", 0) == 0 // AIX
- || msg.rfind("No error information", 0) == 0 // Musl
- || msg.rfind("Unknown error", 0) == 0 // Glibc
-#if defined(_NEWLIB_VERSION)
- || msg.empty()
+ // Exact message format varies by platform.
+#if defined(_AIX)
+ LIBCPP_ASSERT(msg.rfind("Error -1 occurred", 0) == 0);
+#elif defined(_NEWLIB_VERSION)
+ LIBCPP_ASSERT(msg.empty());
+#else
+ LIBCPP_ASSERT(msg.rfind("Unknown error", 0) == 0);
#endif
- );
assert(errno == E2BIG);
}
diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
index dd78707f2540..e6507f7e7767 100644
--- a/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.requirements/iterator.cust/iterator.cust.swap/iter_swap.pass.cpp
@@ -47,6 +47,13 @@ static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, HasIterSwap&>);
static_assert( std::is_invocable_v<IterSwapT&&, HasIterSwap&, int&>);
static_assert(!std::is_invocable_v<IterSwapT&&, int&, HasIterSwap&>);
+struct StructWithNotMoreSpecializedIterSwap {
+ friend void iter_swap(auto&, auto&);
+};
+
+static_assert(
+ !std::is_invocable_v<IterSwapT, StructWithNotMoreSpecializedIterSwap&, StructWithNotMoreSpecializedIterSwap&>);
+
struct NodiscardIterSwap {
[[nodiscard]] friend int iter_swap(NodiscardIterSwap&, NodiscardIterSwap&) { return 0; }
};
diff --git a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp
index 0258ebf87243..8637a933008f 100644
--- a/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.numeric/locale.nm.put/facet.num.put.members/put_long_double.pass.cpp
@@ -22,7 +22,6 @@
#include <locale>
#include <ios>
#include <cassert>
-#include <cstdio>
#include <streambuf>
#include <cmath>
#include "test_macros.h"
@@ -8935,12 +8934,11 @@ void test4()
char str[200];
std::locale lc = std::locale::classic();
std::locale lg(lc, new my_numpunct);
-
- std::string inf;
-
- // This should match the underlying C library
- std::sprintf(str, "%f", INFINITY);
- inf = str;
+#ifdef _AIX
+ std::string inf = "INF";
+#else
+ std::string inf = "inf";
+#endif
const my_facet f(1);
{
@@ -10729,27 +10727,24 @@ void test5()
std::locale lc = std::locale::classic();
std::locale lg(lc, new my_numpunct);
const my_facet f(1);
-
- std::string nan;
- std::string NaN;
- std::string pnan_sign;
-
- // The output here depends on the underlying C library, so work out what
- // that does.
- std::sprintf(str, "%f", std::nan(""));
- nan = str;
-
- std::sprintf(str, "%F", std::nan(""));
- NaN = str;
-
- std::sprintf(str, "%+f", std::nan(""));
- if (str[0] == '+') {
- pnan_sign = "+";
- }
-
- std::string nan_padding25 = std::string(25 - nan.length(), '*');
- std::string pnan_padding25 = std::string(25 - nan.length() - pnan_sign.length(), '*');
-
+#if defined(_AIX)
+ std::string nan= "NaNQ";
+ std::string NaN = "NaNQ";
+ std::string nan_padding25 = "*********************";
+ std::string pnan_sign = "+";
+ std::string pnan_padding25 = "********************";
+#else
+ std::string nan= "nan";
+ std::string NaN = "NAN";
+ std::string nan_padding25 = "**********************";
+#if defined(TEST_HAS_GLIBC) || defined(_WIN32)
+ std::string pnan_sign = "+";
+ std::string pnan_padding25 = "*********************";
+#else
+ std::string pnan_sign = "";
+ std::string pnan_padding25 = "**********************";
+#endif
+#endif
{
long double v = std::nan("");
std::ios ios(0);
diff --git a/libcxx/test/std/ranges/range.access/begin.pass.cpp b/libcxx/test/std/ranges/range.access/begin.pass.cpp
index ca25fc297a01..5ca3d59abb14 100644
--- a/libcxx/test/std/ranges/range.access/begin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/begin.pass.cpp
@@ -192,7 +192,7 @@ struct BeginFunction {
};
static_assert( std::is_invocable_v<RangeBeginT, BeginFunction const&>);
static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &&>);
-static_assert(!std::is_invocable_v<RangeBeginT, BeginFunction &>);
+static_assert(std::is_invocable_v<RangeBeginT, BeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction const&>);
static_assert( std::is_invocable_v<RangeCBeginT, BeginFunction &>);
@@ -245,7 +245,7 @@ private:
constexpr bool testBeginFunction() {
BeginFunction a{};
const BeginFunction aa{};
- static_assert(!std::invocable<RangeBeginT, decltype((a))>);
+ assert(std::ranges::begin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cbegin(a) == &a.x);
assert(std::ranges::begin(aa) == &aa.x);
assert(std::ranges::cbegin(aa) == &aa.x);
@@ -266,21 +266,21 @@ constexpr bool testBeginFunction() {
BeginFunctionReturnsEmptyPtr d{};
const BeginFunctionReturnsEmptyPtr dd{};
- static_assert(!std::invocable<RangeBeginT, decltype((d))>);
+ assert(std::ranges::begin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cbegin(d) == &d.x);
assert(std::ranges::begin(dd) == &dd.x);
assert(std::ranges::cbegin(dd) == &dd.x);
BeginFunctionWithDataMember e{};
const BeginFunctionWithDataMember ee{};
- static_assert(!std::invocable<RangeBeginT, decltype((e))>);
+ assert(std::ranges::begin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::begin(ee) == &ee.x);
assert(std::ranges::cbegin(e) == &e.x);
assert(std::ranges::cbegin(ee) == &ee.x);
BeginFunctionWithPrivateBeginMember f{};
const BeginFunctionWithPrivateBeginMember ff{};
- static_assert(!std::invocable<RangeBeginT, decltype((f))>);
+ assert(std::ranges::begin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cbegin(f) == &f.y);
assert(std::ranges::begin(ff) == &ff.y);
assert(std::ranges::cbegin(ff) == &ff.y);
diff --git a/libcxx/test/std/ranges/range.access/end.pass.cpp b/libcxx/test/std/ranges/range.access/end.pass.cpp
index 21d97354ef08..3e465b357e98 100644
--- a/libcxx/test/std/ranges/range.access/end.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/end.pass.cpp
@@ -193,7 +193,7 @@ static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
static_assert( std::is_invocable_v<RangeEndT, EndFunction const&>);
static_assert(!std::is_invocable_v<RangeEndT, EndFunction &&>);
-static_assert(!std::is_invocable_v<RangeEndT, EndFunction &>);
+static_assert(std::is_invocable_v<RangeEndT, EndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
static_assert( std::is_invocable_v<RangeCEndT, EndFunction const&>);
static_assert( std::is_invocable_v<RangeCEndT, EndFunction &>);
@@ -271,7 +271,7 @@ constexpr bool testEndFunction() {
assert(std::ranges::end(a) == &a.x);
assert(std::ranges::cend(a) == &a.x);
EndFunction aa{};
- static_assert(!std::is_invocable_v<RangeEndT, decltype((aa))>);
+ assert(std::ranges::end(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cend(aa) == &aa.x);
EndFunctionByValue b;
@@ -286,28 +286,28 @@ constexpr bool testEndFunction() {
assert(std::ranges::end(d) == &d.x);
assert(std::ranges::cend(d) == &d.x);
EndFunctionReturnsEmptyPtr dd{};
- static_assert(!std::is_invocable_v<RangeEndT, decltype((dd))>);
+ assert(std::ranges::end(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cend(dd) == &dd.x);
const EndFunctionWithDataMember e{};
assert(std::ranges::end(e) == &e.x);
assert(std::ranges::cend(e) == &e.x);
EndFunctionWithDataMember ee{};
- static_assert(!std::is_invocable_v<RangeEndT, decltype((ee))>);
+ assert(std::ranges::end(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cend(ee) == &ee.x);
const EndFunctionWithPrivateEndMember f{};
assert(std::ranges::end(f) == &f.y);
assert(std::ranges::cend(f) == &f.y);
EndFunctionWithPrivateEndMember ff{};
- static_assert(!std::is_invocable_v<RangeEndT, decltype((ff))>);
+ assert(std::ranges::end(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cend(ff) == &ff.y);
const BeginMemberEndFunction g{};
assert(std::ranges::end(g) == &g.x);
assert(std::ranges::cend(g) == &g.x);
BeginMemberEndFunction gg{};
- static_assert(!std::is_invocable_v<RangeEndT, decltype((gg))>);
+ assert(std::ranges::end(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::cend(gg) == &gg.x);
return true;
diff --git a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
index e1a564c94ed9..3997f38efd02 100644
--- a/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rbegin.pass.cpp
@@ -187,7 +187,8 @@ struct RBeginFunction {
};
static_assert( std::is_invocable_v<RangeRBeginT, RBeginFunction const&>);
static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &&>);
-static_assert(!std::is_invocable_v<RangeRBeginT, RBeginFunction &>);
+static_assert(
+ std::is_invocable_v<RangeRBeginT, RBeginFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction const&>);
static_assert( std::is_invocable_v<RangeCRBeginT, RBeginFunction &>);
@@ -246,7 +247,7 @@ private:
constexpr bool testRBeginFunction() {
RBeginFunction a{};
const RBeginFunction aa{};
- static_assert(!std::invocable<RangeRBeginT, decltype((a))>);
+ assert(std::ranges::rbegin(a) == &a.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crbegin(a) == &a.x);
assert(std::ranges::rbegin(aa) == &aa.x);
assert(std::ranges::crbegin(aa) == &aa.x);
@@ -267,21 +268,21 @@ constexpr bool testRBeginFunction() {
RBeginFunctionReturnsEmptyPtr d{};
const RBeginFunctionReturnsEmptyPtr dd{};
- static_assert(!std::invocable<RangeRBeginT, decltype((d))>);
+ assert(std::ranges::rbegin(d) == &d.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crbegin(d) == &d.x);
assert(std::ranges::rbegin(dd) == &dd.x);
assert(std::ranges::crbegin(dd) == &dd.x);
RBeginFunctionWithDataMember e{};
const RBeginFunctionWithDataMember ee{};
- static_assert(!std::invocable<RangeRBeginT, decltype((e))>);
+ assert(std::ranges::rbegin(e) == &e.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::rbegin(ee) == &ee.x);
assert(std::ranges::crbegin(e) == &e.x);
assert(std::ranges::crbegin(ee) == &ee.x);
RBeginFunctionWithPrivateBeginMember f{};
const RBeginFunctionWithPrivateBeginMember ff{};
- static_assert(!std::invocable<RangeRBeginT, decltype((f))>);
+ assert(std::ranges::rbegin(f) == &f.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crbegin(f) == &f.y);
assert(std::ranges::rbegin(ff) == &ff.y);
assert(std::ranges::crbegin(ff) == &ff.y);
diff --git a/libcxx/test/std/ranges/range.access/rend.pass.cpp b/libcxx/test/std/ranges/range.access/rend.pass.cpp
index 5ba244b6b18c..f5f59edf1939 100644
--- a/libcxx/test/std/ranges/range.access/rend.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/rend.pass.cpp
@@ -196,7 +196,7 @@ static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
static_assert( std::is_invocable_v<RangeREndT, REndFunction const&>);
static_assert(!std::is_invocable_v<RangeREndT, REndFunction &&>);
-static_assert(!std::is_invocable_v<RangeREndT, REndFunction &>);
+static_assert(std::is_invocable_v<RangeREndT, REndFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
static_assert( std::is_invocable_v<RangeCREndT, REndFunction const&>);
static_assert( std::is_invocable_v<RangeCREndT, REndFunction &>);
@@ -272,7 +272,7 @@ constexpr bool testREndFunction() {
assert(std::ranges::rend(a) == &a.x);
assert(std::ranges::crend(a) == &a.x);
REndFunction aa{};
- static_assert(!std::is_invocable_v<RangeREndT, decltype((aa))>);
+ assert(std::ranges::rend(aa) == &aa.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crend(aa) == &aa.x);
REndFunctionByValue b;
@@ -287,28 +287,28 @@ constexpr bool testREndFunction() {
assert(std::ranges::rend(d) == &d.x);
assert(std::ranges::crend(d) == &d.x);
REndFunctionReturnsEmptyPtr dd{};
- static_assert(!std::is_invocable_v<RangeREndT, decltype((dd))>);
+ assert(std::ranges::rend(dd) == &dd.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crend(dd) == &dd.x);
const REndFunctionWithDataMember e{};
assert(std::ranges::rend(e) == &e.x);
assert(std::ranges::crend(e) == &e.x);
REndFunctionWithDataMember ee{};
- static_assert(!std::is_invocable_v<RangeREndT, decltype((ee))>);
+ assert(std::ranges::rend(ee) == &ee.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crend(ee) == &ee.x);
const REndFunctionWithPrivateEndMember f{};
assert(std::ranges::rend(f) == &f.y);
assert(std::ranges::crend(f) == &f.y);
REndFunctionWithPrivateEndMember ff{};
- static_assert(!std::is_invocable_v<RangeREndT, decltype((ff))>);
+ assert(std::ranges::rend(ff) == &ff.y); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crend(ff) == &ff.y);
const RBeginMemberEndFunction g{};
assert(std::ranges::rend(g) == &g.x);
assert(std::ranges::crend(g) == &g.x);
RBeginMemberEndFunction gg{};
- static_assert(!std::is_invocable_v<RangeREndT, decltype((gg))>);
+ assert(std::ranges::rend(gg) == &gg.x); // Ill-formed before P2602R2 Poison Pills are Too Toxic
assert(std::ranges::crend(gg) == &gg.x);
return true;
diff --git a/libcxx/test/std/ranges/range.access/size.pass.cpp b/libcxx/test/std/ranges/range.access/size.pass.cpp
index fd7d0a8b9975..ee44aa815ba9 100644
--- a/libcxx/test/std/ranges/range.access/size.pass.cpp
+++ b/libcxx/test/std/ranges/range.access/size.pass.cpp
@@ -219,7 +219,8 @@ inline constexpr bool std::ranges::disable_sized_range<const ImproperlyDisabledF
static_assert( std::is_invocable_v<RangeSizeT, ImproperlyDisabledMember&>);
static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledMember&>);
-static_assert(!std::is_invocable_v<RangeSizeT, ImproperlyDisabledFunction&>);
+static_assert(std::is_invocable_v<RangeSizeT,
+ ImproperlyDisabledFunction&>); // Ill-formed before P2602R2 Poison Pills are Too Toxic
static_assert( std::is_invocable_v<RangeSizeT, const ImproperlyDisabledFunction&>);
// No begin end.
diff --git a/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp b/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp
new file mode 100644
index 000000000000..1b3da814d080
--- /dev/null
+++ b/libcxx/test/std/ranges/robust_against_poison_pills.compile.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// <compare>, <iterator>, <ranges>
+
+// ADL should be performed. Ordinary unqualified lookup should not be performed.
+
+namespace ns {
+struct StructWithGlobalFunctions {};
+} // namespace ns
+
+struct ConvertibleToCmpType;
+ConvertibleToCmpType strong_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&);
+ConvertibleToCmpType weak_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&);
+ConvertibleToCmpType partial_order(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&);
+
+int&& iter_move(const ns::StructWithGlobalFunctions&);
+void iter_swap(const ns::StructWithGlobalFunctions&, const ns::StructWithGlobalFunctions&);
+
+int* begin(const ns::StructWithGlobalFunctions&);
+int* end(const ns::StructWithGlobalFunctions&);
+int* rbegin(const ns::StructWithGlobalFunctions&);
+int* rend(const ns::StructWithGlobalFunctions&);
+unsigned int size(const ns::StructWithGlobalFunctions&);
+
+#include <compare>
+#include <ranges>
+#include <type_traits>
+
+struct ConvertibleToCmpType {
+ operator std::strong_ordering() const;
+ operator std::weak_ordering() const;
+ operator std::partial_ordering() const;
+};
+
+struct StructWithHiddenFriends {
+ friend ConvertibleToCmpType strong_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&);
+ friend ConvertibleToCmpType weak_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&);
+ friend ConvertibleToCmpType partial_order(const StructWithHiddenFriends&, const StructWithHiddenFriends&);
+
+ friend int&& iter_move(const StructWithHiddenFriends&);
+ friend void iter_swap(const StructWithHiddenFriends&, const StructWithHiddenFriends&);
+
+ friend int* begin(const StructWithHiddenFriends&);
+ friend int* end(const StructWithHiddenFriends&);
+ friend int* rbegin(const StructWithHiddenFriends&);
+ friend int* rend(const StructWithHiddenFriends&);
+ friend unsigned int size(const StructWithHiddenFriends&);
+};
+
+// [cmp.alg] ADL should be performed.
+static_assert(std::is_invocable_v<decltype(std::strong_order), StructWithHiddenFriends&, StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::weak_order), StructWithHiddenFriends&, StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::partial_order), StructWithHiddenFriends&, StructWithHiddenFriends&>);
+
+// [cmp.alg] Ordinary unqualified lookup should not be performed.
+static_assert(
+ !std::is_invocable_v<decltype(std::strong_order), ns::StructWithGlobalFunctions&, ns::StructWithGlobalFunctions&>);
+static_assert(
+ !std::is_invocable_v<decltype(std::weak_order), ns::StructWithGlobalFunctions&, ns::StructWithGlobalFunctions&>);
+static_assert(
+ !std::is_invocable_v<decltype(std::partial_order), ns::StructWithGlobalFunctions&, ns::StructWithGlobalFunctions&>);
+
+// [iterator.cust] ADL should be performed.
+static_assert(std::is_invocable_v<decltype(std::ranges::iter_move), StructWithHiddenFriends&>);
+static_assert(
+ std::is_invocable_v<decltype(std::ranges::iter_swap), StructWithHiddenFriends&, StructWithHiddenFriends&>);
+
+// [iterator.cust] Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<decltype(std::ranges::iter_move), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::iter_swap),
+ ns::StructWithGlobalFunctions&,
+ ns::StructWithGlobalFunctions&>);
+
+// [range.access] ADL should be performed.
+static_assert(std::is_invocable_v<decltype(std::ranges::begin), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::cbegin), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::end), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::cend), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::rbegin), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::crbegin), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::rend), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::crend), StructWithHiddenFriends&>);
+static_assert(std::is_invocable_v<decltype(std::ranges::size), StructWithHiddenFriends&>);
+
+// [range.access] Ordinary unqualified lookup should not be performed.
+static_assert(!std::is_invocable_v<decltype(std::ranges::begin), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::cbegin), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::end), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::cend), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::rbegin), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::crbegin), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::rend), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::crend), ns::StructWithGlobalFunctions&>);
+static_assert(!std::is_invocable_v<decltype(std::ranges::size), ns::StructWithGlobalFunctions&>);
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index b183cb423111..a88da986bb38 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -23,7 +23,6 @@
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FormatVariadic.h"
#include <regex>
@@ -161,7 +160,17 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
}
}
- // Second, also lastly, try `expr` as a source expression to evaluate.
+ // Second, try `expr` as a persistent variable.
+ if (expr.starts_with("$"))
+ if (auto *state = target.GetPersistentExpressionStateForLanguage(language))
+ if (auto var_sp = state->GetVariable(expr))
+ if (auto valobj_sp = var_sp->GetValueObject()) {
+ valobj_sp->Dump(result.GetOutputStream(), dump_options);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return;
+ }
+
+ // Third, and lastly, try `expr` as a source expression to evaluate.
{
auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
ValueObjectSP valobj_sp;
diff --git a/lldb/source/Host/common/Alarm.cpp b/lldb/source/Host/common/Alarm.cpp
index 80c544773d76..245cdc7ae5c2 100644
--- a/lldb/source/Host/common/Alarm.cpp
+++ b/lldb/source/Host/common/Alarm.cpp
@@ -34,7 +34,7 @@ Alarm::Handle Alarm::Create(std::function<void()> callback) {
Handle handle = INVALID_HANDLE;
{
- std::lock_guard alarm_guard(m_alarm_mutex);
+ std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex);
// Create a new unique entry and remember its handle.
m_entries.emplace_back(callback, expiration);
@@ -59,7 +59,7 @@ bool Alarm::Restart(Handle handle) {
const TimePoint expiration = GetNextExpiration();
{
- std::lock_guard alarm_guard(m_alarm_mutex);
+ std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex);
// Find the entry corresponding to the given handle.
const auto it =
@@ -86,7 +86,7 @@ bool Alarm::Cancel(Handle handle) {
return false;
{
- std::lock_guard alarm_guard(m_alarm_mutex);
+ std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex);
const auto it =
std::find_if(m_entries.begin(), m_entries.end(),
@@ -126,7 +126,7 @@ void Alarm::StartAlarmThread() {
void Alarm::StopAlarmThread() {
if (m_alarm_thread.IsJoinable()) {
{
- std::lock_guard alarm_guard(m_alarm_mutex);
+ std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex);
m_exit = true;
}
m_alarm_cv.notify_one();
@@ -154,7 +154,7 @@ lldb::thread_result_t Alarm::AlarmThread() {
//
// Below we only deal with the timeout expiring and fall through for dealing
// with the rest.
- std::unique_lock alarm_lock(m_alarm_mutex);
+ std::unique_lock<std::mutex> alarm_lock(m_alarm_mutex);
if (next_alarm) {
if (!m_alarm_cv.wait_until(alarm_lock, *next_alarm, predicate)) {
// The timeout for the next alarm expired.
diff --git a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py
index 040632096c70..c650b1e3533e 100644
--- a/lldb/test/API/commands/dwim-print/TestDWIMPrint.py
+++ b/lldb/test/API/commands/dwim-print/TestDWIMPrint.py
@@ -146,3 +146,15 @@ class TestCase(TestBase):
self, "// break here", lldb.SBFileSpec("main.c")
)
self.expect("dwim-print (void)15", matching=False, patterns=["(?i)error"])
+
+ def test_preserves_persistent_variables(self):
+ """Test dwim-print does not delete persistent variables."""
+ self.build()
+ lldbutil.run_to_source_breakpoint(
+ self, "// break here", lldb.SBFileSpec("main.c")
+ )
+ self.expect("dwim-print int $i = 15")
+ # Run the same expression twice and verify success. This ensures the
+ # first command does not delete the persistent variable.
+ for _ in range(2):
+ self.expect("dwim-print $i", startstr="(int) 15")
diff --git a/lldb/unittests/Host/AlarmTest.cpp b/lldb/unittests/Host/AlarmTest.cpp
index e5895574376e..9f6ad189dee9 100644
--- a/lldb/unittests/Host/AlarmTest.cpp
+++ b/lldb/unittests/Host/AlarmTest.cpp
@@ -46,7 +46,7 @@ TEST(AlarmTest, Create) {
ALARM_TIMEOUT);
alarm.Create([&callbacks_actual, &m, i]() {
- std::lock_guard guard(m);
+ std::lock_guard<std::mutex> guard(m);
callbacks_actual[i] = std::chrono::system_clock::now();
});
@@ -75,7 +75,7 @@ TEST(AlarmTest, Exit) {
callbacks.emplace_back(false);
handles.push_back(alarm.Create([&callbacks, &m, i]() {
- std::lock_guard guard(m);
+ std::lock_guard<std::mutex> guard(m);
callbacks[i] = true;
}));
}
@@ -101,7 +101,7 @@ TEST(AlarmTest, Cancel) {
callbacks.emplace_back(false);
handles.push_back(alarm.Create([&callbacks, &m, i]() {
- std::lock_guard guard(m);
+ std::lock_guard<std::mutex> guard(m);
callbacks[i] = true;
}));
}
@@ -137,7 +137,7 @@ TEST(AlarmTest, Restart) {
ALARM_TIMEOUT);
handles.push_back(alarm.Create([&callbacks_actual, &m, i]() {
- std::lock_guard guard(m);
+ std::lock_guard<std::mutex> guard(m);
callbacks_actual[i] = std::chrono::system_clock::now();
}));
diff --git a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
index f237dd63ab1c..4379ffac9d74 100644
--- a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
+++ b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp
@@ -102,7 +102,7 @@ protected:
EXPECT_EQ(line, entry.line);
EXPECT_EQ(address, entry.range.GetBaseAddress());
- EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.file));
+ EXPECT_TRUE(FileSpecMatchesAsBaseOrFull(spec, entry.GetFile()));
}
bool ContainsCompileUnit(const SymbolContextList &sc_list,
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 5610880da710..d84d9d7cca68 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -1637,8 +1637,14 @@ function(add_unittest test_suite test_name)
# The runtime benefits of LTO don't outweight the compile time costs for tests.
if(LLVM_ENABLE_LTO)
if((UNIX OR MINGW) AND LINKER_IS_LLD)
- set_property(TARGET ${test_name} APPEND_STRING PROPERTY
- LINK_FLAGS " -Wl,--lto-O0")
+ if(LLVM_ENABLE_FATLTO)
+ # When using FatLTO, just use relocatable linking.
+ set_property(TARGET ${test_name} APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,--no-fat-lto-objects")
+ else()
+ set_property(TARGET ${test_name} APPEND_STRING PROPERTY
+ LINK_FLAGS " -Wl,--lto-O0")
+ endif()
elseif(LINKER_IS_LLD_LINK)
set_property(TARGET ${test_name} APPEND_STRING PROPERTY
LINK_FLAGS " /opt:lldlto=0")
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake
index 745a8354f118..92fa9839db65 100644
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -32,6 +32,8 @@ endif()
set(LLVM_ENABLE_LTO OFF CACHE STRING "Build LLVM with LTO. May be specified as Thin or Full to use a particular kind of LTO")
string(TOUPPER "${LLVM_ENABLE_LTO}" uppercase_LLVM_ENABLE_LTO)
+option(LLVM_ENABLE_FATLTO "Build LLVM with -ffat-lto-objects." OFF)
+
# Ninja Job Pool support
# The following only works with the Ninja generator in CMake >= 3.0.
set(LLVM_PARALLEL_COMPILE_JOBS "" CACHE STRING
@@ -1280,6 +1282,13 @@ elseif(LLVM_ENABLE_LTO)
endif()
endif()
+if(LLVM_ENABLE_FATLTO AND (FUCHSIA OR UNIX))
+ append("-ffat-lto-objects" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ if(NOT LINKER_IS_LLD_LINK)
+ append("-ffat-lto-objects" CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS)
+ endif()
+endif()
+
# Set an AIX default for LLVM_EXPORT_SYMBOLS_FOR_PLUGINS based on whether we are
# doing dynamic linking (see below).
set(LLVM_EXPORT_SYMBOLS_FOR_PLUGINS_AIX_default OFF)
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 00536c71c3e2..5c72f06f96ed 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -21,7 +21,8 @@ def int_dx_create_handle : ClangBuiltin<"__builtin_hlsl_create_handle">,
Intrinsic<[ llvm_ptr_ty ], [llvm_i8_ty], [IntrWillReturn]>;
def int_dx_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
-
+def int_dx_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;
+def int_dx_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;
def int_dx_dot :
Intrinsic<[LLVMVectorElementType<0>],
[llvm_anyvector_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>],
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 6822cfdb4957..8817a2585646 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -626,6 +626,52 @@ public:
void invokePipelineEarlySimplificationEPCallbacks(ModulePassManager &MPM,
OptimizationLevel Level);
+ static bool checkParametrizedPassName(StringRef Name, StringRef PassName) {
+ if (!Name.consume_front(PassName))
+ return false;
+ // normal pass name w/o parameters == default parameters
+ if (Name.empty())
+ return true;
+ return Name.starts_with("<") && Name.ends_with(">");
+ }
+
+ /// This performs customized parsing of pass name with parameters.
+ ///
+ /// We do not need parametrization of passes in textual pipeline very often,
+ /// yet on a rare occasion ability to specify parameters right there can be
+ /// useful.
+ ///
+ /// \p Name - parameterized specification of a pass from a textual pipeline
+ /// is a string in a form of :
+ /// PassName '<' parameter-list '>'
+ ///
+ /// Parameter list is being parsed by the parser callable argument, \p Parser,
+ /// It takes a string-ref of parameters and returns either StringError or a
+ /// parameter list in a form of a custom parameters type, all wrapped into
+ /// Expected<> template class.
+ ///
+ template <typename ParametersParseCallableT>
+ static auto parsePassParameters(ParametersParseCallableT &&Parser,
+ StringRef Name, StringRef PassName)
+ -> decltype(Parser(StringRef{})) {
+ using ParametersT = typename decltype(Parser(StringRef{}))::value_type;
+
+ StringRef Params = Name;
+ if (!Params.consume_front(PassName)) {
+ llvm_unreachable(
+ "unable to strip pass name from parametrized pass specification");
+ }
+ if (!Params.empty() &&
+ (!Params.consume_front("<") || !Params.consume_back(">"))) {
+ llvm_unreachable("invalid format for parametrized pass name");
+ }
+
+ Expected<ParametersT> Result = Parser(Params);
+ assert((Result || Result.template errorIsA<StringError>()) &&
+ "Pass parameter parser can only return StringErrors.");
+ return Result;
+ }
+
private:
// O1 pass pipeline
FunctionPassManager
diff --git a/llvm/include/llvm/TextAPI/Record.h b/llvm/include/llvm/TextAPI/Record.h
index 98639b064eaa..ef152ce43387 100644
--- a/llvm/include/llvm/TextAPI/Record.h
+++ b/llvm/include/llvm/TextAPI/Record.h
@@ -51,7 +51,8 @@ class Record {
public:
Record() = default;
Record(StringRef Name, RecordLinkage Linkage, SymbolFlags Flags)
- : Name(Name), Linkage(Linkage), Flags(mergeFlags(Flags, Linkage)) {}
+ : Name(Name), Linkage(Linkage), Flags(mergeFlags(Flags, Linkage)),
+ Verified(false) {}
bool isWeakDefined() const {
return (Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined;
@@ -79,6 +80,9 @@ public:
bool isExported() const { return Linkage >= RecordLinkage::Rexported; }
bool isRexported() const { return Linkage == RecordLinkage::Rexported; }
+ bool isVerified() const { return Verified; }
+ void setVerify(bool V = true) { Verified = V; }
+
StringRef getName() const { return Name; }
SymbolFlags getFlags() const { return Flags; }
@@ -89,6 +93,7 @@ protected:
StringRef Name;
RecordLinkage Linkage;
SymbolFlags Flags;
+ bool Verified;
friend class RecordsSlice;
};
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 4d1eb10d2d41..0204730f750a 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -503,15 +503,6 @@ static std::optional<int> parseDevirtPassName(StringRef Name) {
return Count;
}
-static bool checkParametrizedPassName(StringRef Name, StringRef PassName) {
- if (!Name.consume_front(PassName))
- return false;
- // normal pass name w/o parameters == default parameters
- if (Name.empty())
- return true;
- return Name.starts_with("<") && Name.ends_with(">");
-}
-
static std::optional<OptimizationLevel> parseOptLevel(StringRef S) {
return StringSwitch<std::optional<OptimizationLevel>>(S)
.Case("O0", OptimizationLevel::O0)
@@ -525,42 +516,6 @@ static std::optional<OptimizationLevel> parseOptLevel(StringRef S) {
namespace {
-/// This performs customized parsing of pass name with parameters.
-///
-/// We do not need parametrization of passes in textual pipeline very often,
-/// yet on a rare occasion ability to specify parameters right there can be
-/// useful.
-///
-/// \p Name - parameterized specification of a pass from a textual pipeline
-/// is a string in a form of :
-/// PassName '<' parameter-list '>'
-///
-/// Parameter list is being parsed by the parser callable argument, \p Parser,
-/// It takes a string-ref of parameters and returns either StringError or a
-/// parameter list in a form of a custom parameters type, all wrapped into
-/// Expected<> template class.
-///
-template <typename ParametersParseCallableT>
-auto parsePassParameters(ParametersParseCallableT &&Parser, StringRef Name,
- StringRef PassName) -> decltype(Parser(StringRef{})) {
- using ParametersT = typename decltype(Parser(StringRef{}))::value_type;
-
- StringRef Params = Name;
- if (!Params.consume_front(PassName)) {
- assert(false &&
- "unable to strip pass name from parametrized pass specification");
- }
- if (!Params.empty() &&
- (!Params.consume_front("<") || !Params.consume_back(">"))) {
- assert(false && "invalid format for parametrized pass name");
- }
-
- Expected<ParametersT> Result = Parser(Params);
- assert((Result || Result.template errorIsA<StringError>()) &&
- "Pass parameter parser can only return StringErrors.");
- return Result;
-}
-
/// Parser of parameters for HardwareLoops pass.
Expected<HardwareLoopOptions> parseHardwareLoopOptions(StringRef Params) {
HardwareLoopOptions HardwareLoopOpts;
@@ -1196,7 +1151,7 @@ static bool isModulePassName(StringRef Name, CallbacksT &Callbacks) {
if (Name == NAME) \
return true;
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
- if (checkParametrizedPassName(Name, NAME)) \
+ if (PassBuilder::checkParametrizedPassName(Name, NAME)) \
return true;
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
@@ -1225,7 +1180,7 @@ static bool isCGSCCPassName(StringRef Name, CallbacksT &Callbacks) {
if (Name == NAME) \
return true;
#define CGSCC_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
- if (checkParametrizedPassName(Name, NAME)) \
+ if (PassBuilder::checkParametrizedPassName(Name, NAME)) \
return true;
#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
@@ -1252,7 +1207,7 @@ static bool isFunctionPassName(StringRef Name, CallbacksT &Callbacks) {
if (Name == NAME) \
return true;
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
- if (checkParametrizedPassName(Name, NAME)) \
+ if (PassBuilder::checkParametrizedPassName(Name, NAME)) \
return true;
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
@@ -1293,7 +1248,7 @@ static bool isLoopNestPassName(StringRef Name, CallbacksT &Callbacks,
if (parseRepeatPassName(Name))
return true;
- if (checkParametrizedPassName(Name, "lnicm")) {
+ if (PassBuilder::checkParametrizedPassName(Name, "lnicm")) {
UseMemorySSA = true;
return true;
}
@@ -1315,7 +1270,7 @@ static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks,
if (parseRepeatPassName(Name))
return true;
- if (checkParametrizedPassName(Name, "licm")) {
+ if (PassBuilder::checkParametrizedPassName(Name, "licm")) {
UseMemorySSA = true;
return true;
}
@@ -1324,7 +1279,7 @@ static bool isLoopPassName(StringRef Name, CallbacksT &Callbacks,
if (Name == NAME) \
return true;
#define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
- if (checkParametrizedPassName(Name, NAME)) \
+ if (PassBuilder::checkParametrizedPassName(Name, NAME)) \
return true;
#define LOOP_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td
index b0e587d2e7ea..216fa5b10c8f 100644
--- a/llvm/lib/Target/DirectX/DXIL.td
+++ b/llvm/lib/Target/DirectX/DXIL.td
@@ -274,8 +274,18 @@ def Round : DXILOpMapping<26, unary, int_round,
"Returns the input rounded to the nearest integer"
"within a floating-point type.",
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
+def FMax : DXILOpMapping<35, binary, int_maxnum,
+ "Float maximum. FMax(a,b) = a > b ? a : b">;
+def FMin : DXILOpMapping<36, binary, int_minnum,
+ "Float minimum. FMin(a,b) = a < b ? a : b">;
+def SMax : DXILOpMapping<37, binary, int_smax,
+ "Signed integer maximum. SMax(a,b) = a > b ? a : b">;
+def SMin : DXILOpMapping<38, binary, int_smin,
+ "Signed integer minimum. SMin(a,b) = a < b ? a : b">;
def UMax : DXILOpMapping<39, binary, int_umax,
"Unsigned integer maximum. UMax(a,b) = a > b ? a : b">;
+def UMin : DXILOpMapping<40, binary, int_umin,
+ "Unsigned integer minimum. UMin(a,b) = a < b ? a : b">;
def FMad : DXILOpMapping<46, tertiary, int_fmuladd,
"Floating point arithmetic multiply/add operation. fmad(m,a,b) = m * a + b.">;
def IMad : DXILOpMapping<48, tertiary, int_dx_imad,
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 0461f0490017..bc38c10a1fce 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -35,6 +35,8 @@ static bool isIntrinsicExpansion(Function &F) {
switch (F.getIntrinsicID()) {
case Intrinsic::exp:
case Intrinsic::dx_any:
+ case Intrinsic::dx_clamp:
+ case Intrinsic::dx_uclamp:
case Intrinsic::dx_lerp:
case Intrinsic::dx_rcp:
return true;
@@ -132,12 +134,59 @@ static bool expandRcpIntrinsic(CallInst *Orig) {
return true;
}
+static Intrinsic::ID getMaxForClamp(Type *ElemTy,
+ Intrinsic::ID ClampIntrinsic) {
+ if (ClampIntrinsic == Intrinsic::dx_uclamp)
+ return Intrinsic::umax;
+ assert(ClampIntrinsic == Intrinsic::dx_clamp);
+ if (ElemTy->isVectorTy())
+ ElemTy = ElemTy->getScalarType();
+ if (ElemTy->isIntegerTy())
+ return Intrinsic::smax;
+ assert(ElemTy->isFloatingPointTy());
+ return Intrinsic::maxnum;
+}
+
+static Intrinsic::ID getMinForClamp(Type *ElemTy,
+ Intrinsic::ID ClampIntrinsic) {
+ if (ClampIntrinsic == Intrinsic::dx_uclamp)
+ return Intrinsic::umin;
+ assert(ClampIntrinsic == Intrinsic::dx_clamp);
+ if (ElemTy->isVectorTy())
+ ElemTy = ElemTy->getScalarType();
+ if (ElemTy->isIntegerTy())
+ return Intrinsic::smin;
+ assert(ElemTy->isFloatingPointTy());
+ return Intrinsic::minnum;
+}
+
+static bool expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic) {
+ Value *X = Orig->getOperand(0);
+ Value *Min = Orig->getOperand(1);
+ Value *Max = Orig->getOperand(2);
+ Type *Ty = X->getType();
+ IRBuilder<> Builder(Orig->getParent());
+ Builder.SetInsertPoint(Orig);
+ auto *MaxCall = Builder.CreateIntrinsic(
+ Ty, getMaxForClamp(Ty, ClampIntrinsic), {X, Min}, nullptr, "dx.max");
+ auto *MinCall =
+ Builder.CreateIntrinsic(Ty, getMinForClamp(Ty, ClampIntrinsic),
+ {MaxCall, Max}, nullptr, "dx.min");
+
+ Orig->replaceAllUsesWith(MinCall);
+ Orig->eraseFromParent();
+ return true;
+}
+
static bool expandIntrinsic(Function &F, CallInst *Orig) {
switch (F.getIntrinsicID()) {
case Intrinsic::exp:
return expandExpIntrinsic(Orig);
case Intrinsic::dx_any:
return expandAnyIntrinsic(Orig);
+ case Intrinsic::dx_uclamp:
+ case Intrinsic::dx_clamp:
+ return expandClampIntrinsic(Orig, F.getIntrinsicID());
case Intrinsic::dx_lerp:
return expandLerpIntrinsic(Orig);
case Intrinsic::dx_rcp:
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index adfcea736158..bdf299ae8ac1 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -1255,28 +1255,6 @@ void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo,
emitRRI(Mips::SD, GPReg, Mips::SP, RegOrOffset, SMLoc(), &STI);
}
-#if 0
- // We haven't support -mabicalls -mno-shared yet.
- if (-mno-shared) {
- MCSymbol *GPSym = MCA.getContext().getOrCreateSymbol("__gnu_local_gp");
- const MipsMCExpr *HiExpr = MipsMCExpr::create(
- MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(GPSym, MCA.getContext()),
- MCA.getContext());
- const MipsMCExpr *LoExpr = MipsMCExpr::create(
- MipsMCExpr::MEK_LO, MCSymbolRefExpr::create(GPSym, MCA.getContext()),
- MCA.getContext());
-
- // lui $gp, %hi(__gnu_local_gp)
- emitRX(Mips::LUi, GPReg, MCOperand::createExpr(HiExpr), SMLoc(), &STI);
-
- // addiu $gp, $gp, %lo(__gnu_local_gp)
- emitRRX(Mips::ADDiu, GPReg, GPReg, MCOperand::createExpr(LoExpr), SMLoc(),
- &STI);
-
- return;
- }
-#endif
-
const MipsMCExpr *HiExpr = MipsMCExpr::createGpOff(
MipsMCExpr::MEK_HI, MCSymbolRefExpr::create(&Sym, MCA.getContext()),
MCA.getContext());
diff --git a/llvm/lib/TextAPI/TextStub.cpp b/llvm/lib/TextAPI/TextStub.cpp
index 24a52607a981..0f742523f820 100644
--- a/llvm/lib/TextAPI/TextStub.cpp
+++ b/llvm/lib/TextAPI/TextStub.cpp
@@ -1079,16 +1079,16 @@ Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {
if (!TAPIFile.ends_with("..."))
return createStringError(std::errc::not_supported, "unsupported file type");
- if (TAPIFile.starts_with("--- !tapi-tbd\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd"))
return FileType::TBD_V4;
- if (TAPIFile.starts_with("--- !tapi-tbd-v3\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd-v3"))
return FileType::TBD_V3;
- if (TAPIFile.starts_with("--- !tapi-tbd-v2\n"))
+ if (TAPIFile.starts_with("--- !tapi-tbd-v2"))
return FileType::TBD_V2;
- if (TAPIFile.starts_with("--- !tapi-tbd-v1\n") ||
+ if (TAPIFile.starts_with("--- !tapi-tbd-v1") ||
TAPIFile.starts_with("---\narchs:"))
return FileType::TBD_V1;
diff --git a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
index e66a1a2ccb31..1caed93b1b66 100644
--- a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
@@ -96,6 +96,11 @@ static cl::opt<bool>
cl::desc("View the CFG before DFA Jump Threading"),
cl::Hidden, cl::init(false));
+static cl::opt<bool> EarlyExitHeuristic(
+ "dfa-early-exit-heuristic",
+ cl::desc("Exit early if an unpredictable value come from the same loop"),
+ cl::Hidden, cl::init(true));
+
static cl::opt<unsigned> MaxPathLength(
"dfa-max-path-length",
cl::desc("Max number of blocks searched to find a threading path"),
@@ -405,7 +410,7 @@ private:
///
/// Also, collect select instructions to unfold.
bool isCandidate(const SwitchInst *SI) {
- std::deque<Value *> Q;
+ std::deque<std::pair<Value *, BasicBlock *>> Q;
SmallSet<Value *, 16> SeenValues;
SelectInsts.clear();
@@ -415,25 +420,28 @@ private:
return false;
// The switch must be in a loop.
- if (!LI->getLoopFor(SI->getParent()))
+ const Loop *L = LI->getLoopFor(SI->getParent());
+ if (!L)
return false;
- addToQueue(SICond, Q, SeenValues);
+ addToQueue(SICond, nullptr, Q, SeenValues);
while (!Q.empty()) {
- Value *Current = Q.front();
+ Value *Current = Q.front().first;
+ BasicBlock *CurrentIncomingBB = Q.front().second;
Q.pop_front();
if (auto *Phi = dyn_cast<PHINode>(Current)) {
- for (Value *Incoming : Phi->incoming_values()) {
- addToQueue(Incoming, Q, SeenValues);
+ for (BasicBlock *IncomingBB : Phi->blocks()) {
+ Value *Incoming = Phi->getIncomingValueForBlock(IncomingBB);
+ addToQueue(Incoming, IncomingBB, Q, SeenValues);
}
LLVM_DEBUG(dbgs() << "\tphi: " << *Phi << "\n");
} else if (SelectInst *SelI = dyn_cast<SelectInst>(Current)) {
if (!isValidSelectInst(SelI))
return false;
- addToQueue(SelI->getTrueValue(), Q, SeenValues);
- addToQueue(SelI->getFalseValue(), Q, SeenValues);
+ addToQueue(SelI->getTrueValue(), CurrentIncomingBB, Q, SeenValues);
+ addToQueue(SelI->getFalseValue(), CurrentIncomingBB, Q, SeenValues);
LLVM_DEBUG(dbgs() << "\tselect: " << *SelI << "\n");
if (auto *SelIUse = dyn_cast<PHINode>(SelI->user_back()))
SelectInsts.push_back(SelectInstToUnfold(SelI, SelIUse));
@@ -446,6 +454,18 @@ private:
// initial switch values that can be ignored (they will hit the
// unthreaded switch) but this assumption will get checked later after
// paths have been enumerated (in function getStateDefMap).
+
+ // If the unpredictable value comes from the same inner loop it is
+ // likely that it will also be on the enumerated paths, causing us to
+ // exit after we have enumerated all the paths. This heuristic save
+ // compile time because a search for all the paths can become expensive.
+ if (EarlyExitHeuristic &&
+ L->contains(LI->getLoopFor(CurrentIncomingBB))) {
+ LLVM_DEBUG(dbgs()
+ << "\tExiting early due to unpredictability heuristic.\n");
+ return false;
+ }
+
continue;
}
}
@@ -453,11 +473,12 @@ private:
return true;
}
- void addToQueue(Value *Val, std::deque<Value *> &Q,
+ void addToQueue(Value *Val, BasicBlock *BB,
+ std::deque<std::pair<Value *, BasicBlock *>> &Q,
SmallSet<Value *, 16> &SeenValues) {
if (SeenValues.contains(Val))
return;
- Q.push_back(Val);
+ Q.push_back({Val, BB});
SeenValues.insert(Val);
}
diff --git a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
index 67c011b747ac..e991296bd2fb 100644
--- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
@@ -19,6 +19,7 @@
#include "llvm/Transforms/Scalar/LowerMatrixIntrinsics.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/AliasAnalysis.h"
@@ -990,12 +991,15 @@ public:
bool Changed = false;
SmallVector<CallInst *, 16> MaybeFusableInsts;
SmallVector<Instruction *, 16> MatrixInsts;
+ SmallVector<IntrinsicInst *, 16> LifetimeEnds;
// First, collect all instructions with shape information and candidates for
// fusion (currently only matrix multiplies).
ReversePostOrderTraversal<Function *> RPOT(&Func);
for (auto *BB : RPOT)
for (Instruction &I : *BB) {
+ if (match(&I, m_Intrinsic<Intrinsic::lifetime_end>()))
+ LifetimeEnds.push_back(cast<IntrinsicInst>(&I));
if (ShapeMap.find(&I) == ShapeMap.end())
continue;
if (match(&I, m_Intrinsic<Intrinsic::matrix_multiply>()))
@@ -1010,7 +1014,7 @@ public:
// Third, try to fuse candidates.
for (CallInst *CI : MaybeFusableInsts)
- LowerMatrixMultiplyFused(CI, FusedInsts);
+ LowerMatrixMultiplyFused(CI, FusedInsts, LifetimeEnds);
Changed = !FusedInsts.empty();
@@ -1856,8 +1860,10 @@ public:
///
/// Call finalizeLowering on lowered instructions. Instructions that are
/// completely eliminated by fusion are added to \p FusedInsts.
- void LowerMatrixMultiplyFused(CallInst *MatMul,
- SmallPtrSetImpl<Instruction *> &FusedInsts) {
+ void
+ LowerMatrixMultiplyFused(CallInst *MatMul,
+ SmallPtrSetImpl<Instruction *> &FusedInsts,
+ SmallVector<IntrinsicInst *, 16> &LifetimeEnds) {
if (!FuseMatrix || !DT)
return;
@@ -1946,6 +1952,55 @@ public:
for (Instruction *I : ToHoist)
I->moveBefore(MatMul);
+ // Deal with lifetime.end calls that might be between Load0/Load1 and the
+ // store. To avoid introducing loads to dead objects (i.e. after the
+ // lifetime has been termined by @llvm.lifetime.end), either sink them
+ // after the store if in the same block, or remove the lifetime.end marker
+ // otherwise. This might pessimize further optimizations, by extending the
+ // lifetime of the object until the function returns, but should be
+ // conservatively correct.
+ MemoryLocation Load0Loc = MemoryLocation::get(LoadOp0);
+ MemoryLocation Load1Loc = MemoryLocation::get(LoadOp1);
+ BasicBlock *StoreParent = Store->getParent();
+ bool FusableOpsInSameBlock = LoadOp0->getParent() == StoreParent &&
+ LoadOp1->getParent() == StoreParent;
+ for (unsigned Idx = 0; Idx != LifetimeEnds.size();) {
+ IntrinsicInst *End = LifetimeEnds[Idx];
+ auto Inc = make_scope_exit([&Idx]() { Idx++; });
+ // If the lifetime.end is guaranteed to be before the loads or after the
+ // store, it won't interfere with fusion.
+ if (DT->dominates(End, LoadOp0) && DT->dominates(End, LoadOp1))
+ continue;
+ if (DT->dominates(Store, End))
+ continue;
+ // If all fusable ops are in the same block and the lifetime.end is in a
+ // different block, it won't interfere with fusion.
+ if (FusableOpsInSameBlock && End->getParent() != StoreParent)
+ continue;
+
+ // If the loads don't alias the lifetime.end, it won't interfere with
+ // fusion.
+ MemoryLocation EndLoc = MemoryLocation::getForArgument(End, 1, nullptr);
+ if (!EndLoc.Ptr)
+ continue;
+ if (AA->isNoAlias(Load0Loc, EndLoc) && AA->isNoAlias(Load1Loc, EndLoc))
+ continue;
+
+ // If both lifetime.end and the store are in the same block, extend the
+ // lifetime until after the store, so the new lifetime covers the loads
+ // we introduce later.
+ if (End->getParent() == StoreParent) {
+ End->moveAfter(Store);
+ continue;
+ }
+
+ // Otherwise remove the conflicting lifetime.end marker.
+ ToRemove.push_back(End);
+ std::swap(LifetimeEnds[Idx], LifetimeEnds.back());
+ LifetimeEnds.pop_back();
+ Inc.release();
+ }
+
emitSIMDTiling(MatMul, LoadOp0, LoadOp1, Store, FusedInsts);
return;
}
diff --git a/llvm/test/CodeGen/DirectX/clamp-vec.ll b/llvm/test/CodeGen/DirectX/clamp-vec.ll
new file mode 100644
index 000000000000..d4f33a18b715
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/clamp-vec.ll
@@ -0,0 +1,74 @@
+; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s
+
+; Make sure dxil operation function calls for clamp are generated for float/int/uint vectors.
+
+; CHECK-LABEL: clamp_half3
+define noundef <3 x half> @clamp_half3(<3 x half> noundef %a, <3 x half> noundef %b, <3 x half> noundef %c) {
+entry:
+ ; CHECK: call <3 x half> @llvm.maxnum.v3f16(<3 x half> %a, <3 x half> %b)
+ ; CHECK: call <3 x half> @llvm.minnum.v3f16(<3 x half> %{{.*}}, <3 x half> %c)
+ %dx.clamp = call <3 x half> @llvm.dx.clamp.v3f16(<3 x half> %a, <3 x half> %b, <3 x half> %c)
+ ret <3 x half> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_float4
+define noundef <4 x float> @clamp_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) {
+entry:
+ ; CHECK: call <4 x float> @llvm.maxnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ; CHECK: call <4 x float> @llvm.minnum.v4f32(<4 x float> %{{.*}}, <4 x float> %c)
+ %dx.clamp = call <4 x float> @llvm.dx.clamp.v4f32(<4 x float> %a, <4 x float> %b, <4 x float> %c)
+ ret <4 x float> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_double2
+define noundef <2 x double> @clamp_double2(<2 x double> noundef %a, <2 x double> noundef %b, <2 x double> noundef %c) {
+entry:
+ ; CHECK: call <2 x double> @llvm.maxnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ; CHECK: call <2 x double> @llvm.minnum.v2f64(<2 x double> %{{.*}}, <2 x double> %c)
+ %dx.clamp = call <2 x double> @llvm.dx.clamp.v2f64(<2 x double> %a, <2 x double> %b, <2 x double> %c)
+ ret <2 x double> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_int4
+define noundef <4 x i32> @clamp_int4(<4 x i32> noundef %a, <4 x i32> noundef %b, <4 x i32> noundef %c) {
+entry:
+ ; CHECK: call <4 x i32> @llvm.smax.v4i32(<4 x i32> %a, <4 x i32> %b)
+ ; CHECK: call <4 x i32> @llvm.smin.v4i32(<4 x i32> %{{.*}}, <4 x i32> %c)
+ %dx.clamp = call <4 x i32> @llvm.dx.clamp.v4i32(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c)
+ ret <4 x i32> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_uint16_t3
+define noundef <3 x i16> @clamp_uint16_t3(<3 x i16> noundef %a, <3 x i16> noundef %b, <3 x i16> noundef %c) {
+entry:
+ ; CHECK: call <3 x i16> @llvm.umax.v3i16(<3 x i16> %a, <3 x i16> %b)
+ ; CHECK: call <3 x i16> @llvm.umin.v3i16(<3 x i16> %{{.*}}, <3 x i16> %c)
+ %dx.clamp = call <3 x i16> @llvm.dx.uclamp.v3i16(<3 x i16> %a, <3 x i16> %b, <3 x i16> %c)
+ ret <3 x i16> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_uint4
+define noundef <4 x i32> @clamp_uint4(<4 x i32> noundef %a, <4 x i32> noundef %b, <4 x i32> noundef %c) {
+entry:
+ ; CHECK: call <4 x i32> @llvm.umax.v4i32(<4 x i32> %a, <4 x i32> %b)
+ ; CHECK: call <4 x i32> @llvm.umin.v4i32(<4 x i32> %{{.*}}, <4 x i32> %c)
+ %dx.clamp = call <4 x i32> @llvm.dx.uclamp.v4i32(<4 x i32> %a, <4 x i32> %b, <4 x i32> %c)
+ ret <4 x i32> %dx.clamp
+}
+
+; CHECK-LABEL: clamp_uint64_t4
+define noundef <2 x i64> @clamp_uint64_t4(<2 x i64> noundef %a, <2 x i64> noundef %b, <2 x i64> noundef %c) {
+entry:
+ ; CHECK: call <2 x i64> @llvm.umax.v2i64(<2 x i64> %a, <2 x i64> %b)
+ ; CHECK: call <2 x i64> @llvm.umin.v2i64(<2 x i64> %{{.*}}, <2 x i64> %c)
+ %dx.clamp = call <2 x i64> @llvm.dx.uclamp.v2i64(<2 x i64> %a, <2 x i64> %b, <2 x i64> %c)
+ ret <2 x i64> %dx.clamp
+}
+
+declare <3 x half> @llvm.dx.clamp.v3f16(<3 x half>, <3 x half>, <3 x half>)
+declare <4 x float> @llvm.dx.clamp.v4f32(<4 x float>, <4 x float>, <4 x float>)
+declare <2 x double> @llvm.dx.clamp.v2f64(<2 x double>, <2 x double>, <2 x double>)
+declare <4 x i32> @llvm.dx.clamp.v4i32(<4 x i32>, <4 x i32>, <4 x i32>)
+declare <3 x i16> @llvm.dx.uclamp.v3i32(<3 x i16>, <3 x i32>, <3 x i16>)
+declare <4 x i32> @llvm.dx.uclamp.v4i32(<4 x i32>, <4 x i32>, <4 x i32>)
+declare <2 x i64> @llvm.dx.uclamp.v2i64(<2 x i64>, <2 x i64>, <2 x i64>)
diff --git a/llvm/test/CodeGen/DirectX/clamp.ll b/llvm/test/CodeGen/DirectX/clamp.ll
new file mode 100644
index 000000000000..f122313b8d7d
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/clamp.ll
@@ -0,0 +1,94 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for clamp/uclamp are generated for half/float/double/i16/i32/i64.
+
+; CHECK-LABEL:test_clamp_i16
+define noundef i16 @test_clamp_i16(i16 noundef %a, i16 noundef %b, i16 noundef %c) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 37, i16 %{{.*}}, i16 %{{.*}})
+; CHECK: call i16 @dx.op.binary.i16(i32 38, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.dx.clamp.i16(i16 %a, i16 %b, i16 %c)
+ ret i16 %0
+}
+
+; CHECK-LABEL:test_clamp_i32
+define noundef i32 @test_clamp_i32(i32 noundef %a, i32 noundef %b, i32 noundef %c) {
+entry:
+; CHECK: call i32 @dx.op.binary.i32(i32 37, i32 %{{.*}}, i32 %{{.*}})
+; CHECK: call i32 @dx.op.binary.i32(i32 38, i32 %{{.*}}, i32 %{{.*}})
+ %0 = call i32 @llvm.dx.clamp.i32(i32 %a, i32 %b, i32 %c)
+ ret i32 %0
+}
+
+; CHECK-LABEL:test_clamp_i64
+define noundef i64 @test_clamp_i64(i64 noundef %a, i64 noundef %b, i64 noundef %c) {
+entry:
+; CHECK: call i64 @dx.op.binary.i64(i32 37, i64 %a, i64 %b)
+; CHECK: call i64 @dx.op.binary.i64(i32 38, i64 %{{.*}}, i64 %c)
+ %0 = call i64 @llvm.dx.clamp.i64(i64 %a, i64 %b, i64 %c)
+ ret i64 %0
+}
+
+; CHECK-LABEL:test_clamp_half
+define noundef half @test_clamp_half(half noundef %a, half noundef %b, half noundef %c) {
+entry:
+; CHECK: call half @dx.op.binary.f16(i32 35, half %{{.*}}, half %{{.*}})
+; CHECK: call half @dx.op.binary.f16(i32 36, half %{{.*}}, half %{{.*}})
+ %0 = call half @llvm.dx.clamp.f16(half %a, half %b, half %c)
+ ret half %0
+}
+
+; CHECK-LABEL:test_clamp_float
+define noundef float @test_clamp_float(float noundef %a, float noundef %b, float noundef %c) {
+entry:
+; CHECK: call float @dx.op.binary.f32(i32 35, float %{{.*}}, float %{{.*}})
+; CHECK: call float @dx.op.binary.f32(i32 36, float %{{.*}}, float %{{.*}})
+ %0 = call float @llvm.dx.clamp.f32(float %a, float %b, float %c)
+ ret float %0
+}
+
+; CHECK-LABEL:test_clamp_double
+define noundef double @test_clamp_double(double noundef %a, double noundef %b, double noundef %c) {
+entry:
+; CHECK: call double @dx.op.binary.f64(i32 35, double %{{.*}}, double %{{.*}})
+; CHECK: call double @dx.op.binary.f64(i32 36, double %{{.*}}, double %{{.*}})
+ %0 = call double @llvm.dx.clamp.f64(double %a, double %b, double %c)
+ ret double %0
+}
+
+; CHECK-LABEL:test_uclamp_i16
+define noundef i16 @test_uclamp_i16(i16 noundef %a, i16 noundef %b, i16 noundef %c) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 39, i16 %{{.*}}, i16 %{{.*}})
+; CHECK: call i16 @dx.op.binary.i16(i32 40, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.dx.uclamp.i16(i16 %a, i16 %b, i16 %c)
+ ret i16 %0
+}
+
+; CHECK-LABEL:test_uclamp_i32
+define noundef i32 @test_uclamp_i32(i32 noundef %a, i32 noundef %b, i32 noundef %c) {
+entry:
+; CHECK: call i32 @dx.op.binary.i32(i32 39, i32 %{{.*}}, i32 %{{.*}})
+; CHECK: call i32 @dx.op.binary.i32(i32 40, i32 %{{.*}}, i32 %{{.*}})
+ %0 = call i32 @llvm.dx.uclamp.i32(i32 %a, i32 %b, i32 %c)
+ ret i32 %0
+}
+
+; CHECK-LABEL:test_uclamp_i64
+define noundef i64 @test_uclamp_i64(i64 noundef %a, i64 noundef %b, i64 noundef %c) {
+entry:
+; CHECK: call i64 @dx.op.binary.i64(i32 39, i64 %a, i64 %b)
+; CHECK: call i64 @dx.op.binary.i64(i32 40, i64 %{{.*}}, i64 %c)
+ %0 = call i64 @llvm.dx.uclamp.i64(i64 %a, i64 %b, i64 %c)
+ ret i64 %0
+}
+
+declare half @llvm.dx.clamp.f16(half, half, half)
+declare float @llvm.dx.clamp.f32(float, float, float)
+declare double @llvm.dx.clamp.f64(double, double, double)
+declare i16 @llvm.dx.clamp.i16(i16, i16, i16)
+declare i32 @llvm.dx.clamp.i32(i32, i32, i32)
+declare i64 @llvm.dx.clamp.i64(i64, i64, i64)
+declare i16 @llvm.dx.uclamp.i16(i16, i16, i16)
+declare i32 @llvm.dx.uclamp.i32(i32, i32, i32)
+declare i64 @llvm.dx.uclamp.i64(i64, i64, i64)
diff --git a/llvm/test/CodeGen/DirectX/fmax.ll b/llvm/test/CodeGen/DirectX/fmax.ll
new file mode 100644
index 000000000000..aff722c29309
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/fmax.ll
@@ -0,0 +1,31 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for fmax are generated for half/float/double.
+
+; CHECK-LABEL:test_fmax_half
+define noundef half @test_fmax_half(half noundef %a, half noundef %b) {
+entry:
+; CHECK: call half @dx.op.binary.f16(i32 35, half %{{.*}}, half %{{.*}})
+ %0 = call half @llvm.maxnum.f16(half %a, half %b)
+ ret half %0
+}
+
+; CHECK-LABEL:test_fmax_float
+define noundef float @test_fmax_float(float noundef %a, float noundef %b) {
+entry:
+; CHECK: call float @dx.op.binary.f32(i32 35, float %{{.*}}, float %{{.*}})
+ %0 = call float @llvm.maxnum.f32(float %a, float %b)
+ ret float %0
+}
+
+; CHECK-LABEL:test_fmax_double
+define noundef double @test_fmax_double(double noundef %a, double noundef %b) {
+entry:
+; CHECK: call double @dx.op.binary.f64(i32 35, double %{{.*}}, double %{{.*}})
+ %0 = call double @llvm.maxnum.f64(double %a, double %b)
+ ret double %0
+}
+
+declare half @llvm.maxnum.f16(half, half)
+declare float @llvm.maxnum.f32(float, float)
+declare double @llvm.maxnum.f64(double, double)
diff --git a/llvm/test/CodeGen/DirectX/fmin.ll b/llvm/test/CodeGen/DirectX/fmin.ll
new file mode 100644
index 000000000000..2f7c209f0278
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/fmin.ll
@@ -0,0 +1,31 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for fmin are generated for half/float/double.
+
+; CHECK-LABEL:test_fmin_half
+define noundef half @test_fmin_half(half noundef %a, half noundef %b) {
+entry:
+; CHECK: call half @dx.op.binary.f16(i32 36, half %{{.*}}, half %{{.*}})
+ %0 = call half @llvm.minnum.f16(half %a, half %b)
+ ret half %0
+}
+
+; CHECK-LABEL:test_fmin_float
+define noundef float @test_fmin_float(float noundef %a, float noundef %b) {
+entry:
+; CHECK: call float @dx.op.binary.f32(i32 36, float %{{.*}}, float %{{.*}})
+ %0 = call float @llvm.minnum.f32(float %a, float %b)
+ ret float %0
+}
+
+; CHECK-LABEL:test_fmin_double
+define noundef double @test_fmin_double(double noundef %a, double noundef %b) {
+entry:
+; CHECK: call double @dx.op.binary.f64(i32 36, double %{{.*}}, double %{{.*}})
+ %0 = call double @llvm.minnum.f64(double %a, double %b)
+ ret double %0
+}
+
+declare half @llvm.minnum.f16(half, half)
+declare float @llvm.minnum.f32(float, float)
+declare double @llvm.minnum.f64(double, double)
diff --git a/llvm/test/CodeGen/DirectX/smax.ll b/llvm/test/CodeGen/DirectX/smax.ll
new file mode 100644
index 000000000000..8b2406782c09
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/smax.ll
@@ -0,0 +1,31 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for smax are generated for i16/i32/i64.
+
+; CHECK-LABEL:test_smax_i16
+define noundef i16 @test_smax_i16(i16 noundef %a, i16 noundef %b) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 37, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.smax.i16(i16 %a, i16 %b)
+ ret i16 %0
+}
+
+; CHECK-LABEL:test_smax_i32
+define noundef i32 @test_smax_i32(i32 noundef %a, i32 noundef %b) {
+entry:
+; CHECK: call i32 @dx.op.binary.i32(i32 37, i32 %{{.*}}, i32 %{{.*}})
+ %0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
+ ret i32 %0
+}
+
+; CHECK-LABEL:test_smax_i64
+define noundef i64 @test_smax_i64(i64 noundef %a, i64 noundef %b) {
+entry:
+; CHECK: call i64 @dx.op.binary.i64(i32 37, i64 %{{.*}}, i64 %{{.*}})
+ %0 = call i64 @llvm.smax.i64(i64 %a, i64 %b)
+ ret i64 %0
+}
+
+declare i16 @llvm.smax.i16(i16, i16)
+declare i32 @llvm.smax.i32(i32, i32)
+declare i64 @llvm.smax.i64(i64, i64)
diff --git a/llvm/test/CodeGen/DirectX/smin.ll b/llvm/test/CodeGen/DirectX/smin.ll
new file mode 100644
index 000000000000..b2b40a1b6243
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/smin.ll
@@ -0,0 +1,31 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for smin are generated for i16/i32/i64.
+
+; CHECK-LABEL:test_smin_i16
+define noundef i16 @test_smin_i16(i16 noundef %a, i16 noundef %b) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 38, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.smin.i16(i16 %a, i16 %b)
+ ret i16 %0
+}
+
+; CHECK-LABEL:test_smin_i32
+define noundef i32 @test_smin_i32(i32 noundef %a, i32 noundef %b) {
+entry:
+; CHECK: call i32 @dx.op.binary.i32(i32 38, i32 %{{.*}}, i32 %{{.*}})
+ %0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
+ ret i32 %0
+}
+
+; CHECK-LABEL:test_smin_i64
+define noundef i64 @test_smin_i64(i64 noundef %a, i64 noundef %b) {
+entry:
+; CHECK: call i64 @dx.op.binary.i64(i32 38, i64 %{{.*}}, i64 %{{.*}})
+ %0 = call i64 @llvm.smin.i64(i64 %a, i64 %b)
+ ret i64 %0
+}
+
+declare i16 @llvm.smin.i16(i16, i16)
+declare i32 @llvm.smin.i32(i32, i32)
+declare i64 @llvm.smin.i64(i64, i64)
diff --git a/llvm/test/CodeGen/DirectX/umax.ll b/llvm/test/CodeGen/DirectX/umax.ll
index c7b6a8759927..be0f557fc8da 100644
--- a/llvm/test/CodeGen/DirectX/umax.ll
+++ b/llvm/test/CodeGen/DirectX/umax.ll
@@ -1,30 +1,31 @@
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
-; Make sure dxil operation function calls for umax are generated for i32/i64.
+; Make sure dxil operation function calls for umax are generated for i16/i32/i64.
-target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
-target triple = "dxil-pc-shadermodel6.7-library"
+; CHECK-LABEL:test_umax_i16
+define noundef i16 @test_umax_i16(i16 noundef %a, i16 noundef %b) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 39, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.umax.i16(i16 %a, i16 %b)
+ ret i16 %0
+}
; CHECK-LABEL:test_umax_i32
-; Function Attrs: noinline nounwind optnone
-define noundef i32 @test_umax_i32(i32 noundef %a, i32 noundef %b) #0 {
+define noundef i32 @test_umax_i32(i32 noundef %a, i32 noundef %b) {
entry:
-; CHECK:call i32 @dx.op.binary.i32(i32 39, i32 %{{.*}}, i32 %{{.*}})
+; CHECK: call i32 @dx.op.binary.i32(i32 39, i32 %{{.*}}, i32 %{{.*}})
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
ret i32 %0
}
; CHECK-LABEL:test_umax_i64
-define noundef i64 @test_umax_i64(i64 noundef %a, i64 noundef %b) #0 {
+define noundef i64 @test_umax_i64(i64 noundef %a, i64 noundef %b) {
entry:
-; CHECK:call i64 @dx.op.binary.i64(i32 39, i64 %{{.*}}, i64 %{{.*}})
+; CHECK: call i64 @dx.op.binary.i64(i32 39, i64 %{{.*}}, i64 %{{.*}})
%0 = call i64 @llvm.umax.i64(i64 %a, i64 %b)
ret i64 %0
}
-; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
-declare i32 @llvm.umax.i32(i32, i32) #1
-declare i64 @llvm.umax.i64(i64, i64) #1
-
-attributes #0 = { noinline nounwind }
-attributes #1 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
+declare i16 @llvm.umax.i16(i16, i16)
+declare i32 @llvm.umax.i32(i32, i32)
+declare i64 @llvm.umax.i64(i64, i64)
diff --git a/llvm/test/CodeGen/DirectX/umin.ll b/llvm/test/CodeGen/DirectX/umin.ll
new file mode 100644
index 000000000000..5051c7117448
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/umin.ll
@@ -0,0 +1,31 @@
+; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
+
+; Make sure dxil operation function calls for umin are generated for i16/i32/i64.
+
+; CHECK-LABEL:test_umin_i16
+define noundef i16 @test_umin_i16(i16 noundef %a, i16 noundef %b) {
+entry:
+; CHECK: call i16 @dx.op.binary.i16(i32 40, i16 %{{.*}}, i16 %{{.*}})
+ %0 = call i16 @llvm.umin.i16(i16 %a, i16 %b)
+ ret i16 %0
+}
+
+; CHECK-LABEL:test_umin_i32
+define noundef i32 @test_umin_i32(i32 noundef %a, i32 noundef %b) {
+entry:
+; CHECK: call i32 @dx.op.binary.i32(i32 40, i32 %{{.*}}, i32 %{{.*}})
+ %0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
+ ret i32 %0
+}
+
+; CHECK-LABEL:test_umin_i64
+define noundef i64 @test_umin_i64(i64 noundef %a, i64 noundef %b) {
+entry:
+; CHECK: call i64 @dx.op.binary.i64(i32 40, i64 %{{.*}}, i64 %{{.*}})
+ %0 = call i64 @llvm.umin.i64(i64 %a, i64 %b)
+ ret i64 %0
+}
+
+declare i16 @llvm.umin.i16(i16, i16)
+declare i32 @llvm.umin.i32(i32, i32)
+declare i64 @llvm.umin.i64(i64, i64)
diff --git a/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll b/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
index df725b9a7fa4..696bd55d2dfd 100644
--- a/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
+++ b/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=dfa-jump-threading %s | FileCheck %s
+; RUN: opt -S -passes=dfa-jump-threading -dfa-early-exit-heuristic=false %s | FileCheck %s
; These tests check if selects are unfolded properly for jump threading
; opportunities. There are three different patterns to consider:
diff --git a/llvm/test/Transforms/DFAJumpThreading/unpredictable-heuristic.ll b/llvm/test/Transforms/DFAJumpThreading/unpredictable-heuristic.ll
new file mode 100644
index 000000000000..9743f0acc816
--- /dev/null
+++ b/llvm/test/Transforms/DFAJumpThreading/unpredictable-heuristic.ll
@@ -0,0 +1,124 @@
+; REQUIRES: asserts
+; RUN: opt -S -passes=dfa-jump-threading %s -debug-only=dfa-jump-threading 2>&1 | FileCheck %s
+
+; CHECK-COUNT-3: Exiting early due to unpredictability heuristic.
+
+@.str.1 = private unnamed_addr constant [3 x i8] c"10\00", align 1
+@.str.2 = private unnamed_addr constant [3 x i8] c"30\00", align 1
+@.str.3 = private unnamed_addr constant [3 x i8] c"20\00", align 1
+@.str.4 = private unnamed_addr constant [3 x i8] c"40\00", align 1
+
+define void @test1(i32 noundef %num, i32 noundef %num2) {
+entry:
+ br label %while.body
+
+while.body: ; preds = %entry, %sw.epilog
+ %num.addr.0 = phi i32 [ %num, %entry ], [ %num.addr.1, %sw.epilog ]
+ switch i32 %num.addr.0, label %sw.default [
+ i32 10, label %sw.bb
+ i32 30, label %sw.bb1
+ i32 20, label %sw.bb2
+ i32 40, label %sw.bb3
+ ]
+
+sw.bb: ; preds = %while.body
+ %call.i = tail call i32 @bar(ptr noundef nonnull @.str.1)
+ br label %sw.epilog
+
+sw.bb1: ; preds = %while.body
+ %call.i4 = tail call i32 @bar(ptr noundef nonnull @.str.2)
+ br label %sw.epilog
+
+sw.bb2: ; preds = %while.body
+ %call.i5 = tail call i32 @bar(ptr noundef nonnull @.str.3)
+ br label %sw.epilog
+
+sw.bb3: ; preds = %while.body
+ %call.i6 = tail call i32 @bar(ptr noundef nonnull @.str.4)
+ %call = tail call noundef i32 @foo()
+ %add = add nsw i32 %call, %num2
+ br label %sw.epilog
+
+sw.default: ; preds = %while.body
+ ret void
+
+sw.epilog: ; preds = %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb
+ %num.addr.1 = phi i32 [ %add, %sw.bb3 ], [ 40, %sw.bb2 ], [ 20, %sw.bb1 ], [ 30, %sw.bb ]
+ br label %while.body
+}
+
+
+define void @test2(i32 noundef %num, i32 noundef %num2) {
+entry:
+ br label %while.body
+
+while.body: ; preds = %entry, %sw.epilog
+ %num.addr.0 = phi i32 [ %num, %entry ], [ %num.addr.1, %sw.epilog ]
+ switch i32 %num.addr.0, label %sw.default [
+ i32 10, label %sw.epilog
+ i32 30, label %sw.bb1
+ i32 20, label %sw.bb2
+ i32 40, label %sw.bb3
+ ]
+
+sw.bb1: ; preds = %while.body
+ br label %sw.epilog
+
+sw.bb2: ; preds = %while.body
+ br label %sw.epilog
+
+sw.bb3: ; preds = %while.body
+ br label %sw.epilog
+
+sw.default: ; preds = %while.body
+ ret void
+
+sw.epilog: ; preds = %while.body, %sw.bb3, %sw.bb2, %sw.bb1
+ %.str.4.sink = phi ptr [ @.str.4, %sw.bb3 ], [ @.str.3, %sw.bb2 ], [ @.str.2, %sw.bb1 ], [ @.str.1, %while.body ]
+ %num.addr.1 = phi i32 [ %num2, %sw.bb3 ], [ 40, %sw.bb2 ], [ 20, %sw.bb1 ], [ 30, %while.body ]
+ %call.i6 = tail call i32 @bar(ptr noundef nonnull %.str.4.sink)
+ br label %while.body
+}
+
+
+define void @test3(i32 noundef %num, i32 noundef %num2) {
+entry:
+ %add = add nsw i32 %num2, 40
+ br label %while.body
+
+while.body: ; preds = %entry, %sw.epilog
+ %num.addr.0 = phi i32 [ %num, %entry ], [ %num.addr.1, %sw.epilog ]
+ switch i32 %num.addr.0, label %sw.default [
+ i32 10, label %sw.bb
+ i32 30, label %sw.bb1
+ i32 20, label %sw.bb2
+ i32 40, label %sw.bb3
+ ]
+
+sw.bb: ; preds = %while.body
+ %call.i = tail call i32 @bar(ptr noundef nonnull @.str.1)
+ br label %sw.epilog
+
+sw.bb1: ; preds = %while.body
+ %call.i5 = tail call i32 @bar(ptr noundef nonnull @.str.2)
+ br label %sw.epilog
+
+sw.bb2: ; preds = %while.body
+ %call.i6 = tail call i32 @bar(ptr noundef nonnull @.str.3)
+ br label %sw.epilog
+
+sw.bb3: ; preds = %while.body
+ %call.i7 = tail call i32 @bar(ptr noundef nonnull @.str.4)
+ br label %sw.epilog
+
+sw.default: ; preds = %while.body
+ ret void
+
+sw.epilog: ; preds = %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb
+ %num.addr.1 = phi i32 [ %add, %sw.bb3 ], [ 40, %sw.bb2 ], [ 20, %sw.bb1 ], [ 30, %sw.bb ]
+ br label %while.body
+}
+
+
+declare noundef i32 @foo()
+declare noundef i32 @bar(ptr nocapture noundef readonly)
diff --git a/llvm/test/Transforms/LowerMatrixIntrinsics/multiply-fused-lifetime-ends.ll b/llvm/test/Transforms/LowerMatrixIntrinsics/multiply-fused-lifetime-ends.ll
index ef8665b79690..bdd0c6f728ae 100644
--- a/llvm/test/Transforms/LowerMatrixIntrinsics/multiply-fused-lifetime-ends.ll
+++ b/llvm/test/Transforms/LowerMatrixIntrinsics/multiply-fused-lifetime-ends.ll
@@ -6,15 +6,11 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
; Tests to make sure no loads are introduced after a lifetime.end by multiply
; fusion.
-; FIXME: Currently the tests are mis-compiled, with loads being introduced after
-; llvm.lifetime.end calls.
-
define void @lifetime_for_first_arg_before_multiply(ptr noalias %B, ptr noalias %C) {
; CHECK-LABEL: @lifetime_for_first_arg_before_multiply(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = alloca <4 x double>, align 32
; CHECK-NEXT: call void @init(ptr [[A]])
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
@@ -77,6 +73,7 @@ define void @lifetime_for_first_arg_before_multiply(ptr noalias %B, ptr noalias
; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
; CHECK-NEXT: ret void
;
entry:
@@ -95,7 +92,6 @@ define void @lifetime_for_second_arg_before_multiply(ptr noalias %A, ptr noalias
; CHECK-NEXT: entry:
; CHECK-NEXT: [[B:%.*]] = alloca <4 x double>, align 32
; CHECK-NEXT: call void @init(ptr [[B]])
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A:%.*]], i64 0
; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
@@ -158,6 +154,7 @@ define void @lifetime_for_second_arg_before_multiply(ptr noalias %A, ptr noalias
; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B]])
; CHECK-NEXT: ret void
;
entry:
@@ -177,7 +174,6 @@ define void @lifetime_for_first_arg_before_multiply_load_from_offset(ptr noalias
; CHECK-NEXT: [[A:%.*]] = alloca <8 x double>, align 64
; CHECK-NEXT: call void @init(ptr [[A]])
; CHECK-NEXT: [[GEP_8:%.*]] = getelementptr i8, ptr [[A]], i64 8
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[GEP_8]], i64 0
; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
@@ -240,6 +236,7 @@ define void @lifetime_for_first_arg_before_multiply_load_from_offset(ptr noalias
; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
; CHECK-NEXT: ret void
;
entry:
@@ -261,7 +258,6 @@ define void @lifetime_for_first_arg_before_multiply_lifetime_does_not_dominate(p
; CHECK-NEXT: call void @init(ptr [[A]])
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
@@ -352,7 +348,6 @@ define void @lifetime_for_second_arg_before_multiply_lifetime_does_not_dominate(
; CHECK-NEXT: call void @init(ptr [[B]])
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B]])
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A:%.*]], i64 0
@@ -441,10 +436,9 @@ define void @lifetime_for_ptr_first_arg_before_multiply(ptr noalias %A, ptr noal
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A:%.*]])
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A:%.*]], i64 0
; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
@@ -528,15 +522,104 @@ define void @lifetime_for_both_ptr_args_before_multiply(ptr noalias %A, ptr noal
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B:%.*]])
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A:%.*]])
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
-; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A:%.*]], i64 0
; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
-; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B]], i64 0
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B:%.*]], i64 0
+; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
+; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
+; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
+; CHECK-NEXT: [[BLOCK:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x double> poison, double [[TMP2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <1 x double> [[BLOCK]], [[SPLAT_SPLAT]]
+; CHECK-NEXT: [[BLOCK5:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <1 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT7:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT6]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK5]], <1 x double> [[SPLAT_SPLAT7]], <1 x double> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <1 x double> [[TMP5]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP6]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK8:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK9:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT10:%.*]] = insertelement <1 x double> poison, double [[TMP8]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT11:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT10]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP9:%.*]] = fmul contract <1 x double> [[BLOCK9]], [[SPLAT_SPLAT11]]
+; CHECK-NEXT: [[BLOCK12:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <1 x double> poison, double [[TMP10]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT14:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT13]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK12]], <1 x double> [[SPLAT_SPLAT14]], <1 x double> [[TMP9]])
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <1 x double> [[TMP11]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[BLOCK15:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT16:%.*]] = insertelement <1 x double> poison, double [[TMP14]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT17:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT16]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP15:%.*]] = fmul contract <1 x double> [[BLOCK15]], [[SPLAT_SPLAT17]]
+; CHECK-NEXT: [[BLOCK18:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP16:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT19:%.*]] = insertelement <1 x double> poison, double [[TMP16]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT20:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT19]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP17:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK18]], <1 x double> [[SPLAT_SPLAT20]], <1 x double> [[TMP15]])
+; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <1 x double> [[TMP17]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP18]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK21:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK22:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP20:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT23:%.*]] = insertelement <1 x double> poison, double [[TMP20]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT24:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT23]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP21:%.*]] = fmul contract <1 x double> [[BLOCK22]], [[SPLAT_SPLAT24]]
+; CHECK-NEXT: [[BLOCK25:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT26:%.*]] = insertelement <1 x double> poison, double [[TMP22]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT27:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT26]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP23:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK25]], <1 x double> [[SPLAT_SPLAT27]], <1 x double> [[TMP21]])
+; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <1 x double> [[TMP23]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> [[TMP24]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[TMP26:%.*]] = getelementptr double, ptr [[C1:%.*]], i64 0
+; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
+; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
+; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: ret void
+;
+entry:
+ %a = load <4 x double>, ptr %A, align 8
+ %b = load <4 x double>, ptr %B, align 8
+ br i1 %c.0, label %then, label %exit
+
+then:
+ call void @llvm.lifetime.end(i64 -1, ptr %B)
+ call void @llvm.lifetime.end(i64 -1, ptr %A)
+ br label %exit
+
+exit:
+ %m = call <4 x double> @llvm.matrix.multiply(<4 x double> %a, <4 x double> %b, i32 2, i32 2, i32 2)
+ store <4 x double> %m, ptr %C, align 8
+ ret void
+}
+
+define void @multiple_unrelated_lifetimes(ptr noalias %A, ptr noalias %B, ptr noalias %C, i1 %c.0) {
+; CHECK-LABEL: @multiple_unrelated_lifetimes(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ALLOC_1:%.*]] = alloca i32, align 4
+; CHECK-NEXT: [[ALLOC_2:%.*]] = alloca i32, align 4
+; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
+; CHECK: then:
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[ALLOC_1]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[ALLOC_2]])
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A:%.*]], i64 0
+; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
+; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
+; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B:%.*]], i64 0
; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
@@ -597,13 +680,17 @@ define void @lifetime_for_both_ptr_args_before_multiply(ptr noalias %A, ptr noal
; CHECK-NEXT: ret void
;
entry:
+ %alloc.1 = alloca i32
+ %alloc.2 = alloca i32
%a = load <4 x double>, ptr %A, align 8
%b = load <4 x double>, ptr %B, align 8
br i1 %c.0, label %then, label %exit
then:
call void @llvm.lifetime.end(i64 -1, ptr %B)
+ call void @llvm.lifetime.end(i64 -1, ptr %alloc.1)
call void @llvm.lifetime.end(i64 -1, ptr %A)
+ call void @llvm.lifetime.end(i64 -1, ptr %alloc.2)
br label %exit
exit:
@@ -618,7 +705,6 @@ define void @lifetime_for_ptr_select_before_multiply(ptr noalias %A, ptr noalias
; CHECK-NEXT: [[P:%.*]] = select i1 [[C_0:%.*]], ptr [[A:%.*]], ptr [[B:%.*]]
; CHECK-NEXT: br i1 [[C_1:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
; CHECK: then:
-; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[P]])
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[P]], i64 0
@@ -701,6 +787,374 @@ exit:
ret void
}
+define void @lifetimes_for_args_in_different_blocks(ptr noalias %B, ptr noalias %C, i1 %c.0) {
+; CHECK-LABEL: @lifetimes_for_args_in_different_blocks(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca <4 x double>, align 32
+; CHECK-NEXT: call void @init(ptr [[A]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
+; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
+; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B:%.*]], i64 0
+; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
+; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
+; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
+; CHECK-NEXT: [[BLOCK:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x double> poison, double [[TMP2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <1 x double> [[BLOCK]], [[SPLAT_SPLAT]]
+; CHECK-NEXT: [[BLOCK5:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <1 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT7:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT6]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK5]], <1 x double> [[SPLAT_SPLAT7]], <1 x double> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <1 x double> [[TMP5]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP6]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK8:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK9:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT10:%.*]] = insertelement <1 x double> poison, double [[TMP8]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT11:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT10]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP9:%.*]] = fmul contract <1 x double> [[BLOCK9]], [[SPLAT_SPLAT11]]
+; CHECK-NEXT: [[BLOCK12:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <1 x double> poison, double [[TMP10]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT14:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT13]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK12]], <1 x double> [[SPLAT_SPLAT14]], <1 x double> [[TMP9]])
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <1 x double> [[TMP11]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[BLOCK15:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT16:%.*]] = insertelement <1 x double> poison, double [[TMP14]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT17:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT16]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP15:%.*]] = fmul contract <1 x double> [[BLOCK15]], [[SPLAT_SPLAT17]]
+; CHECK-NEXT: [[BLOCK18:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP16:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT19:%.*]] = insertelement <1 x double> poison, double [[TMP16]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT20:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT19]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP17:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK18]], <1 x double> [[SPLAT_SPLAT20]], <1 x double> [[TMP15]])
+; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <1 x double> [[TMP17]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP18]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK21:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK22:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP20:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT23:%.*]] = insertelement <1 x double> poison, double [[TMP20]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT24:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT23]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP21:%.*]] = fmul contract <1 x double> [[BLOCK22]], [[SPLAT_SPLAT24]]
+; CHECK-NEXT: [[BLOCK25:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT26:%.*]] = insertelement <1 x double> poison, double [[TMP22]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT27:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT26]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP23:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK25]], <1 x double> [[SPLAT_SPLAT27]], <1 x double> [[TMP21]])
+; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <1 x double> [[TMP23]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> [[TMP24]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[TMP26:%.*]] = getelementptr double, ptr [[C1:%.*]], i64 0
+; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
+; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
+; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B]])
+; CHECK-NEXT: ret void
+;
+entry:
+ %A = alloca <4 x double>
+ call void @init(ptr %A)
+ br i1 %c.0, label %then, label %exit
+
+then:
+ %a = load <4 x double>, ptr %A, align 8
+ %b = load <4 x double>, ptr %B, align 8
+ %m = call <4 x double> @llvm.matrix.multiply(<4 x double> %a, <4 x double> %b, i32 2, i32 2, i32 2)
+ store <4 x double> %m, ptr %C, align 8
+ br label %exit
+
+exit:
+ call void @llvm.lifetime.end(i64 -1, ptr %A)
+ call void @llvm.lifetime.end(i64 -1, ptr %B)
+ ret void
+}
+
+define void @lifetimes_for_args_in_different_blocks2(ptr noalias %B, ptr noalias %C, i1 %c.0) {
+; CHECK-LABEL: @lifetimes_for_args_in_different_blocks2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca <4 x double>, align 32
+; CHECK-NEXT: call void @init(ptr [[A]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
+; CHECK: then:
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A]])
+; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B:%.*]])
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
+; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
+; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B]], i64 0
+; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
+; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
+; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
+; CHECK-NEXT: [[BLOCK:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x double> poison, double [[TMP2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <1 x double> [[BLOCK]], [[SPLAT_SPLAT]]
+; CHECK-NEXT: [[BLOCK5:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <1 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT7:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT6]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK5]], <1 x double> [[SPLAT_SPLAT7]], <1 x double> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <1 x double> [[TMP5]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP6]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK8:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK9:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT10:%.*]] = insertelement <1 x double> poison, double [[TMP8]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT11:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT10]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP9:%.*]] = fmul contract <1 x double> [[BLOCK9]], [[SPLAT_SPLAT11]]
+; CHECK-NEXT: [[BLOCK12:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <1 x double> poison, double [[TMP10]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT14:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT13]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK12]], <1 x double> [[SPLAT_SPLAT14]], <1 x double> [[TMP9]])
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <1 x double> [[TMP11]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[BLOCK15:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT16:%.*]] = insertelement <1 x double> poison, double [[TMP14]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT17:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT16]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP15:%.*]] = fmul contract <1 x double> [[BLOCK15]], [[SPLAT_SPLAT17]]
+; CHECK-NEXT: [[BLOCK18:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP16:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT19:%.*]] = insertelement <1 x double> poison, double [[TMP16]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT20:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT19]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP17:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK18]], <1 x double> [[SPLAT_SPLAT20]], <1 x double> [[TMP15]])
+; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <1 x double> [[TMP17]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP18]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK21:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK22:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP20:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT23:%.*]] = insertelement <1 x double> poison, double [[TMP20]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT24:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT23]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP21:%.*]] = fmul contract <1 x double> [[BLOCK22]], [[SPLAT_SPLAT24]]
+; CHECK-NEXT: [[BLOCK25:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT26:%.*]] = insertelement <1 x double> poison, double [[TMP22]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT27:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT26]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP23:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK25]], <1 x double> [[SPLAT_SPLAT27]], <1 x double> [[TMP21]])
+; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <1 x double> [[TMP23]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> [[TMP24]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[TMP26:%.*]] = getelementptr double, ptr [[C1:%.*]], i64 0
+; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
+; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
+; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: ret void
+;
+entry:
+ %A = alloca <4 x double>
+ call void @init(ptr %A)
+ br i1 %c.0, label %then, label %exit
+
+then:
+ call void @llvm.lifetime.end(i64 -1, ptr %A)
+ call void @llvm.lifetime.end(i64 -1, ptr %B)
+ br label %exit
+
+exit:
+ %a = load <4 x double>, ptr %A, align 8
+ %b = load <4 x double>, ptr %B, align 8
+ %m = call <4 x double> @llvm.matrix.multiply(<4 x double> %a, <4 x double> %b, i32 2, i32 2, i32 2)
+ store <4 x double> %m, ptr %C, align 8
+ ret void
+}
+
+define void @lifetimes_for_args_load0_in_different_block(ptr noalias %B, ptr noalias %C, i1 %c.0) {
+; CHECK-LABEL: @lifetimes_for_args_load0_in_different_block(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca <4 x double>, align 32
+; CHECK-NEXT: call void @init(ptr [[A]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
+; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
+; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B:%.*]], i64 0
+; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
+; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
+; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
+; CHECK-NEXT: [[BLOCK:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x double> poison, double [[TMP2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <1 x double> [[BLOCK]], [[SPLAT_SPLAT]]
+; CHECK-NEXT: [[BLOCK5:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <1 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT7:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT6]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK5]], <1 x double> [[SPLAT_SPLAT7]], <1 x double> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <1 x double> [[TMP5]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP6]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK8:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK9:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT10:%.*]] = insertelement <1 x double> poison, double [[TMP8]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT11:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT10]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP9:%.*]] = fmul contract <1 x double> [[BLOCK9]], [[SPLAT_SPLAT11]]
+; CHECK-NEXT: [[BLOCK12:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <1 x double> poison, double [[TMP10]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT14:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT13]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK12]], <1 x double> [[SPLAT_SPLAT14]], <1 x double> [[TMP9]])
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <1 x double> [[TMP11]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[BLOCK15:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT16:%.*]] = insertelement <1 x double> poison, double [[TMP14]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT17:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT16]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP15:%.*]] = fmul contract <1 x double> [[BLOCK15]], [[SPLAT_SPLAT17]]
+; CHECK-NEXT: [[BLOCK18:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP16:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT19:%.*]] = insertelement <1 x double> poison, double [[TMP16]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT20:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT19]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP17:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK18]], <1 x double> [[SPLAT_SPLAT20]], <1 x double> [[TMP15]])
+; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <1 x double> [[TMP17]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP18]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK21:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK22:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP20:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT23:%.*]] = insertelement <1 x double> poison, double [[TMP20]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT24:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT23]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP21:%.*]] = fmul contract <1 x double> [[BLOCK22]], [[SPLAT_SPLAT24]]
+; CHECK-NEXT: [[BLOCK25:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT26:%.*]] = insertelement <1 x double> poison, double [[TMP22]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT27:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT26]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP23:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK25]], <1 x double> [[SPLAT_SPLAT27]], <1 x double> [[TMP21]])
+; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <1 x double> [[TMP23]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> [[TMP24]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[TMP26:%.*]] = getelementptr double, ptr [[C1:%.*]], i64 0
+; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
+; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
+; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ %A = alloca <4 x double>
+ call void @init(ptr %A)
+ %a = load <4 x double>, ptr %A, align 8
+ call void @llvm.lifetime.end(i64 -1, ptr %A)
+ br i1 %c.0, label %then, label %exit
+
+then:
+ %b = load <4 x double>, ptr %B, align 8
+ %m = call <4 x double> @llvm.matrix.multiply(<4 x double> %a, <4 x double> %b, i32 2, i32 2, i32 2)
+ store <4 x double> %m, ptr %C, align 8
+ br label %exit
+
+exit:
+ call void @llvm.lifetime.end(i64 -1, ptr %B)
+ ret void
+}
+
+define void @lifetimes_for_args_load1_in_different_block(ptr noalias %B, ptr noalias %C, i1 %c.0) {
+; CHECK-LABEL: @lifetimes_for_args_load1_in_different_block(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A:%.*]] = alloca <4 x double>, align 32
+; CHECK-NEXT: call void @init(ptr [[A]])
+; CHECK-NEXT: br i1 [[C:%.*]], label [[THEN:%.*]], label [[EXIT:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr double, ptr [[A]], i64 0
+; CHECK-NEXT: [[COL_LOAD:%.*]] = load <2 x double>, ptr [[TMP0]], align 8
+; CHECK-NEXT: [[VEC_GEP:%.*]] = getelementptr double, ptr [[TMP0]], i64 2
+; CHECK-NEXT: [[COL_LOAD1:%.*]] = load <2 x double>, ptr [[VEC_GEP]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr double, ptr [[B:%.*]], i64 0
+; CHECK-NEXT: [[COL_LOAD2:%.*]] = load <2 x double>, ptr [[TMP1]], align 8
+; CHECK-NEXT: [[VEC_GEP3:%.*]] = getelementptr double, ptr [[TMP1]], i64 2
+; CHECK-NEXT: [[COL_LOAD4:%.*]] = load <2 x double>, ptr [[VEC_GEP3]], align 8
+; CHECK-NEXT: [[BLOCK:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement <1 x double> poison, double [[TMP2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP3:%.*]] = fmul contract <1 x double> [[BLOCK]], [[SPLAT_SPLAT]]
+; CHECK-NEXT: [[BLOCK5:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP4:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT6:%.*]] = insertelement <1 x double> poison, double [[TMP4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT7:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT6]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK5]], <1 x double> [[SPLAT_SPLAT7]], <1 x double> [[TMP3]])
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <1 x double> [[TMP5]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP6]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK8:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK9:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT10:%.*]] = insertelement <1 x double> poison, double [[TMP8]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT11:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT10]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP9:%.*]] = fmul contract <1 x double> [[BLOCK9]], [[SPLAT_SPLAT11]]
+; CHECK-NEXT: [[BLOCK12:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP10:%.*]] = extractelement <2 x double> [[COL_LOAD2]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT13:%.*]] = insertelement <1 x double> poison, double [[TMP10]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT14:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT13]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK12]], <1 x double> [[SPLAT_SPLAT14]], <1 x double> [[TMP9]])
+; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <1 x double> [[TMP11]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <2 x double> [[TMP7]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[BLOCK15:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP14:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT16:%.*]] = insertelement <1 x double> poison, double [[TMP14]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT17:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT16]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP15:%.*]] = fmul contract <1 x double> [[BLOCK15]], [[SPLAT_SPLAT17]]
+; CHECK-NEXT: [[BLOCK18:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP16:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT19:%.*]] = insertelement <1 x double> poison, double [[TMP16]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT20:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT19]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP17:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK18]], <1 x double> [[SPLAT_SPLAT20]], <1 x double> [[TMP15]])
+; CHECK-NEXT: [[TMP18:%.*]] = shufflevector <1 x double> [[TMP17]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> zeroinitializer, <2 x double> [[TMP18]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[BLOCK21:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[BLOCK22:%.*]] = shufflevector <2 x double> [[COL_LOAD]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP20:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLATINSERT23:%.*]] = insertelement <1 x double> poison, double [[TMP20]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT24:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT23]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP21:%.*]] = fmul contract <1 x double> [[BLOCK22]], [[SPLAT_SPLAT24]]
+; CHECK-NEXT: [[BLOCK25:%.*]] = shufflevector <2 x double> [[COL_LOAD1]], <2 x double> poison, <1 x i32> <i32 1>
+; CHECK-NEXT: [[TMP22:%.*]] = extractelement <2 x double> [[COL_LOAD4]], i64 1
+; CHECK-NEXT: [[SPLAT_SPLATINSERT26:%.*]] = insertelement <1 x double> poison, double [[TMP22]], i64 0
+; CHECK-NEXT: [[SPLAT_SPLAT27:%.*]] = shufflevector <1 x double> [[SPLAT_SPLATINSERT26]], <1 x double> poison, <1 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP23:%.*]] = call contract <1 x double> @llvm.fmuladd.v1f64(<1 x double> [[BLOCK25]], <1 x double> [[SPLAT_SPLAT27]], <1 x double> [[TMP21]])
+; CHECK-NEXT: [[TMP24:%.*]] = shufflevector <1 x double> [[TMP23]], <1 x double> poison, <2 x i32> <i32 0, i32 poison>
+; CHECK-NEXT: [[TMP25:%.*]] = shufflevector <2 x double> [[TMP19]], <2 x double> [[TMP24]], <2 x i32> <i32 0, i32 2>
+; CHECK-NEXT: [[TMP26:%.*]] = getelementptr double, ptr [[C1:%.*]], i64 0
+; CHECK-NEXT: store <2 x double> [[TMP13]], ptr [[TMP26]], align 8
+; CHECK-NEXT: [[VEC_GEP28:%.*]] = getelementptr double, ptr [[TMP26]], i64 2
+; CHECK-NEXT: store <2 x double> [[TMP25]], ptr [[VEC_GEP28]], align 8
+; CHECK-NEXT: br label [[EXIT]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ %A = alloca <4 x double>
+ call void @init(ptr %A)
+ %b = load <4 x double>, ptr %B, align 8
+ call void @llvm.lifetime.end(i64 -1, ptr %B)
+ br i1 %c.0, label %then, label %exit
+
+then:
+ %a = load <4 x double>, ptr %A, align 8
+ %m = call <4 x double> @llvm.matrix.multiply(<4 x double> %a, <4 x double> %b, i32 2, i32 2, i32 2)
+ store <4 x double> %m, ptr %C, align 8
+ br label %exit
+
+exit:
+ call void @llvm.lifetime.end(i64 -1, ptr %A)
+ ret void
+}
+
declare void @init(ptr)
declare void @llvm.lifetime.end(i64, ptr)
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib
new file mode 100755
index 000000000000..051e28f33d74
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib
Binary files differ
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib
new file mode 100755
index 000000000000..d3a339057abc
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib
Binary files differ
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test
new file mode 100644
index 000000000000..b1b96a41a329
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test
@@ -0,0 +1,86 @@
+RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
+RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
+
+RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
+RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
+
+CHK32: baseMethods 0x660 (struct method_list_t *)
+CHK32-NEXT: entsize 12 (relative)
+CHK32-NEXT: count 3
+CHK32-NEXT: name 0x144 (0x{{[0-9a-f]*}}) instance_method_00
+CHK32-NEXT: types 0x91 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffff18 (0x{{[0-9a-f]*}}) -[MyClass instance_method_00]
+CHK32-NEXT: name 0x13c (0x{{[0-9a-f]*}}) instance_method_01
+CHK32-NEXT: types 0x85 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffff28 (0x{{[0-9a-f]*}}) -[MyClass instance_method_01]
+CHK32-NEXT: name 0x134 (0x{{[0-9a-f]*}}) instance_method_02
+CHK32-NEXT: types 0x79 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffff38 (0x{{[0-9a-f]*}}) -[MyClass instance_method_02]
+
+CHK32: baseMethods 0x630 (struct method_list_t *)
+CHK32-NEXT: entsize 12 (relative)
+CHK32-NEXT: count 3
+CHK32-NEXT: name 0x180 (0x{{[0-9a-f]*}}) class_method_00
+CHK32-NEXT: types 0xc1 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffff9c (0x{{[0-9a-f]*}}) +[MyClass class_method_00]
+CHK32-NEXT: name 0x178 (0x{{[0-9a-f]*}}) class_method_01
+CHK32-NEXT: types 0xb5 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffffac (0x{{[0-9a-f]*}}) +[MyClass class_method_01]
+CHK32-NEXT: name 0x170 (0x{{[0-9a-f]*}}) class_method_02
+CHK32-NEXT: types 0xa9 (0x{{[0-9a-f]*}}) v8@0:4
+CHK32-NEXT: imp 0xffffffbc (0x{{[0-9a-f]*}}) +[MyClass class_method_02]
+
+CHK64: baseMethods 0x6e0 (struct method_list_t *)
+CHK64-NEXT: entsize 12 (relative)
+CHK64-NEXT: count 3
+CHK64-NEXT: name 0x188 (0x{{[0-9a-f]*}}) instance_method_00
+CHK64-NEXT: types 0x91 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffffa8 (0x{{[0-9a-f]*}}) -[MyClass instance_method_00]
+CHK64-NEXT: name 0x184 (0x{{[0-9a-f]*}}) instance_method_01
+CHK64-NEXT: types 0x85 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffffa0 (0x{{[0-9a-f]*}}) -[MyClass instance_method_01]
+CHK64-NEXT: name 0x180 (0x{{[0-9a-f]*}}) instance_method_02
+CHK64-NEXT: types 0x79 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffff98 (0x{{[0-9a-f]*}}) -[MyClass instance_method_02]
+
+CHK64: baseMethods 0x6b0 (struct method_list_t *)
+CHK64-NEXT: entsize 12 (relative)
+CHK64-NEXT: count 3
+CHK64-NEXT: name 0x1d0 (0x{{[0-9a-f]*}}) class_method_00
+CHK64-NEXT: types 0xc1 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffffe4 (0x{{[0-9a-f]*}}) +[MyClass class_method_00]
+CHK64-NEXT: name 0x1cc (0x{{[0-9a-f]*}}) class_method_01
+CHK64-NEXT: types 0xb5 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffffdc (0x{{[0-9a-f]*}}) +[MyClass class_method_01]
+CHK64-NEXT: name 0x1c8 (0x{{[0-9a-f]*}}) class_method_02
+CHK64-NEXT: types 0xa9 (0x{{[0-9a-f]*}}) v16@0:8
+CHK64-NEXT: imp 0xffffffd4 (0x{{[0-9a-f]*}}) +[MyClass class_method_02]
+
+######## Generate rel-method-lists-arm64.dylib ########
+// clang -c main.mm -o main.o -target arm64-apple-macos -arch arm64
+// ld64.ld64 -dylib -demangle -dynamic main.o -o rel-method-lists-arm64.dylib -syslibroot MacOSX14.2.sdk -segalign 0x10 -objc_relative_method_lists
+
+######## Generate rel-method-lists-arm64_32.dylib ########
+// clang -c main.mm -o main.o -target arm64_32-apple-watchos -arch arm64_32
+// ld64.ld64 -dylib -demangle -dynamic main.o -o rel-method-lists-arm64_32.dylib -syslibroot WatchOS.sdk -segalign 0x10 -objc_relative_method_lists
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~ main.mm ~~~~~~~~~~~~~~~~~~~~~~~~~
+__attribute__((objc_root_class))
+@interface MyClass
+- (void)instance_method_00;
+- (void)instance_method_01;
+- (void)instance_method_02;
++ (void)class_method_00;
++ (void)class_method_01;
++ (void)class_method_02;
+@end
+@implementation MyClass
+- (void)instance_method_00 {}
+- (void)instance_method_01 {}
+- (void)instance_method_02 {}
++ (void)class_method_00 {}
++ (void)class_method_01 {}
++ (void)class_method_02 {}
+@end
+void *_objc_empty_cache;
+void *_objc_empty_vtable;
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 0e6935c0ac58..1b0e5ba279d0 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -3661,6 +3661,10 @@ struct class_ro32_t {
#define RO_ROOT (1 << 1)
#define RO_HAS_CXX_STRUCTORS (1 << 2)
+/* Values for method_list{64,32}_t->entsize */
+#define ML_HAS_RELATIVE_PTRS (1 << 31)
+#define ML_ENTSIZE_MASK 0xFFFF
+
struct method_list64_t {
uint32_t entsize;
uint32_t count;
@@ -3685,6 +3689,12 @@ struct method32_t {
uint32_t imp; /* IMP (32-bit pointer) */
};
+struct method_relative_t {
+ int32_t name; /* SEL (32-bit relative) */
+ int32_t types; /* const char * (32-bit relative) */
+ int32_t imp; /* IMP (32-bit relative) */
+};
+
struct protocol_list64_t {
uint64_t count; /* uintptr_t (a 64-bit value) */
/* struct protocol64_t * list[0]; These pointers follow inline */
@@ -3986,6 +3996,12 @@ inline void swapStruct(struct method32_t &m) {
sys::swapByteOrder(m.imp);
}
+inline void swapStruct(struct method_relative_t &m) {
+ sys::swapByteOrder(m.name);
+ sys::swapByteOrder(m.types);
+ sys::swapByteOrder(m.imp);
+}
+
inline void swapStruct(struct protocol_list64_t &pl) {
sys::swapByteOrder(pl.count);
}
@@ -4440,6 +4456,84 @@ static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
print_layout_map(layout_map, left);
}
+static void print_relative_method_list(uint32_t structSizeAndFlags,
+ uint32_t structCount, uint64_t p,
+ struct DisassembleInfo *info,
+ const char *indent,
+ uint32_t pointerBits) {
+ struct method_relative_t m;
+ const char *r, *name;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+
+ assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&
+ "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");
+
+ outs() << indent << "\t\t entsize "
+ << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";
+ outs() << indent << "\t\t count " << structCount << "\n";
+
+ for (i = 0; i < structCount; i++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ memset(&m, '\0', sizeof(struct method_relative_t));
+ if (left < sizeof(struct method_relative_t)) {
+ memcpy(&m, r, left);
+ outs() << indent << " (method_t extends past the end of the section)\n";
+ } else
+ memcpy(&m, r, sizeof(struct method_relative_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(m);
+
+ outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
+ uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);
+ uint64_t absNameRefVA = relNameRefVA + m.name;
+ outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
+
+ // since this is a relative list, absNameRefVA is the address of the
+ // __objc_selrefs entry, so a pointer, not the actual name
+ const char *nameRefPtr =
+ get_pointer_64(absNameRefVA, xoffset, left, xS, info);
+ if (nameRefPtr) {
+ uint32_t pointerSize = pointerBits / CHAR_BIT;
+ if (left < pointerSize)
+ outs() << indent << " (nameRefPtr extends past the end of the section)";
+ else {
+ if (pointerSize == 64) {
+ name = get_pointer_64(*reinterpret_cast<const uint64_t *>(nameRefPtr),
+ xoffset, left, xS, info);
+ } else {
+ name = get_pointer_32(*reinterpret_cast<const uint32_t *>(nameRefPtr),
+ xoffset, left, xS, info);
+ }
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ }
+ }
+ outs() << "\n";
+
+ outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
+ uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);
+ uint64_t absTypesVA = relTypesVA + m.types;
+ outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
+ name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
+ uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);
+ uint64_t absImpVA = relImpVA + m.imp;
+ outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
+ name = GuessSymbolName(absImpVA, info->AddrMap);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ p += sizeof(struct method_relative_t);
+ offset += sizeof(struct method_relative_t);
+ }
+}
+
static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
const char *indent) {
struct method_list64_t ml;
@@ -4461,10 +4555,17 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
memcpy(&ml, r, sizeof(struct method_list64_t));
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
swapStruct(ml);
+ p += sizeof(struct method_list64_t);
+
+ if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
+ print_relative_method_list(ml.entsize, ml.count, p, info, indent,
+ /*pointerBits=*/64);
+ return;
+ }
+
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
outs() << indent << "\t\t count " << ml.count << "\n";
- p += sizeof(struct method_list64_t);
offset += sizeof(struct method_list64_t);
for (i = 0; i < ml.count; i++) {
r = get_pointer_64(p, offset, left, S, info);
@@ -4552,10 +4653,17 @@ static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
memcpy(&ml, r, sizeof(struct method_list32_t));
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
swapStruct(ml);
+ p += sizeof(struct method_list32_t);
+
+ if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
+ print_relative_method_list(ml.entsize, ml.count, p, info, indent,
+ /*pointerBits=*/32);
+ return;
+ }
+
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
outs() << indent << "\t\t count " << ml.count << "\n";
- p += sizeof(struct method_list32_t);
offset += sizeof(struct method_list32_t);
for (i = 0; i < ml.count; i++) {
r = get_pointer_32(p, offset, left, S, info);
diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 8a070d256398..c591e5056480 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -17,6 +17,7 @@
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/ShapedOpInterfaces.h"
+#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Support/MathExtras.h"
#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/ScopeExit.h"
@@ -220,6 +221,8 @@ void AffineDialect::initialize() {
#include "mlir/Dialect/Affine/IR/AffineOps.cpp.inc"
>();
addInterfaces<AffineInlinerInterface>();
+ declarePromisedInterfaces<ValueBoundsOpInterface, AffineApplyOp, AffineMaxOp,
+ AffineMinOp>();
}
/// Materialize a single constant operation from a given attribute value with
diff --git a/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp b/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
index 745c5706a838..6a593185cced 100644
--- a/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
+++ b/mlir/lib/Dialect/Arith/IR/ArithDialect.cpp
@@ -8,9 +8,12 @@
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/UB/IR/UBOps.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/DialectImplementation.h"
+#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/TypeSwitch.h"
@@ -46,6 +49,12 @@ void arith::ArithDialect::initialize() {
>();
addInterfaces<ArithInlinerInterface>();
declarePromisedInterface<ArithDialect, ConvertToLLVMPatternInterface>();
+ declarePromisedInterface<SelectOp,
+ bufferization::BufferDeallocationOpInterface>();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface, ConstantOp,
+ IndexCastOp, SelectOp>();
+ declarePromisedInterfaces<ValueBoundsOpInterface, AddIOp, ConstantOp, SubIOp,
+ MulIOp>();
}
/// Materialize an integer or floating point constant.
diff --git a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
index 34a0c594a5a5..2b226c7a1207 100644
--- a/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
+++ b/mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
@@ -252,16 +252,6 @@ LogicalResult AllocTensorOp::verify() {
<< getType().getNumDynamicDims() << " dynamic sizes";
if (getCopy() && getCopy().getType() != getType())
return emitError("expected that `copy` and return type match");
-
- // For sparse tensor allocation, we require that none of its
- // uses escapes the function boundary directly.
- if (sparse_tensor::getSparseTensorEncoding(getType())) {
- for (auto &use : getOperation()->getUses())
- if (isa<func::ReturnOp, func::CallOp, func::CallIndirectOp>(
- use.getOwner()))
- return emitError("sparse tensor allocation should not escape function");
- }
-
return success();
}
diff --git a/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp b/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
index d242d75bd51f..c6b02b9703e7 100644
--- a/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
+++ b/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
@@ -10,6 +10,8 @@
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Builders.h"
@@ -69,6 +71,10 @@ void ControlFlowDialect::initialize() {
>();
addInterfaces<ControlFlowInlinerInterface>();
declarePromisedInterface<ControlFlowDialect, ConvertToLLVMPatternInterface>();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface, BranchOp,
+ CondBranchOp>();
+ declarePromisedInterface<CondBranchOp,
+ bufferization::BufferDeallocationOpInterface>();
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/Func/IR/FuncOps.cpp b/mlir/lib/Dialect/Func/IR/FuncOps.cpp
index d18ec279e85c..ed2ecfe9d0fb 100644
--- a/mlir/lib/Dialect/Func/IR/FuncOps.cpp
+++ b/mlir/lib/Dialect/Func/IR/FuncOps.cpp
@@ -9,6 +9,7 @@
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/IRMapping.h"
@@ -43,6 +44,8 @@ void FuncDialect::initialize() {
>();
declarePromisedInterface<FuncDialect, DialectInlinerInterface>();
declarePromisedInterface<FuncDialect, ConvertToLLVMPatternInterface>();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface, CallOp,
+ FuncOp, ReturnOp>();
}
/// Materialize a single constant operation from a given attribute value with
diff --git a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
index 33ce5c159db4..a02eca8b1179 100644
--- a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
+++ b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
@@ -13,6 +13,7 @@
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
@@ -215,6 +216,8 @@ void GPUDialect::initialize() {
#include "mlir/Dialect/GPU/IR/GPUOpsAttributes.cpp.inc"
>();
addInterfaces<GPUInlinerInterface>();
+ declarePromisedInterface<TerminatorOp,
+ bufferization::BufferDeallocationOpInterface>();
}
static std::string getSparseHandleKeyword(SparseHandleKind kind) {
diff --git a/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp b/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp
index 027058d4de63..a6936fde4370 100644
--- a/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp
+++ b/mlir/lib/Dialect/Linalg/IR/LinalgDialect.cpp
@@ -21,7 +21,10 @@
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/DialectImplementation.h"
+#include "mlir/Interfaces/DestinationStyleOpInterface.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
+#include "mlir/Interfaces/SubsetOpInterface.h"
+#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Parser/Parser.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Transforms/InliningUtils.h"
@@ -125,6 +128,23 @@ void mlir::linalg::LinalgDialect::initialize() {
#define GET_OP_LIST
#include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
>();
+ declarePromisedInterface<CopyOp, SubsetOpInterface>();
+ declarePromisedInterface<CopyOp, SubsetInsertionOpInterface>();
+ declarePromisedInterface<IndexOp, ValueBoundsOpInterface>();
+ declarePromisedInterface<linalg::GenericOp, TilingInterface>();
+ declarePromisedInterface<linalg::GenericOp, PartialReductionOpInterface>();
+ declarePromisedInterfaces<TilingInterface,
+#define GET_OP_LIST
+#include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
+ >();
+ declarePromisedInterfaces<PartialReductionOpInterface,
+#define GET_OP_LIST
+#include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
+ >();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface,
+#define GET_OP_LIST
+#include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc"
+ >();
}
LogicalResult LinalgDialect::verifyOperationAttribute(Operation *op,
diff --git a/mlir/lib/Dialect/MLProgram/IR/CMakeLists.txt b/mlir/lib/Dialect/MLProgram/IR/CMakeLists.txt
index 90c9c9aa7875..725bb5fd9da9 100644
--- a/mlir/lib/Dialect/MLProgram/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/MLProgram/IR/CMakeLists.txt
@@ -15,5 +15,6 @@ add_mlir_dialect_library(MLIRMLProgramDialect
MLIRControlFlowInterfaces
MLIRFunctionInterfaces
MLIRInferTypeOpInterface
+ MLIRTransforms
MLIRIR
)
diff --git a/mlir/lib/Dialect/MLProgram/IR/MLProgramDialect.cpp b/mlir/lib/Dialect/MLProgram/IR/MLProgramDialect.cpp
index 1a8fe208d409..bda1032ed988 100644
--- a/mlir/lib/Dialect/MLProgram/IR/MLProgramDialect.cpp
+++ b/mlir/lib/Dialect/MLProgram/IR/MLProgramDialect.cpp
@@ -8,6 +8,7 @@
#include "mlir/Dialect/MLProgram/IR/MLProgram.h"
#include "mlir/IR/DialectImplementation.h"
+#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/TypeSwitch.h"
using namespace mlir;
@@ -24,6 +25,18 @@ using namespace mlir::ml_program;
#include "mlir/Dialect/MLProgram/IR/MLProgramTypes.cpp.inc"
namespace {
+
+struct MLProgramInlinerInterface : public DialectInlinerInterface {
+ using DialectInlinerInterface::DialectInlinerInterface;
+
+ bool isLegalToInline(Operation *, Region *, bool,
+ IRMapping &) const override {
+ // We have no specific opinion on whether ops defined in this dialect should
+ // be inlined.
+ return true;
+ }
+};
+
struct MLProgramOpAsmDialectInterface : public OpAsmDialectInterface {
using OpAsmDialectInterface::OpAsmDialectInterface;
@@ -53,5 +66,5 @@ void ml_program::MLProgramDialect::initialize() {
#include "mlir/Dialect/MLProgram/IR/MLProgramOps.cpp.inc"
>();
- addInterfaces<MLProgramOpAsmDialectInterface>();
+ addInterfaces<MLProgramInlinerInterface, MLProgramOpAsmDialectInterface>();
}
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
index d71669a274b8..41082a85a485 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
@@ -8,8 +8,13 @@
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Interfaces/MemorySlotInterfaces.h"
+#include "mlir/Interfaces/RuntimeVerifiableOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Transforms/InliningUtils.h"
#include <optional>
@@ -43,6 +48,13 @@ void mlir::memref::MemRefDialect::initialize() {
>();
addInterfaces<MemRefInlinerInterface>();
declarePromisedInterface<MemRefDialect, ConvertToLLVMPatternInterface>();
+ declarePromisedInterfaces<bufferization::AllocationOpInterface, AllocOp,
+ AllocaOp, ReallocOp>();
+ declarePromisedInterfaces<RuntimeVerifiableOpInterface, CastOp, ExpandShapeOp,
+ LoadOp, ReinterpretCastOp, StoreOp, SubViewOp>();
+ declarePromisedInterfaces<ValueBoundsOpInterface, AllocOp, AllocaOp, CastOp,
+ DimOp, GetGlobalOp, RankOp, SubViewOp>();
+ declarePromisedInterface<MemRefType, DestructurableTypeInterface>();
}
/// Finds the unique dealloc operation (if one exists) for `allocValue`.
diff --git a/mlir/lib/Dialect/SCF/IR/SCF.cpp b/mlir/lib/Dialect/SCF/IR/SCF.cpp
index 233e702dbb22..ddb9676eb4f6 100644
--- a/mlir/lib/Dialect/SCF/IR/SCF.cpp
+++ b/mlir/lib/Dialect/SCF/IR/SCF.cpp
@@ -9,6 +9,8 @@
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Arith/Utils/Utils.h"
+#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/SCF/IR/DeviceMappingInterface.h"
@@ -18,6 +20,7 @@
#include "mlir/IR/Matchers.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
+#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Support/MathExtras.h"
#include "mlir/Transforms/InliningUtils.h"
#include "llvm/ADT/MapVector.h"
@@ -71,6 +74,12 @@ void SCFDialect::initialize() {
#include "mlir/Dialect/SCF/IR/SCFOps.cpp.inc"
>();
addInterfaces<SCFInlinerInterface>();
+ declarePromisedInterfaces<bufferization::BufferDeallocationOpInterface,
+ InParallelOp, ReduceReturnOp>();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface, ConditionOp,
+ ExecuteRegionOp, ForOp, IfOp, IndexSwitchOp,
+ ForallOp, InParallelOp, WhileOp, YieldOp>();
+ declarePromisedInterface<ForOp, ValueBoundsOpInterface>();
}
/// Default callback for IfOp builders. Inserts a yield without arguments.
diff --git a/mlir/lib/Dialect/Shape/IR/Shape.cpp b/mlir/lib/Dialect/Shape/IR/Shape.cpp
index d9ee39a4e8dd..f5a3717f815d 100644
--- a/mlir/lib/Dialect/Shape/IR/Shape.cpp
+++ b/mlir/lib/Dialect/Shape/IR/Shape.cpp
@@ -11,6 +11,7 @@
#include "mlir/Dialect/Shape/IR/Shape.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/CommonFolders.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Traits.h"
@@ -143,6 +144,8 @@ void ShapeDialect::initialize() {
// still evolving it makes it simple to start with an unregistered ops and
// try different variants before actually defining the op.
allowUnknownOperations();
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface, AssumingOp,
+ AssumingYieldOp>();
}
Operation *ShapeDialect::materializeConstant(OpBuilder &builder,
diff --git a/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp b/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
index 7750efdd9add..6da51bb6b9ca 100644
--- a/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
+++ b/mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/SparseTensor/IR/SparseTensorType.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/DialectImplementation.h"
@@ -1956,6 +1957,10 @@ void SparseTensorDialect::initialize() {
#define GET_OP_LIST
#include "mlir/Dialect/SparseTensor/IR/SparseTensorOps.cpp.inc"
>();
+ declarePromisedInterfaces<
+ bufferization::BufferizableOpInterface, ConcatenateOp, ConvertOp, LoadOp,
+ NewOp, NumberOfEntriesOp, AssembleOp, DisassembleOp,
+ ToCoordinatesBufferOp, ToCoordinatesOp, ToPositionsOp, ToValuesOp>();
}
#define GET_OP_CLASSES
diff --git a/mlir/lib/Dialect/SparseTensor/Transforms/StageSparseOperations.cpp b/mlir/lib/Dialect/SparseTensor/Transforms/StageSparseOperations.cpp
index 5b4395cc31a4..c370d104e098 100644
--- a/mlir/lib/Dialect/SparseTensor/Transforms/StageSparseOperations.cpp
+++ b/mlir/lib/Dialect/SparseTensor/Transforms/StageSparseOperations.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/SparseTensor/IR/SparseTensor.h"
#include "mlir/Dialect/SparseTensor/IR/SparseTensorType.h"
#include "mlir/Dialect/SparseTensor/Transforms/Passes.h"
@@ -16,6 +17,37 @@ using namespace mlir::sparse_tensor;
namespace {
+struct GuardSparseAlloc
+ : public OpRewritePattern<bufferization::AllocTensorOp> {
+ using OpRewritePattern<bufferization::AllocTensorOp>::OpRewritePattern;
+
+ LogicalResult matchAndRewrite(bufferization::AllocTensorOp op,
+ PatternRewriter &rewriter) const override {
+ // Only rewrite sparse allocations.
+ if (!getSparseTensorEncoding(op.getResult().getType()))
+ return failure();
+
+ // Only rewrite sparse allocations that escape the method
+ // without any chance of a finalizing operation in between.
+ // Here we assume that sparse tensor setup never crosses
+ // method boundaries. The current rewriting only repairs
+ // the most obvious allocate-call/return cases.
+ if (!llvm::all_of(op->getUses(), [](OpOperand &use) {
+ return isa<func::ReturnOp, func::CallOp, func::CallIndirectOp>(
+ use.getOwner());
+ }))
+ return failure();
+
+ // Guard escaping empty sparse tensor allocations with a finalizing
+ // operation that leaves the underlying storage in a proper state
+ // before the tensor escapes across the method boundary.
+ rewriter.setInsertionPointAfter(op);
+ auto load = rewriter.create<LoadOp>(op.getLoc(), op.getResult(), true);
+ rewriter.replaceAllUsesExcept(op, load, load);
+ return success();
+ }
+};
+
template <typename StageWithSortOp>
struct StageUnorderedSparseOps : public OpRewritePattern<StageWithSortOp> {
using OpRewritePattern<StageWithSortOp>::OpRewritePattern;
@@ -37,6 +69,6 @@ struct StageUnorderedSparseOps : public OpRewritePattern<StageWithSortOp> {
} // namespace
void mlir::populateStageSparseOperationsPatterns(RewritePatternSet &patterns) {
- patterns.add<StageUnorderedSparseOps<ConvertOp>,
+ patterns.add<GuardSparseAlloc, StageUnorderedSparseOps<ConvertOp>,
StageUnorderedSparseOps<ConcatenateOp>>(patterns.getContext());
}
diff --git a/mlir/lib/Dialect/Tensor/IR/TensorDialect.cpp b/mlir/lib/Dialect/Tensor/IR/TensorDialect.cpp
index 62032ff301be..5ca9510408c3 100644
--- a/mlir/lib/Dialect/Tensor/IR/TensorDialect.cpp
+++ b/mlir/lib/Dialect/Tensor/IR/TensorDialect.cpp
@@ -8,8 +8,11 @@
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/Complex/IR/Complex.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
+#include "mlir/Dialect/Transform/IR/TransformInterfaces.h"
+#include "mlir/Interfaces/SubsetOpInterface.h"
#include "mlir/Transforms/InliningUtils.h"
using namespace mlir;
@@ -45,4 +48,22 @@ void TensorDialect::initialize() {
#include "mlir/Dialect/Tensor/IR/TensorOps.cpp.inc"
>();
addInterfaces<TensorInlinerInterface>();
+ declarePromisedInterfaces<
+ bufferization::BufferizableOpInterface, CastOp, CollapseShapeOp, DimOp,
+ EmptyOp, ExpandShapeOp, ExtractSliceOp, ExtractOp, FromElementsOp,
+ GenerateOp, InsertOp, InsertSliceOp, PadOp, ParallelInsertSliceOp, RankOp,
+ ReshapeOp, SplatOp>();
+ declarePromisedInterfaces<transform::FindPayloadReplacementOpInterface,
+ CollapseShapeOp, ExpandShapeOp, ExtractSliceOp,
+ InsertSliceOp, ReshapeOp>();
+ declarePromisedInterfaces<ReifyRankedShapedTypeOpInterface, ExpandShapeOp,
+ CollapseShapeOp, PadOp>();
+ declarePromisedInterfaces<SubsetOpInterface, ExtractSliceOp, InsertSliceOp,
+ ParallelInsertSliceOp>();
+ declarePromisedInterfaces<SubsetInsertionOpInterface, InsertSliceOp,
+ ParallelInsertSliceOp>();
+ declarePromisedInterface<ExtractSliceOp, SubsetExtractionOpInterface>();
+ declarePromisedInterfaces<TilingInterface, PadOp, PackOp, UnPackOp>();
+ declarePromisedInterfaces<ValueBoundsOpInterface, CastOp, DimOp, EmptyOp,
+ ExtractSliceOp, PadOp, RankOp>();
}
diff --git a/mlir/lib/Dialect/Tosa/CMakeLists.txt b/mlir/lib/Dialect/Tosa/CMakeLists.txt
index ba5343dcd7ac..1911405c63cd 100644
--- a/mlir/lib/Dialect/Tosa/CMakeLists.txt
+++ b/mlir/lib/Dialect/Tosa/CMakeLists.txt
@@ -12,6 +12,7 @@ add_mlir_dialect_library(MLIRTosaDialect
MLIRTosaDialectBytecodeIncGen
MLIRTosaOpsIncGen
MLIRTosaInterfacesIncGen
+ MLIRShardingInterfaceIncGen
LINK_LIBS PUBLIC
MLIRIR
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
index 62d07859e32f..f461e7e1a555 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaOps.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Tosa/IR/TosaOps.h"
+#include "mlir/Dialect/Mesh/Interfaces/ShardingInterface.h"
#include "mlir/Dialect/Quant/QuantOps.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Tosa/Utils/QuantUtils.h"
@@ -136,6 +137,14 @@ void TosaDialect::initialize() {
#include "mlir/Dialect/Tosa/IR/TosaAttributes.cpp.inc"
>();
addInterfaces<TosaDialectBytecodeInterface, TosaInlinerInterface>();
+ declarePromisedInterfaces<
+ mesh::ShardingInterface, ClampOp, SigmoidOp, TanhOp, AddOp,
+ ArithmeticRightShiftOp, BitwiseAndOp, BitwiseOrOp, BitwiseXorOp, DivOp,
+ LogicalAndOp, LogicalLeftShiftOp, LogicalRightShiftOp, LogicalOrOp,
+ LogicalXorOp, MaximumOp, MinimumOp, MulOp, PowOp, SubOp, AbsOp,
+ BitwiseNotOp, CeilOp, ClzOp, ExpOp, FloorOp, LogOp, LogicalNotOp,
+ NegateOp, ReciprocalOp, RsqrtOp, SelectOp, EqualOp, GreaterOp,
+ GreaterEqualOp, MatMulOp>();
}
Operation *TosaDialect::materializeConstant(OpBuilder &builder, Attribute value,
diff --git a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
index 75f6220ad8f3..35296824246e 100644
--- a/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
+++ b/mlir/lib/Dialect/Vector/IR/VectorOps.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/Affine/IR/ValueBoundsOpInterfaceImpl.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Arith/Utils/Utils.h"
+#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Utils/IndexingUtils.h"
@@ -31,6 +32,7 @@
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/TypeUtilities.h"
+#include "mlir/Interfaces/SubsetOpInterface.h"
#include "mlir/Interfaces/ValueBoundsOpInterface.h"
#include "mlir/Support/LLVM.h"
#include "mlir/Transforms/InliningUtils.h"
@@ -374,6 +376,14 @@ void VectorDialect::initialize() {
>();
addInterfaces<VectorInlinerInterface>();
+
+ declarePromisedInterfaces<bufferization::BufferizableOpInterface,
+ TransferReadOp, TransferWriteOp, GatherOp, MaskOp,
+ YieldOp>();
+ declarePromisedInterfaces<SubsetOpInterface, TransferReadOp,
+ TransferWriteOp>();
+ declarePromisedInterface<TransferReadOp, SubsetExtractionOpInterface>();
+ declarePromisedInterface<TransferWriteOp, SubsetInsertionOpInterface>();
}
/// Materialize a single constant operation from a given attribute value with
@@ -6054,7 +6064,7 @@ LogicalResult MaskOp::fold(FoldAdaptor adaptor,
maskableOp->dropAllUses();
maskableOp->moveBefore(getOperation());
- results.push_back(maskableOp->getResult(0));
+ llvm::append_range(results, maskableOp->getResults());
return success();
}
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index eaf9373e7616..e7e314f739fa 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -223,8 +223,10 @@ DebugTranslation::translateRecursive(DIRecursiveTypeAttrInterface attr) {
}
auto setRecursivePlaceholder = [&](llvm::DIType *placeholder) {
- auto [iter, inserted] =
+ [[maybe_unused]] auto [iter, inserted] =
recursiveTypeMap.try_emplace(recursiveId, placeholder);
+ (void)iter;
+ (void)inserted;
assert(inserted && "illegal reuse of recursive id");
};
diff --git a/mlir/test/Dialect/Bufferization/invalid.mlir b/mlir/test/Dialect/Bufferization/invalid.mlir
index 83f8ef786154..4ebdb0a8f049 100644
--- a/mlir/test/Dialect/Bufferization/invalid.mlir
+++ b/mlir/test/Dialect/Bufferization/invalid.mlir
@@ -26,29 +26,6 @@ func.func @alloc_tensor_copy_and_dims(%t: tensor<?xf32>, %sz: index) {
// -----
-#DCSR = #sparse_tensor.encoding<{ map = (d0, d1) -> (d0 : compressed, d1 : compressed) }>
-
-func.func @sparse_alloc_direct_return() -> tensor<20x40xf32, #DCSR> {
- // expected-error @+1{{sparse tensor allocation should not escape function}}
- %0 = bufferization.alloc_tensor() : tensor<20x40xf32, #DCSR>
- return %0 : tensor<20x40xf32, #DCSR>
-}
-
-// -----
-
-#DCSR = #sparse_tensor.encoding<{ map = (d0, d1) -> (d0 : compressed, d1 : compressed) }>
-
-func.func private @foo(tensor<20x40xf32, #DCSR>) -> ()
-
-func.func @sparse_alloc_call() {
- // expected-error @+1{{sparse tensor allocation should not escape function}}
- %0 = bufferization.alloc_tensor() : tensor<20x40xf32, #DCSR>
- call @foo(%0) : (tensor<20x40xf32, #DCSR>) -> ()
- return
-}
-
-// -----
-
// expected-error @+1{{invalid value for 'bufferization.access'}}
func.func private @invalid_buffer_access_type(tensor<*xf32> {bufferization.access = "foo"})
diff --git a/mlir/test/Dialect/MLProgram/inlining.mlir b/mlir/test/Dialect/MLProgram/inlining.mlir
new file mode 100644
index 000000000000..ac3677e1b928
--- /dev/null
+++ b/mlir/test/Dialect/MLProgram/inlining.mlir
@@ -0,0 +1,19 @@
+// RUN: mlir-opt %s -inline | FileCheck %s
+
+// Verifies that regions with operations from the ml_program dialect can
+// be inlined.
+
+ml_program.global private @global(dense<4> : tensor<4xi32>) : tensor<4xi32>
+
+// CHECK: @inline_into
+func.func @inline_into() -> tensor<4xi32> {
+ // CHECK-NOT: @inline_from
+ // CHECK: ml_program.global_load_const
+ %0 = call @inline_from() : () -> tensor<4xi32>
+ return %0 : tensor<4xi32>
+}
+
+func.func @inline_from() -> tensor<4xi32> {
+ %0 = ml_program.global_load_const @global : tensor<4xi32>
+ return %0 : tensor<4xi32>
+}
diff --git a/mlir/test/Dialect/SparseTensor/invalid.mlir b/mlir/test/Dialect/SparseTensor/invalid.mlir
index 48f28ef390ed..18851f29d8ea 100644
--- a/mlir/test/Dialect/SparseTensor/invalid.mlir
+++ b/mlir/test/Dialect/SparseTensor/invalid.mlir
@@ -868,16 +868,6 @@ func.func @sparse_sort_coo_no_perm(%arg0: index, %arg1: memref<?xindex>) -> (mem
// -----
-#CSR = #sparse_tensor.encoding<{map = (d0, d1) -> (d0 : dense, d1 : compressed)}>
-
-func.func @sparse_alloc_escapes(%arg0: index) -> tensor<10x?xf64, #CSR> {
- // expected-error@+1 {{sparse tensor allocation should not escape function}}
- %0 = bufferization.alloc_tensor(%arg0) : tensor<10x?xf64, #CSR>
- return %0: tensor<10x?xf64, #CSR>
-}
-
-// -----
-
#UnorderedCOO = #sparse_tensor.encoding<{map = (d0, d1) -> (d0 : compressed(nonunique, nonordered), d1 : singleton(nonordered))}>
#OrderedCOOPerm = #sparse_tensor.encoding<{map = (d0, d1) -> (d1 : compressed(nonunique), d0 : singleton)}>
diff --git a/mlir/test/Dialect/Vector/canonicalize.mlir b/mlir/test/Dialect/Vector/canonicalize.mlir
index 4c73a6271786..627ac54cf145 100644
--- a/mlir/test/Dialect/Vector/canonicalize.mlir
+++ b/mlir/test/Dialect/Vector/canonicalize.mlir
@@ -2483,6 +2483,18 @@ func.func @all_true_vector_mask(%a : vector<3x4xf32>) -> vector<3x4xf32> {
// -----
+// CHECK-LABEL: func @all_true_vector_mask_no_result(
+func.func @all_true_vector_mask_no_result(%a : vector<3x4xf32>, %m : memref<3x4xf32>) {
+// CHECK-NOT: vector.mask
+// CHECK: vector.transfer_write
+ %c0 = arith.constant 0 : index
+ %all_true = vector.constant_mask [3, 4] : vector<3x4xi1>
+ vector.mask %all_true { vector.transfer_write %a, %m[%c0, %c0] : vector<3x4xf32>, memref<3x4xf32> } : vector<3x4xi1>
+ return
+}
+
+// -----
+
// CHECK-LABEL: func.func @fold_shape_cast_with_mask(
// CHECK-SAME: %[[VAL_0:.*]]: tensor<1x?xf32>) -> vector<1x4xi1> {
func.func @fold_shape_cast_with_mask(%arg0: tensor<1x?xf32>) -> vector<1x4xi1> {
diff --git a/mlir/test/Integration/Dialect/Linalg/CPU/mmt4d.mlir b/mlir/test/Integration/Dialect/Linalg/CPU/mmt4d.mlir
index 8ee4e1fb48fe..92c7039c8496 100644
--- a/mlir/test/Integration/Dialect/Linalg/CPU/mmt4d.mlir
+++ b/mlir/test/Integration/Dialect/Linalg/CPU/mmt4d.mlir
@@ -1,6 +1,6 @@
// DEFINE: %{compile} = mlir-opt %s \
// DEFINE: -transform-interpreter -test-transform-dialect-erase-schedule \
-// DEFINE: -one-shot-bufferize -func-bufferize -cse -canonicalize -convert-vector-to-scf -test-lower-to-llvm -o %t
+// DEFINE: -one-shot-bufferize="bufferize-function-boundaries" -buffer-deallocation-pipeline -cse -canonicalize -convert-vector-to-scf -test-lower-to-llvm -o %t
// DEFINE: %{entry_point} = mmt4d
// DEFINE: %{run} = mlir-cpu-runner %t -e %{entry_point} -entry-point-result=void \
// DEFINE: -shared-libs=%mlir_runner_utils,%mlir_c_runner_utils
diff --git a/mlir/test/Integration/Dialect/Linalg/CPU/test-matmul-masked-vec.mlir b/mlir/test/Integration/Dialect/Linalg/CPU/test-matmul-masked-vec.mlir
index 0378d638df61..a70d794506c4 100644
--- a/mlir/test/Integration/Dialect/Linalg/CPU/test-matmul-masked-vec.mlir
+++ b/mlir/test/Integration/Dialect/Linalg/CPU/test-matmul-masked-vec.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-opt %s -transform-interpreter -test-transform-dialect-erase-schedule -one-shot-bufferize -func-bufferize -lower-vector-mask --test-lower-to-llvm | \
+// RUN: mlir-opt %s -transform-interpreter -test-transform-dialect-erase-schedule -one-shot-bufferize="bufferize-function-boundaries" -buffer-deallocation-pipeline -lower-vector-mask --test-lower-to-llvm | \
// RUN: mlir-cpu-runner -e main -entry-point-result=void --shared-libs=%mlir_c_runner_utils,%mlir_runner_utils | \
// RUN: FileCheck %s
diff --git a/mlir/test/Integration/Dialect/Memref/reinterpret-cast-runtime-verification.mlir b/mlir/test/Integration/Dialect/Memref/reinterpret-cast-runtime-verification.mlir
index 370029154054..2239ba50b662 100644
--- a/mlir/test/Integration/Dialect/Memref/reinterpret-cast-runtime-verification.mlir
+++ b/mlir/test/Integration/Dialect/Memref/reinterpret-cast-runtime-verification.mlir
@@ -34,7 +34,8 @@ func.func @main() {
%5 = arith.constant 5 : index
%alloca_1 = memref.alloca() : memref<1xf32>
- %alloc_4 = memref.alloc(%4) : memref<?xf32>
+ %alloca_4 = memref.alloca() : memref<4xf32>
+ %alloca_4_dyn = memref.cast %alloca_4 : memref<4xf32> to memref<?xf32>
// Offset is out-of-bounds
// CHECK: ERROR: Runtime op verification failed
@@ -55,20 +56,20 @@ func.func @main() {
// CHECK-NEXT: "memref.reinterpret_cast"(%{{.*}})
// CHECK-NEXT: ^ result of reinterpret_cast is out-of-bounds of the base memref
// CHECK-NEXT: Location: loc({{.*}})
- func.call @reinterpret_cast_fully_dynamic(%alloc_4, %0, %5, %1) : (memref<?xf32>, index, index, index) -> ()
+ func.call @reinterpret_cast_fully_dynamic(%alloca_4_dyn, %0, %5, %1) : (memref<?xf32>, index, index, index) -> ()
// Stride is out-of-bounds
// CHECK: ERROR: Runtime op verification failed
// CHECK-NEXT: "memref.reinterpret_cast"(%{{.*}})
// CHECK-NEXT: ^ result of reinterpret_cast is out-of-bounds of the base memref
// CHECK-NEXT: Location: loc({{.*}})
- func.call @reinterpret_cast_fully_dynamic(%alloc_4, %0, %4, %4) : (memref<?xf32>, index, index, index) -> ()
+ func.call @reinterpret_cast_fully_dynamic(%alloca_4_dyn, %0, %4, %4) : (memref<?xf32>, index, index, index) -> ()
// CHECK-NOT: ERROR: Runtime op verification failed
func.call @reinterpret_cast(%alloca_1, %0) : (memref<1xf32>, index) -> ()
// CHECK-NOT: ERROR: Runtime op verification failed
- func.call @reinterpret_cast_fully_dynamic(%alloc_4, %0, %4, %1) : (memref<?xf32>, index, index, index) -> ()
+ func.call @reinterpret_cast_fully_dynamic(%alloca_4_dyn, %0, %4, %1) : (memref<?xf32>, index, index, index) -> ()
return
}
diff --git a/mlir/test/Integration/Dialect/Memref/subview-runtime-verification.mlir b/mlir/test/Integration/Dialect/Memref/subview-runtime-verification.mlir
index 48987ce216f1..3ccf8b1be6d7 100644
--- a/mlir/test/Integration/Dialect/Memref/subview-runtime-verification.mlir
+++ b/mlir/test/Integration/Dialect/Memref/subview-runtime-verification.mlir
@@ -38,14 +38,15 @@ func.func @main() {
%5 = arith.constant 5 : index
%alloca = memref.alloca() : memref<1xf32>
- %alloc = memref.alloc(%4) : memref<?x4xf32>
+ %alloca_4 = memref.alloca() : memref<4x4xf32>
+ %alloca_4_dyn = memref.cast %alloca_4 : memref<4x4xf32> to memref<?x4xf32>
// Offset is out-of-bounds
// CHECK: ERROR: Runtime op verification failed
// CHECK-NEXT: "memref.subview"
// CHECK-NEXT: ^ subview is out-of-bounds of the base memref
// CHECK-NEXT: Location: loc({{.*}})
- func.call @subview_dynamic_rank_reduce(%alloc, %5, %5, %1) : (memref<?x4xf32>, index, index, index) -> ()
+ func.call @subview_dynamic_rank_reduce(%alloca_4_dyn, %5, %5, %1) : (memref<?x4xf32>, index, index, index) -> ()
// Offset is out-of-bounds
// CHECK: ERROR: Runtime op verification failed
@@ -66,23 +67,23 @@ func.func @main() {
// CHECK-NEXT: "memref.subview"
// CHECK-NEXT: ^ subview is out-of-bounds of the base memref
// CHECK-NEXT: Location: loc({{.*}})
- func.call @subview_dynamic(%alloc, %0, %5, %1) : (memref<?x4xf32>, index, index, index) -> ()
+ func.call @subview_dynamic(%alloca_4_dyn, %0, %5, %1) : (memref<?x4xf32>, index, index, index) -> ()
// Stride is out-of-bounds
// CHECK: ERROR: Runtime op verification failed
// CHECK-NEXT: "memref.subview"
// CHECK-NEXT: ^ subview is out-of-bounds of the base memref
// CHECK-NEXT: Location: loc({{.*}})
- func.call @subview_dynamic(%alloc, %0, %4, %4) : (memref<?x4xf32>, index, index, index) -> ()
+ func.call @subview_dynamic(%alloca_4_dyn, %0, %4, %4) : (memref<?x4xf32>, index, index, index) -> ()
// CHECK-NOT: ERROR: Runtime op verification failed
func.call @subview(%alloca, %0) : (memref<1xf32>, index) -> ()
// CHECK-NOT: ERROR: Runtime op verification failed
- func.call @subview_dynamic(%alloc, %0, %4, %1) : (memref<?x4xf32>, index, index, index) -> ()
+ func.call @subview_dynamic(%alloca_4_dyn, %0, %4, %1) : (memref<?x4xf32>, index, index, index) -> ()
// CHECK-NOT: ERROR: Runtime op verification failed
- func.call @subview_dynamic_rank_reduce(%alloc, %0, %1, %0) : (memref<?x4xf32>, index, index, index) -> ()
+ func.call @subview_dynamic_rank_reduce(%alloca_4_dyn, %0, %1, %0) : (memref<?x4xf32>, index, index, index) -> ()
return
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_empty.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_empty.mlir
new file mode 100755
index 000000000000..bcd71f7bd674
--- /dev/null
+++ b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_empty.mlir
@@ -0,0 +1,144 @@
+//--------------------------------------------------------------------------------------------------
+// WHEN CREATING A NEW TEST, PLEASE JUST COPY & PASTE WITHOUT EDITS.
+//
+// Set-up that's shared across all tests in this directory. In principle, this
+// config could be moved to lit.local.cfg. However, there are downstream users that
+// do not use these LIT config files. Hence why this is kept inline.
+//
+// DEFINE: %{sparsifier_opts} = enable-runtime-library=true
+// DEFINE: %{sparsifier_opts_sve} = enable-arm-sve=true %{sparsifier_opts}
+// DEFINE: %{compile} = mlir-opt %s --sparsifier="%{sparsifier_opts}"
+// DEFINE: %{compile_sve} = mlir-opt %s --sparsifier="%{sparsifier_opts_sve}"
+// DEFINE: %{run_libs} = -shared-libs=%mlir_c_runner_utils,%mlir_runner_utils
+// DEFINE: %{run_opts} = -e main -entry-point-result=void
+// DEFINE: %{run} = mlir-cpu-runner %{run_opts} %{run_libs}
+// DEFINE: %{run_sve} = %mcr_aarch64_cmd --march=aarch64 --mattr="+sve" %{run_opts} %{run_libs}
+//
+// DEFINE: %{env} =
+//--------------------------------------------------------------------------------------------------
+
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false enable-buffer-initialization=true
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and vectorization.
+// REDEFINE: %{sparsifier_opts} = enable-runtime-library=false enable-buffer-initialization=true vl=2 reassociate-fp-reductions=true enable-index-optimizations=true
+// RUN: %{compile} | %{run} | FileCheck %s
+//
+// Do the same run, but now with direct IR generation and VLA vectorization.
+// RUN: %if mlir_arm_sve_tests %{ %{compile_sve} | %{run_sve} | FileCheck %s %}
+
+
+#map = affine_map<(d0) -> (d0)>
+
+#SV = #sparse_tensor.encoding<{
+ map = (d0) -> (d0 : compressed)
+}>
+
+module {
+
+ // This directly yields an empty sparse vector.
+ func.func @empty() -> tensor<10xf32, #SV> {
+ %0 = tensor.empty() : tensor<10xf32, #SV>
+ return %0 : tensor<10xf32, #SV>
+ }
+
+ // This also directly yields an empty sparse vector.
+ func.func @empty_alloc() -> tensor<10xf32, #SV> {
+ %0 = bufferization.alloc_tensor() : tensor<10xf32, #SV>
+ return %0 : tensor<10xf32, #SV>
+ }
+
+ // This yields a hidden empty sparse vector (all zeros).
+ func.func @zeros() -> tensor<10xf32, #SV> {
+ %cst = arith.constant 0.0 : f32
+ %0 = bufferization.alloc_tensor() : tensor<10xf32, #SV>
+ %1 = linalg.generic {
+ indexing_maps = [#map],
+ iterator_types = ["parallel"]}
+ outs(%0 : tensor<10xf32, #SV>) {
+ ^bb0(%out: f32):
+ linalg.yield %cst : f32
+ } -> tensor<10xf32, #SV>
+ return %1 : tensor<10xf32, #SV>
+ }
+
+ // This yields a filled sparse vector (all ones).
+ func.func @ones() -> tensor<10xf32, #SV> {
+ %cst = arith.constant 1.0 : f32
+ %0 = bufferization.alloc_tensor() : tensor<10xf32, #SV>
+ %1 = linalg.generic {
+ indexing_maps = [#map],
+ iterator_types = ["parallel"]}
+ outs(%0 : tensor<10xf32, #SV>) {
+ ^bb0(%out: f32):
+ linalg.yield %cst : f32
+ } -> tensor<10xf32, #SV>
+ return %1 : tensor<10xf32, #SV>
+ }
+
+ //
+ // Main driver.
+ //
+ func.func @main() {
+
+ %0 = call @empty() : () -> tensor<10xf32, #SV>
+ %1 = call @empty_alloc() : () -> tensor<10xf32, #SV>
+ %2 = call @zeros() : () -> tensor<10xf32, #SV>
+ %3 = call @ones() : () -> tensor<10xf32, #SV>
+
+ //
+ // Verify the output. In particular, make sure that
+ // all empty sparse vector data structures are properly
+ // finalized with a pair (0,0) for positions.
+ //
+ // CHECK: ---- Sparse Tensor ----
+ // CHECK-NEXT: nse = 0
+ // CHECK-NEXT: dim = ( 10 )
+ // CHECK-NEXT: lvl = ( 10 )
+ // CHECK-NEXT: pos[0] : ( 0, 0,
+ // CHECK-NEXT: crd[0] : (
+ // CHECK-NEXT: values : (
+ // CHECK-NEXT: ----
+ //
+ // CHECK-NEXT: ---- Sparse Tensor ----
+ // CHECK-NEXT: nse = 0
+ // CHECK-NEXT: dim = ( 10 )
+ // CHECK-NEXT: lvl = ( 10 )
+ // CHECK-NEXT: pos[0] : ( 0, 0,
+ // CHECK-NEXT: crd[0] : (
+ // CHECK-NEXT: values : (
+ // CHECK-NEXT: ----
+ //
+ // CHECK-NEXT: ---- Sparse Tensor ----
+ // CHECK-NEXT: nse = 0
+ // CHECK-NEXT: dim = ( 10 )
+ // CHECK-NEXT: lvl = ( 10 )
+ // CHECK-NEXT: pos[0] : ( 0, 0,
+ // CHECK-NEXT: crd[0] : (
+ // CHECK-NEXT: values : (
+ // CHECK-NEXT: ----
+ //
+ // CHECK-NEXT: ---- Sparse Tensor ----
+ // CHECK-NEXT: nse = 10
+ // CHECK-NEXT: dim = ( 10 )
+ // CHECK-NEXT: lvl = ( 10 )
+ // CHECK-NEXT: pos[0] : ( 0, 10,
+ // CHECK-NEXT: crd[0] : ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ // CHECK-NEXT: values : ( 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ // CHECK-NEXT: ----
+ //
+ sparse_tensor.print %0 : tensor<10xf32, #SV>
+ sparse_tensor.print %1 : tensor<10xf32, #SV>
+ sparse_tensor.print %2 : tensor<10xf32, #SV>
+ sparse_tensor.print %3 : tensor<10xf32, #SV>
+
+ bufferization.dealloc_tensor %0 : tensor<10xf32, #SV>
+ bufferization.dealloc_tensor %1 : tensor<10xf32, #SV>
+ bufferization.dealloc_tensor %2 : tensor<10xf32, #SV>
+ bufferization.dealloc_tensor %3 : tensor<10xf32, #SV>
+ return
+ }
+}
diff --git a/mlir/test/Integration/Dialect/Tosa/CPU/test-fully-connected.mlir b/mlir/test/Integration/Dialect/Tosa/CPU/test-fully-connected.mlir
index bf178c826574..258b1b4f2fab 100644
--- a/mlir/test/Integration/Dialect/Tosa/CPU/test-fully-connected.mlir
+++ b/mlir/test/Integration/Dialect/Tosa/CPU/test-fully-connected.mlir
@@ -1,5 +1,5 @@
// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(tosa-to-linalg-named,tosa-to-linalg,tosa-to-arith))" | \
-// RUN: mlir-opt -one-shot-bufferize -func-bufferize -test-lower-to-llvm | \
+// RUN: mlir-opt -one-shot-bufferize="bufferize-function-boundaries" -buffer-deallocation-pipeline -test-lower-to-llvm | \
// RUN: mlir-cpu-runner -O3 -e main -entry-point-result=void \
// RUN: -shared-libs=%mlir_runner_utils \
// RUN: | FileCheck %s
diff --git a/openmp/libomptarget/plugins-nextgen/common/include/PluginInterface.h b/openmp/libomptarget/plugins-nextgen/common/include/PluginInterface.h
index 9645ab2a6726..118bb7d3051b 100644
--- a/openmp/libomptarget/plugins-nextgen/common/include/PluginInterface.h
+++ b/openmp/libomptarget/plugins-nextgen/common/include/PluginInterface.h
@@ -1393,7 +1393,7 @@ protected:
};
/// A static check on whether or not we support RPC in libomptarget.
-const bool libomptargetSupportsRPC();
+bool libomptargetSupportsRPC();
} // namespace plugin
} // namespace target
diff --git a/openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp b/openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp
index 8c8c52de0c21..414506f30b8f 100644
--- a/openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp
+++ b/openmp/libomptarget/plugins-nextgen/common/src/PluginInterface.cpp
@@ -1560,7 +1560,7 @@ Expected<bool> GenericPluginTy::checkELFImage(StringRef Image) const {
return isELFCompatible(Image);
}
-const bool llvm::omp::target::plugin::libomptargetSupportsRPC() {
+bool llvm::omp::target::plugin::libomptargetSupportsRPC() {
#ifdef LIBOMPTARGET_RPC_SUPPORT
return true;
#else
diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h
index 569a1ab9b477..885d6636abe4 100644
--- a/openmp/runtime/src/kmp.h
+++ b/openmp/runtime/src/kmp.h
@@ -1402,19 +1402,9 @@ extern void __kmp_query_cpuid(kmp_cpuinfo_t *p);
// subleaf is only needed for cache and topology discovery and can be set to
// zero in most cases
static inline void __kmp_x86_cpuid(int leaf, int subleaf, struct kmp_cpuid *p) {
-#if KMP_ARCH_X86 && (defined(__pic__) || defined(__PIC__))
- // on i386 arch, the ebx reg. is used by pic, thus we need to preserve from
- // being trashed beforehand
- __asm__ __volatile__("mov %%ebx, %%edi\n"
- "cpuid\n"
- "xchg %%edi, %%ebx\n"
- : "=a"(p->eax), "=b"(p->ebx), "=c"(p->ecx), "=d"(p->edx)
- : "a"(leaf), "c"(subleaf));
-#else
__asm__ __volatile__("cpuid"
: "=a"(p->eax), "=b"(p->ebx), "=c"(p->ecx), "=d"(p->edx)
: "a"(leaf), "c"(subleaf));
-#endif
}
// Load p into FPU control word
static inline void __kmp_load_x87_fpu_control_word(const kmp_int16 *p) {
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 073353a89c89..bb054b648102 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -528,6 +528,7 @@ libc_support_library(
":__support_cpp_type_traits",
":__support_ctype_utils",
":__support_str_to_num_result",
+ ":__support_uint128",
":errno",
],
)
diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
index c14869fe3867..0c67f331a5b6 100644
--- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
@@ -3889,6 +3889,7 @@ cc_library(
":ControlFlowInterfaces",
":DialectUtils",
":IR",
+ ":InliningUtils",
":LoopLikeInterface",
":MemRefDialect",
":ShapedOpInterfaces",
@@ -4296,6 +4297,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":LoopLikeInterface",
":MemRefDialect",
":ParallelCombiningOpInterface",
@@ -4367,6 +4369,18 @@ cc_library(
)
cc_library(
+ name = "InliningUtils",
+ srcs = ["lib/Transforms/Utils/InliningUtils.cpp"],
+ hdrs = ["include/mlir/Transforms/InliningUtils.h"],
+ includes = ["include"],
+ deps = [
+ ":CallOpInterfaces",
+ ":IR",
+ "//llvm:Support",
+ ],
+)
+
+cc_library(
name = "LoopLikeInterface",
srcs = ["lib/Interfaces/LoopLikeInterface.cpp"],
hdrs = ["include/mlir/Interfaces/LoopLikeInterface.h"],
@@ -4543,6 +4557,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MLIRShapeCanonicalizationIncGen",
":ShapeOpsIncGen",
":SideEffectInterfaces",
@@ -4706,6 +4721,7 @@ cc_library(
":ControlFlowOpsIncGen",
":ConvertToLLVMInterface",
":IR",
+ ":InliningUtils",
":SideEffectInterfaces",
":Support",
"//llvm:Support",
@@ -4742,7 +4758,7 @@ cc_library(
hdrs = glob([
"include/mlir/Dialect/Func/IR/*.h",
"include/mlir/Dialect/Func/Utils/*.h",
- ]) + ["include/mlir/Transforms/InliningUtils.h"],
+ ]),
includes = ["include"],
deps = [
":ArithDialect",
@@ -4756,6 +4772,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":SideEffectInterfaces",
":Support",
"//llvm:Support",
@@ -4772,6 +4789,7 @@ cc_library(
":FuncDialect",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MeshShardingInterface",
],
)
@@ -4928,6 +4946,7 @@ cc_library(
":DialectUtils",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MaskableOpInterface",
":MaskingOpInterface",
":MemRefDialect",
@@ -5344,7 +5363,6 @@ cc_library(
"include/mlir/Dialect/LLVMIR/*X86Vector*.h",
],
) + [
- "include/mlir/Transforms/InliningUtils.h",
"include/mlir/Transforms/Mem2Reg.h",
],
includes = ["include"],
@@ -5355,6 +5373,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":LLVMDialectInterfaceIncGen",
":LLVMIntrinsicOpsIncGen",
":LLVMOpsIncGen",
@@ -5561,6 +5580,7 @@ cc_library(
":IR",
":InferIntRangeInterface",
":InferTypeOpInterface",
+ ":InliningUtils",
":LLVMDialect",
":MemRefDialect",
":SCFDialect",
@@ -6895,7 +6915,7 @@ cc_library(
srcs = glob([
"lib/Dialect/SPIRV/IR/*.cpp",
"lib/Dialect/SPIRV/IR/*.h",
- ]) + ["include/mlir/Transforms/InliningUtils.h"],
+ ]),
hdrs = glob([
"include/mlir/Dialect/SPIRV/IR/*.h",
]),
@@ -6907,6 +6927,7 @@ cc_library(
":GPUDialect",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":Parser",
":SPIRVAttrUtilsGen",
":SPIRVAttributesIncGen",
@@ -7311,7 +7332,6 @@ gentbl_cc_library(
cc_library(
name = "TensorDialect",
srcs = [
- "include/mlir/Transforms/InliningUtils.h",
"lib/Dialect/Tensor/IR/TensorDialect.cpp",
"lib/Dialect/Tensor/IR/TensorOps.cpp",
"lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp",
@@ -7332,6 +7352,7 @@ cc_library(
":DialectUtils",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":LoopLikeInterface",
":ParallelCombiningOpInterface",
":ShapedOpInterfaces",
@@ -7522,15 +7543,19 @@ cc_library(
cc_library(
name = "TransformUtils",
- srcs = glob([
- "lib/Transforms/Utils/*.cpp",
- "lib/Transforms/Utils/*.h",
- ]),
+ srcs = glob(
+ include = [
+ "lib/Transforms/Utils/*.cpp",
+ "lib/Transforms/Utils/*.h",
+ ],
+ exclude = ["lib/Transforms/Utils/InliningUtils.cpp"],
+ ),
hdrs = glob(
- [
- "include/mlir/Transforms/*.h",
+ include = ["include/mlir/Transforms/*.h"],
+ exclude = [
+ "include/mlir/Transforms/InliningUtils.h",
+ "include/mlir/Transforms/Passes.h",
],
- exclude = ["include/mlir/Transforms/Passes.h"],
),
includes = ["include"],
deps = [
@@ -7538,6 +7563,7 @@ cc_library(
":ControlFlowInterfaces",
":FunctionInterfaces",
":IR",
+ ":InliningUtils",
":LoopLikeInterface",
":MemorySlotInterfaces",
":Pass",
@@ -7867,6 +7893,7 @@ cc_library(
":ControlFlowInterfaces",
":FunctionInterfaces",
":IR",
+ ":InliningUtils",
":LoopLikeInterface",
":MemorySlotInterfaces",
":Pass",
@@ -10963,6 +10990,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":LinalgEnumsIncGen",
":LinalgInterfacesIncGen",
":LinalgNamedStructuredOpsYamlIncGen",
@@ -11709,6 +11737,7 @@ cc_library(
":FuncDialect",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":LoopLikeInterface",
":MeshDialect",
":MeshShardingInterface",
@@ -12323,6 +12352,7 @@ cc_library(
":ConvertToLLVMInterface",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":SideEffectInterfaces",
"//llvm:Support",
],
@@ -12574,7 +12604,6 @@ cc_library(
],
hdrs = [
"include/mlir/Dialect/Arith/IR/Arith.h",
- "include/mlir/Transforms/InliningUtils.h",
],
includes = ["include"],
deps = [
@@ -12589,6 +12618,7 @@ cc_library(
":InferIntRangeCommon",
":InferIntRangeInterface",
":InferTypeOpInterface",
+ ":InliningUtils",
":Support",
":UBDialect",
":VectorInterfaces",
@@ -12750,6 +12780,7 @@ cc_library(
":ConvertToLLVMInterface",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MathBaseIncGen",
":MathOpsIncGen",
":SideEffectInterfaces",
@@ -12898,6 +12929,7 @@ cc_library(
":DialectUtils",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MemRefBaseIncGen",
":MemRefOpsIncGen",
":MemorySlotInterfaces",
@@ -13521,6 +13553,7 @@ cc_library(
":FunctionInterfaces",
":IR",
":InferTypeOpInterface",
+ ":InliningUtils",
":MemRefDialect",
":SparseTensorDialect",
":SubsetOpInterface",
@@ -13918,7 +13951,6 @@ gentbl_cc_library(
cc_library(
name = "UBDialect",
srcs = [
- "include/mlir/Transforms/InliningUtils.h",
"lib/Dialect/UB/IR/UBOps.cpp",
],
hdrs = ["include/mlir/Dialect/UB/IR/UBOps.h"],
@@ -13926,6 +13958,7 @@ cc_library(
deps = [
":ConvertToLLVMInterface",
":IR",
+ ":InliningUtils",
":SideEffectInterfaces",
":UBOpsIncGen",
":UBOpsInterfacesIncGen",
diff --git a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
index 91706af935ac..ccfef3f24340 100644
--- a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
@@ -399,6 +399,7 @@ cc_library(
"//mlir:IR",
"//mlir:InferIntRangeInterface",
"//mlir:InferTypeOpInterface",
+ "//mlir:InliningUtils",
"//mlir:LLVMDialect",
"//mlir:LinalgDialect",
"//mlir:LoopLikeInterface",
@@ -407,7 +408,6 @@ cc_library(
"//mlir:SideEffectInterfaces",
"//mlir:Support",
"//mlir:TensorDialect",
- "//mlir:TransformUtils",
"//mlir:Transforms",
"//mlir:ViewLikeInterface",
],
@@ -532,7 +532,7 @@ cc_library(
"//mlir:PDLInterpDialect",
"//mlir:Pass",
"//mlir:Support",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -570,7 +570,7 @@ cc_library(
"//mlir:SCFDialect",
"//mlir:SPIRVDialect",
"//mlir:Support",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -600,7 +600,7 @@ cc_library(
"//mlir:Pass",
"//mlir:SCFDialect",
"//mlir:SCFTransforms",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -695,7 +695,6 @@ cc_library(
"//mlir:SCFToControlFlow",
"//mlir:SPIRVDialect",
"//mlir:ToLLVMIRTranslation",
- "//mlir:TransformUtils",
"//mlir:Transforms",
"//mlir:VectorDialect",
"//mlir:VectorToLLVM",
@@ -728,7 +727,6 @@ cc_library(
"//mlir:SCFTransforms",
"//mlir:TensorDialect",
"//mlir:TensorTransforms",
- "//mlir:TransformUtils",
"//mlir:Transforms",
"//mlir:VectorDialect",
"//mlir:VectorToSCF",
@@ -770,7 +768,7 @@ cc_library(
"//mlir:MathTransforms",
"//mlir:Pass",
"//mlir:SCFDialect",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
"//mlir:VectorDialect",
"//mlir:X86VectorDialect",
],
@@ -786,7 +784,7 @@ cc_library(
"//mlir:IR",
"//mlir:MathDialect",
"//mlir:Pass",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
"//mlir:VCIXDialect",
"//mlir:VectorDialect",
],
@@ -850,7 +848,7 @@ cc_library(
"//mlir:Pass",
"//mlir:SCFDialect",
"//mlir:Support",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -869,7 +867,7 @@ cc_library(
"//mlir:SCFDialect",
"//mlir:SCFTransforms",
"//mlir:SCFUtils",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -994,7 +992,7 @@ cc_library(
"//mlir:FuncTransforms",
"//mlir:IR",
"//mlir:Pass",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)
@@ -1033,7 +1031,7 @@ cc_library(
"//mlir:SCFDialect",
"//mlir:Support",
"//mlir:TensorDialect",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
"//mlir:VectorDialect",
"//mlir:VectorToSCF",
"//mlir:VectorTransforms",
@@ -1119,6 +1117,6 @@ cc_library(
"//mlir:Parser",
"//mlir:Pass",
"//mlir:Support",
- "//mlir:TransformUtils",
+ "//mlir:Transforms",
],
)