diff options
| author | YunQiang Su <yunqiang@isrc.iscas.ac.cn> | 2024-10-10 17:46:08 -0700 |
|---|---|---|
| committer | Vitaly Buka <vitalybuka@google.com> | 2024-10-10 17:46:08 -0700 |
| commit | 46374e8623812db538ecd1331281143b4dfb5227 (patch) | |
| tree | 1a8a1841e3d77e22036407c0bdae3833dec436ef | |
| parent | 5e9272e50610634f1b0c42aaad47d0f90a8c9762 (diff) | |
| parent | 72fb37922577997f3666203dbdb2601f0fc97748 (diff) | |
[𝘀𝗽𝗿] changes introduced through rebaseusers/vitalybuka/spr/main.nfcasan-cleanup-asanthreadidandname-ctorinit
Created using spr 1.3.4
[skip ci]
71 files changed, 1961 insertions, 1036 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/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 ®) { + 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 ®ion, 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 ®ion : 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 ®ions, @@ -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", |
