FEXGetConfig: Showcase RMW versus loadstore atomic differences

This differs on X2E, so it's good to showcase it.
This commit is contained in:
Ryan Houdek committed 2026-05-12 12:38:44 -07:00
1 parent 0d72890482
commit 8a4982383a
1 file changed
+74 -2
+74 -2
View File
@@ -131,6 +131,41 @@ __attribute__((naked)) void atomic_load_u128(std::byte* Data) {
: "x1", "x2", "x3", "memory");
}
__attribute__((naked)) void atomic_set_u16(std::byte* Data, uint16_t value) {
asm volatile(R"(
.word 0x78e13002; // ldsetalh w1, w2, [x0];
ret;
)" ::
: "memory");
}
__attribute__((naked)) void atomic_set_u32(std::byte* Data, uint32_t value) {
asm volatile(R"(
.word 0xb8e13002; // ldsetal w1, w2, [x0];
ret;
)" ::
: "memory");
}
__attribute__((naked)) void atomic_set_u64(std::byte* Data, uint64_t value) {
asm volatile(R"(
.word 0xf8e13002; // ldsetal x1, x2, [x0];
ret;
)" ::
: "memory");
}
__attribute__((naked)) void atomic_set_u128_impl(__uint128_t expected, __uint128_t desired, std::byte* Data) {
asm volatile(R"(
.word 0x4860fc82; // caspal x0, x1, x2, x3, [x4];
ret;
)" ::
: "memory");
}
static inline void atomic_set_u128(std::byte* Data, __uint128_t value) {
atomic_set_u128_impl(*reinterpret_cast<__uint128_t*>(Data), value, Data);
}
static void HandleSIGBUS(int, siginfo_t* info, void* context) {
FaultArray[reinterpret_cast<uintptr_t>(info->si_addr) & 63] = true;
@@ -154,6 +189,13 @@ void TestSIGBUS() {
}
};
auto test_rmw_fault = [](bool* FaultOffsets, auto AccessFunction, std::byte* AccessArray) {
FaultArray = FaultOffsets;
for (size_t i = 0; i < 64; ++i) {
AccessFunction(AccessArray + i, 1);
}
};
auto print_granule = [](const char* size, bool* FaultArray) {
std::string output {};
for (size_t i = 0; i < 64; ++i) {
@@ -176,19 +218,50 @@ void TestSIGBUS() {
bool FaultOffset_64bit[64] {};
bool FaultOffset_128bit[64] {};
bool FaultOffset_RMW_16bit[64] {};
bool FaultOffset_RMW_32bit[64] {};
bool FaultOffset_RMW_64bit[64] {};
bool FaultOffset_RMW_128bit[64] {};
test_fault(FaultOffset_16bit, atomic_load_u16, ptr);
test_fault(FaultOffset_32bit, atomic_load_u32, ptr);
test_fault(FaultOffset_64bit, atomic_load_u64, ptr);
test_fault(FaultOffset_128bit, atomic_load_u128, ptr);
auto TSOFacts = GetTSOEmulationFacts();
if (TSOFacts.LSE) {
test_rmw_fault(FaultOffset_RMW_16bit, atomic_set_u16, ptr);
test_rmw_fault(FaultOffset_RMW_32bit, atomic_set_u32, ptr);
test_rmw_fault(FaultOffset_RMW_64bit, atomic_set_u64, ptr);
test_rmw_fault(FaultOffset_RMW_128bit, atomic_set_u128, ptr);
}
munmap(ptr, 4096);
sigaction(SIGBUS, &act, nullptr);
fprintf(stdout, "Fault Granularity: Split every 16 bytes\n");
const bool RMWIsDifferent = TSOFacts.LSE && (memcmp(FaultOffset_16bit, FaultOffset_RMW_16bit, sizeof(FaultOffset_16bit)) != 0 ||
memcmp(FaultOffset_32bit, FaultOffset_RMW_32bit, sizeof(FaultOffset_32bit)) != 0 ||
memcmp(FaultOffset_64bit, FaultOffset_RMW_64bit, sizeof(FaultOffset_64bit)) != 0 ||
memcmp(FaultOffset_128bit, FaultOffset_RMW_128bit, sizeof(FaultOffset_128bit)) != 0);
if (!RMWIsDifferent) {
fprintf(stdout, "Fault Granularity: Split every 16 bytes\n");
} else {
fprintf(stdout, "Load/Store Fault Granularity: Split every 16 bytes\n");
}
print_granule(" 16-bit", FaultOffset_16bit);
print_granule(" 32-bit", FaultOffset_32bit);
print_granule(" 64-bit", FaultOffset_64bit);
print_granule("128-bit", FaultOffset_128bit);
if (RMWIsDifferent) {
fprintf(stdout, "RMW Atomic Fault Granularity: Split every 16 bytes\n");
print_granule(" 16-bit", FaultOffset_RMW_16bit);
print_granule(" 32-bit", FaultOffset_RMW_32bit);
print_granule(" 64-bit", FaultOffset_RMW_64bit);
print_granule("128-bit", FaultOffset_RMW_128bit);
}
}
} // namespace SIGBUSTest
#endif
@@ -330,7 +403,6 @@ int main(int argc, char** argv, char** envp) {
FEX_CONFIG_OPT(VectorTSOEnabled, VECTORTSOENABLED);
FEX_CONFIG_OPT(HalfBarrierTSOEnabled, HALFBARRIERTSOENABLED);
FEX_CONFIG_OPT(StrictInProcessSplitLocks, STRICTINPROCESSSPLITLOCKS);
fprintf(stderr, "Strict: %d\n", StrictInProcessSplitLocks());
fprintf(stdout, "\nConfiguration:\n");
fprintf(stdout, "\tTSO Emulation: %s\n", TSOEnabled() ? "Enabled" : "Disabled");