diff --git a/src/binaryen_stubs_expressions.c b/src/binaryen_stubs_expressions.c index cc9b9da9..07328cf2 100644 --- a/src/binaryen_stubs_expressions.c +++ b/src/binaryen_stubs_expressions.c @@ -2074,3 +2074,119 @@ caml_binaryen_tablegrow_set_delta(value _exp, value _delta) { BinaryenTableGrowSetDelta(exp, delta); CAMLreturn(Val_unit); } + +// Atomics + +CAMLprim value +caml_binaryen_atomic_load(value _module, value _bytes, value _offset, value _ty, value _ptr, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ty, _ptr); + CAMLxparam1(_memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + int bytes = Int_val(_bytes); + int offset = Int_val(_offset); + BinaryenType ty = BinaryenType_val(_ty); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicLoad(module, bytes, offset, ty, ptr, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +CAMLprim value +caml_binaryen_atomic_load__bytecode(value * argv) { + return caml_binaryen_atomic_load(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +CAMLprim value +caml_binaryen_atomic_store(value _module, value _bytes, value _offset, value _ptr, value _val, value _ty, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ptr, _val); + CAMLxparam2(_ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + int bytes = Int_val(_bytes); + int offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_val); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicStore(module, bytes, offset, ptr, val, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +CAMLprim value +caml_binaryen_atomic_store__bytecode(value * argv) { + return caml_binaryen_atomic_store(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + +CAMLprim value +caml_binaryen_atomic_rmw(value _module, value _op, value _bytes, value _offset, value _ptr, value _val, value _ty, value _memoryName) { + CAMLparam5(_module, _op, _bytes, _offset, _ptr); + CAMLxparam3(_val, _ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenOp op = BinaryenOp_val(_op); + BinaryenIndex bytes = Int_val(_bytes); + BinaryenIndex offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_val); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicRMW(module, op, bytes, offset, ptr, val, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +CAMLprim value +caml_binaryen_atomic_rmw__bytecode(value * argv) { + return caml_binaryen_atomic_rmw(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +CAMLprim value +caml_binaryen_atomic_cmpxchg(value _module, value _bytes, value _offset, value _ptr, value _expected, value _replacement, value _ty, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ptr, _expected); + CAMLxparam3(_replacement, _ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenIndex bytes = Int_val(_bytes); + BinaryenIndex offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef expected = BinaryenExpressionRef_val(_expected); + BinaryenExpressionRef replacement = BinaryenExpressionRef_val(_replacement); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicCmpxchg(module, bytes, offset, ptr, expected, replacement, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +CAMLprim value +caml_binaryen_atomic_cmpxchg__bytecode(value * argv) { + return caml_binaryen_atomic_cmpxchg(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +CAMLprim value +caml_binaryen_atomic_wait(value _module, value _ptr, value _expected, value _timeout, value _ty, value _memoryName) { + CAMLparam5(_module, _ptr, _expected, _timeout, _ty); + CAMLxparam1(_memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef expected = BinaryenExpressionRef_val(_expected); + BinaryenExpressionRef timeout = BinaryenExpressionRef_val(_timeout); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicWait(module, ptr, expected, timeout, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +CAMLprim value +caml_binaryen_atomic_wait__bytecode(value * argv) { + return caml_binaryen_atomic_wait(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +CAMLprim value +caml_binaryen_atomic_notify(value _module, value _ptr, value _notifyCount, value _memoryName) { + CAMLparam4(_module, _ptr, _notifyCount, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef notifyCount = BinaryenExpressionRef_val(_notifyCount); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicNotify(module, ptr, notifyCount, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} + +CAMLprim value +caml_binaryen_atomic_fence(value _module) { + CAMLparam1(_module); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef res = BinaryenAtomicFence(module); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} diff --git a/src/binaryen_stubs_expressions.js b/src/binaryen_stubs_expressions.js index 93be0c36..2f3029bc 100644 --- a/src/binaryen_stubs_expressions.js +++ b/src/binaryen_stubs_expressions.js @@ -1826,3 +1826,131 @@ function caml_binaryen_tablegrow_get_delta(exp) { function caml_binaryen_tablegrow_set_delta(exp, delta) { return Binaryen.TableGrow.setDelta(exp, delta); } + +// Atomics + +//Provides: +//Requires: +function caml_binaryen_atomic_load(value _module, value _bytes, value _offset, value _ty, value _ptr, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ty, _ptr); + CAMLxparam1(_memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + int bytes = Int_val(_bytes); + int offset = Int_val(_offset); + BinaryenType ty = BinaryenType_val(_ty); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicLoad(module, bytes, offset, ty, ptr, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +//Provides: +//Requires: +function caml_binaryen_atomic_load__bytecode(value * argv) { + return caml_binaryen_atomic_load(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_store(value _module, value _bytes, value _offset, value _ptr, value _val, value _ty, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ptr, _val); + CAMLxparam2(_ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + int bytes = Int_val(_bytes); + int offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_val); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicStore(module, bytes, offset, ptr, val, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +//Provides: +//Requires: +function caml_binaryen_atomic_store__bytecode(value * argv) { + return caml_binaryen_atomic_store(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_rmw(value _module, value _op, value _bytes, value _offset, value _ptr, value _val, value _ty, value _memoryName) { + CAMLparam5(_module, _op, _bytes, _offset, _ptr); + CAMLxparam3(_val, _ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenOp op = BinaryenOp_val(_op); + BinaryenIndex bytes = Int_val(_bytes); + BinaryenIndex offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef val = BinaryenExpressionRef_val(_val); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicRMW(module, op, bytes, offset, ptr, val, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +//Provides: +//Requires: +function caml_binaryen_atomic_rmw__bytecode(value * argv) { + return caml_binaryen_atomic_rmw(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_cmpxchg(value _module, value _bytes, value _offset, value _ptr, value _expected, value _replacement, value _ty, value _memoryName) { + CAMLparam5(_module, _bytes, _offset, _ptr, _expected); + CAMLxparam3(_replacement, _ty, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenIndex bytes = Int_val(_bytes); + BinaryenIndex offset = Int_val(_offset); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef expected = BinaryenExpressionRef_val(_expected); + BinaryenExpressionRef replacement = BinaryenExpressionRef_val(_replacement); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicCmpxchg(module, bytes, offset, ptr, expected, replacement, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +//Provides: +//Requires: +function caml_binaryen_atomic_cmpxchg__bytecode(value * argv) { + return caml_binaryen_atomic_cmpxchg(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_wait(value _module, value _ptr, value _expected, value _timeout, value _ty, value _memoryName) { + CAMLparam5(_module, _ptr, _expected, _timeout, _ty); + CAMLxparam1(_memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef expected = BinaryenExpressionRef_val(_expected); + BinaryenExpressionRef timeout = BinaryenExpressionRef_val(_timeout); + BinaryenType ty = BinaryenType_val(_ty); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicWait(module, ptr, expected, timeout, ty, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} +//Provides: +//Requires: +function caml_binaryen_atomic_wait__bytecode(value * argv) { + return caml_binaryen_atomic_wait(argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_notify(value _module, value _ptr, value _notifyCount, value _memoryName) { + CAMLparam4(_module, _ptr, _notifyCount, _memoryName); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef ptr = BinaryenExpressionRef_val(_ptr); + BinaryenExpressionRef notifyCount = BinaryenExpressionRef_val(_notifyCount); + char* memoryName = Safe_String_val(_memoryName); + BinaryenExpressionRef res = BinaryenAtomicNotify(module, ptr, notifyCount, memoryName); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} + +//Provides: +//Requires: +function caml_binaryen_atomic_fence(value _module) { + CAMLparam1(_module); + BinaryenModuleRef module = BinaryenModuleRef_val(_module); + BinaryenExpressionRef res = BinaryenAtomicFence(module); + CAMLreturn(alloc_BinaryenExpressionRef(res)); +} diff --git a/src/expression.ml b/src/expression.ml index 9fb08d4e..0528a0c0 100644 --- a/src/expression.ml +++ b/src/expression.ml @@ -897,3 +897,67 @@ module Table_grow = struct external set_delta : t -> t -> unit = "caml_binaryen_tablegrow_set_delta" (** Sets the delta of a `Table.grow` expression. *) end + +module Atomic = struct + external load : + Module.t -> + bytes:int -> + offset:int -> + typ:Type.t -> + ptr:t -> + memory_name:string -> + t = "caml_binaryen_atomic_load__bytecode" "caml_binaryen_atomic_load" + (** module, bytes, offset, ty, ptr, memoryName *) + + external store : + Module.t -> + bytes:int -> + offset:int -> + ptr:t -> + value:t -> + typ:Type.t -> + memory_name:string -> + t = "caml_binaryen_atomic_store__bytecode" "caml_binaryen_atomic_store" + (** module, bytes, offset, ptr, val, ty, memoryName *) + + external rmw : + Module.t -> + op:Op.t -> + bytes:int -> + offset:int -> + ptr:t -> + value:t -> + typ:Type.t -> + memory_name:string -> + t = "caml_binaryen_atomic_rmw__bytecode" "caml_binaryen_atomic_rmw" + (** module, op, bytes, offset, ptr, val, ty, memoryName *) + + external cmpxchg : + Module.t -> + bytes:int -> + offset:int -> + ptr:t -> + expected:t -> + replacement:t -> + typ:Type.t -> + memory_name:string -> + t = "caml_binaryen_atomic_cmpxchg__bytecode" "caml_binaryen_atomic_cmpxchg" + (** module, bytes, offset, ptr, expected, replacement, ty, memoryName *) + + external wait : + Module.t -> + ptr:t -> + expected:t -> + timeout:t -> + typ:Type.t -> + memory_name:string -> + t = "caml_binaryen_atomic_wait__bytecode" "caml_binaryen_atomic_wait" + (** module, ptr, expected, timeout, ty, memoryName *) + + external notify : + Module.t -> ptr:t -> notify_count:t -> memory_name:string -> t + = "caml_binaryen_atomic_notify" + (** module, ptr, notifyCount, memoryName *) + + external fence : Module.t -> t = "caml_binaryen_atomic_fence" +end diff --git a/src/expression.mli b/src/expression.mli index 28736a9f..1094c41b 100644 --- a/src/expression.mli +++ b/src/expression.mli @@ -417,3 +417,65 @@ module Table_grow : sig val set_delta : t -> t -> unit (** Sets the delta of a `Table.grow` expression. *) end + +module Atomic : sig + val load : + Module.t -> + bytes:int -> + offset:int -> + typ:Type.t -> + ptr:t -> + memory_name:string -> + t + (** module, bytes, offset, ty, ptr, memoryName *) + + val store : + Module.t -> + bytes:int -> + offset:int -> + ptr:t -> + value:t -> + typ:Type.t -> + memory_name:string -> + t + (** module, bytes, offset, ptr, val, ty, memoryName *) + + val rmw : + Module.t -> + op:Op.t -> + bytes:int -> + offset:int -> + ptr:t -> + value:t -> + typ:Type.t -> + memory_name:string -> + t + (** module, op, bytes, offset, ptr, val, ty, memoryName *) + + val cmpxchg : + Module.t -> + bytes:int -> + offset:int -> + ptr:t -> + expected:t -> + replacement:t -> + typ:Type.t -> + memory_name:string -> + t + (** module, bytes, offset, ptr, expected, replacement, ty, memoryName *) + + val wait : + Module.t -> + ptr:t -> + expected:t -> + timeout:t -> + typ:Type.t -> + memory_name:string -> + t + (** module, ptr, expected, timeout, ty, memoryName *) + + val notify : Module.t -> ptr:t -> notify_count:t -> memory_name:string -> t + (** module, ptr, notifyCount, memoryName *) + + val fence : Module.t -> t +end diff --git a/test/test.expected b/test/test.expected index cbb5e5e5..2d74dbb7 100644 --- a/test/test.expected +++ b/test/test.expected @@ -6,6 +6,26 @@ (ref.null func) (i32.const 0) ) +(i32.atomic.store $0 + (i32.const 0) + (i32.atomic.load $0 + (i32.const 0) + ) +) +(drop + (memory.atomic.wait32 $0 + (i32.const 0) + (i32.const 0) + (i64.const 111) + ) +) +(drop + (memory.atomic.notify $0 + (i32.const 0) + (i32.const 0) + ) +) +(atomic.fence) (module (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (type $none_=>_none (func)) diff --git a/test/test.ml b/test/test.ml index 2ba0e310..4de0bff8 100644 --- a/test/test.ml +++ b/test/test.ml @@ -172,6 +172,33 @@ let _ = Memory.set_memory max_memory_wasm_mod 1 2 "memory" [] false "0" let _ = assert (Memory.has_max max_memory_wasm_mod "0" = true) let _ = assert (Memory.get_max max_memory_wasm_mod "0" = 2) +(* Atomics *) +let atomics_ptr = Expression.Const.make wasm_mod (Literal.int32 0l) +let atomics_timeout = Expression.Const.make wasm_mod (Literal.int64 111L) + +let atomic_store = + Expression.Atomic.store wasm_mod ~bytes:4 ~offset:0 ~ptr:atomics_ptr + ~value: + (Expression.Atomic.load wasm_mod ~bytes:4 ~offset:0 ~typ:Type.int32 + ~ptr:atomics_ptr ~memory_name:"0") + ~typ:Type.int32 ~memory_name:"0" + +let atomic_wait = + Expression.Drop.make wasm_mod + (Expression.Atomic.wait wasm_mod ~ptr:atomics_ptr ~expected:atomics_ptr + ~timeout:atomics_timeout ~typ:Type.int32 ~memory_name:"0") + +let atomic_notify = + Expression.Drop.make wasm_mod + (Expression.Atomic.notify wasm_mod ~ptr:atomics_ptr + ~notify_count:atomics_ptr ~memory_name:"0") + +let atomic_fence = Expression.Atomic.fence wasm_mod +let () = Expression.print atomic_store +let () = Expression.print atomic_wait +let () = Expression.print atomic_notify +let () = Expression.print atomic_fence + (* Create an imported "write" function i32 (anyref, i32, i32) *) (* Similar to the example here: https://bytecodealliance.org/articles/reference-types-in-wasmtime *)