From 5c85d0d8115fe6cbb8ce9e3f4a6a63cfe75f656e Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Mon, 2 Dec 2024 17:42:43 +0100 Subject: [PATCH] base --- .../gtest/riscv/test_assembler_riscv.cpp | 176 +++++++++++++++--- 1 file changed, 145 insertions(+), 31 deletions(-) diff --git a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp index 7df6c6b933ea4..3f026eccfafe0 100644 --- a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp +++ b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp @@ -30,6 +30,7 @@ #include "asm/macroAssembler.hpp" #include "memory/resourceArea.hpp" #include "runtime/orderAccess.hpp" +#include "threadHelper.inline.hpp" #include "unittest.hpp" typedef int64_t (*zicond_func)(int64_t cmp1, int64_t cmp2, int64_t dst, int64_t src); @@ -54,7 +55,7 @@ class CmovTester { } }; -void run_cmov_tests() { +static void run_cmov_tests() { // If 42(a0) eq 42(a1): assign dest(a2/66) the src(a3/77), expect result: 77 CmovTester::test(&MacroAssembler::cmov_eq, 42, 42, 66, 77, 77); // If 41(a0) eq 42(a1): assign dest(a2/66) the src(a3/77), expect result: 66 @@ -107,40 +108,43 @@ TEST_VM(RiscV, cmov) { template class CmpxchgTester { - public: typedef TESTSIZE (*cmpxchg_func)(intptr_t addr, TESTSIZE expected, TESTSIZE new_value, TESTSIZE result); - static TESTSIZE base_cmpxchg(int variant, intptr_t addr, TESTSIZE expected, TESTSIZE new_value, TESTSIZE result, bool boolean_result = false) { - BufferBlob* bb = BufferBlob::create("riscvTest", 128); - CodeBuffer code(bb); + BufferBlob* _bb; + cmpxchg_func _func; + + public: + CmpxchgTester(int variant, bool boolean_result) { + _bb = BufferBlob::create("riscvTest", 128); + CodeBuffer code(_bb); MacroAssembler _masm(&code); address entry = _masm.pc(); { switch(variant) { default: _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, Assembler::aq, Assembler::rl, /*result*/ c_rarg3, boolean_result); _masm.mv(c_rarg0, c_rarg3); break; case 1: // expected == result _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, Assembler::aq, Assembler::rl, /*result*/ c_rarg1, boolean_result); _masm.mv(c_rarg0, c_rarg1); break; case 2: // new_value == result _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, Assembler::aq, Assembler::rl, /*result*/ c_rarg2, boolean_result); _masm.mv(c_rarg0, c_rarg2); break; case 3: // expected == new_value _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/ c_rarg1, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, Assembler::aq, Assembler::rl, /*result*/ c_rarg2, boolean_result); _masm.mv(c_rarg0, c_rarg2); break; @@ -149,22 +153,29 @@ class CmpxchgTester { _masm.ret(); } _masm.flush(); // icache invalidate - TESTSIZE ret = ((cmpxchg_func)entry)(addr, expected, new_value, result); - BufferBlob::free(bb); - return ret; + _func = ((cmpxchg_func)entry); + } + + ~CmpxchgTester() { + BufferBlob::free(_bb); + } + + TESTSIZE cmpxchg(intptr_t addr, TESTSIZE expected, TESTSIZE new_value) { + return _func(addr, expected, new_value, /* dummy result */ 67); } }; template -void plain_cmpxchg_test(int variant, TESTSIZE dv, TESTSIZE ex, TESTSIZE nv, TESTSIZE eret, TESTSIZE edata, bool bv) { +static void plain_cmpxchg_test(int variant, TESTSIZE dv, TESTSIZE ex, TESTSIZE nv, TESTSIZE eret, TESTSIZE edata, bool bv) { + CmpxchgTester cmpxchg(variant, bv); TESTSIZE data = dv; - TESTSIZE ret = CmpxchgTester::base_cmpxchg(variant, (intptr_t)&data, ex, nv, /* dummy */ 67, bv); + TESTSIZE ret = cmpxchg.cmpxchg((intptr_t)&data, ex, nv); ASSERT_EQ(ret, eret); ASSERT_EQ(data, edata); } template -void run_plain_cmpxchg_tests() { +static void run_plain_cmpxchg_tests() { // Normal plain_cmpxchg_test( 0 /* variant */ , 1337 /* start value*/, 1337 /* expected */, 42 /* new value */, @@ -234,41 +245,90 @@ void run_plain_cmpxchg_tests() { 0 /* return */ , 1337 /* end value*/, true /* boolean ret*/); } -TEST_VM(RiscV, cmpxchg_int64_plain_lr_sc) { +TEST_VM(RiscV, cmpxchg_int64_lr_sc) { bool zacas = UseZacas; UseZacas = false; run_plain_cmpxchg_tests(); UseZacas = zacas; } -TEST_VM(RiscV, cmpxchg_int64_plain_maybe_zacas) { +TEST_VM(RiscV, cmpxchg_int64_maybe_zacas) { if (UseZacas) { run_plain_cmpxchg_tests(); } } -TEST_VM(RiscV, cmpxchg_int32_plain_lr_sc) { +TEST_VM(RiscV, cmpxchg_int32_lr_sc) { bool zacas = UseZacas; UseZacas = false; run_plain_cmpxchg_tests(); UseZacas = zacas; } -TEST_VM(RiscV, cmpxchg_int32_plain_maybe_zacas) { +TEST_VM(RiscV, cmpxchg_int32_maybe_zacas) { if (UseZacas) { run_plain_cmpxchg_tests(); } } +template +static void run_concurrent_cmpxchg_tests() { + volatile TESTSIZE data = 0; + int num_threads = 4; + CmpxchgTester cmpxchg(0, false); // variant 0, not bool ret + auto incThread = [&](Thread* _current, int _id) { + for (int i = 0; i < 10000; i++) { + TESTSIZE oldvalue = _id + num_threads * i; + TESTSIZE newvalue = oldvalue + 1; + TESTSIZE ret; + do { + ret = cmpxchg.cmpxchg((intptr_t)&data, oldvalue, newvalue); + } while (ret != oldvalue); + } + }; + TestThreadGroup ttg(incThread, num_threads); + ttg.doit(); + ttg.join(); +} + +TEST_VM(RiscV, cmpxchg_int64_concurrent_lr_sc) { + bool zacas = UseZacas; + UseZacas = false; + run_concurrent_cmpxchg_tests(); + UseZacas = zacas; +} + +TEST_VM(RiscV, cmpxchg_int64_concurrent_maybe_zacas) { + if (UseZacas) { + run_concurrent_cmpxchg_tests(); + } +} + +TEST_VM(RiscV, cmpxchg_int32_concurrent_lr_sc) { + bool zacas = UseZacas; + UseZacas = false; + run_concurrent_cmpxchg_tests(); + UseZacas = zacas; +} + +TEST_VM(RiscV, cmpxchg_int32_concurrent_maybe_zacas) { + if (UseZacas) { + run_concurrent_cmpxchg_tests(); + } +} + template class NarrowCmpxchgTester { - public: typedef TESTSIZE (*cmpxchg_func)(intptr_t addr, TESTSIZE expected, TESTSIZE new_value, TESTSIZE result, int64_t scratch0, int64_t scratch1, int64_t scratch2); - static TESTSIZE narrow_cmpxchg(intptr_t addr, TESTSIZE expected, TESTSIZE new_value, TESTSIZE result, bool boolean_result = false) { - BufferBlob* bb = BufferBlob::create("riscvTest", 128); - CodeBuffer code(bb); + BufferBlob* _bb; + cmpxchg_func _func; + + public: + NarrowCmpxchgTester(bool boolean_result) { + _bb = BufferBlob::create("riscvTest", 128); + CodeBuffer code(_bb); MacroAssembler _masm(&code); address entry = _masm.pc(); { @@ -279,14 +339,22 @@ class NarrowCmpxchgTester { _masm.ret(); } _masm.flush(); // icache invalidate - TESTSIZE ret = ((cmpxchg_func)entry)(addr, expected, new_value, result, -1, -1, -1); - BufferBlob::free(bb); - return ret; + _func = ((cmpxchg_func)entry); + } + + ~NarrowCmpxchgTester() { + BufferBlob::free(_bb); + } + + TESTSIZE narrow_cmpxchg(intptr_t addr, TESTSIZE expected, TESTSIZE new_value) { + return _func(addr, expected, new_value, /* dummy result */ 67, -1, -1, -1); } }; template -void run_narrow_cmpxchg_tests() { +static void run_narrow_cmpxchg_tests() { + NarrowCmpxchgTester cmpxchg(false); + NarrowCmpxchgTester cmpxchg_bool(true); // Assume natural aligned TESTSIZE data[8]; TESTSIZE ret; @@ -294,22 +362,22 @@ void run_narrow_cmpxchg_tests() { memset(data, -1, sizeof(data)); data[i] = 121; - ret = NarrowCmpxchgTester::narrow_cmpxchg((intptr_t)&data[i], 121, 42, /* result */ 67, false); + ret = cmpxchg.narrow_cmpxchg((intptr_t)&data[i], 121, 42); ASSERT_EQ(ret, 121); ASSERT_EQ(data[i], 42); data[i] = 121; - ret = NarrowCmpxchgTester::narrow_cmpxchg((intptr_t)&data[i], 120, 42, /* result */ 67, false); + ret = cmpxchg.narrow_cmpxchg((intptr_t)&data[i], 120, 42); ASSERT_EQ(ret, 121); ASSERT_EQ(data[i], 121); data[i] = 121; - ret = NarrowCmpxchgTester::narrow_cmpxchg((intptr_t)&data[i], 121, 42, /* result */ 67, true); + ret = cmpxchg_bool.narrow_cmpxchg((intptr_t)&data[i], 121, 42); ASSERT_EQ(ret, 1); ASSERT_EQ(data[i], 42); data[i] = 121; - ret = NarrowCmpxchgTester::narrow_cmpxchg((intptr_t)&data[i], 120, 42, /* result */ 67, true); + ret = cmpxchg_bool.narrow_cmpxchg((intptr_t)&data[i], 120, 42); ASSERT_EQ(ret, 0); ASSERT_EQ(data[i], 121); } @@ -341,4 +409,50 @@ TEST_VM(RiscV, cmpxchg_int8_maybe_zacas) { } } +template +static void run_concurrent_narrow_cmpxchg_tests() { + volatile TESTSIZE data = 0; + int num_threads = 4; + NarrowCmpxchgTester cmpxchg(false); // not bool ret + auto incThread = [&](Thread* _current, int _id) { + for (int i = 0; i < 10000; i++) { + TESTSIZE oldvalue = _id + num_threads * i; + TESTSIZE newvalue = oldvalue + 1; + TESTSIZE ret; + do { + ret = cmpxchg.narrow_cmpxchg((intptr_t)&data, oldvalue, newvalue); + } while (ret != oldvalue); + } + }; + TestThreadGroup ttg(incThread, num_threads); + ttg.doit(); + ttg.join(); +} + +TEST_VM(RiscV, cmpxchg_int16_concurrent_lr_sc) { + bool zacas = UseZacas; + UseZacas = false; + run_concurrent_narrow_cmpxchg_tests(); + UseZacas = zacas; +} + +TEST_VM(RiscV, cmpxchg_int16_concurrent_maybe_zacas) { + if (UseZacas) { + run_concurrent_narrow_cmpxchg_tests(); + } +} + +TEST_VM(RiscV, cmpxchg_int8_concurrent_lr_sc) { + bool zacas = UseZacas; + UseZacas = false; + run_concurrent_narrow_cmpxchg_tests(); + UseZacas = zacas; +} + +TEST_VM(RiscV, cmpxchg_int8_concurrent_maybe_zacas) { + if (UseZacas) { + run_concurrent_narrow_cmpxchg_tests(); + } +} + #endif // RISCV