summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYunQiang Su <yunqiang@isrc.iscas.ac.cn>2024-10-10 17:54:02 -0700
committerVitaly Buka <vitalybuka@google.com>2024-10-10 17:54:02 -0700
commit344061245236c55749e77e0ba16e9ac69b396191 (patch)
tree1a8a1841e3d77e22036407c0bdae3833dec436ef
parent744449313fff3f637e02280d58e0037eeffcca2b (diff)
parent72fb37922577997f3666203dbdb2601f0fc97748 (diff)
Created using spr 1.3.4 [skip ci]
-rw-r--r--clang/docs/ReleaseNotes.rst2
-rw-r--r--clang/include/clang/Basic/Builtins.td6
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp10
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.h1
-rw-r--r--clang/lib/Headers/hlsl/hlsl_intrinsics.h30
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp1
-rw-r--r--clang/test/CodeGenHLSL/builtins/degrees.hlsl64
-rw-r--r--clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl26
-rw-r--r--clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl1
-rw-r--r--compiler-rt/lib/asan/asan_descriptions.cpp23
-rw-r--r--lld/ELF/SymbolTable.cpp34
-rw-r--r--lld/test/ELF/version-script-reassign-glob.s4
-rw-r--r--lld/test/ELF/version-script-warn.s35
-rw-r--r--lldb/include/lldb/API/SBProcess.h1
-rw-r--r--lldb/include/lldb/Target/DynamicLoader.h12
-rw-r--r--lldb/include/lldb/Target/Process.h21
-rw-r--r--lldb/include/lldb/Target/StopInfo.h6
-rw-r--r--lldb/include/lldb/lldb-enumerations.h6
-rw-r--r--lldb/packages/Python/lldbsuite/test/gdbclientutils.py5
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py175
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbreverse.py418
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbtest.py2
-rw-r--r--lldb/source/API/SBProcess.cpp8
-rw-r--r--lldb/source/API/SBThread.cpp2
-rw-r--r--lldb/source/Core/DynamicLoader.cpp7
-rw-r--r--lldb/source/Interpreter/CommandInterpreter.cpp3
-rw-r--r--lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp80
-rw-r--r--lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h6
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp3
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp10
-rw-r--r--lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h2
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp8
-rw-r--r--lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp22
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h6
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp1
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp77
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h2
-rw-r--r--lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp20
-rw-r--r--lldb/source/Plugins/Process/minidump/ProcessMinidump.h5
-rw-r--r--lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp20
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp9
-rw-r--r--lldb/source/Plugins/Process/scripted/ScriptedProcess.h2
-rw-r--r--lldb/source/Target/Process.cpp65
-rw-r--r--lldb/source/Target/StopInfo.cpp29
-rw-r--r--lldb/source/Target/Thread.cpp8
-rw-r--r--lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py77
-rw-r--r--lldb/test/API/functionalities/process_save_core_minidump/main.cpp1
-rw-r--r--lldb/test/API/functionalities/reverse-execution/Makefile3
-rw-r--r--lldb/test/API/functionalities/reverse-execution/TestReverseContinueBreakpoints.py115
-rw-r--r--lldb/test/API/functionalities/reverse-execution/TestReverseContinueNotSupported.py30
-rw-r--r--lldb/test/API/functionalities/reverse-execution/main.c14
-rw-r--r--lldb/tools/lldb-dap/JSONUtils.cpp3
-rw-r--r--lldb/tools/lldb-dap/LLDBUtils.cpp1
-rw-r--r--llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h13
-rw-r--r--llvm/include/llvm/IR/IntrinsicsDirectX.td1
-rw-r--r--llvm/include/llvm/IR/IntrinsicsSPIRV.td1
-rw-r--r--llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h4
-rw-r--r--llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp24
-rw-r--r--llvm/lib/ExecutionEngine/Orc/LLJIT.cpp4
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp3
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td53
-rw-r--r--llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp12
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp2
-rw-r--r--llvm/test/CodeGen/AArch64/fp-fcanonicalize.ll587
-rw-r--r--llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll560
-rw-r--r--llvm/test/CodeGen/DirectX/degrees.ll54
-rw-r--r--llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll52
-rw-r--r--llvm/test/CodeGen/SPIRV/opencl/degrees.ll50
-rw-r--r--llvm/tools/llvm-jitlink/llvm-jitlink.cpp4
-rw-r--r--utils/bazel/llvm-project-overlay/clang-tools-extra/include-cleaner/BUILD.bazel70
-rw-r--r--utils/bazel/llvm-project-overlay/lldb/source/Plugins/BUILD.bazel2
72 files changed, 1975 insertions, 1045 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e48835d47380..df165b912525 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -172,7 +172,7 @@ C++23 Feature Support
- Removed the restriction to literal types in constexpr functions in C++23 mode.
- Extend lifetime of temporaries in mem-default-init for P2718R0. Clang now fully
- supported `P2718R0 Lifetime extension in range-based for loops <https://wg21.link/P2718R0>`_.
+ supports `P2718R0 Lifetime extension in range-based for loops <https://wg21.link/P2718R0>`_.
C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 9ebee81fcb0d..7068473a0e12 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4745,6 +4745,12 @@ def HLSLCross: LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}
+def HLSLDegrees : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_elementwise_degrees"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
+
def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_dot"];
let Attributes = [NoThrow, Const];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 06140d6d4ce2..ff678ee04f9c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -18755,6 +18755,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef<Value *>{X},
nullptr, "hlsl.normalize");
}
+ case Builtin::BI__builtin_hlsl_elementwise_degrees: {
+ Value *X = EmitScalarExpr(E->getArg(0));
+
+ assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
+ "degree operand must have a float representation");
+
+ return Builder.CreateIntrinsic(
+ /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(),
+ ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
+ }
case Builtin::BI__builtin_hlsl_elementwise_frac: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 05ff325216f5..282fa44af212 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -75,6 +75,7 @@ public:
GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(Cross, cross)
+ GENERATE_HLSL_INTRINSIC_FUNCTION(Degrees, degrees)
GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac)
GENERATE_HLSL_INTRINSIC_FUNCTION(Length, length)
GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index 813f8a317bf6..137467e5a782 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -767,6 +767,36 @@ _HLSL_BUILTIN_ALIAS(__builtin_elementwise_popcount)
uint64_t4 countbits(uint64_t4);
//===----------------------------------------------------------------------===//
+// degrees builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn T degrees(T x)
+/// \brief Converts the specified value from radians to degrees.
+/// \param x The specified input value.
+
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half degrees(half);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half2 degrees(half2);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half3 degrees(half3);
+_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+half4 degrees(half4);
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float degrees(float);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float2 degrees(float2);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float3 degrees(float3);
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_degrees)
+float4 degrees(float4);
+
+//===----------------------------------------------------------------------===//
// dot product builtins
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index b0acbbbbb2b1..137b15c8fcfe 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1896,6 +1896,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
+ case Builtin::BI__builtin_hlsl_elementwise_degrees:
case Builtin::BI__builtin_hlsl_elementwise_radians:
case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
case Builtin::BI__builtin_hlsl_elementwise_frac: {
diff --git a/clang/test/CodeGenHLSL/builtins/degrees.hlsl b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
new file mode 100644
index 000000000000..9e131f4badc1
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/degrees.hlsl
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -finclude-default-header -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: -DFNATTRS=noundef -DTARGET=dx
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm -disable-llvm-passes \
+// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
+// RUN: -DFNATTRS=noundef -DTARGET=dx
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -fnative-half-type \
+// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s \
+// RUN: --check-prefixes=CHECK,NATIVE_HALF \
+// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv
+// RUN: %clang_cc1 -finclude-default-header -triple \
+// RUN: spirv-unknown-vulkan-compute %s -emit-llvm -disable-llvm-passes \
+// RUN: -o - | FileCheck %s --check-prefixes=CHECK,NO_HALF \
+// RUN: -DFNATTRS="spir_func noundef" -DTARGET=spv
+
+// NATIVE_HALF: define [[FNATTRS]] half @
+// NATIVE_HALF: %hlsl.degrees = call half @llvm.[[TARGET]].degrees.f16(
+// NATIVE_HALF: ret half %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] float @
+// NO_HALF: %hlsl.degrees = call float @llvm.[[TARGET]].degrees.f32(
+// NO_HALF: ret float %hlsl.degrees
+half test_degrees_half(half p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <2 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <2 x half> @llvm.[[TARGET]].degrees.v2f16
+// NATIVE_HALF: ret <2 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <2 x float> @
+// NO_HALF: %hlsl.degrees = call <2 x float> @llvm.[[TARGET]].degrees.v2f32(
+// NO_HALF: ret <2 x float> %hlsl.degrees
+half2 test_degrees_half2(half2 p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <3 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <3 x half> @llvm.[[TARGET]].degrees.v3f16
+// NATIVE_HALF: ret <3 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <3 x float> @
+// NO_HALF: %hlsl.degrees = call <3 x float> @llvm.[[TARGET]].degrees.v3f32(
+// NO_HALF: ret <3 x float> %hlsl.degrees
+half3 test_degrees_half3(half3 p0) { return degrees(p0); }
+// NATIVE_HALF: define [[FNATTRS]] <4 x half> @
+// NATIVE_HALF: %hlsl.degrees = call <4 x half> @llvm.[[TARGET]].degrees.v4f16
+// NATIVE_HALF: ret <4 x half> %hlsl.degrees
+// NO_HALF: define [[FNATTRS]] <4 x float> @
+// NO_HALF: %hlsl.degrees = call <4 x float> @llvm.[[TARGET]].degrees.v4f32(
+// NO_HALF: ret <4 x float> %hlsl.degrees
+half4 test_degrees_half4(half4 p0) { return degrees(p0); }
+
+// CHECK: define [[FNATTRS]] float @
+// CHECK: %hlsl.degrees = call float @llvm.[[TARGET]].degrees.f32(
+// CHECK: ret float %hlsl.degrees
+float test_degrees_float(float p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <2 x float> @
+// CHECK: %hlsl.degrees = call <2 x float> @llvm.[[TARGET]].degrees.v2f32
+// CHECK: ret <2 x float> %hlsl.degrees
+float2 test_degrees_float2(float2 p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <3 x float> @
+// CHECK: %hlsl.degrees = call <3 x float> @llvm.[[TARGET]].degrees.v3f32
+// CHECK: ret <3 x float> %hlsl.degrees
+float3 test_degrees_float3(float3 p0) { return degrees(p0); }
+// CHECK: define [[FNATTRS]] <4 x float> @
+// CHECK: %hlsl.degrees = call <4 x float> @llvm.[[TARGET]].degrees.v4f32
+// CHECK: ret <4 x float> %hlsl.degrees
+float4 test_degrees_float4(float4 p0) { return degrees(p0); }
diff --git a/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
new file mode 100644
index 000000000000..9e981f697357
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/degrees-errors.hlsl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify
+
+float test_too_few_arg() {
+ return __builtin_hlsl_elementwise_degrees();
+ // expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+float2 test_too_many_arg(float2 p0) {
+ return __builtin_hlsl_elementwise_degrees(p0, p0);
+ // expected-error@-1 {{too many arguments to function call, expected 1, have 2}}
+}
+
+float builtin_bool_to_float_type_promotion(bool p1) {
+ return __builtin_hlsl_elementwise_degrees(p1);
+ // expected-error@-1 {{passing 'bool' to parameter of incompatible type 'float'}}
+}
+
+float builtin_degrees_int_to_float_promotion(int p1) {
+ return __builtin_hlsl_elementwise_degrees(p1);
+ // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}}
+}
+
+float2 builtin_degrees_int2_to_float2_promotion(int2 p1) {
+ return __builtin_hlsl_elementwise_degrees(p1);
+ // expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type '__attribute__((__vector_size__(2 * sizeof(float)))) float' (vector of 2 'float' values)}}
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
index 2cecf7aeb00e..cdd130052b6a 100644
--- a/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/half-float-only-errors.hlsl
@@ -17,6 +17,7 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_tan
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_tanh
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_elementwise_trunc
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_hlsl_elementwise_degrees
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -DTEST_FUNC=__builtin_hlsl_elementwise_radians
double test_double_builtin(double p0) {
diff --git a/compiler-rt/lib/asan/asan_descriptions.cpp b/compiler-rt/lib/asan/asan_descriptions.cpp
index 778e134f1cf2..674fe9c1e90b 100644
--- a/compiler-rt/lib/asan/asan_descriptions.cpp
+++ b/compiler-rt/lib/asan/asan_descriptions.cpp
@@ -48,9 +48,20 @@ void DescribeThread(AsanThreadContext *context) {
return;
}
context->announced = true;
+
+ AsanThreadContext *parent_context =
+ context->parent_tid == kInvalidTid
+ ? nullptr
+ : GetThreadContextByTidLocked(context->parent_tid);
+
+ // `context->parent_tid` may point to reused slot. Check `unique_id` which
+ // is always smaller for the parent, always greater for a new user.
+ if (context->unique_id <= parent_context->unique_id)
+ parent_context = nullptr;
+
InternalScopedString str;
str.AppendF("Thread %s", AsanThreadIdAndName(context).c_str());
- if (context->parent_tid == kInvalidTid) {
+ if (!parent_context) {
str.Append(" created by unknown thread\n");
Printf("%s", str.data());
return;
@@ -60,14 +71,8 @@ void DescribeThread(AsanThreadContext *context) {
Printf("%s", str.data());
StackDepotGet(context->stack_id).Print();
// Recursively described parent thread if needed.
- if (flags()->print_full_thread_history) {
- AsanThreadContext *parent_context =
- GetThreadContextByTidLocked(context->parent_tid);
- // `context->parent_tid` may point to reused slot, double check, `unique_id`
- // of new user will always be greater then the child.
- if (context->unique_id > parent_context->unique_id)
- DescribeThread(parent_context);
- }
+ if (flags()->print_full_thread_history)
+ DescribeThread(parent_context);
}
// Shadow descriptions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index db8ee8f4d7b3..b9ef28f0436f 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -309,13 +309,43 @@ void SymbolTable::scanVersionScript() {
// Then, assign versions to "*". In GNU linkers they have lower priority than
// other wildcards.
+ bool globalAsteriskFound = false;
+ bool localAsteriskFound = false;
+ bool asteriskReported = false;
+ auto assignAsterisk = [&](SymbolVersion &pat, VersionDefinition *ver,
+ bool isLocal) {
+ // Avoid issuing a warning if both '--retain-symbol-file' and a version
+ // script with `global: *` are used.
+ //
+ // '--retain-symbol-file' adds a "*" pattern to
+ // 'config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns', see
+ // 'readConfigs()' in 'Driver.cpp'. Note that it is not '.localPatterns',
+ // and may seem counterintuitive, but still works as expected. Here we can
+ // exploit that and skip analyzing the pattern added for this option.
+ if (!asteriskReported && (isLocal || ver->id > VER_NDX_LOCAL)) {
+ if ((isLocal && globalAsteriskFound) ||
+ (!isLocal && localAsteriskFound)) {
+ warn("wildcard pattern '*' is used for both 'local' and 'global' "
+ "scopes in version script");
+ asteriskReported = true;
+ } else if (!isLocal && globalAsteriskFound) {
+ warn("wildcard pattern '*' is used for multiple version definitions in "
+ "version script");
+ asteriskReported = true;
+ } else {
+ localAsteriskFound = isLocal;
+ globalAsteriskFound = !isLocal;
+ }
+ }
+ assignWildcard(pat, isLocal ? VER_NDX_LOCAL : ver->id, ver->name);
+ };
for (VersionDefinition &v : llvm::reverse(ctx.arg.versionDefinitions)) {
for (SymbolVersion &pat : v.nonLocalPatterns)
if (pat.hasWildcard && pat.name == "*")
- assignWildcard(pat, v.id, v.name);
+ assignAsterisk(pat, &v, false);
for (SymbolVersion &pat : v.localPatterns)
if (pat.hasWildcard && pat.name == "*")
- assignWildcard(pat, VER_NDX_LOCAL, v.name);
+ assignAsterisk(pat, &v, true);
}
// Symbol themselves might know their versions because symbols
diff --git a/lld/test/ELF/version-script-reassign-glob.s b/lld/test/ELF/version-script-reassign-glob.s
index 39d19a26fc44..8de36467bd8e 100644
--- a/lld/test/ELF/version-script-reassign-glob.s
+++ b/lld/test/ELF/version-script-reassign-glob.s
@@ -10,7 +10,8 @@
# RUN: llvm-readelf --dyn-syms %t.so | FileCheck --check-prefix=BAR %s
# RUN: echo 'bar1 { *; }; bar2 { *; };' > %t2.ver
-# RUN: ld.lld --version-script %t2.ver %t.o -shared -o %t2.so --fatal-warnings
+# RUN: ld.lld --version-script %t2.ver %t.o -shared -o %t2.so 2>&1 | \
+# RUN: FileCheck --check-prefix=DUPWARN %s
# RUN: llvm-readelf --dyn-syms %t2.so | FileCheck --check-prefix=BAR2 %s
## If both a non-* glob and a * match, non-* wins.
@@ -21,6 +22,7 @@
## When there are multiple * patterns, the last wins.
# BAR2: GLOBAL DEFAULT 7 foo@@bar2
+# DUPWARN: warning: wildcard pattern '*' is used for multiple version definitions in version script
.globl foo
foo:
diff --git a/lld/test/ELF/version-script-warn.s b/lld/test/ELF/version-script-warn.s
new file mode 100644
index 000000000000..9aba59616579
--- /dev/null
+++ b/lld/test/ELF/version-script-warn.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+
+# RUN: echo 'foo { *; }; bar { *; };' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN: FileCheck --check-prefix=MULTVER %s
+
+# RUN: echo '{ global: *; local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN: FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { global: *; }; V2 { local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN: FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { local: *; }; V2 { global: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so 2>&1 | \
+# RUN: FileCheck --check-prefix=LOCGLOB %s
+
+# RUN: echo 'V1 { local: *; }; V2 { local: *;};' > %t.ver
+# RUN: ld.lld --version-script %t.ver %t.o -shared -o %t.so --fatal-warnings
+
+## --retain-symbols-file uses the same internal infrastructure as the support
+## for version scripts. Do not show the warings if they both are used.
+# RUN: echo 'foo' > %t_retain.txt
+# RUN: echo '{ local: *; };' > %t_local.ver
+# RUN: echo '{ global: *; };' > %t_global.ver
+# RUN: ld.lld --retain-symbols-file=%t_retain.txt --version-script %t_local.ver %t.o -shared -o %t.so --fatal-warnings
+# RUN: ld.lld --retain-symbols-file=%t_retain.txt --version-script %t_global.ver %t.o -shared -o %t.so --fatal-warnings
+
+# MULTVER: warning: wildcard pattern '*' is used for multiple version definitions in version script
+# LOCGLOB: warning: wildcard pattern '*' is used for both 'local' and 'global' scopes in version script
+
+.globl foo
+foo:
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 8b8ed830b54c..1624e02070b1 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -159,7 +159,6 @@ public:
lldb::SBError Destroy();
lldb::SBError Continue();
- lldb::SBError Continue(RunDirection direction);
lldb::SBError Stop();
diff --git a/lldb/include/lldb/Target/DynamicLoader.h b/lldb/include/lldb/Target/DynamicLoader.h
index 0629e2faae7e..75bb6cb6bb90 100644
--- a/lldb/include/lldb/Target/DynamicLoader.h
+++ b/lldb/include/lldb/Target/DynamicLoader.h
@@ -11,6 +11,7 @@
#include "lldb/Core/Address.h"
#include "lldb/Core/PluginInterface.h"
+#include "lldb/Target/CoreFileMemoryRanges.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/UUID.h"
@@ -337,6 +338,17 @@ public:
return std::nullopt;
}
+ /// Returns a list of memory ranges that should be saved in the core file,
+ /// specific for this dynamic loader.
+ ///
+ /// For example, an implementation of this function can save the thread
+ /// local data of a given thread.
+ virtual void CalculateDynamicSaveCoreRanges(
+ lldb_private::Process &process,
+ std::vector<lldb_private::MemoryRegionInfo> &ranges,
+ llvm::function_ref<bool(const lldb_private::Thread &)>
+ save_thread_predicate) {};
+
protected:
// Utility methods for derived classes
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index fe7fbc50fd57..b8c53a474ba6 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -857,10 +857,10 @@ public:
/// \see Thread:Resume()
/// \see Thread:Step()
/// \see Thread:Suspend()
- Status Resume(lldb::RunDirection direction = lldb::eRunForward);
+ Status Resume();
/// Resume a process, and wait for it to stop.
- Status ResumeSynchronous(Stream *stream, lldb::RunDirection direction = lldb::eRunForward);
+ Status ResumeSynchronous(Stream *stream);
/// Halts a running process.
///
@@ -1104,14 +1104,9 @@ public:
/// \see Thread:Resume()
/// \see Thread:Step()
/// \see Thread:Suspend()
- virtual Status DoResume(lldb::RunDirection direction) {
- if (direction == lldb::RunDirection::eRunForward) {
- return Status::FromErrorStringWithFormatv(
- "error: {0} does not support resuming processes", GetPluginName());
- } else {
- return Status::FromErrorStringWithFormatv(
- "error: {0} does not support reverse execution of processes", GetPluginName());
- }
+ virtual Status DoResume() {
+ return Status::FromErrorStringWithFormatv(
+ "error: {0} does not support resuming processes", GetPluginName());
}
/// Called after resuming a process.
@@ -2337,8 +2332,6 @@ public:
bool IsRunning() const;
- lldb::RunDirection GetLastRunDirection() { return m_last_run_direction; }
-
DynamicCheckerFunctions *GetDynamicCheckers() {
return m_dynamic_checkers_up.get();
}
@@ -2858,7 +2851,7 @@ protected:
///
/// \return
/// An Status object describing the success or failure of the resume.
- Status PrivateResume(lldb::RunDirection direction = lldb::eRunForward);
+ Status PrivateResume();
// Called internally
void CompleteAttach();
@@ -3134,8 +3127,6 @@ protected:
// m_currently_handling_do_on_removals are true,
// Resume will only request a resume, using this
// flag to check.
- // The direction of execution from the last time this process was resumed.
- lldb::RunDirection m_last_run_direction;
lldb::tid_t m_interrupt_tid; /// The tid of the thread that issued the async
/// interrupt, used by thread plan timeout. It
diff --git a/lldb/include/lldb/Target/StopInfo.h b/lldb/include/lldb/Target/StopInfo.h
index 072f71f6b112..fae90364deaf 100644
--- a/lldb/include/lldb/Target/StopInfo.h
+++ b/lldb/include/lldb/Target/StopInfo.h
@@ -142,12 +142,6 @@ public:
static lldb::StopInfoSP
CreateStopReasonProcessorTrace(Thread &thread, const char *description);
- // This creates a StopInfo indicating that execution stopped because
- // it was replaying some recorded execution history, and execution reached
- // the end of that recorded history.
- static lldb::StopInfoSP
- CreateStopReasonHistoryBoundary(Thread &thread, const char *description);
-
static lldb::StopInfoSP CreateStopReasonFork(Thread &thread,
lldb::pid_t child_pid,
lldb::tid_t child_tid);
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 232d1dfdb5c9..938f6e3abe8f 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -135,9 +135,6 @@ FLAGS_ENUM(LaunchFlags){
/// Thread Run Modes.
enum RunMode { eOnlyThisThread, eAllThreads, eOnlyDuringStepping };
-/// Execution directions
-enum RunDirection { eRunForward, eRunReverse };
-
/// Byte ordering definitions.
enum ByteOrder {
eByteOrderInvalid = 0,
@@ -257,9 +254,6 @@ enum StopReason {
eStopReasonVFork,
eStopReasonVForkDone,
eStopReasonInterrupt, ///< Thread requested interrupt
- // Indicates that execution stopped because the debugger backend relies
- // on recorded data and we reached the end of that data.
- eStopReasonHistoryBoundary,
};
/// Command Return Status Types.
diff --git a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
index 732d61713206..1784487323ad 100644
--- a/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
+++ b/lldb/packages/Python/lldbsuite/test/gdbclientutils.py
@@ -510,9 +510,8 @@ class MockGDBServer:
self._thread.start()
def stop(self):
- if self._thread is not None:
- self._thread.join()
- self._thread = None
+ self._thread.join()
+ self._thread = None
def get_connect_address(self):
return self._socket.get_connect_address()
diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py b/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
deleted file mode 100644
index 2a9592bf4545..000000000000
--- a/lldb/packages/Python/lldbsuite/test/lldbgdbproxy.py
+++ /dev/null
@@ -1,175 +0,0 @@
-import logging
-import os
-import os.path
-import random
-
-import lldb
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.gdbclientutils import *
-import lldbgdbserverutils
-from lldbsuite.support import seven
-
-
-class GDBProxyTestBase(TestBase):
- """
- Base class for gdbserver proxy tests.
-
- This class will setup and start a mock GDB server for the test to use.
- It pases through requests to a regular lldb-server/debugserver and
- forwards replies back to the LLDB under test.
- """
-
- """The gdbserver that we implement."""
- server = None
- """The inner lldb-server/debugserver process that we proxy requests into."""
- monitor_server = None
- monitor_sock = None
-
- server_socket_class = TCPServerSocket
-
- DEFAULT_TIMEOUT = 20 * (10 if ("ASAN_OPTIONS" in os.environ) else 1)
-
- _verbose_log_handler = None
- _log_formatter = logging.Formatter(fmt="%(asctime)-15s %(levelname)-8s %(message)s")
-
- def setUpBaseLogging(self):
- self.logger = logging.getLogger(__name__)
-
- if len(self.logger.handlers) > 0:
- return # We have set up this handler already
-
- self.logger.propagate = False
- self.logger.setLevel(logging.DEBUG)
-
- # log all warnings to stderr
- handler = logging.StreamHandler()
- handler.setLevel(logging.WARNING)
- handler.setFormatter(self._log_formatter)
- self.logger.addHandler(handler)
-
- def setUp(self):
- TestBase.setUp(self)
-
- self.setUpBaseLogging()
-
- if self.isVerboseLoggingRequested():
- # If requested, full logs go to a log file
- log_file_name = self.getLogBasenameForCurrentTest() + "-proxy.log"
- self._verbose_log_handler = logging.FileHandler(
- log_file_name
- )
- self._verbose_log_handler.setFormatter(self._log_formatter)
- self._verbose_log_handler.setLevel(logging.DEBUG)
- self.logger.addHandler(self._verbose_log_handler)
-
- lldb_server_exe = lldbgdbserverutils.get_lldb_server_exe()
- if lldb_server_exe is None:
- self.debug_monitor_exe = lldbgdbserverutils.get_debugserver_exe()
- self.assertTrue(self.debug_monitor_exe is not None)
- self.debug_monitor_extra_args = []
- else:
- self.debug_monitor_exe = lldb_server_exe
- self.debug_monitor_extra_args = ["gdbserver"]
-
- self.server = MockGDBServer(self.server_socket_class())
- self.server.responder = self
-
- def tearDown(self):
- # TestBase.tearDown will kill the process, but we need to kill it early
- # so its client connection closes and we can stop the server before
- # finally calling the base tearDown.
- if self.process() is not None:
- self.process().Kill()
- self.server.stop()
-
- self.logger.removeHandler(self._verbose_log_handler)
- self._verbose_log_handler = None
-
- TestBase.tearDown(self)
-
- def isVerboseLoggingRequested(self):
- # We will report our detailed logs if the user requested that the "gdb-remote" channel is
- # logged.
- return any(("gdb-remote" in channel) for channel in lldbtest_config.channels)
-
- def connect(self, target):
- """
- Create a process by connecting to the mock GDB server.
- """
- self.prep_debug_monitor_and_inferior()
- self.server.start()
-
- listener = self.dbg.GetListener()
- error = lldb.SBError()
- process = target.ConnectRemote(
- listener, self.server.get_connect_url(), "gdb-remote", error
- )
- self.assertTrue(error.Success(), error.description)
- self.assertTrue(process, PROCESS_IS_VALID)
- return process
-
- def get_next_port(self):
- return 12000 + random.randint(0, 3999)
-
- def prep_debug_monitor_and_inferior(self):
- inferior_exe_path = self.getBuildArtifact("a.out")
- self.connect_to_debug_monitor([inferior_exe_path])
- self.assertIsNotNone(self.monitor_server)
- self.initial_handshake()
-
- def initial_handshake(self):
- self.monitor_server.send_packet(seven.bitcast_to_bytes("+"))
- reply = seven.bitcast_to_string(self.monitor_server.get_normal_packet())
- self.assertEqual(reply, "+")
- self.monitor_server.send_packet(seven.bitcast_to_bytes("QStartNoAckMode"))
- reply = seven.bitcast_to_string(self.monitor_server.get_normal_packet())
- self.assertEqual(reply, "+")
- reply = seven.bitcast_to_string(self.monitor_server.get_normal_packet())
- self.assertEqual(reply, "OK")
- self.monitor_server.send_packet(seven.bitcast_to_bytes("+"))
- reply = seven.bitcast_to_string(self.monitor_server.get_normal_packet())
- self.assertEqual(reply, "+")
-
- def get_debug_monitor_command_line_args(self, connect_address, launch_args):
- return self.debug_monitor_extra_args + ["--reverse-connect", connect_address] + launch_args
-
- def launch_debug_monitor(self, launch_args):
- family, type, proto, _, addr = socket.getaddrinfo(
- "localhost", 0, proto=socket.IPPROTO_TCP
- )[0]
- sock = socket.socket(family, type, proto)
- sock.settimeout(self.DEFAULT_TIMEOUT)
- sock.bind(addr)
- sock.listen(1)
- addr = sock.getsockname()
- connect_address = "[{}]:{}".format(*addr)
-
- commandline_args = self.get_debug_monitor_command_line_args(
- connect_address, launch_args
- )
-
- # Start the server.
- self.logger.info(f"Spawning monitor {commandline_args}")
- monitor_process = self.spawnSubprocess(
- self.debug_monitor_exe, commandline_args, install_remote=False
- )
- self.assertIsNotNone(monitor_process)
-
- self.monitor_sock = sock.accept()[0]
- self.monitor_sock.settimeout(self.DEFAULT_TIMEOUT)
- return monitor_process
-
- def connect_to_debug_monitor(self, launch_args):
- monitor_process = self.launch_debug_monitor(launch_args)
- self.monitor_server = lldbgdbserverutils.Server(self.monitor_sock, monitor_process)
-
- def respond(self, packet):
- """Subclasses can override this to change how packets are handled."""
- return self.pass_through(packet)
-
- def pass_through(self, packet):
- self.logger.info(f"Sending packet {packet}")
- self.monitor_server.send_packet(seven.bitcast_to_bytes(packet))
- reply = seven.bitcast_to_string(self.monitor_server.get_normal_packet())
- self.logger.info(f"Received reply {reply}")
- return reply
diff --git a/lldb/packages/Python/lldbsuite/test/lldbreverse.py b/lldb/packages/Python/lldbsuite/test/lldbreverse.py
deleted file mode 100644
index 0f02fdffbdea..000000000000
--- a/lldb/packages/Python/lldbsuite/test/lldbreverse.py
+++ /dev/null
@@ -1,418 +0,0 @@
-import os
-import os.path
-import lldb
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.gdbclientutils import *
-from lldbsuite.test.lldbgdbproxy import *
-import lldbgdbserverutils
-import re
-
-
-class ThreadSnapshot:
- def __init__(self, thread_id, registers):
- self.thread_id = thread_id
- self.registers = registers
-
-
-class MemoryBlockSnapshot:
- def __init__(self, address, data):
- self.address = address
- self.data = data
-
-
-class StateSnapshot:
- def __init__(self, thread_snapshots, memory):
- self.thread_snapshots = thread_snapshots
- self.memory = memory
- self.thread_id = None
-
-
-class RegisterInfo:
- def __init__(self, lldb_index, bitsize, little_endian):
- self.lldb_index = lldb_index
- self.bitsize = bitsize
- self.little_endian = little_endian
-
-
-BELOW_STACK_POINTER = 16384
-ABOVE_STACK_POINTER = 4096
-
-BLOCK_SIZE = 1024
-
-SOFTWARE_BREAKPOINTS = 0
-HARDWARE_BREAKPOINTS = 1
-WRITE_WATCHPOINTS = 2
-
-
-class ReverseTestBase(GDBProxyTestBase):
- """
- Base class for tests that need reverse execution.
-
- This class uses a gdbserver proxy to add very limited reverse-
- execution capability to lldb-server/debugserver for testing
- purposes only.
-
- To use this class, run the inferior forward until some stopping point.
- Then call `start_recording()` and execute forward again until reaching
- a software breakpoint; this class records the state before each execution executes.
- At that point, the server will accept "bc" and "bs" packets to step
- backwards through the state.
- When executing during recording, we only allow single-step and continue without
- delivering a signal, and only software breakpoint stops are allowed.
-
- We assume that while recording is enabled, the only effects of instructions
- are on general-purpose registers (read/written by the 'g' and 'G' packets)
- and on memory bytes between [SP - BELOW_STACK_POINTER, SP + ABOVE_STACK_POINTER).
- """
-
- """
- A list of StateSnapshots in time order.
-
- There is one snapshot per single-stepped instruction,
- representing the state before that instruction was
- executed. The last snapshot in the list is the
- snapshot before the last instruction was executed.
- This is an undo log; we snapshot a superset of the state that may have
- been changed by the instruction's execution.
- """
- snapshots = None
- recording_enabled = False
-
- breakpoints = None
-
- pid = None
-
- pc_register_info = None
- sp_register_info = None
- general_purpose_register_info = None
-
- def __init__(self, *args, **kwargs):
- GDBProxyTestBase.__init__(self, *args, **kwargs)
- self.breakpoints = [set(), set(), set(), set(), set()]
-
- def respond(self, packet):
- if not packet:
- raise ValueError("Invalid empty packet")
- if packet == self.server.PACKET_INTERRUPT:
- # Don't send a response. We'll just run to completion.
- return []
- if self.is_command(packet, "qSupported", ":"):
- reply = self.pass_through(packet)
- return reply + ";ReverseStep+;ReverseContinue+"
- if self.is_command(packet, "vCont", ";"):
- if self.recording_enabled:
- return self.continue_with_recording(packet)
- snapshots = []
- if packet[0] == "c" or packet[0] == "s" or packet[0] == "C" or packet[0] == "S":
- raise ValueError("LLDB should not be sending old-style continuation packets")
- if packet == "bc":
- return self.reverse_continue()
- if packet == "bs":
- return self.reverse_step()
- if packet == 'jThreadsInfo':
- # Suppress this because it contains thread stop reasons which we might
- # need to modify, and we don't want to have to implement that.
- return ""
- if packet[0] == "z" or packet[0] == "Z":
- reply = self.pass_through(packet)
- if reply == "OK":
- self.update_breakpoints(packet)
- return reply
- return GDBProxyTestBase.respond(self, packet)
-
- def start_recording(self):
- self.recording_enabled = True
- self.snapshots = []
-
- def stop_recording(self):
- """
- Don't record when executing foward.
-
- Reverse execution is still supported until the next forward continue.
- """
- self.recording_enabled = False
-
- def is_command(self, packet, cmd, follow_token):
- return packet == cmd or packet[0:len(cmd) + 1] == cmd + follow_token
-
- def update_breakpoints(self, packet):
- m = re.match("([zZ])([01234]),([0-9a-f]+),([0-9a-f]+)", packet)
- if m is None:
- raise ValueError("Invalid breakpoint packet: " + packet)
- t = int(m.group(2))
- addr = int(m.group(3), 16)
- kind = int(m.group(4), 16)
- if m.group(1) == 'Z':
- self.breakpoints[t].add((addr, kind))
- else:
- self.breakpoints[t].discard((addr, kind))
-
- def breakpoint_triggered_at(self, pc):
- if any(addr == pc for addr, kind in self.breakpoints[SOFTWARE_BREAKPOINTS]):
- return True
- if any(addr == pc for addr, kind in self.breakpoints[HARDWARE_BREAKPOINTS]):
- return True
- return False
-
- def watchpoint_triggered(self, new_value_block, current_contents):
- """Returns the address or None."""
- for watch_addr, kind in breakpoints[WRITE_WATCHPOINTS]:
- for offset in range(0, kind):
- addr = watch_addr + offset
- if (addr >= new_value_block.address and
- addr < new_value_block.address + len(new_value_block.data)):
- index = addr - new_value_block.address
- if new_value_block.data[index*2:(index + 1)*2] != current_contents[index*2:(index + 1)*2]:
- return watch_addr
- return None
-
- def continue_with_recording(self, packet):
- self.logger.debug("Continue with recording enabled")
-
- step_packet = "vCont;s"
- if packet == "vCont":
- requested_step = False
- else:
- m = re.match("vCont;(c|s)(.*)", packet)
- if m is None:
- raise ValueError("Unsupported vCont packet: " + packet)
- requested_step = m.group(1) == 's'
- step_packet += m.group(2)
-
- while True:
- snapshot = self.capture_snapshot()
- reply = self.pass_through(step_packet)
- (stop_signal, stop_pairs) = self.parse_stop(reply)
- if stop_signal != 5:
- raise ValueError("Unexpected stop signal: " + reply)
- is_swbreak = False
- thread_id = None
- for key, value in stop_pairs.items():
- if key == "thread":
- thread_id = self.parse_thread_id(value)
- continue
- if re.match('[0-9a-f]+', key):
- continue
- if key == "swbreak" or (key == "reason" and value == "breakpoint"):
- is_swbreak = True
- continue
- if key in ["name", "threads", "thread-pcs", "reason"]:
- continue
- raise ValueError(f"Unknown stop key '{key}' in {reply}")
- if is_swbreak:
- self.logger.debug("Recording stopped")
- return reply
- if thread_id is None:
- return ValueError("Expected thread ID: " + reply)
- snapshot.thread_id = thread_id
- self.snapshots.append(snapshot)
- if requested_step:
- self.logger.debug("Recording stopped for step")
- return reply
-
- def parse_stop(self, reply):
- result = {}
- if not reply:
- raise ValueError("Invalid empty packet")
- if reply[0] == "T" and len(reply) >= 3:
- result = {k:v for k, v in self.parse_pairs(reply[3:])}
- return (int(reply[1:3], 16), result)
- raise "Unsupported stop reply: " + reply
-
- def parse_pairs(self, text):
- for pair in text.split(";"):
- if not pair:
- continue
- m = re.match("([^:]+):(.*)", pair)
- if m is None:
- raise ValueError("Invalid pair text: " + text)
- yield (m.group(1), m.group(2))
-
- def capture_snapshot(self):
- """Snapshot all threads and their stack memories."""
- self.ensure_register_info()
- current_thread = self.get_current_thread()
- thread_snapshots = []
- memory = []
- for thread_id in self.get_thread_list():
- registers = {}
- for index in sorted(self.general_purpose_register_info.keys()):
- reply = self.pass_through(f"p{index:x};thread:{thread_id:x};")
- if reply == "" or reply[0] == 'E':
- raise ValueError("Can't read register")
- registers[index] = reply
- thread_snapshot = ThreadSnapshot(thread_id, registers)
- thread_sp = self.get_register(self.sp_register_info, thread_snapshot.registers)
- memory += self.read_memory(thread_sp - BELOW_STACK_POINTER, thread_sp + ABOVE_STACK_POINTER)
- thread_snapshots.append(thread_snapshot)
- self.set_current_thread(current_thread)
- return StateSnapshot(thread_snapshots, memory)
-
- def restore_snapshot(self, snapshot):
- """
- Restore the snapshot during reverse execution.
-
- If this triggers a breakpoint or watchpoint, return the stop reply,
- otherwise None.
- """
- current_thread = self.get_current_thread()
- stop_reasons = []
- for thread_snapshot in snapshot.thread_snapshots:
- thread_id = thread_snapshot.thread_id
- for lldb_index in sorted(thread_snapshot.registers.keys()):
- data = thread_snapshot.registers[lldb_index]
- reply = self.pass_through(f"P{lldb_index:x}={data};thread:{thread_id:x};")
- if reply != "OK":
- raise ValueError("Can't restore thread register")
- if thread_id == snapshot.thread_id:
- new_pc = self.get_register(self.pc_register_info, thread_snapshot.registers)
- if self.breakpoint_triggered_at(new_pc):
- stop_reasons.append([("reason", "breakpoint")])
- self.set_current_thread(current_thread)
- for block in snapshot.memory:
- current_memory = self.pass_through(f"m{block.address:x},{(len(block.data)/2):x}")
- if not current_memory or current_memory[0] == 'E':
- raise ValueError("Can't read back memory")
- reply = self.pass_through(f"M{block.address:x},{len(block.data)/2:x}:" + block.data)
- if reply != "OK":
- raise ValueError("Can't restore memory")
- watch_addr = self.watchpoint_triggered(block, current_memory[1:])
- if watch_addr is not None:
- stop_reasons.append([("reason", "watchpoint"), ("watch", f"{watch_addr:x}")])
- if stop_reasons:
- pairs = ";".join(f"{key}:{value}" for key, value in stop_reasons[0])
- return f"T05thread:{self.pid:x}.{snapshot.thread_id:x};{pairs};"
- return None
-
- def reverse_step(self):
- if not self.snapshots:
- self.logger.debug("Reverse-step at history boundary")
- return self.history_boundary_reply(self.get_current_thread())
- self.logger.debug("Reverse-step started")
- snapshot = self.snapshots.pop()
- stop_reply = self.restore_snapshot(snapshot)
- self.set_current_thread(snapshot.thread_id)
- self.logger.debug("Reverse-step stopped")
- if stop_reply is None:
- return self.singlestep_stop_reply(snapshot.thread_id)
- return stop_reply
-
- def reverse_continue(self):
- self.logger.debug("Reverse-continue started")
- thread_id = None
- while self.snapshots:
- snapshot = self.snapshots.pop()
- stop_reply = self.restore_snapshot(snapshot)
- thread_id = snapshot.thread_id
- if stop_reply is not None:
- self.set_current_thread(thread_id)
- self.logger.debug("Reverse-continue stopped")
- return stop_reply
- if thread_id is None:
- thread_id = self.get_current_thread()
- else:
- self.set_current_thread(snapshot.thread_id)
- self.logger.debug("Reverse-continue stopped at history boundary")
- return self.history_boundary_reply(thread_id)
-
- def get_current_thread(self):
- reply = self.pass_through("qC")
- return self.parse_thread_id(reply[2:])
-
- def parse_thread_id(self, thread_id):
- m = re.match("(p([0-9a-f]+)[.])?([0-9a-f]+)$", thread_id)
- if m is None:
- raise ValueError("Invalid thread ID: " + thread_id)
- if self.pid is None:
- self.pid = int(m.group(2), 16)
- return int(m.group(3), 16)
-
- def history_boundary_reply(self, thread_id):
- return f"T00thread:{self.pid:x}.{thread_id:x};replaylog:begin;"
-
- def singlestep_stop_reply(self, thread_id):
- return f"T05thread:{self.pid:x}.{thread_id:x};"
-
- def set_current_thread(self, thread_id):
- """
- Set current thread in inner gdbserver.
- """
- if thread_id >= 0:
- self.pass_through(f"Hg{self.pid:x}.{thread_id:x}")
- self.pass_through(f"Hc{self.pid:x}.{thread_id:x}")
- else:
- self.pass_through(f"Hc-1.-1")
- self.pass_through(f"Hg-1.-1")
-
- def get_register(self, register_info, registers):
- if register_info.bitsize % 8 != 0:
- raise ValueError("Register size must be a multiple of 8 bits")
- if register_info.lldb_index not in registers:
- raise ValueError("Register value not captured")
- data = registers[register_info.lldb_index]
- num_bytes = register_info.bitsize//8
- bytes = []
- for i in range(0, num_bytes):
- bytes.append(int(data[i*2:(i + 1)*2], 16))
- if register_info.little_endian:
- bytes.reverse()
- result = 0
- for byte in bytes:
- result = (result << 8) + byte
- return result
-
- def read_memory(self, start_addr, end_addr):
- """
- Read a region of memory from the target.
-
- Some of the addresses may extend into invalid virtual memory;
- skip those areas.
- Return a list of blocks containing the valid area(s) in the
- requested range.
- """
- regions = []
- start_addr = start_addr & (BLOCK_SIZE - 1)
- end_addr = (end_addr + BLOCK_SIZE - 1) & (BLOCK_SIZE - 1)
- for addr in range(start_addr, end_addr, BLOCK_SIZE):
- reply = self.pass_through(f"m{addr:x},{(BLOCK_SIZE - 1):x}")
- if reply and reply[0] != 'E':
- block = MemoryBlockSnapshot(addr, reply[1:])
- regions.append(block)
- return regions
-
- def ensure_register_info(self):
- if self.general_purpose_register_info is not None:
- return
- reply = self.pass_through("qHostInfo")
- little_endian = any(kv == ("endian", "little") for kv in self.parse_pairs(reply))
- self.general_purpose_register_info = {}
- lldb_index = 0
- while True:
- reply = self.pass_through(f"qRegisterInfo{lldb_index:x}")
- if not reply or reply[0] == 'E':
- break
- info = {k:v for k, v in self.parse_pairs(reply)}
- reg_info = RegisterInfo(lldb_index, int(info["bitsize"]), little_endian)
- if info["set"] == "General Purpose Registers" and not "container-regs" in info:
- self.general_purpose_register_info[lldb_index] = reg_info
- if "generic" in info:
- if info["generic"] == "pc":
- self.pc_register_info = reg_info
- elif info["generic"] == "sp":
- self.sp_register_info = reg_info
- lldb_index += 1
- if self.pc_register_info is None or self.sp_register_info is None:
- raise ValueError("Can't find generic pc or sp register")
-
- def get_thread_list(self):
- threads = []
- reply = self.pass_through("qfThreadInfo")
- while True:
- if not reply:
- raise ValueError("Missing reply packet")
- if reply[0] == 'm':
- for id in reply[1:].split(","):
- threads.append(self.parse_thread_id(id))
- elif reply[0] == 'l':
- return threads
- reply = self.pass_through("qsThreadInfo")
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index 7cc1ac9749ec..8884ef5933ad 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -143,8 +143,6 @@ STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint"
-STOPPED_DUE_TO_HISTORY_BOUNDARY = "Process should be stopped due to history boundary"
-
DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
VALID_BREAKPOINT = "Got a valid breakpoint"
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index 07780f9f9c83..9773144723c3 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -564,10 +564,6 @@ uint32_t SBProcess::GetAddressByteSize() const {
}
SBError SBProcess::Continue() {
- return Continue(RunDirection::eRunForward);
-}
-
-SBError SBProcess::Continue(RunDirection direction) {
LLDB_INSTRUMENT_VA(this);
SBError sb_error;
@@ -578,9 +574,9 @@ SBError SBProcess::Continue(RunDirection direction) {
process_sp->GetTarget().GetAPIMutex());
if (process_sp->GetTarget().GetDebugger().GetAsyncExecution())
- sb_error.ref() = process_sp->Resume(direction);
+ sb_error.ref() = process_sp->Resume();
else
- sb_error.ref() = process_sp->ResumeSynchronous(nullptr, direction);
+ sb_error.ref() = process_sp->ResumeSynchronous(nullptr);
} else
sb_error = Status::FromErrorString("SBProcess is invalid");
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index aca8a0399529..a99456e06d03 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -172,7 +172,6 @@ size_t SBThread::GetStopReasonDataCount() {
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:
case eStopReasonVForkDone:
- case eStopReasonHistoryBoundary:
// There is no data for these stop reasons.
return 0;
@@ -234,7 +233,6 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) {
case eStopReasonInstrumentation:
case eStopReasonProcessorTrace:
case eStopReasonVForkDone:
- case eStopReasonHistoryBoundary:
// There is no data for these stop reasons.
return 0;
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index 7758a87403b5..68d6ab085085 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -83,7 +83,11 @@ ModuleSP DynamicLoader::GetTargetExecutable() {
ModuleSpec module_spec(executable->GetFileSpec(),
executable->GetArchitecture());
auto module_sp = std::make_shared<Module>(module_spec);
-
+ // If we're a coredump and we already have a main executable, we don't
+ // need to reload the module list that target already has
+ if (!m_process->IsLiveDebugSession()) {
+ return executable;
+ }
// Check if the executable has changed and set it to the target
// executable if they differ.
if (module_sp && module_sp->GetUUID().IsValid() &&
@@ -369,4 +373,3 @@ void DynamicLoader::LoadOperatingSystemPlugin(bool flush)
if (m_process)
m_process->LoadOperatingSystemPlugin(flush);
}
-
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index ea60492ac46a..8d3a82ef6c99 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -2553,8 +2553,7 @@ bool CommandInterpreter::DidProcessStopAbnormally() const {
const StopReason reason = stop_info->GetStopReason();
if (reason == eStopReasonException ||
reason == eStopReasonInstrumentation ||
- reason == eStopReasonProcessorTrace || reason == eStopReasonInterrupt ||
- reason == eStopReasonHistoryBoundary)
+ reason == eStopReasonProcessorTrace || reason == eStopReasonInterrupt)
return true;
if (reason == eStopReasonSignal) {
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index b9c0e174c3be..34aca50df0ac 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -18,6 +18,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Platform.h"
+#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
@@ -866,3 +867,82 @@ bool DynamicLoaderPOSIXDYLD::AlwaysRelyOnEHUnwindInfo(
bool DynamicLoaderPOSIXDYLD::IsCoreFile() const {
return !m_process->IsLiveDebugSession();
}
+
+// For our ELF/POSIX builds save off the fs_base/gs_base regions
+static void AddThreadLocalMemoryRegions(Process &process, ThreadSP &thread_sp,
+ std::vector<MemoryRegionInfo> &ranges) {
+ lldb::RegisterContextSP reg_ctx = thread_sp->GetRegisterContext();
+ if (!reg_ctx)
+ return;
+
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
+ lldb::RegisterKind::eRegisterKindGeneric, LLDB_REGNUM_GENERIC_TP);
+ if (!reg_info)
+ return;
+
+ lldb_private::RegisterValue thread_local_register_value;
+ bool success = reg_ctx->ReadRegister(reg_info, thread_local_register_value);
+ if (!success)
+ return;
+
+ const uint64_t fail_value = UINT64_MAX;
+ bool readSuccess = false;
+ const lldb::addr_t reg_value_addr =
+ thread_local_register_value.GetAsUInt64(fail_value, &readSuccess);
+ if (!readSuccess || reg_value_addr == fail_value)
+ return;
+
+ MemoryRegionInfo thread_local_region;
+ Status err = process.GetMemoryRegionInfo(reg_value_addr, thread_local_region);
+ if (err.Fail())
+ return;
+
+ ranges.push_back(thread_local_region);
+}
+
+// Save off the link map for core files.
+static void AddLinkMapSections(Process &process,
+ std::vector<MemoryRegionInfo> &ranges) {
+ ModuleList &module_list = process.GetTarget().GetImages();
+ Target *target = &process.GetTarget();
+ for (size_t idx = 0; idx < module_list.GetSize(); idx++) {
+ ModuleSP module_sp = module_list.GetModuleAtIndex(idx);
+ if (!module_sp)
+ continue;
+
+ ObjectFile *obj = module_sp->GetObjectFile();
+ if (!obj)
+ continue;
+ Address addr = obj->GetImageInfoAddress(target);
+ addr_t load_addr = addr.GetLoadAddress(target);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ continue;
+
+ MemoryRegionInfo link_map_section;
+ Status err = process.GetMemoryRegionInfo(load_addr, link_map_section);
+ if (err.Fail())
+ continue;
+
+ ranges.push_back(link_map_section);
+ }
+}
+
+void DynamicLoaderPOSIXDYLD::CalculateDynamicSaveCoreRanges(
+ lldb_private::Process &process,
+ std::vector<lldb_private::MemoryRegionInfo> &ranges,
+ llvm::function_ref<bool(const lldb_private::Thread &)>
+ save_thread_predicate) {
+ ThreadList &thread_list = process.GetThreadList();
+ for (size_t idx = 0; idx < thread_list.GetSize(); idx++) {
+ ThreadSP thread_sp = thread_list.GetThreadAtIndex(idx);
+ if (!thread_sp)
+ continue;
+
+ if (!save_thread_predicate(*thread_sp))
+ continue;
+
+ AddThreadLocalMemoryRegions(process, thread_sp, ranges);
+ }
+
+ AddLinkMapSections(process, ranges);
+}
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
index 4c92335602cd..bde334aaca40 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -60,6 +60,12 @@ public:
lldb::addr_t base_addr,
bool base_addr_is_offset) override;
+ void CalculateDynamicSaveCoreRanges(
+ lldb_private::Process &process,
+ std::vector<lldb_private::MemoryRegionInfo> &ranges,
+ llvm::function_ref<bool(const lldb_private::Thread &)>
+ save_thread_predicate) override;
+
protected:
/// Runtime linker rendezvous structure.
DYLDRendezvous m_rendezvous;
diff --git a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
index b0aa664775b4..de047ee214c1 100644
--- a/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp
@@ -82,9 +82,6 @@ void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info,
case eStopReasonProcessorTrace:
log.Printf("%s: %s processor trace", __FUNCTION__, header);
return;
- case eStopReasonHistoryBoundary:
- log.Printf("%s: %s history boundary", __FUNCTION__, header);
- return;
default:
log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header,
static_cast<uint32_t>(stop_info.reason));
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index 367fce442bb8..9b2907c68099 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -402,17 +402,9 @@ lldb_private::DynamicLoader *ProcessKDP::GetDynamicLoader() {
Status ProcessKDP::WillResume() { return Status(); }
-Status ProcessKDP::DoResume(RunDirection direction) {
+Status ProcessKDP::DoResume() {
Status error;
Log *log = GetLog(KDPLog::Process);
-
- if (direction == RunDirection::eRunReverse) {
- error.FromErrorStringWithFormatv(
- "error: {0} does not support reverse execution of processes",
- GetPluginName());
- return error;
- }
-
// Only start the async thread if we try to do any process control
if (!m_async_thread.IsJoinable())
StartAsyncThread();
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
index 1b71d83f70b0..e5ec5914f960 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h
@@ -90,7 +90,7 @@ public:
// Process Control
lldb_private::Status WillResume() override;
- lldb_private::Status DoResume(lldb::RunDirection direction) override;
+ lldb_private::Status DoResume() override;
lldb_private::Status DoHalt(bool &caused_stop) override;
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 76b7095deaa5..703aa082f047 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -204,17 +204,11 @@ ProcessWindows::DoAttachToProcessWithID(lldb::pid_t pid,
return error;
}
-Status ProcessWindows::DoResume(RunDirection direction) {
+Status ProcessWindows::DoResume() {
Log *log = GetLog(WindowsLog::Process);
llvm::sys::ScopedLock lock(m_mutex);
Status error;
- if (direction == RunDirection::eRunReverse) {
- error.SetErrorStringWithFormatv(
- "error: {0} does not support reverse execution of processes", GetPluginName());
- return error;
- }
-
StateType private_state = GetPrivateState();
if (private_state == eStateStopped || private_state == eStateCrashed) {
LLDB_LOG(log, "process {0} is in state {1}. Resuming...",
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
index 97284b7cd143..e97cfb790248 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h
@@ -52,7 +52,7 @@ public:
Status DoAttachToProcessWithID(
lldb::pid_t pid,
const lldb_private::ProcessAttachInfo &attach_info) override;
- Status DoResume(lldb::RunDirection direction) override;
+ Status DoResume() override;
Status DoDestroy() override;
Status DoHalt(bool &caused_stop) override;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index fc792a440941..e42526c8fd72 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -199,20 +199,6 @@ uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() {
return m_max_packet_size;
}
-bool GDBRemoteCommunicationClient::GetReverseContinueSupported() {
- if (m_supports_reverse_continue == eLazyBoolCalculate) {
- GetRemoteQSupported();
- }
- return m_supports_reverse_continue == eLazyBoolYes;
-}
-
-bool GDBRemoteCommunicationClient::GetReverseStepSupported() {
- if (m_supports_reverse_step == eLazyBoolCalculate) {
- GetRemoteQSupported();
- }
- return m_supports_reverse_step == eLazyBoolYes;
-}
-
bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() {
if (m_supports_not_sending_acks == eLazyBoolCalculate) {
m_send_acks = true;
@@ -309,8 +295,6 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_supports_qXfer_siginfo_read = eLazyBoolCalculate;
m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
m_uses_native_signals = eLazyBoolCalculate;
- m_supports_reverse_continue = eLazyBoolCalculate;
- m_supports_reverse_step = eLazyBoolCalculate;
m_supports_qProcessInfoPID = true;
m_supports_qfProcessInfo = true;
m_supports_qUserName = true;
@@ -364,8 +348,6 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_memory_tagging = eLazyBoolNo;
m_supports_qSaveCore = eLazyBoolNo;
m_uses_native_signals = eLazyBoolNo;
- m_supports_reverse_continue = eLazyBoolNo;
- m_supports_reverse_step = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
// not, we assume no limit
@@ -419,10 +401,6 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_qSaveCore = eLazyBoolYes;
else if (x == "native-signals+")
m_uses_native_signals = eLazyBoolYes;
- else if (x == "ReverseContinue+")
- m_supports_reverse_continue = eLazyBoolYes;
- else if (x == "ReverseStep+")
- m_supports_reverse_step = eLazyBoolYes;
// Look for a list of compressions in the features list e.g.
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
// deflate,lzma
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 116b47c1edf0..898d176abc34 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -331,10 +331,6 @@ public:
bool GetMultiprocessSupported();
- bool GetReverseContinueSupported();
-
- bool GetReverseStepSupported();
-
LazyBool SupportsAllocDeallocMemory() // const
{
// Uncomment this to have lldb pretend the debug server doesn't respond to
@@ -565,8 +561,6 @@ protected:
LazyBool m_supports_memory_tagging = eLazyBoolCalculate;
LazyBool m_supports_qSaveCore = eLazyBoolCalculate;
LazyBool m_uses_native_signals = eLazyBoolCalculate;
- LazyBool m_supports_reverse_continue = eLazyBoolCalculate;
- LazyBool m_supports_reverse_step = eLazyBoolCalculate;
bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
m_supports_qUserName : 1, m_supports_qGroupName : 1,
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 4016cde74ebe..35fa93e53bc6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -716,7 +716,6 @@ static const char *GetStopReasonString(StopReason stop_reason) {
return "vforkdone";
case eStopReasonInterrupt:
return "async interrupt";
- case eStopReasonHistoryBoundary:
case eStopReasonInstrumentation:
case eStopReasonInvalid:
case eStopReasonPlanComplete:
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 3fc03bd05d5d..3e09c316d74f 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -169,10 +169,6 @@ public:
}
};
-std::chrono::seconds ResumeTimeout() {
- return std::chrono::seconds(5);
-}
-
} // namespace
static PluginProperties &GetGlobalPluginProperties() {
@@ -1184,11 +1180,10 @@ Status ProcessGDBRemote::WillResume() {
return Status();
}
-Status ProcessGDBRemote::DoResume(RunDirection direction) {
+Status ProcessGDBRemote::DoResume() {
Status error;
Log *log = GetLog(GDBRLog::Process);
- LLDB_LOGF(log, "ProcessGDBRemote::Resume(%s)",
- direction == RunDirection::eRunForward ? "" : "reverse");
+ LLDB_LOGF(log, "ProcessGDBRemote::Resume()");
ListenerSP listener_sp(
Listener::MakeListener("gdb-remote.resume-packet-sent"));
@@ -1202,21 +1197,12 @@ Status ProcessGDBRemote::DoResume(RunDirection direction) {
StreamString continue_packet;
bool continue_packet_error = false;
- // Number of threads continuing with "c", i.e. continuing without a signal to deliver.
- const size_t num_continue_c_tids = m_continue_c_tids.size();
- // Number of threads continuing with "C", i.e. continuing with a signal to deliver.
- const size_t num_continue_C_tids = m_continue_C_tids.size();
- // Number of threads continuing with "s", i.e. single-stepping.
- const size_t num_continue_s_tids = m_continue_s_tids.size();
- // Number of threads continuing with "S", i.e. single-stepping with a signal to deliver.
- const size_t num_continue_S_tids = m_continue_S_tids.size();
- if (direction == RunDirection::eRunForward &&
- m_gdb_comm.HasAnyVContSupport()) {
+ if (m_gdb_comm.HasAnyVContSupport()) {
std::string pid_prefix;
if (m_gdb_comm.GetMultiprocessSupported())
pid_prefix = llvm::formatv("p{0:x-}.", GetID());
- if (num_continue_c_tids == num_threads ||
+ if (m_continue_c_tids.size() == num_threads ||
(m_continue_c_tids.empty() && m_continue_C_tids.empty() &&
m_continue_s_tids.empty() && m_continue_S_tids.empty())) {
// All threads are continuing
@@ -1279,11 +1265,14 @@ Status ProcessGDBRemote::DoResume(RunDirection direction) {
} else
continue_packet_error = true;
- if (direction == RunDirection::eRunForward && continue_packet_error) {
+ if (continue_packet_error) {
// Either no vCont support, or we tried to use part of the vCont packet
- // that wasn't supported by the remote GDB server, or it's the reverse
- // direction. We need to try and make a simple packet that can do our
- // continue.
+ // that wasn't supported by the remote GDB server. We need to try and
+ // make a simple packet that can do our continue
+ const size_t num_continue_c_tids = m_continue_c_tids.size();
+ const size_t num_continue_C_tids = m_continue_C_tids.size();
+ const size_t num_continue_s_tids = m_continue_s_tids.size();
+ const size_t num_continue_S_tids = m_continue_S_tids.size();
if (num_continue_c_tids > 0) {
if (num_continue_c_tids == num_threads) {
// All threads are resuming...
@@ -1374,41 +1363,9 @@ Status ProcessGDBRemote::DoResume(RunDirection direction) {
}
}
- if (direction == RunDirection::eRunReverse && continue_packet_error) {
- if (num_continue_C_tids > 0 || num_continue_S_tids > 0) {
- LLDB_LOGF(log, "ProcessGDBRemote::DoResumeReverse: Signals not supported");
- return Status::FromErrorString("can't deliver signals while running in reverse");
- }
-
- if (num_continue_s_tids > 0) {
- if (num_continue_s_tids > 1) {
- LLDB_LOGF(log, "ProcessGDBRemote::DoResumeReverse: can't step multiple threads");
- return Status::FromErrorString("can't step multiple threads while reverse-stepping");
- }
-
- if (!m_gdb_comm.GetReverseStepSupported()) {
- LLDB_LOGF(log, "ProcessGDBRemote::DoResumeReverse: target does not support reverse-stepping");
- return Status::FromErrorString("target does not support reverse-stepping");
- }
-
- m_gdb_comm.SetCurrentThreadForRun(m_continue_s_tids.front());
- continue_packet.PutCString("bs");
- } else {
- if (!m_gdb_comm.GetReverseContinueSupported()) {
- LLDB_LOGF(log, "ProcessGDBRemote::DoResumeReverse: target does not support reverse-continue");
- return Status::FromErrorString("target does not support reverse-continue");
- }
-
- // All threads continue whether requested or not ---
- // we can't change how threads ran in the past.
- continue_packet.PutCString("bc");
- }
-
- continue_packet_error = false;
- }
-
if (continue_packet_error) {
- return Status::FromErrorString("can't make continue packet for this resume");
+ error =
+ Status::FromErrorString("can't make continue packet for this resume");
} else {
EventSP event_sp;
if (!m_async_thread.IsJoinable()) {
@@ -1423,7 +1380,7 @@ Status ProcessGDBRemote::DoResume(RunDirection direction) {
std::make_shared<EventDataBytes>(continue_packet.GetString());
m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp);
- if (!listener_sp->GetEvent(event_sp, ResumeTimeout())) {
+ if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) {
error = Status::FromErrorString("Resume timed out.");
LLDB_LOGF(log, "ProcessGDBRemote::DoResume: Resume timed out.");
} else if (event_sp->BroadcasterIs(&m_async_broadcaster)) {
@@ -1906,10 +1863,6 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException(
*thread_sp, description.c_str()));
handled = true;
- } else if (reason == "replaylog") {
- thread_sp->SetStopInfo(StopInfo::CreateStopReasonHistoryBoundary(
- *thread_sp, description.c_str()));
- handled = true;
} else if (reason == "exec") {
did_exec = true;
thread_sp->SetStopInfo(
@@ -2365,8 +2318,6 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
description = std::string(ostr.GetString());
} else if (key.compare("swbreak") == 0 || key.compare("hwbreak") == 0) {
reason = "breakpoint";
- } else if (key.compare("replaylog") == 0) {
- reason = "replaylog";
} else if (key.compare("library") == 0) {
auto error = LoadModules();
if (error) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index fa3e1cec76e2..249279585138 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -111,7 +111,7 @@ public:
// Process Control
Status WillResume() override;
- Status DoResume(lldb::RunDirection direction) override;
+ Status DoResume() override;
Status DoHalt(bool &caused_stop) override;
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index 32ffba763c08..5ea3db23f114 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -21,11 +21,13 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
@@ -34,6 +36,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Threading.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
#include "Plugins/ObjectFile/Placeholder/ObjectFilePlaceholder.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
@@ -333,6 +336,16 @@ ArchSpec ProcessMinidump::GetArchitecture() {
return ArchSpec(triple);
}
+DataExtractor ProcessMinidump::GetAuxvData() {
+ std::optional<llvm::ArrayRef<uint8_t>> auxv =
+ m_minidump_parser->GetStream(StreamType::LinuxAuxv);
+ if (!auxv)
+ return DataExtractor();
+
+ return DataExtractor(auxv->data(), auxv->size(), GetByteOrder(),
+ GetAddressByteSize(), GetAddressByteSize());
+}
+
void ProcessMinidump::BuildMemoryRegions() {
if (m_memory_regions)
return;
@@ -534,7 +547,12 @@ void ProcessMinidump::ReadModuleList() {
module_sp = Module::CreateModuleFromObjectFile<ObjectFilePlaceholder>(
module_spec, load_addr, load_size);
- GetTarget().GetImages().Append(module_sp, true /* notify */);
+ // If we haven't loaded a main executable yet, set the first module to be
+ // main executable
+ if (!GetTarget().GetExecutableModule())
+ GetTarget().SetExecutableModule(module_sp);
+ else
+ GetTarget().GetImages().Append(module_sp, true /* notify */);
}
bool load_addr_changed = false;
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
index f2ea0a2b61d1..3d235670a33a 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -53,12 +53,11 @@ public:
Status DoLoadCore() override;
- DynamicLoader *GetDynamicLoader() override { return nullptr; }
+ // Returns AUXV structure found in the core file
+ lldb_private::DataExtractor GetAuxvData() override;
llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
- SystemRuntime *GetSystemRuntime() override { return nullptr; }
-
Status DoDestroy() override;
void RefreshStateAfterStop() override;
diff --git a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
index e879c4931565..f305d1b7031d 100644
--- a/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
+++ b/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_x86_64.cpp
@@ -44,6 +44,17 @@ static void writeRegister(const void *reg_src, uint8_t *context,
memcpy(reg_dest.data(), reg_src, reg_dest.size());
}
+// TODO: Fix the registers in this file!
+// writeRegister checks x86_64 registers without base registers. This causes
+// an overlap in the register enum values. So we were truncating fs_base.
+// We should standardize to the x86_64_with_base registers.
+static void writeBaseRegister(const void *reg_src, uint8_t *context,
+ const RegisterInfo &reg) {
+ auto bytes = reg.mutable_data(context);
+ llvm::MutableArrayRef<uint8_t> reg_dest = bytes.take_front(8);
+ memcpy(reg_dest.data(), reg_src, reg_dest.size());
+}
+
lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_64(
llvm::ArrayRef<uint8_t> source_data,
RegisterInfoInterface *target_reg_interface) {
@@ -105,11 +116,12 @@ lldb::DataBufferSP lldb_private::minidump::ConvertMinidumpContext_x86_64(
writeRegister(&context->r15, result_base, reg_info[lldb_r15_x86_64]);
}
+ // See comment on base regsiter
if ((context_flags & LLDBSpecificFlag) == LLDBSpecificFlag) {
- writeRegister(&context->fs_base, result_base,
- reg_info[x86_64_with_base::lldb_fs_base]);
- writeRegister(&context->gs_base, result_base,
- reg_info[x86_64_with_base::lldb_gs_base]);
+ writeBaseRegister(&context->fs_base, result_base,
+ reg_info[x86_64_with_base::lldb_fs_base]);
+ writeBaseRegister(&context->gs_base, result_base,
+ reg_info[x86_64_with_base::lldb_gs_base]);
}
// TODO parse the floating point registers
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
index 304c12173dd3..d2111ce877ce 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -182,15 +182,10 @@ void ScriptedProcess::DidResume() {
m_pid = GetInterface().GetProcessID();
}
-Status ScriptedProcess::DoResume(RunDirection direction) {
+Status ScriptedProcess::DoResume() {
LLDB_LOGF(GetLog(LLDBLog::Process), "ScriptedProcess::%s resuming process", __FUNCTION__);
- if (direction == RunDirection::eRunForward) {
- return GetInterface().Resume();
- } else {
- return Status::FromErrorStringWithFormatv(
- "error: {0} does not support reverse execution of processes", GetPluginName());
- }
+ return GetInterface().Resume();
}
Status ScriptedProcess::DoAttach(const ProcessAttachInfo &attach_info) {
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
index 8ebe4ca5f3d4..0335364b4010 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
@@ -52,7 +52,7 @@ public:
void DidResume() override;
- Status DoResume(lldb::RunDirection direction) override;
+ Status DoResume() override;
Status DoAttachToProcessWithID(lldb::pid_t pid,
const ProcessAttachInfo &attach_info) override;
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index ff6a2f59eba3..c009d17d3ba5 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -446,8 +446,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
m_memory_cache(*this), m_allocated_memory_cache(*this),
m_should_detach(false), m_next_event_action_up(), m_public_run_lock(),
m_private_run_lock(), m_currently_handling_do_on_removals(false),
- m_resume_requested(false), m_last_run_direction(eRunForward),
- m_interrupt_tid(LLDB_INVALID_THREAD_ID),
+ m_resume_requested(false), m_interrupt_tid(LLDB_INVALID_THREAD_ID),
m_finalizing(false), m_destructing(false),
m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
@@ -846,7 +845,6 @@ bool Process::HandleProcessStateChangedEvent(
switch (thread_stop_reason) {
case eStopReasonInvalid:
case eStopReasonNone:
- case eStopReasonHistoryBoundary:
break;
case eStopReasonSignal: {
@@ -1354,7 +1352,7 @@ void Process::SetPublicState(StateType new_state, bool restarted) {
}
}
-Status Process::Resume(RunDirection direction) {
+Status Process::Resume() {
Log *log(GetLog(LLDBLog::State | LLDBLog::Process));
LLDB_LOGF(log, "(plugin = %s) -- locking run lock", GetPluginName().data());
if (!m_public_run_lock.TrySetRunning()) {
@@ -1363,7 +1361,7 @@ Status Process::Resume(RunDirection direction) {
return Status::FromErrorString(
"Resume request failed - process still running.");
}
- Status error = PrivateResume(direction);
+ Status error = PrivateResume();
if (!error.Success()) {
// Undo running state change
m_public_run_lock.SetStopped();
@@ -1371,7 +1369,7 @@ Status Process::Resume(RunDirection direction) {
return error;
}
-Status Process::ResumeSynchronous(Stream *stream, RunDirection direction) {
+Status Process::ResumeSynchronous(Stream *stream) {
Log *log(GetLog(LLDBLog::State | LLDBLog::Process));
LLDB_LOGF(log, "Process::ResumeSynchronous -- locking run lock");
if (!m_public_run_lock.TrySetRunning()) {
@@ -1384,7 +1382,7 @@ Status Process::ResumeSynchronous(Stream *stream, RunDirection direction) {
Listener::MakeListener(ResumeSynchronousHijackListenerName.data()));
HijackProcessEvents(listener_sp);
- Status error = PrivateResume(direction);
+ Status error = PrivateResume();
if (error.Success()) {
StateType state =
WaitForProcessToStop(std::nullopt, nullptr, true, listener_sp, stream,
@@ -3241,7 +3239,7 @@ Status Process::ConnectRemote(llvm::StringRef remote_url) {
return error;
}
-Status Process::PrivateResume(RunDirection direction) {
+Status Process::PrivateResume() {
Log *log(GetLog(LLDBLog::Process | LLDBLog::Step));
LLDB_LOGF(log,
"Process::PrivateResume() m_stop_id = %u, public state: %s "
@@ -3257,15 +3255,6 @@ Status Process::PrivateResume(RunDirection direction) {
if (!GetModID().IsLastResumeForUserExpression())
ResetExtendedCrashInfoDict();
- if (m_last_run_direction != direction) {
- // In the future we might want to support mixed-direction plans,
- // e.g. a forward step-over stops at a breakpoint, the user does
- // a reverse-step, then disables the breakpoint and continues forward.
- // This code will need to be changed to support that.
- m_thread_list.DiscardThreadPlans();
- m_last_run_direction = direction;
- }
-
Status error(WillResume());
// Tell the process it is about to resume before the thread list
if (error.Success()) {
@@ -3283,7 +3272,7 @@ Status Process::PrivateResume(RunDirection direction) {
"Process::PrivateResume PreResumeActions failed, not resuming.");
} else {
m_mod_id.BumpResumeID();
- error = DoResume(direction);
+ error = DoResume();
if (error.Success()) {
DidResume();
m_thread_list.DidResume();
@@ -3746,7 +3735,7 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) {
"from state: %s",
static_cast<void *>(event_ptr), StateAsCString(state));
ProcessEventData::SetRestartedInEvent(event_ptr, true);
- PrivateResume(m_last_run_direction);
+ PrivateResume();
}
} else {
return_value = true;
@@ -4357,7 +4346,7 @@ void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) {
SetRestarted(true);
// Use the private resume method here, since we aren't changing the run
// lock state.
- process_sp->PrivateResume(process_sp->m_last_run_direction);
+ process_sp->PrivateResume();
} else {
bool hijacked = process_sp->IsHijackedForEvent(eBroadcastBitStateChanged) &&
!process_sp->StateChangedIsHijackedForSynchronousResume();
@@ -6539,6 +6528,29 @@ static void AddRegion(const MemoryRegionInfo &region, bool try_dirty_pages,
CreateCoreFileMemoryRange(region));
}
+static void SaveDynamicLoaderSections(Process &process,
+ const SaveCoreOptions &options,
+ CoreFileMemoryRanges &ranges,
+ std::set<addr_t> &stack_ends) {
+ DynamicLoader *dyld = process.GetDynamicLoader();
+ if (!dyld)
+ return;
+
+ std::vector<MemoryRegionInfo> dynamic_loader_mem_regions;
+ std::function<bool(const lldb_private::Thread &)> save_thread_predicate =
+ [&](const lldb_private::Thread &t) -> bool {
+ return options.ShouldThreadBeSaved(t.GetID());
+ };
+ dyld->CalculateDynamicSaveCoreRanges(process, dynamic_loader_mem_regions,
+ save_thread_predicate);
+ for (const auto &region : dynamic_loader_mem_regions) {
+ // The Dynamic Loader can give us regions that could include a truncated
+ // stack
+ if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0)
+ AddRegion(region, true, ranges);
+ }
+}
+
static void SaveOffRegionsWithStackPointers(Process &process,
const SaveCoreOptions &core_options,
const MemoryRegionInfos &regions,
@@ -6570,11 +6582,13 @@ static void SaveOffRegionsWithStackPointers(Process &process,
// off in other calls
sp_region.GetRange().SetRangeBase(stack_head);
sp_region.GetRange().SetByteSize(stack_size);
- stack_ends.insert(sp_region.GetRange().GetRangeEnd());
+ const addr_t range_end = sp_region.GetRange().GetRangeEnd();
+ stack_ends.insert(range_end);
// This will return true if the threadlist the user specified is empty,
// or contains the thread id from thread_sp.
- if (core_options.ShouldThreadBeSaved(thread_sp->GetID()))
+ if (core_options.ShouldThreadBeSaved(thread_sp->GetID())) {
AddRegion(sp_region, try_dirty_pages, ranges);
+ }
}
}
}
@@ -6683,9 +6697,14 @@ Status Process::CalculateCoreFileSaveRanges(const SaveCoreOptions &options,
std::set<addr_t> stack_ends;
// For fully custom set ups, we don't want to even look at threads if there
// are no threads specified.
- if (core_style != lldb::eSaveCoreCustomOnly || options.HasSpecifiedThreads())
+ if (core_style != lldb::eSaveCoreCustomOnly ||
+ options.HasSpecifiedThreads()) {
SaveOffRegionsWithStackPointers(*this, options, regions, ranges,
stack_ends);
+ // Save off the dynamic loader sections, so if we are on an architecture
+ // that supports Thread Locals, that we include those as well.
+ SaveDynamicLoaderSections(*this, options, ranges, stack_ends);
+ }
switch (core_style) {
case eSaveCoreUnspecified:
diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp
index 08e9a7c099ba..bd7032b803df 100644
--- a/lldb/source/Target/StopInfo.cpp
+++ b/lldb/source/Target/StopInfo.cpp
@@ -1212,30 +1212,6 @@ public:
}
};
-// StopInfoHistoryBoundary
-
-class StopInfoHistoryBoundary : public StopInfo {
-public:
- StopInfoHistoryBoundary(Thread &thread, const char *description)
- : StopInfo(thread, LLDB_INVALID_UID) {
- if (description)
- SetDescription(description);
- }
-
- ~StopInfoHistoryBoundary() override = default;
-
- StopReason GetStopReason() const override {
- return eStopReasonHistoryBoundary;
- }
-
- const char *GetDescription() override {
- if (m_description.empty())
- return "history boundary";
- else
- return m_description.c_str();
- }
-};
-
// StopInfoThreadPlan
class StopInfoThreadPlan : public StopInfo {
@@ -1463,11 +1439,6 @@ StopInfoSP StopInfo::CreateStopReasonProcessorTrace(Thread &thread,
return StopInfoSP(new StopInfoProcessorTrace(thread, description));
}
-StopInfoSP StopInfo::CreateStopReasonHistoryBoundary(Thread &thread,
- const char *description) {
- return StopInfoSP(new StopInfoHistoryBoundary(thread, description));
-}
-
StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) {
return StopInfoSP(new StopInfoExec(thread));
}
diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp
index bbb586f033b7..902fbb2b519e 100644
--- a/lldb/source/Target/Thread.cpp
+++ b/lldb/source/Target/Thread.cpp
@@ -624,12 +624,10 @@ void Thread::SetupForResume() {
// what the current plan is.
lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext());
- ProcessSP process_sp(GetProcess());
- if (reg_ctx_sp && process_sp &&
- process_sp->GetLastRunDirection() == eRunForward) {
+ if (reg_ctx_sp) {
const addr_t thread_pc = reg_ctx_sp->GetPC();
BreakpointSiteSP bp_site_sp =
- process_sp->GetBreakpointSiteList().FindByAddress(thread_pc);
+ GetProcess()->GetBreakpointSiteList().FindByAddress(thread_pc);
if (bp_site_sp) {
// Note, don't assume there's a ThreadPlanStepOverBreakpoint, the
// target may not require anything special to step over a breakpoint.
@@ -1734,8 +1732,6 @@ std::string Thread::StopReasonAsString(lldb::StopReason reason) {
return "processor trace";
case eStopReasonInterrupt:
return "async interrupt";
- case eStopReasonHistoryBoundary:
- return "history boundary";
}
return "StopReason = " + std::to_string(reason);
diff --git a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py
index 03cc415924e0..4818dde4f3b8 100644
--- a/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py
+++ b/lldb/test/API/functionalities/process_save_core_minidump/TestProcessSaveCoreMinidump.py
@@ -523,8 +523,10 @@ class ProcessSaveCoreMinidumpTestCase(TestBase):
finally:
self.assertTrue(self.dbg.DeleteTarget(target))
- def minidump_deterministic_difference(self):
- """Test that verifies that two minidumps produced are identical."""
+ @skipUnlessPlatform(["linux"])
+ @skipUnlessArch("x86_64")
+ def minidump_saves_fs_base_region(self):
+ """Test that verifies the minidump file saves region for fs_base"""
self.build()
exe = self.getBuildArtifact("a.out")
@@ -534,6 +536,45 @@ class ProcessSaveCoreMinidumpTestCase(TestBase):
None, None, self.get_process_working_directory()
)
self.assertState(process.GetState(), lldb.eStateStopped)
+ thread = process.GetThreadAtIndex(0)
+ custom_file = self.getBuildArtifact("core.reg_region.dmp")
+ options = lldb.SBSaveCoreOptions()
+ options.SetOutputFile(lldb.SBFileSpec(custom_file))
+ options.SetPluginName("minidump")
+ options.SetStyle(lldb.eSaveCoreCustomOnly)
+ options.AddThread(thread)
+ error = process.SaveCore(options)
+ self.assertTrue(error.Success())
+
+ registers = thread.GetFrameAtIndex(0).GetRegisters()
+ fs_base = registers.GetFirstValueByName("fs_base").GetValueAsUnsigned()
+ self.assertTrue(fs_base != 0)
+ core_target = self.dbg.CreateTarget(None)
+ core_proc = core_target.LoadCore(one_region_file)
+ core_region_list = core_proc.GetMemoryRegions()
+ live_region_list = process.GetMemoryRegions()
+ live_region = lldb.SBMemoryRegionInfo()
+ live_region_list.GetMemoryRegionForAddress(fs_base, live_region)
+ core_region = lldb.SBMemoryRegionInfo()
+ error = core_region_list.GetMemoryRegionForAddress(fs_base, core_region)
+ self.assertTrue(error.Success())
+ self.assertEqual(live_region, core_region)
+
+ finally:
+ self.assertTrue(self.dbg.DeleteTarget(target))
+ self.assertTrue(self.dbg.DeleteTarget(core_target))
+ if os.path.isfile(custom_file):
+ os.unlink(custom_file)
+
+ def minidump_deterministic_difference(self):
+ """Test that verifies that two minidumps produced are identical."""
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ try:
+ target = self.dbg.CreateTarget(exe)
+ process = target.LaunchSimple(
+ None, None, self.get_process_working_directory()
+ )
core_styles = [
lldb.eSaveCoreStackOnly,
@@ -562,6 +603,36 @@ class ProcessSaveCoreMinidumpTestCase(TestBase):
self.assertEqual(file_one, file_two)
self.assertTrue(os.unlink(spec_one.GetFileName()))
self.assertTrue(os.unlink(spec_two.GetFileName()))
-
finally:
self.assertTrue(self.dbg.DeleteTarget(target))
+
+ @skipUnlessPlatform(["linux"])
+ @skipUnlessArch("x86_64")
+ def minidump_saves_fs_base_region(self):
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ try:
+ target = self.dbg.CreateTarget(exe)
+ process = target.LaunchSimple(
+ None, None, self.get_process_working_directory()
+ )
+ self.assertState(process.GetState(), lldb.eStateStopped)
+ thread = process.GetThreadAtIndex(0)
+ tls_file = self.getBuildArtifact("core.tls.dmp")
+ options = lldb.SBSaveCoreOptions()
+ options.SetOutputFile(lldb.SBFileSpec(tls_file))
+ options.SetPluginName("minidump")
+ options.SetStyle(lldb.eSaveCoreCustomOnly)
+ options.AddThread(thread)
+ error = process.SaveCore(options)
+ self.assertTrue(error.Success())
+ core_target = self.dbg.CreateTarget(None)
+ core_proc = core_target.LoadCore(tls_file)
+ frame = core_proc.GetThreadAtIndex(0).GetFrameAtIndex(0)
+ tls_val = frame.FindValue("lf")
+ self.assertEqual(tls_val.GetValueAsUnsigned(), 42)
+
+ except:
+ self.assertTrue(self.dbg.DeleteTarget(target))
+ if os.path.isfile(tls_file):
+ os.unlink(tls_file)
diff --git a/lldb/test/API/functionalities/process_save_core_minidump/main.cpp b/lldb/test/API/functionalities/process_save_core_minidump/main.cpp
index fa34a371f206..15daa68e9a64 100644
--- a/lldb/test/API/functionalities/process_save_core_minidump/main.cpp
+++ b/lldb/test/API/functionalities/process_save_core_minidump/main.cpp
@@ -1,6 +1,7 @@
#include <cassert>
#include <iostream>
#include <thread>
+thread_local size_t lf = 42;
void g() { assert(false); }
diff --git a/lldb/test/API/functionalities/reverse-execution/Makefile b/lldb/test/API/functionalities/reverse-execution/Makefile
deleted file mode 100644
index 10495940055b..000000000000
--- a/lldb/test/API/functionalities/reverse-execution/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-C_SOURCES := main.c
-
-include Makefile.rules
diff --git a/lldb/test/API/functionalities/reverse-execution/TestReverseContinueBreakpoints.py b/lldb/test/API/functionalities/reverse-execution/TestReverseContinueBreakpoints.py
deleted file mode 100644
index b37578fbd824..000000000000
--- a/lldb/test/API/functionalities/reverse-execution/TestReverseContinueBreakpoints.py
+++ /dev/null
@@ -1,115 +0,0 @@
-import lldb
-import time
-import unittest
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.decorators import *
-from lldbsuite.test.gdbclientutils import *
-from lldbsuite.test.lldbreverse import ReverseTestBase
-from lldbsuite.test import lldbutil
-
-
-class TestReverseContinueBreakpoints(ReverseTestBase):
- NO_DEBUG_INFO_TESTCASE = True
-
- def test_reverse_continue(self):
- self.reverse_continue_internal(async_mode=False)
-
- def test_reverse_continue_async(self):
- self.reverse_continue_internal(async_mode=True)
-
- def reverse_continue_internal(self, async_mode):
- target, process, initial_threads = self.setup_recording(async_mode)
-
- # Reverse-continue. We'll stop at the point where we started recording.
- status = process.Continue(lldb.eRunReverse)
- self.assertSuccess(status)
- self.expect_async_state_changes(async_mode, process, [lldb.eStateRunning, lldb.eStateStopped])
- self.expect(
- "thread list",
- STOPPED_DUE_TO_HISTORY_BOUNDARY,
- substrs=["stopped", "stop reason = history boundary"],
- )
-
- # Continue forward normally until the target exits.
- status = process.Continue()
- self.expect_async_state_changes(async_mode, process, [lldb.eStateRunning, lldb.eStateExited])
- self.assertSuccess(status)
- self.assertState(process.GetState(), lldb.eStateExited)
- self.assertEqual(process.GetExitStatus(), 0)
-
- def test_reverse_continue_breakpoint(self):
- self.reverse_continue_breakpoint_internal(async_mode=False)
-
- def test_reverse_continue_breakpoint_async(self):
- self.reverse_continue_breakpoint_internal(async_mode=True)
-
- def reverse_continue_breakpoint_internal(self, async_mode):
- target, process, initial_threads = self.setup_recording(async_mode)
-
- # Reverse-continue to the function "trigger_breakpoint".
- trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)
- status = process.Continue(lldb.eRunReverse)
- self.assertSuccess(status)
- self.expect_async_state_changes(async_mode, process, [lldb.eStateRunning, lldb.eStateStopped])
- threads_now = lldbutil.get_threads_stopped_at_breakpoint(process, trigger_bkpt)
- self.assertEqual(threads_now, initial_threads)
-
- def test_reverse_continue_skip_breakpoint(self):
- self.reverse_continue_skip_breakpoint_internal(async_mode=False)
-
- def test_reverse_continue_skip_breakpoint_async(self):
- self.reverse_continue_skip_breakpoint_internal(async_mode=True)
-
- def reverse_continue_skip_breakpoint_internal(self, async_mode):
- target, process, initial_threads = self.setup_recording(async_mode)
-
- # Reverse-continue over a breakpoint at "trigger_breakpoint" whose
- # condition is false.
- # This tests that we continue in the correct direction after hitting
- # the breakpoint.
- trigger_bkpt = target.BreakpointCreateByName("trigger_breakpoint", None)
- trigger_bkpt.SetCondition("false_condition")
- status = process.Continue(lldb.eRunReverse)
- self.expect_async_state_changes(async_mode, process, [lldb.eStateRunning, lldb.eStateStopped])
- self.assertSuccess(status)
- self.expect(
- "thread list",
- STOPPED_DUE_TO_HISTORY_BOUNDARY,
- substrs=["stopped", "stop reason = history boundary"],
- )
-
- def setup_recording(self, async_mode):
- """
- Record execution of code between "start_recording" and "stop_recording" breakpoints.
-
- Returns with the target stopped at "stop_recording", with recording disabled,
- ready to reverse-execute.
- """
- self.build()
- target = self.dbg.CreateTarget("")
- process = self.connect(target)
-
- # Record execution from the start of the function "start_recording"
- # to the start of the function "stop_recording". We want to keep the
- # interval that we record as small as possible to minimize the run-time
- # of our single-stepping recorder.
- start_recording_bkpt = target.BreakpointCreateByName("start_recording", None)
- initial_threads = lldbutil.continue_to_breakpoint(process, start_recording_bkpt)
- self.assertEqual(len(initial_threads), 1)
- target.BreakpointDelete(start_recording_bkpt.GetID())
- self.start_recording()
- stop_recording_bkpt = target.BreakpointCreateByName("stop_recording", None)
- lldbutil.continue_to_breakpoint(process, stop_recording_bkpt)
- target.BreakpointDelete(stop_recording_bkpt.GetID())
- self.stop_recording()
-
- self.dbg.SetAsync(async_mode)
- self.expect_async_state_changes(async_mode, process, [lldb.eStateStopped])
-
- return target, process, initial_threads
-
- def expect_async_state_changes(self, async_mode, process, states):
- if not async_mode:
- return
- listener = self.dbg.GetListener()
- lldbutil.expect_state_changes(self, listener, process, states)
diff --git a/lldb/test/API/functionalities/reverse-execution/TestReverseContinueNotSupported.py b/lldb/test/API/functionalities/reverse-execution/TestReverseContinueNotSupported.py
deleted file mode 100644
index d610761b8cb0..000000000000
--- a/lldb/test/API/functionalities/reverse-execution/TestReverseContinueNotSupported.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import lldb
-import unittest
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test.decorators import *
-from lldbsuite.test import lldbutil
-
-
-class TestReverseContinueNotSupported(TestBase):
- NO_DEBUG_INFO_TESTCASE = True
-
- def test_reverse_continue_not_supported(self):
- self.build()
- exe = self.getBuildArtifact("a.out")
- target = self.dbg.CreateTarget(exe)
- self.assertTrue(target, VALID_TARGET)
-
- main_bkpt = target.BreakpointCreateByName("main", None)
- self.assertTrue(main_bkpt, VALID_BREAKPOINT)
-
- process = target.LaunchSimple(None, None, self.get_process_working_directory())
- self.assertTrue(process, PROCESS_IS_VALID)
-
- # This will fail gracefully.
- status = process.Continue(lldb.eRunReverse)
- self.assertFailure(status, "target does not support reverse-continue")
-
- status = process.Continue()
- self.assertSuccess(status)
- self.assertState(process.GetState(), lldb.eStateExited)
- self.assertEqual(process.GetExitStatus(), 0)
diff --git a/lldb/test/API/functionalities/reverse-execution/main.c b/lldb/test/API/functionalities/reverse-execution/main.c
deleted file mode 100644
index 40e45dc9f5c3..000000000000
--- a/lldb/test/API/functionalities/reverse-execution/main.c
+++ /dev/null
@@ -1,14 +0,0 @@
-volatile int false_condition = 0;
-
-static void start_recording() {}
-
-static void trigger_breakpoint() {}
-
-static void stop_recording() {}
-
-int main() {
- start_recording();
- trigger_breakpoint();
- stop_recording();
- return 0;
-}
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 211fd34957f4..558f889c4b7f 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -1045,9 +1045,6 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
case lldb::eStopReasonProcessorTrace:
body.try_emplace("reason", "processor trace");
break;
- case lldb::eStopReasonHistoryBoundary:
- body.try_emplace("reason", "history boundary");
- break;
case lldb::eStopReasonSignal:
case lldb::eStopReasonException:
body.try_emplace("reason", "exception");
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 1c5e3ac70087..b38833c0fdb6 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -111,7 +111,6 @@ bool ThreadHasStopReason(lldb::SBThread &thread) {
case lldb::eStopReasonVFork:
case lldb::eStopReasonVForkDone:
case lldb::eStopReasonInterrupt:
- case lldb::eStopReasonHistoryBoundary:
return true;
case lldb::eStopReasonThreadExiting:
case lldb::eStopReasonInvalid:
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
index 40b85e327201..54442c91096b 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ELFNixPlatform.h
@@ -106,14 +106,14 @@ public:
/// RuntimeAliases function, in which case the client is responsible for
/// setting up all aliases (including the required ones).
static Expected<std::unique_ptr<ELFNixPlatform>>
- Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
- JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
+ Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
+ std::unique_ptr<DefinitionGenerator> OrcRuntime,
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
/// Construct using a path to the ORC runtime.
static Expected<std::unique_ptr<ELFNixPlatform>>
- Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
- JITDylib &PlatformJD, const char *OrcRuntimePath,
+ Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
+ const char *OrcRuntimePath,
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
ExecutionSession &getExecutionSession() const { return ES; }
@@ -211,8 +211,7 @@ private:
static bool supportedTarget(const Triple &TT);
- ELFNixPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
- JITDylib &PlatformJD,
+ ELFNixPlatform(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator,
Error &Err);
@@ -308,4 +307,4 @@ using SPSELFNixJITDylibDepInfoMap =
} // end namespace orc
} // end namespace llvm
-#endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H \ No newline at end of file
+#endif // LLVM_EXECUTIONENGINE_ORC_ELFNIXPLATFORM_H
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index 1cf6acbf1264..45aea1ccdb6d 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -71,6 +71,7 @@ def int_dx_udot :
[IntrNoMem, Commutative] >;
def int_dx_frac : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>], [IntrNoMem]>;
+def int_dx_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_dx_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
[llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 92d2f67399d2..3d61456589ee 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -62,6 +62,7 @@ let TargetPrefix = "spv" in {
def int_spv_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
def int_spv_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem]>;
def int_spv_cross : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
+ def int_spv_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_lerp : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>,LLVMMatchType<0>],
[IntrNoMem] >;
diff --git a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
index 7d300ea2b60d..5fa57efc1462 100644
--- a/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
+++ b/llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h
@@ -122,6 +122,10 @@ public:
iterator preds_end(DependencyGraph &DAG) const {
return const_cast<DGNode *>(this)->preds_end(DAG);
}
+ /// \Returns a range of DAG predecessors nodes. If this is a MemDGNode then
+ /// this will also include the memory dependency predecessors.
+ /// Please note that this can include the same node more than once, if for
+ /// example it's both a use-def predecessor and a mem dep predecessor.
iterator_range<iterator> preds(DependencyGraph &DAG) const {
return make_range(preds_begin(DAG), preds_end(DAG));
}
diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index d92077dbcbd0..610ecbff5c5c 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -233,10 +233,13 @@ private:
namespace llvm {
namespace orc {
-Expected<std::unique_ptr<ELFNixPlatform>> ELFNixPlatform::Create(
- ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
- JITDylib &PlatformJD, std::unique_ptr<DefinitionGenerator> OrcRuntime,
- std::optional<SymbolAliasMap> RuntimeAliases) {
+Expected<std::unique_ptr<ELFNixPlatform>>
+ELFNixPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer,
+ JITDylib &PlatformJD,
+ std::unique_ptr<DefinitionGenerator> OrcRuntime,
+ std::optional<SymbolAliasMap> RuntimeAliases) {
+
+ auto &ES = ObjLinkingLayer.getExecutionSession();
// If the target is not supported then bail out immediately.
if (!supportedTarget(ES.getTargetTriple()))
@@ -271,15 +274,14 @@ Expected<std::unique_ptr<ELFNixPlatform>> ELFNixPlatform::Create(
// Create the instance.
Error Err = Error::success();
auto P = std::unique_ptr<ELFNixPlatform>(new ELFNixPlatform(
- ES, ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
+ ObjLinkingLayer, PlatformJD, std::move(OrcRuntime), Err));
if (Err)
return std::move(Err);
return std::move(P);
}
Expected<std::unique_ptr<ELFNixPlatform>>
-ELFNixPlatform::Create(ExecutionSession &ES,
- ObjectLinkingLayer &ObjLinkingLayer,
+ELFNixPlatform::Create(ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
std::optional<SymbolAliasMap> RuntimeAliases) {
@@ -289,7 +291,7 @@ ELFNixPlatform::Create(ExecutionSession &ES,
if (!OrcRuntimeArchiveGenerator)
return OrcRuntimeArchiveGenerator.takeError();
- return Create(ES, ObjLinkingLayer, PlatformJD,
+ return Create(ObjLinkingLayer, PlatformJD,
std::move(*OrcRuntimeArchiveGenerator),
std::move(RuntimeAliases));
}
@@ -392,10 +394,10 @@ bool ELFNixPlatform::supportedTarget(const Triple &TT) {
}
ELFNixPlatform::ELFNixPlatform(
- ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
- JITDylib &PlatformJD,
+ ObjectLinkingLayer &ObjLinkingLayer, JITDylib &PlatformJD,
std::unique_ptr<DefinitionGenerator> OrcRuntimeGenerator, Error &Err)
- : ES(ES), PlatformJD(PlatformJD), ObjLinkingLayer(ObjLinkingLayer),
+ : ES(ObjLinkingLayer.getExecutionSession()), PlatformJD(PlatformJD),
+ ObjLinkingLayer(ObjLinkingLayer),
DSOHandleSymbol(ES.intern("__dso_handle")) {
ErrorAsOutParameter _(&Err);
ObjLinkingLayer.addPlugin(std::make_unique<ELFNixPlatformPlugin>(*this));
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index a13443ce57ea..d3dd3b6bedfb 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -1185,8 +1185,8 @@ Expected<JITDylibSP> ExecutorNativePlatform::operator()(LLJIT &J) {
if (!G)
return G.takeError();
- if (auto P = ELFNixPlatform::Create(ES, *ObjLinkingLayer, PlatformJD,
- std::move(*G)))
+ if (auto P =
+ ELFNixPlatform::Create(*ObjLinkingLayer, PlatformJD, std::move(*G)))
J.getExecutionSession().setPlatform(std::move(*P));
else
return P.takeError();
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index c1aefee3793c..8a217cd1ec5c 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -775,6 +775,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
ISD::FMAXNUM,
ISD::FMINIMUM,
ISD::FMAXIMUM,
+ ISD::FCANONICALIZE,
ISD::STRICT_FADD,
ISD::STRICT_FSUB,
ISD::STRICT_FMUL,
@@ -818,6 +819,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationPromotedToType(ISD::FROUNDEVEN, V4Narrow, MVT::v4f32);
setOperationPromotedToType(ISD::FRINT, V4Narrow, MVT::v4f32);
setOperationPromotedToType(ISD::FNEARBYINT, V4Narrow, MVT::v4f32);
+ setOperationPromotedToType(ISD::FCANONICALIZE, V4Narrow, MVT::v4f32);
setOperationAction(ISD::FABS, V4Narrow, Legal);
setOperationAction(ISD::FNEG, V4Narrow, Legal);
@@ -851,6 +853,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SELECT, V8Narrow, Expand);
setOperationAction(ISD::SELECT_CC, V8Narrow, Expand);
setOperationAction(ISD::FP_EXTEND, V8Narrow, Expand);
+ setOperationPromotedToType(ISD::FCANONICALIZE, V8Narrow, MVT::v8f32);
};
if (!Subtarget->hasFullFP16()) {
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 33d05d6039b0..325508b62a9f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -5052,17 +5052,25 @@ def : Pat<(v1f64 (fminnum (v1f64 FPR64:$Rn), (v1f64 FPR64:$Rm))),
def : Pat<(fminnum_ieee (f64 FPR64:$a), (f64 FPR64:$b)),
(FMINNMDrr FPR64:$a, FPR64:$b)>;
-def : Pat<(fminnum_ieee (f32 FPR32:$a), (f32 FPR32:$b)),
- (FMINNMSrr FPR32:$a, FPR32:$b)>;
-def : Pat<(fminnum_ieee (f16 FPR16:$a), (f16 FPR16:$b)),
- (FMINNMHrr FPR16:$a, FPR16:$b)>;
def : Pat<(fmaxnum_ieee (f64 FPR64:$a), (f64 FPR64:$b)),
(FMAXNMDrr FPR64:$a, FPR64:$b)>;
+def : Pat<(f64 (fcanonicalize f64:$a)),
+ (FMINNMDrr f64:$a, f64:$a)>;
+def : Pat<(fminnum_ieee (f32 FPR32:$a), (f32 FPR32:$b)),
+ (FMINNMSrr FPR32:$a, FPR32:$b)>;
def : Pat<(fmaxnum_ieee (f32 FPR32:$a), (f32 FPR32:$b)),
(FMAXNMSrr FPR32:$a, FPR32:$b)>;
+def : Pat<(f32 (fcanonicalize f32:$a)),
+ (FMINNMSrr f32:$a, f32:$a)>;
+
+let Predicates = [HasFullFP16] in {
+def : Pat<(fminnum_ieee (f16 FPR16:$a), (f16 FPR16:$b)),
+ (FMINNMHrr FPR16:$a, FPR16:$b)>;
def : Pat<(fmaxnum_ieee (f16 FPR16:$a), (f16 FPR16:$b)),
(FMAXNMHrr FPR16:$a, FPR16:$b)>;
-
+def : Pat<(f16 (fcanonicalize f16:$a)),
+ (FMINNMHrr f16:$a, f16:$a)>;
+}
//===----------------------------------------------------------------------===//
// Floating point three operand instructions.
//===----------------------------------------------------------------------===//
@@ -5567,26 +5575,41 @@ defm FMINNM : SIMDThreeSameVectorFP<0,1,0b000,"fminnm", any_fminnum>;
defm FMINP : SIMDThreeSameVectorFP<1,1,0b110,"fminp", int_aarch64_neon_fminp>;
defm FMIN : SIMDThreeSameVectorFP<0,1,0b110,"fmin", any_fminimum>;
+let Predicates = [HasNEON] in {
def : Pat<(v2f64 (fminnum_ieee (v2f64 V128:$Rn), (v2f64 V128:$Rm))),
(v2f64 (FMINNMv2f64 (v2f64 V128:$Rn), (v2f64 V128:$Rm)))>;
-def : Pat<(v4f32 (fminnum_ieee (v4f32 V128:$Rn), (v4f32 V128:$Rm))),
- (v4f32 (FMINNMv4f32 (v4f32 V128:$Rn), (v4f32 V128:$Rm)))>;
-def : Pat<(v8f16 (fminnum_ieee (v8f16 V128:$Rn), (v8f16 V128:$Rm))),
- (v8f16 (FMINNMv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm)))>;
-def : Pat<(v2f32 (fminnum_ieee (v2f32 V64:$Rn), (v2f32 V64:$Rm))),
- (v2f32 (FMINNMv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rm)))>;
-def : Pat<(v4f16 (fminnum_ieee (v4f16 V64:$Rn), (v4f16 V64:$Rm))),
- (v4f16 (FMINNMv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rm)))>;
def : Pat<(v2f64 (fmaxnum_ieee (v2f64 V128:$Rn), (v2f64 V128:$Rm))),
(v2f64 (FMAXNMv2f64 (v2f64 V128:$Rn), (v2f64 V128:$Rm)))>;
+def : Pat<(v2f64 (fcanonicalize (v2f64 V128:$Rn))),
+ (v2f64 (FMINNMv2f64 (v2f64 V128:$Rn), (v2f64 V128:$Rn)))>;
+def : Pat<(v4f32 (fminnum_ieee (v4f32 V128:$Rn), (v4f32 V128:$Rm))),
+ (v4f32 (FMINNMv4f32 (v4f32 V128:$Rn), (v4f32 V128:$Rm)))>;
def : Pat<(v4f32 (fmaxnum_ieee (v4f32 V128:$Rn), (v4f32 V128:$Rm))),
(v4f32 (FMAXNMv4f32 (v4f32 V128:$Rn), (v4f32 V128:$Rm)))>;
-def : Pat<(v8f16 (fmaxnum_ieee (v8f16 V128:$Rn), (v8f16 V128:$Rm))),
- (v8f16 (FMAXNMv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm)))>;
+def : Pat<(v4f32 (fcanonicalize (v4f32 V128:$Rn))),
+ (v4f32 (FMINNMv4f32 (v4f32 V128:$Rn), (v4f32 V128:$Rn)))>;
+def : Pat<(v2f32 (fminnum_ieee (v2f32 V64:$Rn), (v2f32 V64:$Rm))),
+ (v2f32 (FMINNMv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rm)))>;
def : Pat<(v2f32 (fmaxnum_ieee (v2f32 V64:$Rn), (v2f32 V64:$Rm))),
(v2f32 (FMAXNMv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rm)))>;
+def : Pat<(v2f32 (fcanonicalize (v2f32 V64:$Rn))),
+ (v2f32 (FMINNMv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rn)))>;
+}
+
+let Predicates = [HasNEON, HasFullFP16] in {
+def : Pat<(v8f16 (fminnum_ieee (v8f16 V128:$Rn), (v8f16 V128:$Rm))),
+ (v8f16 (FMINNMv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm)))>;
+def : Pat<(v8f16 (fmaxnum_ieee (v8f16 V128:$Rn), (v8f16 V128:$Rm))),
+ (v8f16 (FMAXNMv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm)))>;
+def : Pat<(v8f16 (fcanonicalize (v8f16 V128:$Rn))),
+ (v8f16 (FMINNMv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rn)))>;
+def : Pat<(v4f16 (fminnum_ieee (v4f16 V64:$Rn), (v4f16 V64:$Rm))),
+ (v4f16 (FMINNMv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rm)))>;
def : Pat<(v4f16 (fmaxnum_ieee (v4f16 V64:$Rn), (v4f16 V64:$Rm))),
(v4f16 (FMAXNMv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rm)))>;
+def : Pat<(v4f16 (fcanonicalize (v4f16 V64:$Rn))),
+ (v4f16 (FMINNMv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rn)))>;
+}
// NOTE: The operands of the PatFrag are reordered on FMLA/FMLS because the
// instruction expects the addend first, while the fma intrinsic puts it last.
diff --git a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
index 1e84a7216013..fb5383b3514a 100644
--- a/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
+++ b/llvm/lib/Target/DirectX/DXILIntrinsicExpansion.cpp
@@ -56,6 +56,7 @@ static bool isIntrinsicExpansion(Function &F) {
case Intrinsic::dx_clamp:
case Intrinsic::dx_cross:
case Intrinsic::dx_uclamp:
+ case Intrinsic::dx_degrees:
case Intrinsic::dx_lerp:
case Intrinsic::dx_length:
case Intrinsic::dx_normalize:
@@ -490,6 +491,14 @@ static Value *expandClampIntrinsic(CallInst *Orig,
{MaxCall, Max}, nullptr, "dx.min");
}
+static Value *expandDegreesIntrinsic(CallInst *Orig) {
+ Value *X = Orig->getOperand(0);
+ Type *Ty = X->getType();
+ IRBuilder<> Builder(Orig);
+ Value *DegreesRatio = ConstantFP::get(Ty, 180.0 * llvm::numbers::inv_pi);
+ return Builder.CreateFMul(X, DegreesRatio);
+}
+
static Value *expandSignIntrinsic(CallInst *Orig) {
Value *X = Orig->getOperand(0);
Type *Ty = X->getType();
@@ -549,6 +558,9 @@ static bool expandIntrinsic(Function &F, CallInst *Orig) {
case Intrinsic::dx_clamp:
Result = expandClampIntrinsic(Orig, IntrinsicId);
break;
+ case Intrinsic::dx_degrees:
+ Result = expandDegreesIntrinsic(Orig);
+ break;
case Intrinsic::dx_lerp:
Result = expandLerpIntrinsic(Orig);
break;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index e8b769b6fd69..fd92346717c4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -2513,6 +2513,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::mix, GL::FMix);
case Intrinsic::spv_length:
return selectExtInst(ResVReg, ResType, I, CL::length, GL::Length);
+ case Intrinsic::spv_degrees:
+ return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
case Intrinsic::spv_frac:
return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
case Intrinsic::spv_normalize:
diff --git a/llvm/test/CodeGen/AArch64/fp-fcanonicalize.ll b/llvm/test/CodeGen/AArch64/fp-fcanonicalize.ll
new file mode 100644
index 000000000000..753e2b734339
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/fp-fcanonicalize.ll
@@ -0,0 +1,587 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=aarch64 --mattr=-fullfp16,-neon < %s | FileCheck %s --check-prefix=CHECK-NOFP16-NONEON
+; RUN: llc --mtriple=aarch64 --mattr=+fullfp16,-neon < %s | FileCheck %s --check-prefix=CHECK-FP16-NONEON
+; RUN: llc --mtriple=aarch64 --mattr=-fullfp16,+neon < %s | FileCheck %s --check-prefix=CHECK-NOFP16-NEON
+; RUN: llc --mtriple=aarch64 --mattr=+fullfp16,+neon < %s | FileCheck %s --check-prefixes=CHECK-FP16-NEON
+
+declare half @llvm.fcanonicalize.f16(half)
+declare float @llvm.fcanonicalize.f32(float)
+declare double @llvm.fcanonicalize.f64(double)
+
+define half @fcanonicalize_f16(half %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f16:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f16:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f16:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f16:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call half @llvm.canonicalize.f16(half %x)
+ ret half %z
+}
+
+define half @fcanonicalize_f16_nnan(half %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f16_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f16_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f16_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f16_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan half @llvm.canonicalize.f16(half %x)
+ ret half %z
+}
+
+define <2 x half> @fcanonicalize_v2f16(<2 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f16:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f16:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f16:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v0.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f16:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <2 x half> @llvm.canonicalize.v2f16(<2 x half> %x)
+ ret <2 x half> %z
+}
+
+define <2 x half> @fcanonicalize_v2f16_nnan(<2 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f16_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f16_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f16_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v0.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f16_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <2 x half> @llvm.canonicalize.v2f16(<2 x half> %x)
+ ret <2 x half> %z
+}
+
+define <4 x half> @fcanonicalize_v4f16(<4 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v4f16:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fcvt s2, h2
+; CHECK-NOFP16-NONEON-NEXT: fcvt s3, h3
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h2, s2
+; CHECK-NOFP16-NONEON-NEXT: fcvt h3, s3
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v4f16:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: fminnm h2, h2, h2
+; CHECK-FP16-NONEON-NEXT: fminnm h3, h3, h3
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v4f16:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v0.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v4f16:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <4 x half> @llvm.canonicalize.v4f16(<4 x half> %x)
+ ret <4 x half> %z
+}
+
+define <4 x half> @fcanonicalize_v4f16_nnan(<4 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v4f16_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fcvt s2, h2
+; CHECK-NOFP16-NONEON-NEXT: fcvt s3, h3
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h2, s2
+; CHECK-NOFP16-NONEON-NEXT: fcvt h3, s3
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v4f16_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: fminnm h2, h2, h2
+; CHECK-FP16-NONEON-NEXT: fminnm h3, h3, h3
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v4f16_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v0.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v4f16_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <4 x half> @llvm.canonicalize.v4f16(<4 x half> %x)
+ ret <4 x half> %z
+}
+
+define <8 x half> @fcanonicalize_v8f16(<8 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v8f16:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fcvt s2, h2
+; CHECK-NOFP16-NONEON-NEXT: fcvt s3, h3
+; CHECK-NOFP16-NONEON-NEXT: fcvt s4, h4
+; CHECK-NOFP16-NONEON-NEXT: fcvt s5, h5
+; CHECK-NOFP16-NONEON-NEXT: fcvt s6, h6
+; CHECK-NOFP16-NONEON-NEXT: fcvt s7, h7
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: fminnm s4, s4, s4
+; CHECK-NOFP16-NONEON-NEXT: fminnm s5, s5, s5
+; CHECK-NOFP16-NONEON-NEXT: fminnm s6, s6, s6
+; CHECK-NOFP16-NONEON-NEXT: fminnm s7, s7, s7
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h2, s2
+; CHECK-NOFP16-NONEON-NEXT: fcvt h3, s3
+; CHECK-NOFP16-NONEON-NEXT: fcvt h4, s4
+; CHECK-NOFP16-NONEON-NEXT: fcvt h5, s5
+; CHECK-NOFP16-NONEON-NEXT: fcvt h6, s6
+; CHECK-NOFP16-NONEON-NEXT: fcvt h7, s7
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v8f16:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: fminnm h2, h2, h2
+; CHECK-FP16-NONEON-NEXT: fminnm h3, h3, h3
+; CHECK-FP16-NONEON-NEXT: fminnm h4, h4, h4
+; CHECK-FP16-NONEON-NEXT: fminnm h5, h5, h5
+; CHECK-FP16-NONEON-NEXT: fminnm h6, h6, h6
+; CHECK-FP16-NONEON-NEXT: fminnm h7, h7, h7
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v8f16:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v1.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fcvtl2 v2.4s, v0.8h
+; CHECK-NOFP16-NEON-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v1.4s
+; CHECK-NOFP16-NEON-NEXT: fminnm v1.4s, v2.4s, v2.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn2 v0.8h, v1.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v8f16:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <8 x half> @llvm.canonicalize.v8f16(<8 x half> %x)
+ ret <8 x half> %z
+}
+
+define <8 x half> @fcanonicalize_v8f16_nnan(<8 x half> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v8f16_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fcvt s0, h0
+; CHECK-NOFP16-NONEON-NEXT: fcvt s1, h1
+; CHECK-NOFP16-NONEON-NEXT: fcvt s2, h2
+; CHECK-NOFP16-NONEON-NEXT: fcvt s3, h3
+; CHECK-NOFP16-NONEON-NEXT: fcvt s4, h4
+; CHECK-NOFP16-NONEON-NEXT: fcvt s5, h5
+; CHECK-NOFP16-NONEON-NEXT: fcvt s6, h6
+; CHECK-NOFP16-NONEON-NEXT: fcvt s7, h7
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: fminnm s4, s4, s4
+; CHECK-NOFP16-NONEON-NEXT: fminnm s5, s5, s5
+; CHECK-NOFP16-NONEON-NEXT: fminnm s6, s6, s6
+; CHECK-NOFP16-NONEON-NEXT: fminnm s7, s7, s7
+; CHECK-NOFP16-NONEON-NEXT: fcvt h0, s0
+; CHECK-NOFP16-NONEON-NEXT: fcvt h1, s1
+; CHECK-NOFP16-NONEON-NEXT: fcvt h2, s2
+; CHECK-NOFP16-NONEON-NEXT: fcvt h3, s3
+; CHECK-NOFP16-NONEON-NEXT: fcvt h4, s4
+; CHECK-NOFP16-NONEON-NEXT: fcvt h5, s5
+; CHECK-NOFP16-NONEON-NEXT: fcvt h6, s6
+; CHECK-NOFP16-NONEON-NEXT: fcvt h7, s7
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v8f16_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm h0, h0, h0
+; CHECK-FP16-NONEON-NEXT: fminnm h1, h1, h1
+; CHECK-FP16-NONEON-NEXT: fminnm h2, h2, h2
+; CHECK-FP16-NONEON-NEXT: fminnm h3, h3, h3
+; CHECK-FP16-NONEON-NEXT: fminnm h4, h4, h4
+; CHECK-FP16-NONEON-NEXT: fminnm h5, h5, h5
+; CHECK-FP16-NONEON-NEXT: fminnm h6, h6, h6
+; CHECK-FP16-NONEON-NEXT: fminnm h7, h7, h7
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v8f16_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fcvtl v1.4s, v0.4h
+; CHECK-NOFP16-NEON-NEXT: fcvtl2 v2.4s, v0.8h
+; CHECK-NOFP16-NEON-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn v0.4h, v1.4s
+; CHECK-NOFP16-NEON-NEXT: fminnm v1.4s, v2.4s, v2.4s
+; CHECK-NOFP16-NEON-NEXT: fcvtn2 v0.8h, v1.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v8f16_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <8 x half> @llvm.canonicalize.v8f16(<8 x half> %x)
+ ret <8 x half> %z
+}
+
+define float @fcanonicalize_f32(float %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f32:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f32:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f32:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f32:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call float @llvm.canonicalize.f32(float %x)
+ ret float %z
+}
+
+define float @fcanonicalize_f32_nnan(float %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f32_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f32_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f32_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f32_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan float @llvm.canonicalize.f32(float %x)
+ ret float %z
+}
+
+define <2 x float> @fcanonicalize_v2f32(<2 x float> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f32:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f32:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f32:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f32:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x)
+ ret <2 x float> %z
+}
+
+define <2 x float> @fcanonicalize_v2f32_nnan(<2 x float> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f32_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f32_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f32_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f32_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <2 x float> @llvm.canonicalize.v2f32(<2 x float> %x)
+ ret <2 x float> %z
+}
+
+define <4 x float> @fcanonicalize_v4f32(<4 x float> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v4f32:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v4f32:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-FP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-FP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v4f32:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v4f32:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <4 x float> @llvm.canonicalize.v4f32(<4 x float> %x)
+ ret <4 x float> %z
+}
+
+define <4 x float> @fcanonicalize_v4f32_nnan(<4 x float> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v4f32_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-NOFP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-NOFP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-NOFP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v4f32_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm s0, s0, s0
+; CHECK-FP16-NONEON-NEXT: fminnm s1, s1, s1
+; CHECK-FP16-NONEON-NEXT: fminnm s2, s2, s2
+; CHECK-FP16-NONEON-NEXT: fminnm s3, s3, s3
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v4f32_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v4f32_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <4 x float> @llvm.canonicalize.v4f32(<4 x float> %x)
+ ret <4 x float> %z
+}
+
+define double @fcanonicalize_f64(double %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f64:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f64:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f64:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f64:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call double @llvm.canonicalize.f64(double %x)
+ ret double %z
+}
+
+define double @fcanonicalize_f64_nnan(double %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_f64_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_f64_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_f64_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_f64_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan double @llvm.canonicalize.f64(double %x)
+ ret double %z
+}
+
+define <2 x double> @fcanonicalize_v2f64(<2 x double> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f64:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NONEON-NEXT: fminnm d1, d1, d1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f64:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NONEON-NEXT: fminnm d1, d1, d1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f64:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f64:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call <2 x double> @llvm.canonicalize.v2f64(<2 x double> %x)
+ ret <2 x double> %z
+}
+
+define <2 x double> @fcanonicalize_v2f64_nnan(<2 x double> %x) {
+; CHECK-NOFP16-NONEON-LABEL: fcanonicalize_v2f64_nnan:
+; CHECK-NOFP16-NONEON: // %bb.0:
+; CHECK-NOFP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-NOFP16-NONEON-NEXT: fminnm d1, d1, d1
+; CHECK-NOFP16-NONEON-NEXT: ret
+;
+; CHECK-FP16-NONEON-LABEL: fcanonicalize_v2f64_nnan:
+; CHECK-FP16-NONEON: // %bb.0:
+; CHECK-FP16-NONEON-NEXT: fminnm d0, d0, d0
+; CHECK-FP16-NONEON-NEXT: fminnm d1, d1, d1
+; CHECK-FP16-NONEON-NEXT: ret
+;
+; CHECK-NOFP16-NEON-LABEL: fcanonicalize_v2f64_nnan:
+; CHECK-NOFP16-NEON: // %bb.0:
+; CHECK-NOFP16-NEON-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; CHECK-NOFP16-NEON-NEXT: ret
+;
+; CHECK-FP16-NEON-LABEL: fcanonicalize_v2f64_nnan:
+; CHECK-FP16-NEON: // %bb.0:
+; CHECK-FP16-NEON-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; CHECK-FP16-NEON-NEXT: ret
+ %z = call nnan <2 x double> @llvm.canonicalize.v2f64(<2 x double> %x)
+ ret <2 x double> %z
+}
diff --git a/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll b/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
index b8406179f3cb..bb3f9a3e52a1 100644
--- a/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
+++ b/llvm/test/CodeGen/AArch64/fp-maximumnum-minimumnum.ll
@@ -472,3 +472,563 @@ entry:
%c = call nnan <16 x half> @llvm.minimumnum.v16f16(<16 x half> %a, <16 x half> %b)
ret <16 x half> %c
}
+
+;;;;;;;;;;;;;;;; max_f64
+define double @max_f64(double %a, double %b) {
+; AARCH64-LABEL: max_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm d1, d1, d1
+; AARCH64-NEXT: fminnm d0, d0, d0
+; AARCH64-NEXT: fmaxnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.maximumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @max_v2f64(<2 x double> %a, <2 x double> %b) {
+; AARCH64-LABEL: max_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @max_v3f64(<3 x double> %a, <3 x double> %b) {
+; AARCH64-LABEL: max_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fmaxnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.maximumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @max_v4f64(<4 x double> %a, <4 x double> %b) {
+; AARCH64-LABEL: max_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fmaxnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fmaxnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.maximumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+;;;;;;;;;;;;;;;;;; max_f32
+define float @max_f32(float %a, float %b) {
+; AARCH64-LABEL: max_f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm s1, s1, s1
+; AARCH64-NEXT: fminnm s0, s0, s0
+; AARCH64-NEXT: fmaxnm s0, s0, s1
+; AARCH64-NEXT: ret
+entry:
+ %c = call float @llvm.maximumnum.f32(float %a, float %b)
+ ret float %c
+}
+
+define <2 x float> @max_v2f32(<2 x float> %a, <2 x float> %b) {
+; AARCH64-LABEL: max_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.2s, v1.2s, v1.2s
+; AARCH64-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; AARCH64-NEXT: fmaxnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @max_v3f32(<3 x float> %a, <3 x float> %b) {
+; AARCH64-LABEL: max_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.maximumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @max_v4f32(<4 x float> %a, <4 x float> %b) {
+; AARCH64-LABEL: max_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.maximumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @max_v5f32(<5 x float> %a, <5 x float> %b) {
+; AARCH64-LABEL: max_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fmaxnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.maximumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @max_v8f32(<8 x float> %a, <8 x float> %b) {
+; AARCH64-LABEL: max_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fmaxnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fmaxnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.maximumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+;;;;;;;;;;;;;;;;;; max_f16
+define half @max_f16(half %a, half %b) {
+; AARCH64-LABEL: max_f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm h1, h1, h1
+; AARCH64-NEXT: fminnm h0, h0, h0
+; AARCH64-NEXT: fmaxnm h0, h0, h1
+; AARCH64-NEXT: ret
+entry:
+ %c = call half @llvm.maximumnum.f16(half %a, half %b)
+ ret half %c
+}
+
+define <2 x half> @max_v2f16(<2 x half> %a, <2 x half> %b) {
+; AARCH64-LABEL: max_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4h, v1.4h, v1.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.maximumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @max_v4f16(<4 x half> %a, <4 x half> %b) {
+; AARCH64-LABEL: max_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4h, v1.4h, v1.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; AARCH64-NEXT: fmaxnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.maximumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @max_v8f16(<8 x half> %a, <8 x half> %b) {
+; AARCH64-LABEL: max_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.maximumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @max_v9f16(<9 x half> %a, <9 x half> %b) {
+; AARCH64-LABEL: max_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fmaxnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.maximumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @max_v16f16(<16 x half> %a, <16 x half> %b) {
+; AARCH64-LABEL: max_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fmaxnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fmaxnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.maximumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
+
+;;;;;;;;;;;;;;;; min_f64
+define double @min_f64(double %a, double %b) {
+; AARCH64-LABEL: min_f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm d1, d1, d1
+; AARCH64-NEXT: fminnm d0, d0, d0
+; AARCH64-NEXT: fminnm d0, d0, d1
+; AARCH64-NEXT: ret
+entry:
+ %c = call double @llvm.minimumnum.f64(double %a, double %b)
+ ret double %c
+}
+
+define <2 x double> @min_v2f64(<2 x double> %a, <2 x double> %b) {
+; AARCH64-LABEL: min_v2f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %a, <2 x double> %b)
+ ret <2 x double> %c
+}
+
+define <3 x double> @min_v3f64(<3 x double> %a, <3 x double> %b) {
+; AARCH64-LABEL: min_v3f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $d3 killed $d3 def $q3
+; AARCH64-NEXT: // kill: def $d0 killed $d0 def $q0
+; AARCH64-NEXT: // kill: def $d4 killed $d4 def $q4
+; AARCH64-NEXT: // kill: def $d1 killed $d1 def $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 def $q2
+; AARCH64-NEXT: // kill: def $d5 killed $d5 def $q5
+; AARCH64-NEXT: mov v0.d[1], v1.d[0]
+; AARCH64-NEXT: mov v3.d[1], v4.d[0]
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v1.2d
+; AARCH64-NEXT: fminnm v1.2d, v5.2d, v5.2d
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v1.2d
+; AARCH64-NEXT: ext v1.16b, v0.16b, v0.16b, #8
+; AARCH64-NEXT: // kill: def $d0 killed $d0 killed $q0
+; AARCH64-NEXT: // kill: def $d1 killed $d1 killed $q1
+; AARCH64-NEXT: // kill: def $d2 killed $d2 killed $q2
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x double> @llvm.minimumnum.v3f64(<3 x double> %a, <3 x double> %b)
+ ret <3 x double> %c
+}
+
+define <4 x double> @min_v4f64(<4 x double> %a, <4 x double> %b) {
+; AARCH64-LABEL: min_v4f64:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.2d, v2.2d, v2.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v0.2d
+; AARCH64-NEXT: fminnm v3.2d, v3.2d, v3.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v1.2d
+; AARCH64-NEXT: fminnm v0.2d, v0.2d, v2.2d
+; AARCH64-NEXT: fminnm v1.2d, v1.2d, v3.2d
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x double> @llvm.minimumnum.v4f64(<4 x double> %a, <4 x double> %b)
+ ret <4 x double> %c
+}
+
+;;;;;;;;;;;;;;;;;; min_f32
+define float @min_f32(float %a, float %b) {
+; AARCH64-LABEL: min_f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm s1, s1, s1
+; AARCH64-NEXT: fminnm s0, s0, s0
+; AARCH64-NEXT: fminnm s0, s0, s1
+; AARCH64-NEXT: ret
+entry:
+ %c = call float @llvm.minimumnum.f32(float %a, float %b)
+ ret float %c
+}
+
+define <2 x float> @min_v2f32(<2 x float> %a, <2 x float> %b) {
+; AARCH64-LABEL: min_v2f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.2s, v1.2s, v1.2s
+; AARCH64-NEXT: fminnm v0.2s, v0.2s, v0.2s
+; AARCH64-NEXT: fminnm v0.2s, v0.2s, v1.2s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %a, <2 x float> %b)
+ ret <2 x float> %c
+}
+
+define <3 x float> @min_v3f32(<3 x float> %a, <3 x float> %b) {
+; AARCH64-LABEL: min_v3f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <3 x float> @llvm.minimumnum.v3f32(<3 x float> %a, <3 x float> %b)
+ ret <3 x float> %c
+}
+
+define <4 x float> @min_v4f32(<4 x float> %a, <4 x float> %b) {
+; AARCH64-LABEL: min_v4f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x float> @llvm.minimumnum.v4f32(<4 x float> %a, <4 x float> %b)
+ ret <4 x float> %c
+}
+
+define <5 x float> @min_v5f32(<5 x float> %a, <5 x float> %b) {
+; AARCH64-LABEL: min_v5f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $s0 killed $s0 def $q0
+; AARCH64-NEXT: // kill: def $s5 killed $s5 def $q5
+; AARCH64-NEXT: // kill: def $s1 killed $s1 def $q1
+; AARCH64-NEXT: // kill: def $s6 killed $s6 def $q6
+; AARCH64-NEXT: // kill: def $s2 killed $s2 def $q2
+; AARCH64-NEXT: // kill: def $s7 killed $s7 def $q7
+; AARCH64-NEXT: // kill: def $s3 killed $s3 def $q3
+; AARCH64-NEXT: mov x8, sp
+; AARCH64-NEXT: // kill: def $s4 killed $s4 def $q4
+; AARCH64-NEXT: mov v0.s[1], v1.s[0]
+; AARCH64-NEXT: mov v5.s[1], v6.s[0]
+; AARCH64-NEXT: mov v0.s[2], v2.s[0]
+; AARCH64-NEXT: mov v5.s[2], v7.s[0]
+; AARCH64-NEXT: ldr s2, [sp, #8]
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: mov v0.s[3], v3.s[0]
+; AARCH64-NEXT: ld1 { v5.s }[3], [x8]
+; AARCH64-NEXT: fminnm v3.4s, v4.4s, v4.4s
+; AARCH64-NEXT: fminnm v1.4s, v5.4s, v5.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v4.4s, v3.4s, v2.4s
+; AARCH64-NEXT: // kill: def $s4 killed $s4 killed $q4
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v1.4s
+; AARCH64-NEXT: mov s1, v0.s[1]
+; AARCH64-NEXT: mov s2, v0.s[2]
+; AARCH64-NEXT: mov s3, v0.s[3]
+; AARCH64-NEXT: // kill: def $s0 killed $s0 killed $q0
+; AARCH64-NEXT: ret
+entry:
+ %c = call <5 x float> @llvm.minimumnum.v5f32(<5 x float> %a, <5 x float> %b)
+ ret <5 x float> %c
+}
+
+define <8 x float> @min_v8f32(<8 x float> %a, <8 x float> %b) {
+; AARCH64-LABEL: min_v8f32:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.4s, v2.4s, v2.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v0.4s
+; AARCH64-NEXT: fminnm v3.4s, v3.4s, v3.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v1.4s
+; AARCH64-NEXT: fminnm v0.4s, v0.4s, v2.4s
+; AARCH64-NEXT: fminnm v1.4s, v1.4s, v3.4s
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x float> @llvm.minimumnum.v8f32(<8 x float> %a, <8 x float> %b)
+ ret <8 x float> %c
+}
+
+;;;;;;;;;;;;;;;;;; min_f16
+define half @min_f16(half %a, half %b) {
+; AARCH64-LABEL: min_f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm h1, h1, h1
+; AARCH64-NEXT: fminnm h0, h0, h0
+; AARCH64-NEXT: fminnm h0, h0, h1
+; AARCH64-NEXT: ret
+entry:
+ %c = call half @llvm.minimumnum.f16(half %a, half %b)
+ ret half %c
+}
+
+define <2 x half> @min_v2f16(<2 x half> %a, <2 x half> %b) {
+; AARCH64-LABEL: min_v2f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4h, v1.4h, v1.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <2 x half> @llvm.minimumnum.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+define <4 x half> @min_v4f16(<4 x half> %a, <4 x half> %b) {
+; AARCH64-LABEL: min_v4f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.4h, v1.4h, v1.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v0.4h
+; AARCH64-NEXT: fminnm v0.4h, v0.4h, v1.4h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <4 x half> @llvm.minimumnum.v4f16(<4 x half> %a, <4 x half> %b)
+ ret <4 x half> %c
+}
+
+define <8 x half> @min_v8f16(<8 x half> %a, <8 x half> %b) {
+; AARCH64-LABEL: min_v8f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <8 x half> @llvm.minimumnum.v8f16(<8 x half> %a, <8 x half> %b)
+ ret <8 x half> %c
+}
+
+define <9 x half> @min_v9f16(<9 x half> %a, <9 x half> %b) {
+; AARCH64-LABEL: min_v9f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: // kill: def $h0 killed $h0 def $q0
+; AARCH64-NEXT: // kill: def $h1 killed $h1 def $q1
+; AARCH64-NEXT: // kill: def $h2 killed $h2 def $q2
+; AARCH64-NEXT: add x9, sp, #16
+; AARCH64-NEXT: // kill: def $h3 killed $h3 def $q3
+; AARCH64-NEXT: // kill: def $h4 killed $h4 def $q4
+; AARCH64-NEXT: // kill: def $h5 killed $h5 def $q5
+; AARCH64-NEXT: // kill: def $h6 killed $h6 def $q6
+; AARCH64-NEXT: // kill: def $h7 killed $h7 def $q7
+; AARCH64-NEXT: mov v0.h[1], v1.h[0]
+; AARCH64-NEXT: ldr h1, [sp, #8]
+; AARCH64-NEXT: ld1 { v1.h }[1], [x9]
+; AARCH64-NEXT: add x9, sp, #24
+; AARCH64-NEXT: mov v0.h[2], v2.h[0]
+; AARCH64-NEXT: ldr h2, [sp]
+; AARCH64-NEXT: ld1 { v1.h }[2], [x9]
+; AARCH64-NEXT: add x9, sp, #32
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: mov v0.h[3], v3.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[3], [x9]
+; AARCH64-NEXT: add x9, sp, #40
+; AARCH64-NEXT: ldr h3, [sp, #72]
+; AARCH64-NEXT: ld1 { v1.h }[4], [x9]
+; AARCH64-NEXT: add x9, sp, #48
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[4], v4.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[5], [x9]
+; AARCH64-NEXT: add x9, sp, #56
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v3.8h
+; AARCH64-NEXT: mov v0.h[5], v5.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[6], [x9]
+; AARCH64-NEXT: add x9, sp, #64
+; AARCH64-NEXT: str h2, [x8, #16]
+; AARCH64-NEXT: mov v0.h[6], v6.h[0]
+; AARCH64-NEXT: ld1 { v1.h }[7], [x9]
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: mov v0.h[7], v7.h[0]
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v1.8h
+; AARCH64-NEXT: str q0, [x8]
+; AARCH64-NEXT: ret
+entry:
+ %c = call <9 x half> @llvm.minimumnum.v9f16(<9 x half> %a, <9 x half> %b)
+ ret <9 x half> %c
+}
+
+define <16 x half> @min_v16f16(<16 x half> %a, <16 x half> %b) {
+; AARCH64-LABEL: min_v16f16:
+; AARCH64: // %bb.0: // %entry
+; AARCH64-NEXT: fminnm v2.8h, v2.8h, v2.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v0.8h
+; AARCH64-NEXT: fminnm v3.8h, v3.8h, v3.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v1.8h
+; AARCH64-NEXT: fminnm v0.8h, v0.8h, v2.8h
+; AARCH64-NEXT: fminnm v1.8h, v1.8h, v3.8h
+; AARCH64-NEXT: ret
+entry:
+ %c = call <16 x half> @llvm.minimumnum.v16f16(<16 x half> %a, <16 x half> %b)
+ ret <16 x half> %c
+}
diff --git a/llvm/test/CodeGen/DirectX/degrees.ll b/llvm/test/CodeGen/DirectX/degrees.ll
new file mode 100644
index 000000000000..b38ac13d5f24
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/degrees.ll
@@ -0,0 +1,54 @@
+; RUN: opt -S -dxil-intrinsic-expansion -scalarizer -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+; Make sure dxil op function calls for degrees are expanded and lowered as fmul for float and half.
+
+define noundef half @degrees_half(half noundef %a) {
+; CHECK-LABEL: define noundef half @degrees_half(
+; CHECK-SAME: half noundef [[A:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[DX_DEGREES1:%.*]] = fmul half [[A]], 0xH5329
+; CHECK-NEXT: ret half [[DX_DEGREES1]]
+;
+entry:
+ %dx.degrees = call half @llvm.dx.degrees.f16(half %a)
+ ret half %dx.degrees
+}
+
+define noundef float @degrees_float(float noundef %a) #0 {
+; CHECK-LABEL: define noundef float @degrees_float(
+; CHECK-SAME: float noundef [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[DEGREES:%.*]] = fmul float [[A]], 0x404CA5DC20000000
+; CHECK-NEXT: ret float [[DEGREES]]
+;
+entry:
+ %dx.degrees = call float @llvm.dx.degrees.f32(float %a)
+ ret float %dx.degrees
+}
+
+define noundef <4 x float> @degrees_float4(<4 x float> noundef %a) #0 {
+; CHECK-LABEL: define noundef <4 x float> @degrees_float4(
+; CHECK-SAME: <4 x float> noundef [[A:%.*]]) {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[A0:%.*]] = extractelement <4 x float> [[A]], i64 0
+; CHECK-NEXT: [[DEGREES_A0:%.*]] = fmul float [[A0]], 0x404CA5DC20000000
+; CHECK-NEXT: [[A1:%.*]] = extractelement <4 x float> [[A]], i64 1
+; CHECK-NEXT: [[DEGREES_A1:%.*]] = fmul float [[A1]], 0x404CA5DC20000000
+; CHECK-NEXT: [[A2:%.*]] = extractelement <4 x float> [[A]], i64 2
+; CHECK-NEXT: [[DEGREES_A2:%.*]] = fmul float [[A2]], 0x404CA5DC20000000
+; CHECK-NEXT: [[A3:%.*]] = extractelement <4 x float> [[A]], i64 3
+; CHECK-NEXT: [[DEGREES_A3:%.*]] = fmul float [[A3]], 0x404CA5DC20000000
+; CHECK-NEXT: [[INSERT_0:%.*]] = insertelement <4 x float> poison, float [[DEGREES_A0]], i64 0
+; CHECK-NEXT: [[INSERT_1:%.*]] = insertelement <4 x float> [[INSERT_0]], float [[DEGREES_A1]], i64 1
+; CHECK-NEXT: [[INSERT_2:%.*]] = insertelement <4 x float> [[INSERT_1]], float [[DEGREES_A2]], i64 2
+; CHECK-NEXT: [[RES:%.*]] = insertelement <4 x float> [[INSERT_2]], float [[DEGREES_A3]], i64 3
+; CHECK-NEXT: ret <4 x float> [[RES]]
+;
+entry:
+ %2 = call <4 x float> @llvm.dx.degrees.v4f32(<4 x float> %a)
+ ret <4 x float> %2
+}
+
+declare half @llvm.dx.degrees.f16(half)
+declare float @llvm.dx.degrees.f32(float)
+declare <4 x float> @llvm.dx.degrees.v4f32(<4 x float>)
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
new file mode 100644
index 000000000000..533bcca6f621
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/degrees.ll
@@ -0,0 +1,52 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+
+; CHECK-LABEL: Begin function degrees_float
+define noundef float @degrees_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] Degrees %[[#float_32_arg]]
+ %elt.degrees = call float @llvm.spv.degrees.f32(float %a)
+ ret float %elt.degrees
+}
+
+; CHECK-LABEL: Begin function degrees_half
+define noundef half @degrees_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] Degrees %[[#float_16_arg]]
+ %elt.degrees = call half @llvm.spv.degrees.f16(half %a)
+ ret half %elt.degrees
+}
+
+; CHECK-LABEL: Begin function degrees_float_vector
+define noundef <4 x float> @degrees_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] Degrees %[[#vec4_float_32_arg]]
+ %elt.degrees = call <4 x float> @llvm.spv.degrees.v4f32(<4 x float> %a)
+ ret <4 x float> %elt.degrees
+}
+
+; CHECK-LABEL: Begin function degrees_half_vector
+define noundef <4 x half> @degrees_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Degrees %[[#vec4_float_16_arg]]
+ %elt.degrees = call <4 x half> @llvm.spv.degrees.v4f16(<4 x half> %a)
+ ret <4 x half> %elt.degrees
+}
+
+declare half @llvm.spv.degrees.f16(half)
+declare float @llvm.spv.degrees.f32(float)
+
+declare <4 x float> @llvm.spv.degrees.v4f32(<4 x float>)
+declare <4 x half> @llvm.spv.degrees.v4f16(<4 x half>)
diff --git a/llvm/test/CodeGen/SPIRV/opencl/degrees.ll b/llvm/test/CodeGen/SPIRV/opencl/degrees.ll
new file mode 100644
index 000000000000..88f97835fe71
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/opencl/degrees.ll
@@ -0,0 +1,50 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "OpenCL.std"
+
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+
+declare half @llvm.spv.degrees.f16(half)
+declare float @llvm.spv.degrees.f32(float)
+
+declare <4 x float> @llvm.spv.degrees.v4f32(<4 x float>)
+declare <4 x half> @llvm.spv.degrees.v4f16(<4 x half>)
+
+define noundef float @degrees_float(float noundef %a) {
+entry:
+; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] degrees %[[#float_32_arg]]
+ %elt.degrees = call float @llvm.spv.degrees.f32(float %a)
+ ret float %elt.degrees
+}
+
+define noundef half @degrees_half(half noundef %a) {
+entry:
+; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] degrees %[[#float_16_arg]]
+ %elt.degrees = call half @llvm.spv.degrees.f16(half %a)
+ ret half %elt.degrees
+}
+
+define noundef <4 x float> @degrees_float_vector(<4 x float> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] degrees %[[#vec4_float_32_arg]]
+ %elt.degrees = call <4 x float> @llvm.spv.degrees.v4f32(<4 x float> %a)
+ ret <4 x float> %elt.degrees
+}
+
+define noundef <4 x half> @degrees_half_vector(<4 x half> noundef %a) {
+entry:
+; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]]
+; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] degrees %[[#vec4_float_16_arg]]
+ %elt.degrees = call <4 x half> @llvm.spv.degrees.v4f16(<4 x half> %a)
+ ret <4 x half> %elt.degrees
+}
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index a2c05deefa6b..108cadd2e016 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -1041,8 +1041,8 @@ Session::Session(std::unique_ptr<ExecutorProcessControl> EPC, Error &Err)
return;
}
} else if (TT.isOSBinFormatELF()) {
- if (auto P = ELFNixPlatform::Create(ES, ObjLayer, *PlatformJD,
- OrcRuntime.c_str()))
+ if (auto P =
+ ELFNixPlatform::Create(ObjLayer, *PlatformJD, OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else {
Err = P.takeError();
diff --git a/utils/bazel/llvm-project-overlay/clang-tools-extra/include-cleaner/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang-tools-extra/include-cleaner/BUILD.bazel
index 28f90efb3ba7..5b210ad80c87 100644
--- a/utils/bazel/llvm-project-overlay/clang-tools-extra/include-cleaner/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/clang-tools-extra/include-cleaner/BUILD.bazel
@@ -2,7 +2,9 @@
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+load("//llvm:lit_test.bzl", "lit_test", "package_path")
package(
default_visibility = ["//visibility:public"],
@@ -61,3 +63,71 @@ cc_binary(
"//llvm:Support",
],
)
+
+cc_test(
+ name = "unittests",
+ srcs = glob(["unittests/*.cpp"]),
+ deps = [
+ ":include_cleaner",
+ ":include_cleaner_internal",
+ "//clang:ast",
+ "//clang:basic",
+ "//clang:format",
+ "//clang:frontend",
+ "//clang:lex",
+ "//clang:serialization",
+ "//clang:testing",
+ "//clang:tooling",
+ "//clang:tooling_inclusions",
+ "//llvm:Support",
+ "//llvm:TestingAnnotations",
+ "//third-party/unittest:gmock",
+ "//third-party/unittest:gtest",
+ ],
+)
+
+LLVM_LIT_PATH_FUNCTION = " " + \
+ "# Allow generated file to be relocatable.\n" + \
+ "from pathlib import Path\n" + \
+ "def path(p):\n" + \
+ " p = Path(p)\n" + \
+ " if p.exists: return str(p.resolve())\n" + \
+ " if not p: return ''\n" + \
+ " return str((Path(__file__).parent / p).resolve())\n"
+
+LIT_SITE_CFG_IN_HEADER = "# Autogenerated, do not edit." + LLVM_LIT_PATH_FUNCTION
+
+expand_template(
+ name = "lit_site_cfg_py",
+ testonly = True,
+ out = "test/lit.site.cfg.py",
+ substitutions = {
+ "@CMAKE_CURRENT_BINARY_DIR@": package_path("//clang-tools-extra/include-cleaner:BUILD") + "/test",
+ "@CMAKE_CURRENT_SOURCE_DIR@": package_path("//clang-tools-extra/include-cleaner:BUILD") + "/test",
+ "@CURRENT_TOOLS_DIR@": package_path("//clang-tools-extra/include-cleaner:BUILD"),
+ "@LIT_SITE_CFG_IN_HEADER@": LIT_SITE_CFG_IN_HEADER,
+ "@LLVM_LIBS_DIR@": package_path("//llvm:BUILD"),
+ "@LLVM_LIT_TOOLS_DIR@": package_path("//llvm:BUILD"),
+ "@LLVM_TOOLS_DIR@": package_path("//llvm:BUILD"),
+ "@TARGET_TRIPLE@": "",
+ '"@Python3_EXECUTABLE@"': "sys.executable",
+ },
+ template = "test/lit.site.cfg.py.in",
+)
+
+[
+ lit_test(
+ name = "%s.test" % src,
+ srcs = [src],
+ data = glob(["test/Inputs/**/*"]) + [
+ "test/lit.cfg.py",
+ "test/lit.site.cfg.py",
+ ":clang-include-cleaner",
+ "//llvm:FileCheck",
+ "//llvm:count",
+ "//llvm:not",
+ ],
+ args = ["-svv"],
+ )
+ for src in glob(["test/*.cpp"])
+]
diff --git a/utils/bazel/llvm-project-overlay/lldb/source/Plugins/BUILD.bazel b/utils/bazel/llvm-project-overlay/lldb/source/Plugins/BUILD.bazel
index 96202bf47b84..38493411adde 100644
--- a/utils/bazel/llvm-project-overlay/lldb/source/Plugins/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/lldb/source/Plugins/BUILD.bazel
@@ -2248,6 +2248,8 @@ cc_library(
hdrs = glob(["Process/minidump/*.h"]),
include_prefix = "Plugins",
deps = [
+ ":PluginDynamicLoaderPosixDYLD",
+ ":PluginDynamicLoaderPosixDYLDHeaders",
":PluginObjectFilePlaceholder",
":PluginProcessElfCore",
":PluginProcessUtility",