1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

Implement utils::tx_start (for TSX)

Implement utils::tx_abort helper.
This commit is contained in:
Nekotekina 2020-10-12 15:09:39 +03:00
parent 95c1443e30
commit b57a9c31f0

View File

@ -4,6 +4,80 @@
namespace utils
{
// Transaction helper (Max = max attempts) (result = pair of success and op result, which is only meaningful on success)
template <uint Max = 10, typename F, typename R = std::invoke_result_t<F>>
inline auto tx_start(F op)
{
uint status = -1;
for (uint i = 0; i < Max; i++)
{
#ifndef _MSC_VER
__asm__ goto ("xbegin %l[retry];" ::: "memory" : retry);
#else
status = _xbegin();
if (status != _XBEGIN_STARTED) [[unlikely]]
{
goto retry;
}
#endif
if constexpr (std::is_void_v<R>)
{
std::invoke(op);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return true;
}
else
{
auto result = std::invoke(op);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return std::make_pair(true, std::move(result));
}
retry:
#ifndef _MSC_VER
__asm__ volatile ("movl %%eax, %0;" : "=r" (status) :: "memory");
#endif
if (!(status & _XABORT_RETRY)) [[unlikely]]
{
// In order to abort transaction, tx_abort() can be used, so there is no need for "special" return value
break;
}
}
if constexpr (std::is_void_v<R>)
{
return false;
}
else
{
return std::make_pair(false, R());
}
};
// Special function to abort transaction
[[noreturn]] FORCE_INLINE void tx_abort()
{
#ifndef _MSC_VER
__asm__ volatile ("xabort $0;" ::: "memory");
__builtin_unreachable();
#else
_xabort(0);
__assume(0);
#endif
}
// Rotate helpers
#if defined(__GNUG__)