aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-04-09 17:30:44 -0700
committerAlon Zakai <alonzakai@gmail.com>2014-04-09 17:30:44 -0700
commite2811fed826db20a10af7f70ac44f1aad9f06aa5 (patch)
tree1547479e45b6dd790d57d2d4b765117dc2a60b2e
parent0fa67a6cdc857afd269612117380d0df7ab54b4e (diff)
start on c++11 atomics implementation and test; #2273
-rw-r--r--src/library.js6
-rw-r--r--tests/core/test_atomic_cxx.cpp126
-rw-r--r--tests/core/test_atomic_cxx.txt210
-rw-r--r--tests/test_core.py6
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):