diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-04-09 17:30:44 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-04-09 17:30:44 -0700 |
commit | e2811fed826db20a10af7f70ac44f1aad9f06aa5 (patch) | |
tree | 1547479e45b6dd790d57d2d4b765117dc2a60b2e | |
parent | 0fa67a6cdc857afd269612117380d0df7ab54b4e (diff) |
start on c++11 atomics implementation and test; #2273
-rw-r--r-- | src/library.js | 6 | ||||
-rw-r--r-- | tests/core/test_atomic_cxx.cpp | 126 | ||||
-rw-r--r-- | tests/core/test_atomic_cxx.txt | 210 | ||||
-rw-r--r-- | tests/test_core.py | 6 |
4 files changed, 348 insertions, 0 deletions
diff --git a/src/library.js b/src/library.js index 6c2bfa36..b000c7f4 100644 --- a/src/library.js +++ b/src/library.js @@ -4430,6 +4430,12 @@ LibraryManager.library = { llvm_nacl_atomic_store_i32__inline: true, + // gnu atomics + + __atomic_is_lock_free: function(size, ptr) { + return size <= 4 && (ptr&(size-1)) == 0; + }, + // ========================================================================== // llvm-mono integration // ========================================================================== diff --git a/tests/core/test_atomic_cxx.cpp b/tests/core/test_atomic_cxx.cpp new file mode 100644 index 00000000..8caa3bad --- /dev/null +++ b/tests/core/test_atomic_cxx.cpp @@ -0,0 +1,126 @@ +//------------------------------------------------------------------------------ +// test C++11 atomics +// compile native version with: +// clang -std=c++11 -Wno-format atomic_test.cpp +// compile emscripten version with: +// emcc -std=c++11 -Wno-format atomic_test.cpp +//------------------------------------------------------------------------------ +#include <atomic> +#include <cstdio> + +template<typename TYPE> void test(TYPE mask0, TYPE mask1, TYPE mask2) { + typedef TYPE dog; + + const TYPE numMemoryOrders = 6; + std::memory_order memoryOrder[numMemoryOrders] = { + std::memory_order_relaxed, + std::memory_order_consume, + std::memory_order_acquire, + std::memory_order_release, + std::memory_order_acq_rel, + std::memory_order_seq_cst, + }; + + // test atomic<int> + std::atomic<dog> atomicDog(5); + printf("atomic<int>.is_lock_free(): %s", atomicDog.is_lock_free() ? "true" : "false"); + printf("atomic<int> value: %lld\n", TYPE(atomicDog)); + + // test store/load + for (TYPE i = 0; i < numMemoryOrders; i++) { + atomicDog.store(i, memoryOrder[i]); + printf("store/load %lld: %lld\n", i, atomicDog.load(memoryOrder[i])); + } + + // test exchange + for (TYPE i = 0; i < numMemoryOrders; i++) { + TYPE old = atomicDog.exchange(i, memoryOrder[i]); + printf("exchange %lld: old=%lld new=%lld\n", i, old, TYPE(atomicDog)); + } + + // compare_exchange_weak + for (TYPE i = 0; i < numMemoryOrders; i++) { + bool success = atomicDog.compare_exchange_weak(i, i + 1, memoryOrder[i], memoryOrder[i]); + printf("compare_exchange_weak %ld: success = %s\n", i, success ? "true" : "false"); + } + + // compare_exchange_strong + for (TYPE i = 0; i < numMemoryOrders; i++) { + bool success = atomicDog.compare_exchange_strong(i, i + 1, memoryOrder[i], memoryOrder[i]); + printf("compare_exchange_strong %ld: success = %s\n", i, success ? "true" : "false"); + } + + // fetch_add + atomicDog = 0; + for (TYPE i = 0; i < numMemoryOrders; i++) { + TYPE old = atomicDog.fetch_add(1, memoryOrder[i]); + printf("fetch_add %ld: old=%d new=%ld\n", i, old, TYPE(atomicDog)); + } + + // fetch_sub + for (TYPE i = 0; i < numMemoryOrders; i++) { + TYPE old = atomicDog.fetch_sub(1, memoryOrder[i]); + printf("fetch_sub %ld: old=%d new=%ld\n", i, old, TYPE(atomicDog)); + } + + // fetch_and + for (TYPE i = 0; i < numMemoryOrders; i++) { + atomicDog.store(mask0, memoryOrder[i]); + TYPE old = atomicDog.fetch_and((1<<i), memoryOrder[i]); + printf("fetch_and %ld: old=%lx, new=%lx\n", i, old, TYPE(atomicDog)); + } + + // fetch_or + atomicDog = 0; + for (TYPE i = 0; i < numMemoryOrders; i++) { + TYPE old = atomicDog.fetch_or((1<<i), memoryOrder[i]); + printf("fetch_or %ld: old=%lx, new=%lx\n", i, old, TYPE(atomicDog)); + } + + // fetch_xor + atomicDog = 0; + for (int i = 0; i < numMemoryOrders; i++) { + int old = atomicDog.fetch_xor((1<<i), memoryOrder[i]); + printf("fetch_xor %ld: old=%llx, new=%lx\n", i, old, TYPE(atomicDog)); + } + + // operator++, -- + atomicDog = 0; + atomicDog++; + printf("operator++: %ld\n", TYPE(atomicDog)); + atomicDog--; + printf("operator--: %ld\n", TYPE(atomicDog)); + + // operator +=, -=, &=, |=, ^= + atomicDog += 10; + printf("operator+=: %ld\n", TYPE(atomicDog)); + atomicDog -= 5; + printf("operator-=: %ld\n", TYPE(atomicDog)); + atomicDog |= mask0; + printf("operator|=: %lx\n", TYPE(atomicDog)); + atomicDog &= mask1; + printf("operator|=: %lx\n", TYPE(atomicDog)); + atomicDog ^= mask2; + printf("operator^=: %lx\n", TYPE(atomicDog)); + +} + +int main() { + + // test 8, 16, 32 and 64-bit data types + test<char>(0xFF, 0xF0, 0x0F); + test<short>(0xFFFF, 0xF0F0, 0x0F0F); + test<int>(0xFFFFFFFF, 0xF0F0F0F0, 0x0F0F0F0F); + test<long long>(0xFFFFFFFFFFFFFFFF, 0xF0F0F0F0F0F0F0F0, 0x0F0F0F0F0F0F0F0F); + + // test atomic_flag (should also have memory_orders, but probably doesn't matter + // to find the missing atomic functions) + std::atomic_flag af; + af.clear(); + bool b = af.test_and_set(); + printf("atomic_flag: %s\n", b ? "true" : "false"); + + printf("done.\n"); + return 0; +} + diff --git a/tests/core/test_atomic_cxx.txt b/tests/core/test_atomic_cxx.txt new file mode 100644 index 00000000..25baa0cb --- /dev/null +++ b/tests/core/test_atomic_cxx.txt @@ -0,0 +1,210 @@ +atomic<int>.is_lock_free(): trueatomic<int> value: 5 +store/load 0: 0 +store/load 1: 1 +store/load 2: 2 +store/load 3: 3 +store/load 4: 4 +store/load 5: 5 +exchange 0: old=5 new=0 +exchange 1: old=0 new=1 +exchange 2: old=1 new=2 +exchange 3: old=2 new=3 +exchange 4: old=3 new=4 +exchange 5: old=4 new=5 +compare_exchange_weak 5: success = false +compare_exchange_strong 5: success = false +fetch_add 0: old=0 new=1 +fetch_add 1: old=1 new=2 +fetch_add 2: old=2 new=3 +fetch_add 3: old=3 new=4 +fetch_add 4: old=4 new=5 +fetch_add 5: old=5 new=6 +fetch_sub 0: old=6 new=5 +fetch_sub 1: old=5 new=4 +fetch_sub 2: old=4 new=3 +fetch_sub 3: old=3 new=2 +fetch_sub 4: old=2 new=1 +fetch_sub 5: old=1 new=0 +fetch_and 0: old=ffffffff, new=1 +fetch_and 1: old=ffffffff, new=2 +fetch_and 2: old=ffffffff, new=4 +fetch_and 3: old=ffffffff, new=8 +fetch_and 4: old=ffffffff, new=10 +fetch_and 5: old=ffffffff, new=20 +fetch_or 0: old=0, new=1 +fetch_or 1: old=1, new=3 +fetch_or 2: old=3, new=7 +fetch_or 3: old=7, new=f +fetch_or 4: old=f, new=1f +fetch_or 5: old=1f, new=3f +fetch_xor 0: old=0, new=1 +fetch_xor 1: old=1, new=3 +fetch_xor 2: old=3, new=7 +fetch_xor 3: old=7, new=f +fetch_xor 4: old=f, new=1f +fetch_xor 5: old=1f, new=3f +operator++: 1 +operator--: 0 +operator+=: 10 +operator-=: 5 +operator|=: ffffffff +operator|=: fffffff0 +operator^=: ffffffff +atomic<int>.is_lock_free(): trueatomic<int> value: 5 +store/load 0: 0 +store/load 1: 1 +store/load 2: 2 +store/load 3: 3 +store/load 4: 4 +store/load 5: 5 +exchange 0: old=5 new=0 +exchange 1: old=0 new=1 +exchange 2: old=1 new=2 +exchange 3: old=2 new=3 +exchange 4: old=3 new=4 +exchange 5: old=4 new=5 +compare_exchange_weak 5: success = false +compare_exchange_strong 5: success = false +fetch_add 0: old=0 new=1 +fetch_add 1: old=1 new=2 +fetch_add 2: old=2 new=3 +fetch_add 3: old=3 new=4 +fetch_add 4: old=4 new=5 +fetch_add 5: old=5 new=6 +fetch_sub 0: old=6 new=5 +fetch_sub 1: old=5 new=4 +fetch_sub 2: old=4 new=3 +fetch_sub 3: old=3 new=2 +fetch_sub 4: old=2 new=1 +fetch_sub 5: old=1 new=0 +fetch_and 0: old=ffffffff, new=1 +fetch_and 1: old=ffffffff, new=2 +fetch_and 2: old=ffffffff, new=4 +fetch_and 3: old=ffffffff, new=8 +fetch_and 4: old=ffffffff, new=10 +fetch_and 5: old=ffffffff, new=20 +fetch_or 0: old=0, new=1 +fetch_or 1: old=1, new=3 +fetch_or 2: old=3, new=7 +fetch_or 3: old=7, new=f +fetch_or 4: old=f, new=1f +fetch_or 5: old=1f, new=3f +fetch_xor 0: old=0, new=1 +fetch_xor 1: old=1, new=3 +fetch_xor 2: old=3, new=7 +fetch_xor 3: old=7, new=f +fetch_xor 4: old=f, new=1f +fetch_xor 5: old=1f, new=3f +operator++: 1 +operator--: 0 +operator+=: 10 +operator-=: 5 +operator|=: ffffffff +operator|=: fffff0f0 +operator^=: ffffffff +atomic<int>.is_lock_free(): trueatomic<int> value: 5 +store/load 0: 0 +store/load 1: 1 +store/load 2: 2 +store/load 3: 3 +store/load 4: 4 +store/load 5: 5 +exchange 0: old=5 new=0 +exchange 1: old=0 new=1 +exchange 2: old=1 new=2 +exchange 3: old=2 new=3 +exchange 4: old=3 new=4 +exchange 5: old=4 new=5 +compare_exchange_weak 5: success = false +compare_exchange_strong 5: success = false +fetch_add 0: old=0 new=1 +fetch_add 1: old=1 new=2 +fetch_add 2: old=2 new=3 +fetch_add 3: old=3 new=4 +fetch_add 4: old=4 new=5 +fetch_add 5: old=5 new=6 +fetch_sub 0: old=6 new=5 +fetch_sub 1: old=5 new=4 +fetch_sub 2: old=4 new=3 +fetch_sub 3: old=3 new=2 +fetch_sub 4: old=2 new=1 +fetch_sub 5: old=1 new=0 +fetch_and 0: old=ffffffff, new=1 +fetch_and 1: old=ffffffff, new=2 +fetch_and 2: old=ffffffff, new=4 +fetch_and 3: old=ffffffff, new=8 +fetch_and 4: old=ffffffff, new=10 +fetch_and 5: old=ffffffff, new=20 +fetch_or 0: old=0, new=1 +fetch_or 1: old=1, new=3 +fetch_or 2: old=3, new=7 +fetch_or 3: old=7, new=f +fetch_or 4: old=f, new=1f +fetch_or 5: old=1f, new=3f +fetch_xor 0: old=0, new=1 +fetch_xor 1: old=1, new=3 +fetch_xor 2: old=3, new=7 +fetch_xor 3: old=7, new=f +fetch_xor 4: old=f, new=1f +fetch_xor 5: old=1f, new=3f +operator++: 1 +operator--: 0 +operator+=: 10 +operator-=: 5 +operator|=: ffffffff +operator|=: f0f0f0f0 +operator^=: ffffffff +atomic<int>.is_lock_free(): trueatomic<int> value: 5 +store/load 0: 0 +store/load 1: 1 +store/load 2: 2 +store/load 3: 3 +store/load 4: 4 +store/load 5: 5 +exchange 0: old=5 new=0 +exchange 1: old=0 new=1 +exchange 2: old=1 new=2 +exchange 3: old=2 new=3 +exchange 4: old=3 new=4 +exchange 5: old=4 new=5 +compare_exchange_weak 5: success = false +compare_exchange_strong 5: success = false +fetch_add 0: old=0 new=1 +fetch_add 1: old=1 new=2 +fetch_add 2: old=2 new=3 +fetch_add 3: old=3 new=4 +fetch_add 4: old=4 new=5 +fetch_add 5: old=5 new=6 +fetch_sub 0: old=6 new=5 +fetch_sub 1: old=5 new=4 +fetch_sub 2: old=4 new=3 +fetch_sub 3: old=3 new=2 +fetch_sub 4: old=2 new=1 +fetch_sub 5: old=1 new=0 +fetch_and 0: old=ffffffffffffffff, new=1 +fetch_and 1: old=ffffffffffffffff, new=2 +fetch_and 2: old=ffffffffffffffff, new=4 +fetch_and 3: old=ffffffffffffffff, new=8 +fetch_and 4: old=ffffffffffffffff, new=10 +fetch_and 5: old=ffffffffffffffff, new=20 +fetch_or 0: old=0, new=1 +fetch_or 1: old=1, new=3 +fetch_or 2: old=3, new=7 +fetch_or 3: old=7, new=f +fetch_or 4: old=f, new=1f +fetch_or 5: old=1f, new=3f +fetch_xor 0: old=0, new=1 +fetch_xor 1: old=1, new=3 +fetch_xor 2: old=3, new=7 +fetch_xor 3: old=7, new=f +fetch_xor 4: old=f, new=1f +fetch_xor 5: old=1f, new=3f +operator++: 1 +operator--: 0 +operator+=: 10 +operator-=: 5 +operator|=: ffffffffffffffff +operator|=: f0f0f0f0f0f0f0f0 +operator^=: ffffffffffffffff +atomic_flag: false +done. diff --git a/tests/test_core.py b/tests/test_core.py index d5b855b9..a3712de2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4420,7 +4420,13 @@ PORT: 3979 def test_atomic(self): test_path = path_from_root('tests', 'core', 'test_atomic') src, output = (test_path + s for s in ('.in', '.out')) + self.do_run_from_file(src, output) + def zzztest_atomic_cxx(self): + if self.emcc_args is None: return self.skip('needs emcc') + test_path = path_from_root('tests', 'core', 'test_atomic_cxx') + src, output = (test_path + s for s in ('.cpp', '.txt')) + Building.COMPILER_TEST_OPTS += ['-std=c++11'] self.do_run_from_file(src, output) def test_phiundef(self): |