Skip to content
Merged
1 change: 1 addition & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ignore = [
"B011", # https://docs.astral.sh/ruff/rules/assert-false/
"B023", # https://docs.astral.sh/ruff/rules/function-uses-loop-variable/
"E501", # https://docs.astral.sh/ruff/rules/line-too-long/
"E741", # https://docs.astral.sh/ruff/rules/ambiguous-variable-name/
"PERF401", # https://docs.astral.sh/ruff/rules/manual-list-comprehension/
"PLR0912", # https://docs.astral.sh/ruff/rules/too-many-branches/
"PLR0913", # https://docs.astral.sh/ruff/rules/too-many-arguments/
Expand Down
98 changes: 98 additions & 0 deletions scripts/test/generate-atomic-spec-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import enum
from dataclasses import dataclass
from enum import Enum

# Workaround for python <3.10, escape characters can't appear in f-strings.
# Although we require 3.10 in some places, the formatter complains without this.
newline = "\n"


def indent(s):
return "\n".join(f" {line}" if line else "" for line in s.split("\n"))


class ValueType(Enum):
i32 = enum.auto()
i64 = enum.auto()


class Ordering(Enum):
seqcst = 0
acqrel = 1


@dataclass
class Template:
str: str
value_type: object
args: int


templates = [
Template(str="(drop (i32.atomic.load %(memarg)s%(args)s))", value_type=ValueType.i32, args=1),
Template(str="(drop (i64.atomic.load %(memarg)s%(args)s))", value_type=ValueType.i64, args=1),
Template(str="(i32.atomic.store %(memarg)s%(args)s)", value_type=ValueType.i32, args=2),
Template(str="(i64.atomic.store %(memarg)s%(args)s)", value_type=ValueType.i64, args=2),
]


def statement(template, mem_idx: str | None, ordering: Ordering | None):
"""Return a statement exercising the op in `template` e.g. (i32.atomic.store 1 acqrel (i64.const 42) (i32.const 42))"""
memargs = []
if mem_idx is not None:
memargs.append(mem_idx)
if ordering is not None:
memargs.append(ordering.name)

memarg_str = " ".join(memargs) + " " if memargs else ""
idx_type = ValueType.i64 if mem_idx == "1" else ValueType.i32 if mem_idx == "0" else ValueType.i32

# The first argument (the memory location) must match the memory that we're indexing. Other arguments match the op (e.g. i32 for i32.atomic.load).
args = [f"({idx_type.name}.const 42)"] + [f"({template.value_type.name}.const 42)" for _ in range(template.args - 1)]
return template.str % {"memarg": memarg_str, "args": " ".join(args)}


def func():
"""Return a func exercising all ops in `templates` e.g.
(func $test-all-ops
(drop (i32.atomic.load (i32.const 42)))
(drop (i32.atomic.load acqrel (i32.const 42)))
...
)
"""
statements = [statement(template, mem_idx, ordering) for template in templates for mem_idx in [None, "0", "1"] for ordering in [None, Ordering.acqrel, Ordering.seqcst]]
return f''';; Memory index must come before memory ordering if present.
;; Both immediates are optional; an ommitted memory ordering will be treated as seqcst.
(func $test-all-ops
{indent(newline.join(statements))}
)'''


def text_test():
"""Return a (module ...) that exercises all ops in `templates`."""
return f'''(module
(memory i32 1 1)
(memory i64 1 1)

{indent(func())}
)'''


def invalid_text_test():
return '''(assert_invalid (module
(memory 1 1 shared)

(func $i32load (drop (i32.load acqrel (i32.const 51))))
) "Can't set memory ordering for non-atomic i32.load")'''


def main():
print(";; Generated by scripts/test/generate-atomic-spec-test.py. Do not edit manually.")
print()
print(text_test())
print()
print(invalid_text_test())


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions test/spec/relaxed-atomics.wast
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
;; TODO: replace this with the script generated by scripts/test/generate-atomic-spec-test.py

(module
(memory 1 1 shared)
(memory 1 1 shared)
Expand Down
53 changes: 53 additions & 0 deletions test/spec/relaxed-atomics2.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
;; Generated by scripts/test/generate-atomic-spec-test.py. Do not edit manually.

(module
(memory i32 1 1)
(memory i64 1 1)

;; Memory index must come before memory ordering if present.
;; Both immediates are optional; an ommitted memory ordering will be treated as seqcst.
(func $test-all-ops
(drop (i32.atomic.load (i32.const 42)))
(drop (i32.atomic.load acqrel (i32.const 42)))
(drop (i32.atomic.load seqcst (i32.const 42)))
(drop (i32.atomic.load 0 (i32.const 42)))
(drop (i32.atomic.load 0 acqrel (i32.const 42)))
(drop (i32.atomic.load 0 seqcst (i32.const 42)))
(drop (i32.atomic.load 1 (i64.const 42)))
(drop (i32.atomic.load 1 acqrel (i64.const 42)))
(drop (i32.atomic.load 1 seqcst (i64.const 42)))
(drop (i64.atomic.load (i32.const 42)))
(drop (i64.atomic.load acqrel (i32.const 42)))
(drop (i64.atomic.load seqcst (i32.const 42)))
(drop (i64.atomic.load 0 (i32.const 42)))
(drop (i64.atomic.load 0 acqrel (i32.const 42)))
(drop (i64.atomic.load 0 seqcst (i32.const 42)))
(drop (i64.atomic.load 1 (i64.const 42)))
(drop (i64.atomic.load 1 acqrel (i64.const 42)))
(drop (i64.atomic.load 1 seqcst (i64.const 42)))
(i32.atomic.store (i32.const 42) (i32.const 42))
(i32.atomic.store acqrel (i32.const 42) (i32.const 42))
(i32.atomic.store seqcst (i32.const 42) (i32.const 42))
(i32.atomic.store 0 (i32.const 42) (i32.const 42))
(i32.atomic.store 0 acqrel (i32.const 42) (i32.const 42))
(i32.atomic.store 0 seqcst (i32.const 42) (i32.const 42))
(i32.atomic.store 1 (i64.const 42) (i32.const 42))
(i32.atomic.store 1 acqrel (i64.const 42) (i32.const 42))
(i32.atomic.store 1 seqcst (i64.const 42) (i32.const 42))
(i64.atomic.store (i32.const 42) (i64.const 42))
(i64.atomic.store acqrel (i32.const 42) (i64.const 42))
(i64.atomic.store seqcst (i32.const 42) (i64.const 42))
(i64.atomic.store 0 (i32.const 42) (i64.const 42))
(i64.atomic.store 0 acqrel (i32.const 42) (i64.const 42))
(i64.atomic.store 0 seqcst (i32.const 42) (i64.const 42))
(i64.atomic.store 1 (i64.const 42) (i64.const 42))
(i64.atomic.store 1 acqrel (i64.const 42) (i64.const 42))
(i64.atomic.store 1 seqcst (i64.const 42) (i64.const 42))
)
)

(assert_invalid (module
(memory 1 1 shared)

(func $i32load (drop (i32.load acqrel (i32.const 51))))
) "Can't set memory ordering for non-atomic i32.load")
Loading