diff --git a/.gitignore b/.gitignore index 7eeff05..6cabcdf 100644 --- a/.gitignore +++ b/.gitignore @@ -139,3 +139,9 @@ out/ **/**.spv **/**.amber **/**.spasm + +**/**.pkl +**/**.plist +**/**.metal +**/**.metallib +**/**.txt diff --git a/amber_server.py b/amber_server.py index 659be1b..c85b041 100644 --- a/amber_server.py +++ b/amber_server.py @@ -1,7 +1,9 @@ import argparse import os import platform +import signal import subprocess +import sys import tempfile from functools import reduce from itertools import repeat @@ -31,9 +33,13 @@ MONITOR = Monitor() -STORAGE_CLIENT = storage.Client.from_service_account_json("infra/spirvsmith_gcp.json") -BQ_CLIENT = bigquery.Client.from_service_account_json("infra/spirvsmith_gcp.json") -BUCKET = STORAGE_CLIENT.get_bucket("spirv_shaders_bucket") + +if "pytest" not in sys.modules: + STORAGE_CLIENT = storage.Client.from_service_account_json( + "infra/spirvsmith_gcp.json" + ) + BQ_CLIENT = bigquery.Client.from_service_account_json("infra/spirvsmith_gcp.json") + BUCKET = STORAGE_CLIENT.get_bucket("spirv_shaders_bucket") def get_pending_shaders_query( @@ -122,7 +128,7 @@ def run_amber(amber_filename: str, n_buffers: int, shader_id: str) -> str: print(process.stderr.decode("utf-8")) return None - if process.returncode == 139: + if process.returncode == -signal.SIGSEGV: MONITOR.error( event=Event.AMBER_SEGFAULT, extra={ diff --git a/poetry.lock b/poetry.lock index 3688f2b..075ba2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -691,6 +691,24 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "mypy" +version = "0.950" +description = "Optional static typing for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +mypy-extensions = ">=0.4.3" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "0.4.3" @@ -1063,6 +1081,14 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "typing-extensions" +version = "4.2.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" + [[package]] name = "ulid-py" version = "1.1.0" @@ -1149,7 +1175,7 @@ tests = ["coverage", "flake8", "wheel"] [metadata] lock-version = "1.1" python-versions = ">=3.10,<3.11" -content-hash = "b6f385834c17891aeba61a9a13fecbb241bc5208101678bf16ff729686e7490b" +content-hash = "e0d90a595516b5846ab1105a1c080546245a9e39c15c8c9ead47d6ab95670e46" [metadata.files] antlr4-python3-runtime = [ @@ -1719,6 +1745,31 @@ msgpack = [ {file = "msgpack-1.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:f01b26c2290cbd74316990ba84a14ac3d599af9cebefc543d241a66e785cf17d"}, {file = "msgpack-1.0.3.tar.gz", hash = "sha256:51fdc7fb93615286428ee7758cecc2f374d5ff363bdd884c7ea622a7a327a81e"}, ] +mypy = [ + {file = "mypy-0.950-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf9c261958a769a3bd38c3e133801ebcd284ffb734ea12d01457cb09eacf7d7b"}, + {file = "mypy-0.950-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5b5bd0ffb11b4aba2bb6d31b8643902c48f990cc92fda4e21afac658044f0c0"}, + {file = "mypy-0.950-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e7647df0f8fc947388e6251d728189cfadb3b1e558407f93254e35abc026e22"}, + {file = "mypy-0.950-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eaff8156016487c1af5ffa5304c3e3fd183edcb412f3e9c72db349faf3f6e0eb"}, + {file = "mypy-0.950-cp310-cp310-win_amd64.whl", hash = "sha256:563514c7dc504698fb66bb1cf897657a173a496406f1866afae73ab5b3cdb334"}, + {file = "mypy-0.950-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dd4d670eee9610bf61c25c940e9ade2d0ed05eb44227275cce88701fee014b1f"}, + {file = "mypy-0.950-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca75ecf2783395ca3016a5e455cb322ba26b6d33b4b413fcdedfc632e67941dc"}, + {file = "mypy-0.950-cp36-cp36m-win_amd64.whl", hash = "sha256:6003de687c13196e8a1243a5e4bcce617d79b88f83ee6625437e335d89dfebe2"}, + {file = "mypy-0.950-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c653e4846f287051599ed8f4b3c044b80e540e88feec76b11044ddc5612ffed"}, + {file = "mypy-0.950-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e19736af56947addedce4674c0971e5dceef1b5ec7d667fe86bcd2b07f8f9075"}, + {file = "mypy-0.950-cp37-cp37m-win_amd64.whl", hash = "sha256:ef7beb2a3582eb7a9f37beaf38a28acfd801988cde688760aea9e6cc4832b10b"}, + {file = "mypy-0.950-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0112752a6ff07230f9ec2f71b0d3d4e088a910fdce454fdb6553e83ed0eced7d"}, + {file = "mypy-0.950-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee0a36edd332ed2c5208565ae6e3a7afc0eabb53f5327e281f2ef03a6bc7687a"}, + {file = "mypy-0.950-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77423570c04aca807508a492037abbd72b12a1fb25a385847d191cd50b2c9605"}, + {file = "mypy-0.950-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ce6a09042b6da16d773d2110e44f169683d8cc8687e79ec6d1181a72cb028d2"}, + {file = "mypy-0.950-cp38-cp38-win_amd64.whl", hash = "sha256:5b231afd6a6e951381b9ef09a1223b1feabe13625388db48a8690f8daa9b71ff"}, + {file = "mypy-0.950-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0384d9f3af49837baa92f559d3fa673e6d2652a16550a9ee07fc08c736f5e6f8"}, + {file = "mypy-0.950-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1fdeb0a0f64f2a874a4c1f5271f06e40e1e9779bf55f9567f149466fc7a55038"}, + {file = "mypy-0.950-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:61504b9a5ae166ba5ecfed9e93357fd51aa693d3d434b582a925338a2ff57fd2"}, + {file = "mypy-0.950-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a952b8bc0ae278fc6316e6384f67bb9a396eb30aced6ad034d3a76120ebcc519"}, + {file = "mypy-0.950-cp39-cp39-win_amd64.whl", hash = "sha256:eaea21d150fb26d7b4856766e7addcf929119dd19fc832b22e71d942835201ef"}, + {file = "mypy-0.950-py3-none-any.whl", hash = "sha256:a4d9898f46446bfb6405383b57b96737dcfd0a7f25b748e78ef3e8c576bba3cb"}, + {file = "mypy-0.950.tar.gz", hash = "sha256:1b333cfbca1762ff15808a0ef4f71b5d3eed8528b23ea1c3fb50543c867d68de"}, +] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, @@ -1987,6 +2038,10 @@ tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +typing-extensions = [ + {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, + {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, +] ulid-py = [ {file = "ulid-py-1.1.0.tar.gz", hash = "sha256:dc6884be91558df077c3011b9fb0c87d1097cb8fc6534b11f310161afd5738f0"}, {file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"}, diff --git a/pyproject.toml b/pyproject.toml index afec5f9..c091b19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ black = {version = "^22.3", allow-prereleases = true} autoflake = "^1.4" pytest-flakefinder = "^1.0.0" pre-commit = "^2.18.1" +mypy = "^0.950" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/run.py b/run.py index 5969689..c6c3d4a 100644 --- a/run.py +++ b/run.py @@ -33,7 +33,7 @@ class FuzzingStrategyConfig: w_memory_operation: int = 4 w_logical_operation: int = 4 w_arithmetic_operation: int = 4 - w_control_flow_operation: int = 1 + w_control_flow_operation: int = 0 w_function_operation: int = 1 w_bitwise_operation: int = 4 w_conversion_operation: int = 4 @@ -41,9 +41,7 @@ class FuzzingStrategyConfig: ## Types weights w_scalar_type: int = 1 - w_numerical_type: int = 1 w_container_type: int = 1 - w_arithmetic_type: int = 1 ## Constants weights w_composite_constant: int = 1 @@ -59,7 +57,8 @@ class FuzzingStrategyConfig: @dataclass class MiscConfig: start_web_server: bool = False - broadcast_generated_shaders: bool = True + broadcast_generated_shaders: bool = False + upload_logs: bool = False version: str = get_spirvsmith_version() diff --git a/src/__init__.py b/src/__init__.py index 57da6b7..cf8be05 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -3,11 +3,18 @@ import pickle from abc import ABC from dataclasses import field +from dataclasses import fields +from enum import Enum +from typing import Generic from typing import TYPE_CHECKING +from typing import TypeVar + +from typing_extensions import Self + if TYPE_CHECKING: from src.context import Context -from utils.patched_dataclass import dataclass +from src.patched_dataclass import dataclass import random from src.enums import Capability from ulid import monotonic as ulid @@ -24,107 +31,84 @@ "CompositeOperator": "w_composite_operation", "ScalarType": "w_scalar_type", "ContainerType": "w_container_type", - "ArithmeticType": "w_arithmetic_type", - "NumericalType": "w_numerical_type", "CompositeConstant": "w_composite_constant", "ScalarConstant": "w_scalar_constant", } -excluded_identifiers = [ - "id", - "symbol_table", - "context", - "get_required_capabilities", - "iteritems", - "keys", - "resolve_attribute_spasm", - "to_spasm", - "fuzz", - "get_base_type", -] - class ReparametrizationError(Exception): ... -def members(inst): - return tuple( - [ - x - for x in inst.__dict__ - # if type(y) != FunctionType - if x not in excluded_identifiers and not x.startswith("_") - ] - ) - - -class VoidOp: - pass +class AbortFuzzing(Exception): + ... @dataclass class OpCode(ABC): - id: ULID = field(default_factory=ulid.new) + id: str = field(default_factory=lambda: ulid.new().str, init=False) - def __eq__(self, other): - if type(other) is type(self): - return [getattr(self, attr) for attr in members(self)] == [ - getattr(other, attr) for attr in members(other) - ] - else: - return False + def members(self) -> tuple[str, ...]: + return tuple( + [x.name for x in fields(self.__class__) if x.name not in {"id", "context"}] + ) - def debug_hash(self): - print(members(self)) - print(tuple([hash(getattr(self, attr)) for attr in members(self)])) - print("=========") - return self.__hash__() + def __eq__(self, other) -> bool: + return (other.__class__.__name__ == self.__class__.__name__) and ( + hash(self) == hash(other) + ) - def __hash__(self): + def __hash__(self) -> int: + try: + attrs = tuple([hash(getattr(self, attr)) for attr in self.members()]) + except TypeError: + print(self.hashing_members()) + print([getattr(self, attr) for attr in self.members()]) return int( - hashlib.sha224( - pickle.dumps( - tuple([hash(getattr(self, attr)) for attr in members(self)]) - ) - ).hexdigest(), + hashlib.sha224(pickle.dumps(attrs)).hexdigest(), 16, ) def __str__(self) -> str: - return f"{self.__class__.__name__}({', '.join([str(getattr(self, attr)) for attr in members(self)])})" + return f"{self.__class__.__name__}({', '.join([str(getattr(self, attr)) for attr in self.members()])})" def __repr__(self) -> str: - return f"{self.__class__.__name__}({', '.join([str(getattr(self, attr)) for attr in members(self)])})" + return f"{self.__class__.__name__}({', '.join([str(getattr(self, attr)) for attr in self.members()])})" @staticmethod def get_required_capabilities() -> list[Capability]: return [] - @staticmethod - def fuzz(_: "Context") -> list["OpCode"]: - return [] - - def resolve_attribute_spasm(self, attr, context) -> str: - if self.__class__.__name__ == "OpDecorate": - pass - if attr.__class__.__name__ == "Context" or attr is None: + @classmethod + def fuzz(cls, _: "Context") -> "FuzzResult": + pass + + def resolve_attribute_spasm(self, attr, context: "Context") -> str: + if ( + attr.__class__.__name__ == "Context" + or attr is None + or attr.__class__.__name__ == "EmptyType" + ): return "" elif inspect.isclass(attr) and issubclass(attr, OpCode): attr_spasm = f" {attr.__name__}" elif isinstance(attr, OpCode): if isinstance(attr, (Type, Constant)): + # print("======") + # print(self, attr) attr_spasm = f" %{context.tvc[attr]}" else: attr_spasm = f" %{attr.id}" - elif isinstance(attr, str): + elif isinstance(attr, str) and not isinstance(attr, Enum): attr_spasm = f' "{attr}"' else: attr_spasm = f" {str(attr)}" return attr_spasm def to_spasm(self, context: "Context") -> str: - attrs = members(self) + attrs = self.members() + if self.__class__.__name__ == "OpStore": + pass if isinstance(self, VoidOp): spasm = f"{self.__class__.__name__}" else: @@ -136,17 +120,32 @@ def to_spasm(self, context: "Context") -> str: spasm += self.resolve_attribute_spasm(_attr, context) else: spasm += self.resolve_attribute_spasm(attr, context) + spasm += "\n" return spasm +class VoidOp(OpCode): + ... + + +T = TypeVar("T", bound=OpCode) + + +@dataclass +class FuzzResult(Generic[T]): + opcode: T + side_effects: list[OpCode] = field(default_factory=list) + + # A FuzzDelegator is a transient object, we need to commit # reparametrizations to this global object. PARAMETRIZATIONS: dict[str, dict[str, int]] = {} class FuzzDelegator(OpCode): - def get_subclasses(self): - return self.__class__.__subclasses__() + @classmethod + def get_subclasses(cls) -> set["FuzzDelegator"]: + return set(cls.__subclasses__()) @classmethod def is_parametrized(cls): @@ -162,7 +161,9 @@ def reset_parametrizations(cls): PARAMETRIZATIONS = {} @classmethod - def set_zero_probability(cls, target_cls) -> None: + def set_zero_probability(cls, target_cls, context: "Context") -> None: + if not cls.is_parametrized(): + cls.parametrize(context=context) # There is a tricky case here when an OpCode can be reached # from multiple delegators. # @@ -171,63 +172,81 @@ def set_zero_probability(cls, target_cls) -> None: # the path have been parametrized yet PARAMETRIZATIONS[cls.__name__][target_cls.__name__] = 0 - def parametrize(self, context: "Context") -> None: - subclasses_names = set(map(lambda cls: cls.__name__, self.get_subclasses())) + @classmethod + def parametrize(cls, context: "Context") -> None: + subclasses_names = set(map(lambda cls: cls.__name__, cls.get_subclasses())) # Get parametrization from config for top-level delegators - PARAMETRIZATIONS[self.__class__.__name__] = {} + PARAMETRIZATIONS[cls.__name__] = {} for sub in subclasses_names: - PARAMETRIZATIONS[self.__class__.__name__][sub] = 1 + PARAMETRIZATIONS[cls.__name__][sub] = 1 if any([sub in subclasses_names for sub in randomization_parameters.keys()]): for sub in subclasses_names: if sub in randomization_parameters: - PARAMETRIZATIONS[self.__class__.__name__][sub] = getattr( + PARAMETRIZATIONS[cls.__name__][sub] = getattr( context.config.strategy, randomization_parameters[sub] ) - if self.__class__.__name__ == "Statement": - PARAMETRIZATIONS[self.__class__.__name__]["OpExtInst"] = 0 - - def fuzz(self, context: "Context") -> list[OpCode]: - if not self.__class__.is_parametrized(): - self.parametrize(context=context) - subclasses = self.get_subclasses() - weights = [ - PARAMETRIZATIONS[self.__class__.__name__][sub.__name__] - for sub in subclasses - ] + if cls.__name__ == "Statement": + PARAMETRIZATIONS[cls.__name__]["OpExtInst"] = 0 + + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + # TODO this is terrible, there must be a better way + import src.operators.arithmetic.scalar_arithmetic + import src.operators.arithmetic.linear_algebra + import src.operators.logic + import src.operators.bitwise + import src.operators.conversions + import src.operators.composite + + if context.config.strategy.enable_ext_glsl_std_450: + import src.operators.arithmetic.glsl + if not cls.is_parametrized(): + cls.parametrize(context=context) + subclasses: list["FuzzDelegator"] = list(cls.get_subclasses()) + weights = [PARAMETRIZATIONS[cls.__name__][sub.__name__] for sub in subclasses] + if sum(weights) == 0 or len(weights) == 0: + print(cls, subclasses, weights) try: - return [ - *random.SystemRandom() - .choices(subclasses, weights=weights, k=1)[0]() + return ( + random.SystemRandom() + .choices(subclasses, weights=weights, k=1)[0] .fuzz(context) - ] + ) except ReparametrizationError: - return [ - *random.SystemRandom() - .choices(subclasses, weights=weights, k=1)[0]() + return ( + random.SystemRandom() + .choices(subclasses, weights=weights, k=1)[0] .fuzz(context) - ] - - -class FuzzLeaf(OpCode): - def fuzz(self, context: "Context") -> list[OpCode]: - return [self] + ) +@dataclass class Type(FuzzDelegator): @staticmethod - def get_base_type(): + def get_base_type() -> Self: ... +@dataclass +class FuzzLeafMixin: + @classmethod + def fuzz(cls, _: "Context") -> FuzzResult[Self]: + return FuzzResult(cls()) + + +@dataclass class Constant(FuzzDelegator): type: Type - def get_base_type(self): + def get_base_type(self) -> Type: return self.type.get_base_type() +@dataclass class Statement(FuzzDelegator): - def get_base_type(self): + type: Type + + def get_base_type(self) -> Type: return self.type.get_base_type() diff --git a/src/annotations.py b/src/annotations.py index a98aef1..d5e8978 100644 --- a/src/annotations.py +++ b/src/annotations.py @@ -1,26 +1,29 @@ -from dataclasses import dataclass +from dataclasses import field +from typing import Optional -from src import FuzzLeaf +from src import FuzzLeafMixin from src import OpCode from src import VoidOp from src.enums import Decoration +from src.patched_dataclass import dataclass from src.types.concrete_types import OpTypeStruct -class Annotation(FuzzLeaf, VoidOp): +@dataclass +class Annotation(FuzzLeafMixin, VoidOp): ... @dataclass class OpDecorate(Annotation): - target: OpCode = None - decoration: Decoration = None - extra_operands: tuple[int | str, ...] = None + target: OpCode + decoration: Decoration + extra_operands: Optional[tuple[int | str, ...]] = field(default_factory=tuple) @dataclass class OpMemberDecorate(Annotation): - target_struct: OpTypeStruct = None - member: int = None - decoration: Decoration = None - extra_operands: tuple[int | str, ...] = None + target_struct: OpTypeStruct + member: int + decoration: Decoration + extra_operands: tuple[int | str, ...] = field(default_factory=tuple) diff --git a/src/constants.py b/src/constants.py index 8dade98..2e455e3 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,7 +1,11 @@ import random from typing import TYPE_CHECKING +from typing_extensions import Self + +from src import AbortFuzzing from src import Constant +from src import FuzzResult from src import OpCode from src.predicates import HasType from src.predicates import IsMatrixType @@ -9,99 +13,118 @@ if TYPE_CHECKING: from src.context import Context from src.types.abstract_types import ( - NumericalType, Type, ) from src.types.concrete_types import ( OpTypeArray, OpTypeBool, + OpTypeFloat, OpTypeInt, OpTypeMatrix, OpTypeVector, ) -from utils.patched_dataclass import dataclass +from src.patched_dataclass import dataclass +@dataclass class ScalarConstant(Constant): ... +@dataclass class CompositeConstant(Constant): ... +@dataclass class OpConstantTrue(ScalarConstant): - type: Type = None - - def fuzz(self, _: "Context") -> list[OpCode]: - self.type = OpTypeBool() - return [self.type, self] + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + ScalarConstant.set_zero_probability(cls, context) + return FuzzResult(cls(type=OpTypeBool()), [OpTypeBool()]) +@dataclass class OpConstantFalse(ScalarConstant): - type: Type = None - - def fuzz(self, _: "Context") -> list[OpCode]: - self.type = OpTypeBool() - return [self.type, self] + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + ScalarConstant.set_zero_probability(cls, context) + return FuzzResult(cls(type=OpTypeBool()), [OpTypeBool()]) @dataclass class OpConstant(ScalarConstant): - type: Type = None - value: int | float = None - - def fuzz(self, context: "Context") -> list[OpCode]: - - self.type = NumericalType().fuzz(context)[-1] + value: int | float - if isinstance(self.type, OpTypeInt): - if self.type.signed: - self.value = random.SystemRandom().randint(-100, 100) - else: - self.value = random.SystemRandom().randint(0, 100) - else: - self.value = random.SystemRandom().uniform(0, 100) + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + fuzzed_type: OpTypeInt | OpTypeFloat = ( + random.SystemRandom().choice([OpTypeInt, OpTypeFloat]).fuzz(context).opcode + ) - return [self.type, self] + if isinstance(fuzzed_type, OpTypeInt): + if fuzzed_type.signed: + return FuzzResult( + cls( + type=fuzzed_type, value=random.SystemRandom().randint(-100, 100) + ), + [fuzzed_type], + ) + return FuzzResult( + cls(type=fuzzed_type, value=random.SystemRandom().randint(0, 100)), + [fuzzed_type], + ) + return FuzzResult( + cls(type=fuzzed_type, value=random.SystemRandom().uniform(0, 100)), + [fuzzed_type], + ) +@dataclass class OpConstantComposite(CompositeConstant): - type: Type = None - constituents: tuple[OpCode] = None + constituents: tuple[OpCode, ...] - def fuzz(self, context: "Context") -> list[OpCode]: - composite_type = ( - random.SystemRandom() - .choice([OpTypeArray, OpTypeVector, OpTypeMatrix])() - .fuzz(context) - ) - self.type: OpTypeArray | OpTypeVector | OpTypeMatrix = composite_type[-1] - self.constituents = [] - if IsMatrixType(self): - column_type = self.type.type - for _ in range(len(self.type)): - column_values = OpConstantComposite() - column_values.type = column_type - constituents = column_values.fuzz_constituents(context) - if not constituents: - return [] - column_values.constituents = tuple(constituents) - self.constituents.append(column_values) - else: - self.constituents = self.fuzz_constituents(context) - if not self.constituents: - return [] - self.constituents = tuple(self.constituents) - return [*composite_type, *self.constituents, self] - - def fuzz_constituents(self, context: "Context") -> list[OpCode]: - base_type: Type = self.type.get_base_type() - self.constituents = [] - for _ in range(len(self.type)): + @staticmethod + def fuzz_constituents(base_type: Type, n: int, context: "Context") -> list[OpCode]: + constituents: list[OpCode] = [] + for _ in range(n): constituent: Constant = context.get_random_operand(HasType(base_type)) if constituent: - self.constituents.append(constituent) + constituents.append(constituent) else: - return None - return self.constituents + raise AbortFuzzing + return constituents + + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + fuzzed_inner_type: FuzzResult[Self] = ( + random.SystemRandom() + .choice([OpTypeArray, OpTypeVector, OpTypeMatrix]) + .fuzz(context) + ) + constituents = [] + match fuzzed_inner_type.opcode: + case OpTypeMatrix(): + column_type: OpTypeVector = fuzzed_inner_type.opcode.type + for _ in range(len(fuzzed_inner_type.opcode)): + column_values = OpConstantComposite( + type=column_type, + constituents=tuple( + cls.fuzz_constituents( + column_type.get_base_type(), + len(column_type), + context, + ) + ), + ) + constituents.append(column_values) + case OpTypeArray() | OpTypeVector(): + constituents = cls.fuzz_constituents( + fuzzed_inner_type.opcode.get_base_type(), + len(fuzzed_inner_type.opcode), + context, + ) + return FuzzResult( + cls(type=fuzzed_inner_type.opcode, constituents=tuple(constituents)), + [*fuzzed_inner_type.side_effects, fuzzed_inner_type.opcode, *constituents], + ) diff --git a/src/context.py b/src/context.py index cbc928a..aeb1dad 100644 --- a/src/context.py +++ b/src/context.py @@ -1,12 +1,18 @@ import inspect import random +from dataclasses import dataclass +from dataclasses import field +from types import NoneType from typing import Callable from typing import Iterable from typing import Optional from typing import TYPE_CHECKING -from uuid import UUID -from uuid import uuid4 +import ulid +from typing_extensions import Self + +from src import AbortFuzzing +from src import FuzzResult from src import Statement from src import Untyped from src.annotations import Annotation @@ -23,6 +29,7 @@ from src.function import OpFunction from src.monitor import Event from src.monitor import Monitor +from src.operators import Operand from src.predicates import ( HaveSameTypeLength, ) @@ -35,49 +42,22 @@ if TYPE_CHECKING: from src import OpCode + from src.extension import OpExtInstImport from run import SPIRVSmithConfig from src.operators.memory.memory_access import OpVariable +@dataclass class Context: - id: UUID - symbol_table: list["OpCode"] + id: str = field(default_factory=lambda: ulid.new().str, init=False) function: Optional["OpFunction"] parent_context: Optional["Context"] - tvc: dict["OpCode", str] - annotations: list[Annotation] execution_model: ExecutionModel config: "SPIRVSmithConfig" - extension_sets: dict[str, "OpCode"] - - def __init__( - self, - function: Optional["OpFunction"], - parent_context: Optional["Context"], - annotations: list[Annotation], - execution_model: ExecutionModel, - config: "SPIRVSmithConfig", - ) -> None: - self.id = uuid4() - self.symbol_table = [] - self.function = function - self.annotations = annotations - self.parent_context = parent_context - self.execution_model = execution_model - self.tvc = dict() - self.extension_sets = dict() - self.config = config - - def __eq__(self, other): - if type(other) is type(self): - return self.id == other.id - return False - - def __hash__(self) -> int: - return hash(self.id) - - def __str__(self) -> str: - return f"" + symbol_table: list["OpCode"] = field(default_factory=list) + tvc: dict["OpCode", str] = field(default_factory=dict) + annotations: dict[Annotation, NoneType] = field(default_factory=dict) + extension_sets: dict[str, "OpExtInstImport"] = field(default_factory=dict) @classmethod def create_global_context( @@ -85,39 +65,20 @@ def create_global_context( execution_model: ExecutionModel, config: "SPIRVSmithConfig", ) -> "Context": - context = cls(None, None, [], execution_model, config) - void_type = OpTypeVoid() - main_type = OpTypeFunction() - main_type.return_type = void_type - main_type.parameter_types = () - cls.main_type = main_type - context.tvc[void_type] = void_type.id - context.tvc[main_type] = main_type.id - context.config = config - return context - - def make_child_context(self, function: OpTypeFunction = None): - if function: - context = Context( - function, - self, - self.annotations, - self.execution_model, - self.config, - ) - else: - context = Context( - self.function, - self, - self.annotations, - self.execution_model, - self.config, - ) - context.tvc = self.tvc - context.extension_sets = self.extension_sets - return context + return cls(None, None, execution_model, config) + + def make_child_context(self, function: Optional[OpFunction] = None) -> Self: + return Context( + function if function else self.function, + self, + self.execution_model, + self.config, + tvc=self.tvc, + annotations=self.annotations, + extension_sets=self.extension_sets, + ) - def add_to_tvc(self, opcode: "OpCode"): + def add_to_tvc(self, opcode: "OpCode") -> None: if not opcode in self.tvc: self.tvc[opcode] = opcode.id @@ -141,7 +102,7 @@ def get_random_variable( try: return random.SystemRandom().choice(variables) except IndexError: - Monitor().warning( + Monitor(self.config).info( event=Event.NO_OPERAND_FOUND, extra={ "opcode": inspect.stack()[1][0].f_locals["self"].__class__.__name__, @@ -182,15 +143,17 @@ def get_depth(self) -> int: def gen_types(self): for _ in range(self.config.limits.n_types - 1): try: - opcodes: list["OpCode"] = Type().fuzz(self) - except RecursionError: + fuzzed_type: FuzzResult = Type.fuzz(self) + except (RecursionError, AbortFuzzing): continue - for opcode in opcodes: - self.add_to_tvc(opcode) + for side_effect in fuzzed_type.side_effects: + self.add_to_tvc(side_effect) + self.add_to_tvc(fuzzed_type.opcode) # We should ALWAYS have at least 1 struct type - struct_type: list["OpCode"] = OpTypeStruct().fuzz(self) - for side_effect in struct_type: + struct_type: FuzzResult = OpTypeStruct.fuzz(self) + for side_effect in struct_type.side_effects: self.add_to_tvc(side_effect) + self.add_to_tvc(struct_type.opcode) def gen_constants(self): n_constants = self.config.limits.n_constants @@ -204,20 +167,20 @@ def gen_constants(self): ) for _ in range(n_scalars): try: - opcodes: list["OpCode"] = ScalarConstant().fuzz(self) + fuzzed_constant: FuzzResult = ScalarConstant.fuzz(self) except RecursionError: continue - for opcode in opcodes: - if opcode not in self.tvc: - self.tvc[opcode] = opcode.id + for side_effect in fuzzed_constant.side_effects: + self.add_to_tvc(side_effect) + self.add_to_tvc(fuzzed_constant.opcode) for _ in range(n_constants - n_scalars): try: - opcodes: list["OpCode"] = CompositeConstant().fuzz(self) + fuzzed_constant: FuzzResult = CompositeConstant.fuzz(self) except RecursionError: continue - for opcode in opcodes: - if opcode not in self.tvc: - self.tvc[opcode] = opcode.id + for side_effect in fuzzed_constant.side_effects: + self.add_to_tvc(side_effect) + self.add_to_tvc(fuzzed_constant.opcode) def gen_global_variables(self): n = len(self.tvc) @@ -260,13 +223,13 @@ def gen_program(self) -> list["OpCode"]: functions: list[OpFunction] = [] for function_type in function_types: - function = OpFunction() - function.return_type = function_type.return_type - function.function_type = function_type + self.current_function_type = function_type + fuzzed_function: FuzzResult = OpFunction.fuzz(self) if function_type == self.main_type: - self.main_fn = function - functions.append(function) - function_bodies += function.fuzz(self) + self.main_fn = fuzzed_function.opcode + functions.append(fuzzed_function.opcode) + function_bodies.append(fuzzed_function.opcode) + function_bodies += fuzzed_function.side_effects return function_bodies def get_constants( @@ -283,7 +246,7 @@ def get_random_operand( self, predicate: Callable[[Statement], bool], constraint: Optional[Statement | Constant] = None, - ) -> Optional[Statement | Constant]: + ) -> Operand: statements: list[Statement] = self.get_typed_statements(predicate) constants: list[Constant] = self.get_constants(predicate) if constraint: @@ -300,32 +263,28 @@ def get_random_operand( statements = filter(type_length_predicate, statements) constants = filter(type_length_predicate, constants) - statements: list[Statement] = sorted( - statements, key=lambda sym: sym.id, reverse=True - ) # TODO parametrize using a geometric distribution try: return random.SystemRandom().choice(list(statements) + list(constants)) except IndexError: - Monitor().warning( + Monitor(self.config).info( event=Event.NO_OPERAND_FOUND, extra={ - "opcode": inspect.stack()[1][0].f_locals["self"].__class__.__name__, + "opcode": inspect.stack()[1][0].f_locals["cls"].__name__, "constraint": str(constraint), "constants": self.get_constants(), "statements": self.get_typed_statements(), }, ) - return None + raise AbortFuzzing def get_function_types(self) -> list[OpTypeFunction]: return list(filter(lambda t: isinstance(t, OpTypeFunction), self.tvc.keys())) - def get_interfaces(self) -> list[OpVariable]: - return list( + def get_interfaces(self) -> tuple[OpVariable, ...]: + return tuple( filter( lambda s: isinstance(s, OpVariable) - and not s.context.function and ( s.storage_class == StorageClass.Input or s.storage_class == StorageClass.Output @@ -338,7 +297,6 @@ def get_storage_buffers(self) -> list[OpVariable]: return list( filter( lambda s: isinstance(s, OpVariable) - and not s.context.function and (s.storage_class == StorageClass.StorageBuffer), self.tvc, ) @@ -352,21 +310,17 @@ def is_compute_shader(self) -> bool: def create_on_demand_numerical_constant( self, - target_type: Type, + target_type: type[Type], value: int = 0, width: int = 32, signed: Optional[int] = 0, ) -> OpConstant: - type = target_type() - type.width = width - if hasattr(type, "signed"): - type.signed = signed - constant = OpConstant() - constant.type = type - constant.value = value - if constant in self.tvc: - return constant - self.add_to_tvc(type) + constant_type = target_type.fuzz(self).opcode + constant_type.width = width + if hasattr(constant_type, "signed"): + constant_type.signed = signed + constant = OpConstant(type=constant_type, value=value) + self.add_to_tvc(constant_type) self.add_to_tvc(constant) return constant @@ -375,15 +329,10 @@ def create_on_demand_variable( storage_class: StorageClass, type: Optional[Type] = None, ): - variable: OpVariable = OpVariable() - variable.context = self - - pointer_type = OpTypePointer() - pointer_type.storage_class = storage_class if type: - pointer_type.type = type + pointer_inner_type = type else: - pointer_type.type = random.SystemRandom().choice( + pointer_inner_type = random.SystemRandom().choice( list( filter( lambda tvc: isinstance(tvc, OpTypeStruct), @@ -391,8 +340,12 @@ def create_on_demand_variable( ) ) ) - variable.type = pointer_type - variable.storage_class = storage_class + pointer_type = OpTypePointer( + storage_class=storage_class, type=pointer_inner_type + ) + variable: OpVariable = OpVariable( + type=pointer_type, storage_class=storage_class + ) self.add_to_tvc(pointer_type) if storage_class != StorageClass.Function: self.add_to_tvc(variable) @@ -401,16 +354,18 @@ def create_on_demand_variable( def create_on_demand_vector_constant( self, inner_constant: OpConstant, size: int = 4 ) -> OpConstantComposite: - vector_type = OpTypeVector() - vector_type.type = inner_constant.type - vector_type.size = size - self.add_to_tvc(vector_type) + vector_type = OpTypeVector(inner_constant.type, size) + vector_const = OpConstantComposite(vector_type, tuple([inner_constant] * size)) - vector_const = OpConstantComposite() - vector_const.type = vector_type - vector_const.constituents = tuple([inner_constant for _ in range(size)]) + self.add_to_tvc(vector_type) self.add_to_tvc(vector_const) return vector_const + def get_global_context(self) -> Self: + current_context = self + while current_context.parent_context: + current_context = self.parent_context + return current_context + def add_annotation(self, annotation: Annotation): - self.annotations.append(annotation) + self.get_global_context().annotations[annotation] = None diff --git a/src/enums.py b/src/enums.py index f5e7476..b445768 100644 --- a/src/enums.py +++ b/src/enums.py @@ -1,7 +1,24 @@ +from enum import _EnumDict from enum import Enum +from enum import EnumMeta -class SPIRVEnum(Enum): +class StrEnumMeta(EnumMeta): + def __new__(metacls, cls, bases, oldclassdict): + """ + Scan through `oldclassdict` and convert any value that is a plain tuple + into a `str` of the name instead + """ + newclassdict = _EnumDict() + setattr(newclassdict, "_cls_name", cls) + for k, v in oldclassdict.items(): + if v == (): + v = k + newclassdict[k] = v + return super().__new__(metacls, cls, bases, newclassdict) + + +class SPIRVEnum(str, Enum, metaclass=StrEnumMeta): def __str__(self) -> str: """ @@ -15,1826 +32,1166 @@ def __str__(self) -> str: class SourceLanguage(SPIRVEnum): - Unknown = 0 - ESSL = 1 - GLSL = 2 - OpenCL_C = 3 - OpenCL_CPP = 4 - HLSL = 5 - CPP_for_OpenCL = 6 + Unknown = () + ESSL = () + GLSL = () + OpenCL_C = () + OpenCL_CPP = () + HLSL = () + CPP_for_OpenCL = () class ExecutionModel(SPIRVEnum): - # Vertex = 0 - # TessellationControl = 1 - # TessellationEvaluation = 2 - # Geometry = 3 - Fragment = 4 - GLCompute = 5 - Kernel = 6 - # TaskNV = 5267 - # MeshNV = 5268 - # RayGenerationKHR = 5313 - # RayGenerationNV = 5313 - # IntersectionKHR = 5314 - # IntersectionNV = 5314 - # AnyHitKHR = 5315 - # AnyHitNV = 5315 - # ClosestHitKHR = 5316 - # ClosestHitNV = 5316 - # MissKHR = 5317 - # MissNV = 5317 - # CallableKHR = 5318 - # CallableNV = 5318 + # Vertex = () + # TessellationControl = () + # TessellationEvaluation = () + # Geometry = () + Fragment = () + GLCompute = () + Kernel = () + # TaskNV = () + # MeshNV = () + # RayGenerationKHR = () + # RayGenerationNV = () + # IntersectionKHR = () + # IntersectionNV = () + # AnyHitKHR = () + # AnyHitNV = () + # ClosestHitKHR = () + # ClosestHitNV = () + # MissKHR = () + # MissNV = () + # CallableKHR = () + # CallableNV = () class AddressingModel(SPIRVEnum): - Logical = 0 - Physical32 = 1 - Physical64 = 2 - PhysicalStorageBuffer64 = 5348 - PhysicalStorageBuffer64EXT = 5348 + Logical = () + Physical32 = () + Physical64 = () + PhysicalStorageBuffer64 = () + PhysicalStorageBuffer64EXT = () class MemoryModel(SPIRVEnum): - Simple = 0 - GLSL450 = 1 - OpenCL = 2 - Vulkan = 3 - VulkanKHR = 3 + Simple = () + GLSL450 = () + OpenCL = () + Vulkan = () + VulkanKHR = () class ExecutionMode(SPIRVEnum): - Invocations = 0 - SpacingEqual = 1 - SpacingFractionalEven = 2 - SpacingFractionalOdd = 3 - VertexOrderCw = 4 - VertexOrderCcw = 5 - PixelCenterInteger = 6 - OriginUpperLeft = 7 - OriginLowerLeft = 8 - EarlyFragmentTests = 9 - PointMode = 10 - Xfb = 11 - DepthReplacing = 12 - DepthGreater = 14 - DepthLess = 15 - DepthUnchanged = 16 - LocalSize = 17 - LocalSizeHint = 18 - InputPoints = 19 - InputLines = 20 - InputLinesAdjacency = 21 - Triangles = 22 - InputTrianglesAdjacency = 23 - Quads = 24 - Isolines = 25 - OutputVertices = 26 - OutputPoints = 27 - OutputLineStrip = 28 - OutputTriangleStrip = 29 - VecTypeHint = 30 - ContractionOff = 31 - Initializer = 33 - Finalizer = 34 - SubgroupSize = 35 - SubgroupsPerWorkgroup = 36 - SubgroupsPerWorkgroupId = 37 - LocalSizeId = 38 - LocalSizeHintId = 39 - # SubgroupUniformControlFlowKHR = 4421 - # PostDepthCoverage = 4446 - # DenormPreserve = 4459 - # DenormFlushToZero = 4460 - # SignedZeroInfNanPreserve = 4461 - # RoundingModeRTE = 4462 - # RoundingModeRTZ = 4463 - # StencilRefReplacingEXT = 5027 - # OutputLinesNV = 5269 - # OutputPrimitivesNV = 5270 - # DerivativeGroupQuadsNV = 5289 - # DerivativeGroupLinearNV = 5290 - # OutputTrianglesNV = 5298 - # PixelInterlockOrderedEXT = 5366 - # PixelInterlockUnorderedEXT = 5367 - # SampleInterlockOrderedEXT = 5368 - # SampleInterlockUnorderedEXT = 5369 - # ShadingRateInterlockOrderedEXT = 5370 - # ShadingRateInterlockUnorderedEXT = 5371 - # SharedLocalMemorySizeINTEL = 5618 - # RoundingModeRTPINTEL = 5620 - # RoundingModeRTNINTEL = 5621 - # FloatingPointModeALTINTEL = 5622 - # FloatingPointModeIEEEINTEL = 5623 - # MaxWorkgroupSizeINTEL = 5893 - # MaxWorkDimINTEL = 5894 - # NoGlobalOffsetINTEL = 5895 - # NumSIMDWorkitemsINTEL = 5896 - # SchedulerTargetFmaxMhzINTEL = 5903 + Invocations = () + SpacingEqual = () + SpacingFractionalEven = () + SpacingFractionalOdd = () + VertexOrderCw = () + VertexOrderCcw = () + PixelCenterInteger = () + OriginUpperLeft = () + OriginLowerLeft = () + EarlyFragmentTests = () + PointMode = () + Xfb = () + DepthReplacing = () + DepthGreater = () + DepthLess = () + DepthUnchanged = () + LocalSize = () + LocalSizeHint = () + InputPoints = () + InputLines = () + InputLinesAdjacency = () + Triangles = () + InputTrianglesAdjacency = () + Quads = () + Isolines = () + OutputVertices = () + OutputPoints = () + OutputLineStrip = () + OutputTriangleStrip = () + VecTypeHint = () + ContractionOff = () + Initializer = () + Finalizer = () + SubgroupSize = () + SubgroupsPerWorkgroup = () + SubgroupsPerWorkgroupId = () + LocalSizeId = () + LocalSizeHintId = () + # SubgroupUniformControlFlowKHR = () + # PostDepthCoverage = () + # DenormPreserve = () + # DenormFlushToZero = () + # SignedZeroInfNanPreserve = () + # RoundingModeRTE = () + # RoundingModeRTZ = () + # StencilRefReplacingEXT = () + # OutputLinesNV = () + # OutputPrimitivesNV = () + # DerivativeGroupQuadsNV = () + # DerivativeGroupLinearNV = () + # OutputTrianglesNV = () + # PixelInterlockOrderedEXT = () + # PixelInterlockUnorderedEXT = () + # SampleInterlockOrderedEXT = () + # SampleInterlockUnorderedEXT = () + # ShadingRateInterlockOrderedEXT = () + # ShadingRateInterlockUnorderedEXT = () + # SharedLocalMemorySizeINTEL = () + # RoundingModeRTPINTEL = () + # RoundingModeRTNINTEL = () + # FloatingPointModeALTINTEL = () + # FloatingPointModeIEEEINTEL = () + # MaxWorkgroupSizeINTEL = () + # MaxWorkDimINTEL = () + # NoGlobalOffsetINTEL = () + # NumSIMDWorkitemsINTEL = () + # SchedulerTargetFmaxMhzINTEL = () class StorageClass(SPIRVEnum): - UniformConstant = 0 - Input = 1 - Uniform = 2 - Output = 3 - # Workgroup = 4 - # CrossWorkgroup = 5 - # Private = 6 - Function = 7 - # Generic = 8 - # PushConstant = 9 - # AtomicCounter = 10 - # Image = 11 - StorageBuffer = 12 - # CallableDataKHR = 5328 - # CallableDataNV = 5328 - # IncomingCallableDataKHR = 5329 - # IncomingCallableDataNV = 5329 - # RayPayloadKHR = 5338 - # RayPayloadNV = 5338 - # HitAttributeKHR = 5339 - # HitAttributeNV = 5339 - # IncomingRayPayloadKHR = 5342 - # IncomingRayPayloadNV = 5342 - # ShaderRecordBufferKHR = 5343 - # ShaderRecordBufferNV = 5343 - # PhysicalStorageBuffer = 5349 - # PhysicalStorageBufferEXT = 5349 - # CodeSectionINTEL = 5605 - # DeviceOnlyINTEL = 5936 - # HostOnlyINTEL = 5937 + UniformConstant = () + Input = () + Uniform = () + Output = () + # Workgroup = () + # CrossWorkgroup = () + # Private = () + Function = () + # Generic = () + # PushConstant = () + # AtomicCounter = () + # Image = () + StorageBuffer = () + # CallableDataKHR = () + # CallableDataNV = () + # IncomingCallableDataKHR = () + # IncomingCallableDataNV = () + # RayPayloadKHR = () + # RayPayloadNV = () + # HitAttributeKHR = () + # HitAttributeNV = () + # IncomingRayPayloadKHR = () + # IncomingRayPayloadNV = () + # ShaderRecordBufferKHR = () + # ShaderRecordBufferNV = () + # PhysicalStorageBuffer = () + # PhysicalStorageBufferEXT = () + # CodeSectionINTEL = () + # DeviceOnlyINTEL = () + # HostOnlyINTEL = () class Dim(SPIRVEnum): - Dim1D = 0 - Dim2D = 1 - Dim3D = 2 - Cube = 3 - Rect = 4 - Buffer = 5 - SubpassData = 6 + Dim1D = () + Dim2D = () + Dim3D = () + Cube = () + Rect = () + Buffer = () + SubpassData = () class SamplerAddressingMode(SPIRVEnum): - NONE = 0 - ClampToEdge = 1 - Clamp = 2 - Repeat = 3 - RepeatMirrored = 4 + NONE = () + ClampToEdge = () + Clamp = () + Repeat = () + RepeatMirrored = () class SamplerFilterMode(SPIRVEnum): - Nearest = 0 - Linear = 1 + Nearest = () + Linear = () class ImageFormat(SPIRVEnum): - Unknown = 0 - Rgba32f = 1 - Rgba16f = 2 - R32f = 3 - Rgba8 = 4 - Rgba8Snorm = 5 - Rg32f = 6 - Rg16f = 7 - R11fG11fB10f = 8 - R16f = 9 - Rgba16 = 10 - Rgb10A2 = 11 - Rg16 = 12 - Rg8 = 13 - R16 = 14 - R8 = 15 - Rgba16Snorm = 16 - Rg16Snorm = 17 - Rg8Snorm = 18 - R16Snorm = 19 - R8Snorm = 20 - Rgba32i = 21 - Rgba16i = 22 - Rgba8i = 23 - R32i = 24 - Rg32i = 25 - Rg16i = 26 - Rg8i = 27 - R16i = 28 - R8i = 29 - Rgba32ui = 30 - Rgba16ui = 31 - Rgba8ui = 32 - R32ui = 33 - Rgb10a2ui = 34 - Rg32ui = 35 - Rg16ui = 36 - Rg8ui = 37 - R16ui = 38 - R8ui = 39 - R64ui = 40 - R64i = 41 + Unknown = () + Rgba32f = () + Rgba16f = () + R32f = () + Rgba8 = () + Rgba8Snorm = () + Rg32f = () + Rg16f = () + R11fG11fB10f = () + R16f = () + Rgba16 = () + Rgb10A2 = () + Rg16 = () + Rg8 = () + R16 = () + R8 = () + Rgba16Snorm = () + Rg16Snorm = () + Rg8Snorm = () + R16Snorm = () + R8Snorm = () + Rgba32i = () + Rgba16i = () + Rgba8i = () + R32i = () + Rg32i = () + Rg16i = () + Rg8i = () + R16i = () + R8i = () + Rgba32ui = () + Rgba16ui = () + Rgba8ui = () + R32ui = () + Rgb10a2ui = () + Rg32ui = () + Rg16ui = () + Rg8ui = () + R16ui = () + R8ui = () + R64ui = () + R64i = () class ImageChannelOrder(SPIRVEnum): - R = 0 - A = 1 - RG = 2 - RA = 3 - RGB = 4 - RGBA = 5 - BGRA = 6 - ARGB = 7 - Intensity = 8 - Luminance = 9 - Rx = 10 - RGx = 11 - RGBx = 12 - Depth = 13 - DepthStencil = 14 - sRGB = 15 - sRGBx = 16 - sRGBA = 17 - sBGRA = 18 - ABGR = 19 + R = () + A = () + RG = () + RA = () + RGB = () + RGBA = () + BGRA = () + ARGB = () + Intensity = () + Luminance = () + Rx = () + RGx = () + RGBx = () + Depth = () + DepthStencil = () + sRGB = () + sRGBx = () + sRGBA = () + sBGRA = () + ABGR = () class ImageChannelDataType(SPIRVEnum): - SnormInt8 = 0 - SnormInt16 = 1 - UnormInt8 = 2 - UnormInt16 = 3 - UnormShort565 = 4 - UnormShort555 = 5 - UnormInt101010 = 6 - SignedInt8 = 7 - SignedInt16 = 8 - SignedInt32 = 9 - UnsignedInt8 = 10 - UnsignedInt16 = 11 - UnsignedInt32 = 12 - HalfFloat = 13 - Float = 14 - UnormInt24 = 15 - UnormInt101010_2 = 16 + SnormInt8 = () + SnormInt16 = () + UnormInt8 = () + UnormInt16 = () + UnormShort565 = () + UnormShort555 = () + UnormInt101010 = () + SignedInt8 = () + SignedInt16 = () + SignedInt32 = () + UnsignedInt8 = () + UnsignedInt16 = () + UnsignedInt32 = () + HalfFloat = () + Float = () + UnormInt24 = () + UnormInt101010_2 = () class ImageOperandsShift(SPIRVEnum): - Bias = 0 - Lod = 1 - Grad = 2 - ConstOffset = 3 - Offset = 4 - ConstOffsets = 5 - Sample = 6 - MinLod = 7 - MakeTexelAvailable = 8 - MakeTexelAvailableKHR = 8 - MakeTexelVisible = 9 - MakeTexelVisibleKHR = 9 - NonPrivateTexel = 10 - NonPrivateTexelKHR = 10 - VolatileTexel = 11 - VolatileTexelKHR = 11 - SignExtend = 12 - ZeroExtend = 13 - Nontemporal = 14 - Offsets = 16 + Bias = () + Lod = () + Grad = () + ConstOffset = () + Offset = () + ConstOffsets = () + Sample = () + MinLod = () + MakeTexelAvailable = () + MakeTexelAvailableKHR = () + MakeTexelVisible = () + MakeTexelVisibleKHR = () + NonPrivateTexel = () + NonPrivateTexelKHR = () + VolatileTexel = () + VolatileTexelKHR = () + SignExtend = () + ZeroExtend = () + Nontemporal = () + Offsets = () class ImageOperandsMask(SPIRVEnum): - MaskNone = 0 - Bias = 1 - Lod = 2 - Grad = 4 - ConstOffset = 8 - Offset = 16 - ConstOffsets = 32 - Sample = 64 - MinLod = 128 - MakeTexelAvailable = 256 - MakeTexelAvailableKHR = 256 - MakeTexelVisible = 512 - MakeTexelVisibleKHR = 512 - NonPrivateTexel = 1024 - NonPrivateTexelKHR = 1024 - VolatileTexel = 2048 - VolatileTexelKHR = 2048 - SignExtend = 4096 - ZeroExtend = 8192 - Nontemporal = 16384 - Offsets = 65536 + MaskNone = () + Bias = () + Lod = () + Grad = () + ConstOffset = () + Offset = () + ConstOffsets = () + Sample = () + MinLod = () + MakeTexelAvailable = () + MakeTexelAvailableKHR = () + MakeTexelVisible = () + MakeTexelVisibleKHR = () + NonPrivateTexel = () + NonPrivateTexelKHR = () + VolatileTexel = () + VolatileTexelKHR = () + SignExtend = () + ZeroExtend = () + Nontemporal = () + Offsets = () class FPFastMathModeShift(SPIRVEnum): - NotNaN = 0 - NotInf = 1 - NSZ = 2 - AllowRecip = 3 - Fast = 4 - AllowContractFastINTEL = 16 - AllowReassocINTEL = 17 + NotNaN = () + NotInf = () + NSZ = () + AllowRecip = () + Fast = () + AllowContractFastINTEL = () + AllowReassocINTEL = () class FPFastMathModeMask(SPIRVEnum): - MaskNone = 0 - NotNaN = 1 - NotInf = 2 - NSZ = 4 - AllowRecip = 8 - Fast = 16 - AllowContractFastINTEL = 65536 - AllowReassocINTEL = 131072 + MaskNone = () + NotNaN = () + NotInf = () + NSZ = () + AllowRecip = () + Fast = () + AllowContractFastINTEL = () + AllowReassocINTEL = () class FPRoundingMode(SPIRVEnum): - RTE = 0 - RTZ = 1 - RTP = 2 - RTN = 3 + RTE = () + RTZ = () + RTP = () + RTN = () class LinkageType(SPIRVEnum): - Export = 0 - Import = 1 - LinkOnceODR = 2 + Export = () + Import = () + LinkOnceODR = () class AccessQualifier(SPIRVEnum): - ReadOnly = 0 - WriteOnly = 1 - ReadWrite = 2 + ReadOnly = () + WriteOnly = () + ReadWrite = () class FunctionParameterAttribute(SPIRVEnum): - Zext = 0 - Sext = 1 - ByVal = 2 - Sret = 3 - NoAlias = 4 - NoCapture = 5 - NoWrite = 6 - NoReadWrite = 7 + Zext = () + Sext = () + ByVal = () + Sret = () + NoAlias = () + NoCapture = () + NoWrite = () + NoReadWrite = () class Decoration(SPIRVEnum): - RelaxedPrecision = 0 - SpecId = 1 - Block = 2 - BufferBlock = 3 - RowMajor = 4 - ColMajor = 5 - ArrayStride = 6 - MatrixStride = 7 - GLSLShared = 8 - GLSLPacked = 9 - CPacked = 10 - BuiltIn = 11 - NoPerspective = 13 - Flat = 14 - Patch = 15 - Centroid = 16 - Sample = 17 - Invariant = 18 - Restrict = 19 - Aliased = 20 - Volatile = 21 - Constant = 22 - Coherent = 23 - NonWritable = 24 - NonReadable = 25 - Uniform = 26 - UniformId = 27 - SaturatedConversion = 28 - Stream = 29 - Location = 30 - Component = 31 - Index = 32 - Binding = 33 - DescriptorSet = 34 - Offset = 35 - XfbBuffer = 36 - XfbStride = 37 - FuncParamAttr = 38 - FPRoundingMode = 39 - FPFastMathMode = 40 - LinkageAttributes = 41 - NoContraction = 42 - InputAttachmentIndex = 43 - Alignment = 44 - MaxByteOffset = 45 - AlignmentId = 46 - MaxByteOffsetId = 47 - NoSignedWrap = 4469 - NoUnsignedWrap = 4470 - ExplicitInterpAMD = 4999 - OverrideCoverageNV = 5248 - PassthroughNV = 5250 - ViewportRelativeNV = 5252 - SecondaryViewportRelativeNV = 5256 - PerPrimitiveNV = 5271 - PerViewNV = 5272 - PerTaskNV = 5273 - PerVertexKHR = 5285 - PerVertexNV = 5285 - NonUniform = 5300 - NonUniformEXT = 5300 - RestrictPointer = 5355 - RestrictPointerEXT = 5355 - AliasedPointer = 5356 - AliasedPointerEXT = 5356 - BindlessSamplerNV = 5398 - BindlessImageNV = 5399 - BoundSamplerNV = 5400 - BoundImageNV = 5401 - SIMTCallINTEL = 5599 - ReferencedIndirectlyINTEL = 5602 - ClobberINTEL = 5607 - SideEffectsINTEL = 5608 - VectorComputeVariableINTEL = 5624 - FuncParamIOKindINTEL = 5625 - VectorComputeFunctionINTEL = 5626 - StackCallINTEL = 5627 - GlobalVariableOffsetINTEL = 5628 - CounterBuffer = 5634 - HlslCounterBufferGOOGLE = 5634 - HlslSemanticGOOGLE = 5635 - UserSemantic = 5635 - UserTypeGOOGLE = 5636 - FunctionRoundingModeINTEL = 5822 - FunctionDenormModeINTEL = 5823 - RegisterINTEL = 5825 - MemoryINTEL = 5826 - NumbanksINTEL = 5827 - BankwidthINTEL = 5828 - MaxPrivateCopiesINTEL = 5829 - SinglepumpINTEL = 5830 - DoublepumpINTEL = 5831 - MaxReplicatesINTEL = 5832 - SimpleDualPortINTEL = 5833 - MergeINTEL = 5834 - BankBitsINTEL = 5835 - ForcePow2DepthINTEL = 5836 - BurstCoalesceINTEL = 5899 - CacheSizeINTEL = 5900 - DontStaticallyCoalesceINTEL = 5901 - PrefetchINTEL = 5902 - StallEnableINTEL = 5905 - FuseLoopsInFunctionINTEL = 5907 - BufferLocationINTEL = 5921 - IOPipeStorageINTEL = 5944 - FunctionFloatingPointModeINTEL = 6080 - SingleElementVectorINTEL = 6085 - VectorComputeCallableFunctionINTEL = 6087 - MediaBlockIOINTEL = 6140 + RelaxedPrecision = () + SpecId = () + Block = () + BufferBlock = () + RowMajor = () + ColMajor = () + ArrayStride = () + MatrixStride = () + GLSLShared = () + GLSLPacked = () + CPacked = () + BuiltIn = () + NoPerspective = () + Flat = () + Patch = () + Centroid = () + Sample = () + Invariant = () + Restrict = () + Aliased = () + Volatile = () + Constant = () + Coherent = () + NonWritable = () + NonReadable = () + Uniform = () + UniformId = () + SaturatedConversion = () + Stream = () + Location = () + Component = () + Index = () + Binding = () + DescriptorSet = () + Offset = () + XfbBuffer = () + XfbStride = () + FuncParamAttr = () + FPRoundingMode = () + FPFastMathMode = () + LinkageAttributes = () + NoContraction = () + InputAttachmentIndex = () + Alignment = () + MaxByteOffset = () + AlignmentId = () + MaxByteOffsetId = () + NoSignedWrap = () + NoUnsignedWrap = () + ExplicitInterpAMD = () + OverrideCoverageNV = () + PassthroughNV = () + ViewportRelativeNV = () + SecondaryViewportRelativeNV = () + PerPrimitiveNV = () + PerViewNV = () + PerTaskNV = () + PerVertexKHR = () + PerVertexNV = () + NonUniform = () + NonUniformEXT = () + RestrictPointer = () + RestrictPointerEXT = () + AliasedPointer = () + AliasedPointerEXT = () + BindlessSamplerNV = () + BindlessImageNV = () + BoundSamplerNV = () + BoundImageNV = () + SIMTCallINTEL = () + ReferencedIndirectlyINTEL = () + ClobberINTEL = () + SideEffectsINTEL = () + VectorComputeVariableINTEL = () + FuncParamIOKindINTEL = () + VectorComputeFunctionINTEL = () + StackCallINTEL = () + GlobalVariableOffsetINTEL = () + CounterBuffer = () + HlslCounterBufferGOOGLE = () + HlslSemanticGOOGLE = () + UserSemantic = () + UserTypeGOOGLE = () + FunctionRoundingModeINTEL = () + FunctionDenormModeINTEL = () + RegisterINTEL = () + MemoryINTEL = () + NumbanksINTEL = () + BankwidthINTEL = () + MaxPrivateCopiesINTEL = () + SinglepumpINTEL = () + DoublepumpINTEL = () + MaxReplicatesINTEL = () + SimpleDualPortINTEL = () + MergeINTEL = () + BankBitsINTEL = () + ForcePow2DepthINTEL = () + BurstCoalesceINTEL = () + CacheSizeINTEL = () + DontStaticallyCoalesceINTEL = () + PrefetchINTEL = () + StallEnableINTEL = () + FuseLoopsInFunctionINTEL = () + BufferLocationINTEL = () + IOPipeStorageINTEL = () + FunctionFloatingPointModeINTEL = () + SingleElementVectorINTEL = () + VectorComputeCallableFunctionINTEL = () + MediaBlockIOINTEL = () class BuiltIn(SPIRVEnum): - Position = 0 - PointSize = 1 - ClipDistance = 3 - CullDistance = 4 - VertexId = 5 - InstanceId = 6 - PrimitiveId = 7 - InvocationId = 8 - Layer = 9 - ViewportIndex = 10 - TessLevelOuter = 11 - TessLevelInner = 12 - TessCoord = 13 - PatchVertices = 14 - FragCoord = 15 - PointCoord = 16 - FrontFacing = 17 - SampleId = 18 - SamplePosition = 19 - SampleMask = 20 - FragDepth = 22 - HelperInvocation = 23 - NumWorkgroups = 24 - WorkgroupSize = 25 - WorkgroupId = 26 - LocalInvocationId = 27 - GlobalInvocationId = 28 - LocalInvocationIndex = 29 - WorkDim = 30 - GlobalSize = 31 - EnqueuedWorkgroupSize = 32 - GlobalOffset = 33 - GlobalLinearId = 34 - SubgroupSize = 36 - SubgroupMaxSize = 37 - NumSubgroups = 38 - NumEnqueuedSubgroups = 39 - SubgroupId = 40 - SubgroupLocalInvocationId = 41 - VertexIndex = 42 - InstanceIndex = 43 - SubgroupEqMask = 4416 - SubgroupEqMaskKHR = 4416 - SubgroupGeMask = 4417 - SubgroupGeMaskKHR = 4417 - SubgroupGtMask = 4418 - SubgroupGtMaskKHR = 4418 - SubgroupLeMask = 4419 - SubgroupLeMaskKHR = 4419 - SubgroupLtMask = 4420 - SubgroupLtMaskKHR = 4420 - BaseVertex = 4424 - BaseInstance = 4425 - DrawIndex = 4426 - PrimitiveShadingRateKHR = 4432 - DeviceIndex = 4438 - ViewIndex = 4440 - ShadingRateKHR = 4444 - BaryCoordNoPerspAMD = 4992 - BaryCoordNoPerspCentroidAMD = 4993 - BaryCoordNoPerspSampleAMD = 4994 - BaryCoordSmoothAMD = 4995 - BaryCoordSmoothCentroidAMD = 4996 - BaryCoordSmoothSampleAMD = 4997 - BaryCoordPullModelAMD = 4998 - FragStencilRefEXT = 5014 - ViewportMaskNV = 5253 - SecondaryPositionNV = 5257 - SecondaryViewportMaskNV = 5258 - PositionPerViewNV = 5261 - ViewportMaskPerViewNV = 5262 - FullyCoveredEXT = 5264 - TaskCountNV = 5274 - PrimitiveCountNV = 5275 - PrimitiveIndicesNV = 5276 - ClipDistancePerViewNV = 5277 - CullDistancePerViewNV = 5278 - LayerPerViewNV = 5279 - MeshViewCountNV = 5280 - MeshViewIndicesNV = 5281 - BaryCoordKHR = 5286 - BaryCoordNV = 5286 - BaryCoordNoPerspKHR = 5287 - BaryCoordNoPerspNV = 5287 - FragSizeEXT = 5292 - FragmentSizeNV = 5292 - FragInvocationCountEXT = 5293 - InvocationsPerPixelNV = 5293 - LaunchIdKHR = 5319 - LaunchIdNV = 5319 - LaunchSizeKHR = 5320 - LaunchSizeNV = 5320 - WorldRayOriginKHR = 5321 - WorldRayOriginNV = 5321 - WorldRayDirectionKHR = 5322 - WorldRayDirectionNV = 5322 - ObjectRayOriginKHR = 5323 - ObjectRayOriginNV = 5323 - ObjectRayDirectionKHR = 5324 - ObjectRayDirectionNV = 5324 - RayTminKHR = 5325 - RayTminNV = 5325 - RayTmaxKHR = 5326 - RayTmaxNV = 5326 - InstanceCustomIndexKHR = 5327 - InstanceCustomIndexNV = 5327 - ObjectToWorldKHR = 5330 - ObjectToWorldNV = 5330 - WorldToObjectKHR = 5331 - WorldToObjectNV = 5331 - HitTNV = 5332 - HitKindKHR = 5333 - HitKindNV = 5333 - CurrentRayTimeNV = 5334 - IncomingRayFlagsKHR = 5351 - IncomingRayFlagsNV = 5351 - RayGeometryIndexKHR = 5352 - WarpsPerSMNV = 5374 - SMCountNV = 5375 - WarpIDNV = 5376 - SMIDNV = 5377 + Position = () + PointSize = () + ClipDistance = () + CullDistance = () + VertexId = () + InstanceId = () + PrimitiveId = () + InvocationId = () + Layer = () + ViewportIndex = () + TessLevelOuter = () + TessLevelInner = () + TessCoord = () + PatchVertices = () + FragCoord = () + PointCoord = () + FrontFacing = () + SampleId = () + SamplePosition = () + SampleMask = () + FragDepth = () + HelperInvocation = () + NumWorkgroups = () + WorkgroupSize = () + WorkgroupId = () + LocalInvocationId = () + GlobalInvocationId = () + LocalInvocationIndex = () + WorkDim = () + GlobalSize = () + EnqueuedWorkgroupSize = () + GlobalOffset = () + GlobalLinearId = () + SubgroupSize = () + SubgroupMaxSize = () + NumSubgroups = () + NumEnqueuedSubgroups = () + SubgroupId = () + SubgroupLocalInvocationId = () + VertexIndex = () + InstanceIndex = () + SubgroupEqMask = () + SubgroupEqMaskKHR = () + SubgroupGeMask = () + SubgroupGeMaskKHR = () + SubgroupGtMask = () + SubgroupGtMaskKHR = () + SubgroupLeMask = () + SubgroupLeMaskKHR = () + SubgroupLtMask = () + SubgroupLtMaskKHR = () + BaseVertex = () + BaseInstance = () + DrawIndex = () + PrimitiveShadingRateKHR = () + DeviceIndex = () + ViewIndex = () + ShadingRateKHR = () + BaryCoordNoPerspAMD = () + BaryCoordNoPerspCentroidAMD = () + BaryCoordNoPerspSampleAMD = () + BaryCoordSmoothAMD = () + BaryCoordSmoothCentroidAMD = () + BaryCoordSmoothSampleAMD = () + BaryCoordPullModelAMD = () + FragStencilRefEXT = () + ViewportMaskNV = () + SecondaryPositionNV = () + SecondaryViewportMaskNV = () + PositionPerViewNV = () + ViewportMaskPerViewNV = () + FullyCoveredEXT = () + TaskCountNV = () + PrimitiveCountNV = () + PrimitiveIndicesNV = () + ClipDistancePerViewNV = () + CullDistancePerViewNV = () + LayerPerViewNV = () + MeshViewCountNV = () + MeshViewIndicesNV = () + BaryCoordKHR = () + BaryCoordNV = () + BaryCoordNoPerspKHR = () + BaryCoordNoPerspNV = () + FragSizeEXT = () + FragmentSizeNV = () + FragInvocationCountEXT = () + InvocationsPerPixelNV = () + LaunchIdKHR = () + LaunchIdNV = () + LaunchSizeKHR = () + LaunchSizeNV = () + WorldRayOriginKHR = () + WorldRayOriginNV = () + WorldRayDirectionKHR = () + WorldRayDirectionNV = () + ObjectRayOriginKHR = () + ObjectRayOriginNV = () + ObjectRayDirectionKHR = () + ObjectRayDirectionNV = () + RayTminKHR = () + RayTminNV = () + RayTmaxKHR = () + RayTmaxNV = () + InstanceCustomIndexKHR = () + InstanceCustomIndexNV = () + ObjectToWorldKHR = () + ObjectToWorldNV = () + WorldToObjectKHR = () + WorldToObjectNV = () + HitTNV = () + HitKindKHR = () + HitKindNV = () + CurrentRayTimeNV = () + IncomingRayFlagsKHR = () + IncomingRayFlagsNV = () + RayGeometryIndexKHR = () + WarpsPerSMNV = () + SMCountNV = () + WarpIDNV = () + SMIDNV = () class SelectionControlShift(SPIRVEnum): - Flatten = 0 - DontFlatten = 1 + Flatten = () + DontFlatten = () class SelectionControlMask(SPIRVEnum): - NONE = 0 - Flatten = 1 - DontFlatten = 2 + NONE = () + Flatten = () + DontFlatten = () class LoopControlShift(SPIRVEnum): - Unroll = 0 - DontUnroll = 1 - DependencyInfinite = 2 - DependencyLength = 3 - MinIterations = 4 - MaxIterations = 5 - IterationMultiple = 6 - PeelCount = 7 - PartialCount = 8 - InitiationIntervalINTEL = 16 - MaxConcurrencyINTEL = 17 - DependencyArrayINTEL = 18 - PipelineEnableINTEL = 19 - LoopCoalesceINTEL = 20 - MaxInterleavingINTEL = 21 - SpeculatedIterationsINTEL = 22 - NoFusionINTEL = 23 + Unroll = () + DontUnroll = () + DependencyInfinite = () + DependencyLength = () + MinIterations = () + MaxIterations = () + IterationMultiple = () + PeelCount = () + PartialCount = () + InitiationIntervalINTEL = () + MaxConcurrencyINTEL = () + DependencyArrayINTEL = () + PipelineEnableINTEL = () + LoopCoalesceINTEL = () + MaxInterleavingINTEL = () + SpeculatedIterationsINTEL = () + NoFusionINTEL = () class LoopControlMask(SPIRVEnum): - MaskNone = 0 - Unroll = 1 - DontUnroll = 2 - DependencyInfinite = 4 - DependencyLength = 8 - MinIterations = 16 - MaxIterations = 32 - IterationMultiple = 64 - PeelCount = 128 - PartialCount = 256 - InitiationIntervalINTEL = 65536 - MaxConcurrencyINTEL = 131072 - DependencyArrayINTEL = 262144 - PipelineEnableINTEL = 524288 - LoopCoalesceINTEL = 1048576 - MaxInterleavingINTEL = 2097152 - SpeculatedIterationsINTEL = 4194304 - NoFusionINTEL = 8388608 + MaskNone = () + Unroll = () + DontUnroll = () + DependencyInfinite = () + DependencyLength = () + MinIterations = () + MaxIterations = () + IterationMultiple = () + PeelCount = () + PartialCount = () + InitiationIntervalINTEL = () + MaxConcurrencyINTEL = () + DependencyArrayINTEL = () + PipelineEnableINTEL = () + LoopCoalesceINTEL = () + MaxInterleavingINTEL = () + SpeculatedIterationsINTEL = () + NoFusionINTEL = () class FunctionControlShift(SPIRVEnum): - Inline = 0 - DontInline = 1 - Pure = 2 - Const = 3 - OptNoneINTEL = 16 + Inline = () + DontInline = () + Pure = () + Const = () + OptNoneINTEL = () class FunctionControlMask(SPIRVEnum): - NONE = 0 - Inline = 1 - DontInline = 2 - Pure = 4 - Const = 8 - # OptNoneINTEL = 65536 + NONE = () + Inline = () + DontInline = () + Pure = () + Const = () + # OptNoneINTEL = () class MemorySemanticsShift(SPIRVEnum): - Acquire = 1 - Release = 2 - AcquireRelease = 3 - SequentiallyConsistent = 4 - UniformMemory = 6 - SubgroupMemory = 7 - WorkgroupMemory = 8 - CrossWorkgroupMemory = 9 - AtomicCounterMemory = 10 - ImageMemory = 11 - OutputMemory = 12 - OutputMemoryKHR = 12 - MakeAvailable = 13 - MakeAvailableKHR = 13 - MakeVisible = 14 - MakeVisibleKHR = 14 - Volatile = 15 + Acquire = () + Release = () + AcquireRelease = () + SequentiallyConsistent = () + UniformMemory = () + SubgroupMemory = () + WorkgroupMemory = () + CrossWorkgroupMemory = () + AtomicCounterMemory = () + ImageMemory = () + OutputMemory = () + OutputMemoryKHR = () + MakeAvailable = () + MakeAvailableKHR = () + MakeVisible = () + MakeVisibleKHR = () + Volatile = () class MemorySemanticsMask(SPIRVEnum): - MaskNone = 0 - Acquire = 2 - Release = 4 - AcquireRelease = 8 - SequentiallyConsistent = 16 - UniformMemory = 64 - SubgroupMemory = 128 - WorkgroupMemory = 256 - CrossWorkgroupMemory = 512 - AtomicCounterMemory = 1024 - ImageMemory = 2048 - OutputMemory = 4096 - OutputMemoryKHR = 4096 - MakeAvailable = 8192 - MakeAvailableKHR = 8192 - MakeVisible = 16384 - MakeVisibleKHR = 16384 - Volatile = 32768 + MaskNone = () + Acquire = () + Release = () + AcquireRelease = () + SequentiallyConsistent = () + UniformMemory = () + SubgroupMemory = () + WorkgroupMemory = () + CrossWorkgroupMemory = () + AtomicCounterMemory = () + ImageMemory = () + OutputMemory = () + OutputMemoryKHR = () + MakeAvailable = () + MakeAvailableKHR = () + MakeVisible = () + MakeVisibleKHR = () + Volatile = () class MemoryAccessShift(SPIRVEnum): - Volatile = 0 - Aligned = 1 - Nontemporal = 2 - MakePointerAvailable = 3 - MakePointerAvailableKHR = 3 - MakePointerVisible = 4 - MakePointerVisibleKHR = 4 - NonPrivatePointer = 5 - NonPrivatePointerKHR = 5 + Volatile = () + Aligned = () + Nontemporal = () + MakePointerAvailable = () + MakePointerAvailableKHR = () + MakePointerVisible = () + MakePointerVisibleKHR = () + NonPrivatePointer = () + NonPrivatePointerKHR = () class MemoryAccessMask(SPIRVEnum): - MaskNone = 0 - Volatile = 1 - Aligned = 2 - Nontemporal = 4 - MakePointerAvailable = 8 - MakePointerAvailableKHR = 8 - MakePointerVisible = 16 - MakePointerVisibleKHR = 16 - NonPrivatePointer = 32 - NonPrivatePointerKHR = 32 + MaskNone = () + Volatile = () + Aligned = () + Nontemporal = () + MakePointerAvailable = () + MakePointerAvailableKHR = () + MakePointerVisible = () + MakePointerVisibleKHR = () + NonPrivatePointer = () + NonPrivatePointerKHR = () class Scope(SPIRVEnum): - CrossDevice = 0 - Device = 1 - Workgroup = 2 - Subgroup = 3 - Invocation = 4 - QueueFamily = 5 - QueueFamilyKHR = 5 - ShaderCallKHR = 6 + CrossDevice = () + Device = () + Workgroup = () + Subgroup = () + Invocation = () + QueueFamily = () + QueueFamilyKHR = () + ShaderCallKHR = () class GroupOperation(SPIRVEnum): - Reduce = 0 - InclusiveScan = 1 - ExclusiveScan = 2 - ClusteredReduce = 3 - PartitionedReduceNV = 6 - PartitionedInclusiveScanNV = 7 - PartitionedExclusiveScanNV = 8 + Reduce = () + InclusiveScan = () + ExclusiveScan = () + ClusteredReduce = () + PartitionedReduceNV = () + PartitionedInclusiveScanNV = () + PartitionedExclusiveScanNV = () class KernelEnqueueFlags(SPIRVEnum): - NoWait = 0 - WaitKernel = 1 - WaitWorkGroup = 2 + NoWait = () + WaitKernel = () + WaitWorkGroup = () class KernelProfilingInfoShift(SPIRVEnum): - CmdExecTime = 0 + CmdExecTime = () class KernelProfilingInfoMask(SPIRVEnum): - MaskNone = 0 - CmdExecTime = 1 + MaskNone = () + CmdExecTime = () class Capability(SPIRVEnum): - Matrix = 0 - Shader = 1 - Geometry = 2 - Tessellation = 3 - Addresses = 4 - Linkage = 5 - Kernel = 6 - Vector16 = 7 - Float16Buffer = 8 - Float16 = 9 - Float64 = 10 - Int64 = 11 - Int64Atomics = 12 - ImageBasic = 13 - ImageReadWrite = 14 - ImageMipmap = 15 - Pipes = 17 - Groups = 18 - DeviceEnqueue = 19 - LiteralSampler = 20 - AtomicStorage = 21 - Int16 = 22 - TessellationPointSize = 23 - GeometryPointSize = 24 - ImageGatherExtended = 25 - StorageImageMultisample = 27 - UniformBufferArrayDynamicIndexing = 28 - SampledImageArrayDynamicIndexing = 29 - StorageBufferArrayDynamicIndexing = 30 - StorageImageArrayDynamicIndexing = 31 - ClipDistance = 32 - CullDistance = 33 - ImageCubeArray = 34 - SampleRateShading = 35 - ImageRect = 36 - SampledRect = 37 - GenericPointer = 38 - Int8 = 39 - InputAttachment = 40 - SparseResidency = 41 - MinLod = 42 - Sampled1D = 43 - Image1D = 44 - SampledCubeArray = 45 - SampledBuffer = 46 - ImageBuffer = 47 - ImageMSArray = 48 - StorageImageExtendedFormats = 49 - ImageQuery = 50 - DerivativeControl = 51 - InterpolationFunction = 52 - TransformFeedback = 53 - GeometryStreams = 54 - StorageImageReadWithoutFormat = 55 - StorageImageWriteWithoutFormat = 56 - MultiViewport = 57 - SubgroupDispatch = 58 - NamedBarrier = 59 - PipeStorage = 60 - GroupNonUniform = 61 - GroupNonUniformVote = 62 - GroupNonUniformArithmetic = 63 - GroupNonUniformBallot = 64 - GroupNonUniformShuffle = 65 - GroupNonUniformShuffleRelative = 66 - GroupNonUniformClustered = 67 - GroupNonUniformQuad = 68 - ShaderLayer = 69 - ShaderViewportIndex = 70 - UniformDecoration = 71 - FragmentShadingRateKHR = 4422 - SubgroupBallotKHR = 4423 - DrawParameters = 4427 - WorkgroupMemoryExplicitLayoutKHR = 4428 - WorkgroupMemoryExplicitLayout8BitAccessKHR = 4429 - WorkgroupMemoryExplicitLayout16BitAccessKHR = 4430 - SubgroupVoteKHR = 4431 - StorageBuffer16BitAccess = 4433 - StorageUniformBufferBlock16 = 4433 - StorageUniform16 = 4434 - UniformAndStorageBuffer16BitAccess = 4434 - StoragePushConstant16 = 4435 - StorageInputOutput16 = 4436 - DeviceGroup = 4437 - MultiView = 4439 - VariablePointersStorageBuffer = 4441 - VariablePointers = 4442 - AtomicStorageOps = 4445 - SampleMaskPostDepthCoverage = 4447 - StorageBuffer8BitAccess = 4448 - UniformAndStorageBuffer8BitAccess = 4449 - StoragePushConstant8 = 4450 - DenormPreserve = 4464 - DenormFlushToZero = 4465 - SignedZeroInfNanPreserve = 4466 - RoundingModeRTE = 4467 - RoundingModeRTZ = 4468 - RayQueryProvisionalKHR = 4471 - RayQueryKHR = 4472 - RayTraversalPrimitiveCullingKHR = 4478 - RayTracingKHR = 4479 - Float16ImageAMD = 5008 - ImageGatherBiasLodAMD = 5009 - FragmentMaskAMD = 5010 - StencilExportEXT = 5013 - ImageReadWriteLodAMD = 5015 - Int64ImageEXT = 5016 - ShaderClockKHR = 5055 - SampleMaskOverrideCoverageNV = 5249 - GeometryShaderPassthroughNV = 5251 - ShaderViewportIndexLayerEXT = 5254 - ShaderViewportIndexLayerNV = 5254 - ShaderViewportMaskNV = 5255 - ShaderStereoViewNV = 5259 - PerViewAttributesNV = 5260 - FragmentFullyCoveredEXT = 5265 - MeshShadingNV = 5266 - ImageFootprintNV = 5282 - FragmentBarycentricKHR = 5284 - FragmentBarycentricNV = 5284 - ComputeDerivativeGroupQuadsNV = 5288 - FragmentDensityEXT = 5291 - ShadingRateNV = 5291 - GroupNonUniformPartitionedNV = 5297 - ShaderNonUniform = 5301 - ShaderNonUniformEXT = 5301 - RuntimeDescriptorArray = 5302 - RuntimeDescriptorArrayEXT = 5302 - InputAttachmentArrayDynamicIndexing = 5303 - InputAttachmentArrayDynamicIndexingEXT = 5303 - UniformTexelBufferArrayDynamicIndexing = 5304 - UniformTexelBufferArrayDynamicIndexingEXT = 5304 - StorageTexelBufferArrayDynamicIndexing = 5305 - StorageTexelBufferArrayDynamicIndexingEXT = 5305 - UniformBufferArrayNonUniformIndexing = 5306 - UniformBufferArrayNonUniformIndexingEXT = 5306 - SampledImageArrayNonUniformIndexing = 5307 - SampledImageArrayNonUniformIndexingEXT = 5307 - StorageBufferArrayNonUniformIndexing = 5308 - StorageBufferArrayNonUniformIndexingEXT = 5308 - StorageImageArrayNonUniformIndexing = 5309 - StorageImageArrayNonUniformIndexingEXT = 5309 - InputAttachmentArrayNonUniformIndexing = 5310 - InputAttachmentArrayNonUniformIndexingEXT = 5310 - UniformTexelBufferArrayNonUniformIndexing = 5311 - UniformTexelBufferArrayNonUniformIndexingEXT = 5311 - StorageTexelBufferArrayNonUniformIndexing = 5312 - StorageTexelBufferArrayNonUniformIndexingEXT = 5312 - RayTracingNV = 5340 - RayTracingMotionBlurNV = 5341 - VulkanMemoryModel = 5345 - VulkanMemoryModelKHR = 5345 - VulkanMemoryModelDeviceScope = 5346 - VulkanMemoryModelDeviceScopeKHR = 5346 - PhysicalStorageBufferAddresses = 5347 - PhysicalStorageBufferAddressesEXT = 5347 - ComputeDerivativeGroupLinearNV = 5350 - RayTracingProvisionalKHR = 5353 - CooperativeMatrixNV = 5357 - FragmentShaderSampleInterlockEXT = 5363 - FragmentShaderShadingRateInterlockEXT = 5372 - ShaderSMBuiltinsNV = 5373 - FragmentShaderPixelInterlockEXT = 5378 - DemoteToHelperInvocation = 5379 - DemoteToHelperInvocationEXT = 5379 - BindlessTextureNV = 5390 - SubgroupShuffleINTEL = 5568 - SubgroupBufferBlockIOINTEL = 5569 - SubgroupImageBlockIOINTEL = 5570 - SubgroupImageMediaBlockIOINTEL = 5579 - RoundToInfinityINTEL = 5582 - FloatingPointModeINTEL = 5583 - IntegerFunctions2INTEL = 5584 - FunctionPointersINTEL = 5603 - IndirectReferencesINTEL = 5604 - AsmINTEL = 5606 - AtomicFloat32MinMaxEXT = 5612 - AtomicFloat64MinMaxEXT = 5613 - AtomicFloat16MinMaxEXT = 5616 - VectorComputeINTEL = 5617 - VectorAnyINTEL = 5619 - ExpectAssumeKHR = 5629 - SubgroupAvcMotionEstimationINTEL = 5696 - SubgroupAvcMotionEstimationIntraINTEL = 5697 - SubgroupAvcMotionEstimationChromaINTEL = 5698 - VariableLengthArrayINTEL = 5817 - FunctionFloatControlINTEL = 5821 - FPGAMemoryAttributesINTEL = 5824 - FPFastMathModeINTEL = 5837 - ArbitraryPrecisionIntegersINTEL = 5844 - ArbitraryPrecisionFloatingPointINTEL = 5845 - UnstructuredLoopControlsINTEL = 5886 - FPGALoopControlsINTEL = 5888 - KernelAttributesINTEL = 5892 - FPGAKernelAttributesINTEL = 5897 - FPGAMemoryAccessesINTEL = 5898 - FPGAClusterAttributesINTEL = 5904 - LoopFuseINTEL = 5906 - FPGABufferLocationINTEL = 5920 - ArbitraryPrecisionFixedPointINTEL = 5922 - USMStorageClassesINTEL = 5935 - IOPipesINTEL = 5943 - BlockingPipesINTEL = 5945 - FPGARegINTEL = 5948 - DotProductInputAll = 6016 - DotProductInputAllKHR = 6016 - DotProductInput4x8Bit = 6017 - DotProductInput4x8BitKHR = 6017 - DotProductInput4x8BitPacked = 6018 - DotProductInput4x8BitPackedKHR = 6018 - DotProduct = 6019 - DotProductKHR = 6019 - BitInstructions = 6025 - AtomicFloat32AddEXT = 6033 - AtomicFloat64AddEXT = 6034 - LongConstantCompositeINTEL = 6089 - OptNoneINTEL = 6094 - AtomicFloat16AddEXT = 6095 - DebugInfoModuleINTEL = 6114 + Matrix = () + Shader = () + Geometry = () + Tessellation = () + Addresses = () + Linkage = () + Kernel = () + Vector16 = () + Float16Buffer = () + Float16 = () + Float64 = () + Int64 = () + Int64Atomics = () + ImageBasic = () + ImageReadWrite = () + ImageMipmap = () + Pipes = () + Groups = () + DeviceEnqueue = () + LiteralSampler = () + AtomicStorage = () + Int16 = () + TessellationPointSize = () + GeometryPointSize = () + ImageGatherExtended = () + StorageImageMultisample = () + UniformBufferArrayDynamicIndexing = () + SampledImageArrayDynamicIndexing = () + StorageBufferArrayDynamicIndexing = () + StorageImageArrayDynamicIndexing = () + ClipDistance = () + CullDistance = () + ImageCubeArray = () + SampleRateShading = () + ImageRect = () + SampledRect = () + GenericPointer = () + Int8 = () + InputAttachment = () + SparseResidency = () + MinLod = () + Sampled1D = () + Image1D = () + SampledCubeArray = () + SampledBuffer = () + ImageBuffer = () + ImageMSArray = () + StorageImageExtendedFormats = () + ImageQuery = () + DerivativeControl = () + InterpolationFunction = () + TransformFeedback = () + GeometryStreams = () + StorageImageReadWithoutFormat = () + StorageImageWriteWithoutFormat = () + MultiViewport = () + SubgroupDispatch = () + NamedBarrier = () + PipeStorage = () + GroupNonUniform = () + GroupNonUniformVote = () + GroupNonUniformArithmetic = () + GroupNonUniformBallot = () + GroupNonUniformShuffle = () + GroupNonUniformShuffleRelative = () + GroupNonUniformClustered = () + GroupNonUniformQuad = () + ShaderLayer = () + ShaderViewportIndex = () + UniformDecoration = () + FragmentShadingRateKHR = () + SubgroupBallotKHR = () + DrawParameters = () + WorkgroupMemoryExplicitLayoutKHR = () + WorkgroupMemoryExplicitLayout8BitAccessKHR = () + WorkgroupMemoryExplicitLayout16BitAccessKHR = () + SubgroupVoteKHR = () + StorageBuffer16BitAccess = () + StorageUniformBufferBlock16 = () + StorageUniform16 = () + UniformAndStorageBuffer16BitAccess = () + StoragePushConstant16 = () + StorageInputOutput16 = () + DeviceGroup = () + MultiView = () + VariablePointersStorageBuffer = () + VariablePointers = () + AtomicStorageOps = () + SampleMaskPostDepthCoverage = () + StorageBuffer8BitAccess = () + UniformAndStorageBuffer8BitAccess = () + StoragePushConstant8 = () + DenormPreserve = () + DenormFlushToZero = () + SignedZeroInfNanPreserve = () + RoundingModeRTE = () + RoundingModeRTZ = () + RayQueryProvisionalKHR = () + RayQueryKHR = () + RayTraversalPrimitiveCullingKHR = () + RayTracingKHR = () + Float16ImageAMD = () + ImageGatherBiasLodAMD = () + FragmentMaskAMD = () + StencilExportEXT = () + ImageReadWriteLodAMD = () + Int64ImageEXT = () + ShaderClockKHR = () + SampleMaskOverrideCoverageNV = () + GeometryShaderPassthroughNV = () + ShaderViewportIndexLayerEXT = () + ShaderViewportIndexLayerNV = () + ShaderViewportMaskNV = () + ShaderStereoViewNV = () + PerViewAttributesNV = () + FragmentFullyCoveredEXT = () + MeshShadingNV = () + ImageFootprintNV = () + FragmentBarycentricKHR = () + FragmentBarycentricNV = () + ComputeDerivativeGroupQuadsNV = () + FragmentDensityEXT = () + ShadingRateNV = () + GroupNonUniformPartitionedNV = () + ShaderNonUniform = () + ShaderNonUniformEXT = () + RuntimeDescriptorArray = () + RuntimeDescriptorArrayEXT = () + InputAttachmentArrayDynamicIndexing = () + InputAttachmentArrayDynamicIndexingEXT = () + UniformTexelBufferArrayDynamicIndexing = () + UniformTexelBufferArrayDynamicIndexingEXT = () + StorageTexelBufferArrayDynamicIndexing = () + StorageTexelBufferArrayDynamicIndexingEXT = () + UniformBufferArrayNonUniformIndexing = () + UniformBufferArrayNonUniformIndexingEXT = () + SampledImageArrayNonUniformIndexing = () + SampledImageArrayNonUniformIndexingEXT = () + StorageBufferArrayNonUniformIndexing = () + StorageBufferArrayNonUniformIndexingEXT = () + StorageImageArrayNonUniformIndexing = () + StorageImageArrayNonUniformIndexingEXT = () + InputAttachmentArrayNonUniformIndexing = () + InputAttachmentArrayNonUniformIndexingEXT = () + UniformTexelBufferArrayNonUniformIndexing = () + UniformTexelBufferArrayNonUniformIndexingEXT = () + StorageTexelBufferArrayNonUniformIndexing = () + StorageTexelBufferArrayNonUniformIndexingEXT = () + RayTracingNV = () + RayTracingMotionBlurNV = () + VulkanMemoryModel = () + VulkanMemoryModelKHR = () + VulkanMemoryModelDeviceScope = () + VulkanMemoryModelDeviceScopeKHR = () + PhysicalStorageBufferAddresses = () + PhysicalStorageBufferAddressesEXT = () + ComputeDerivativeGroupLinearNV = () + RayTracingProvisionalKHR = () + CooperativeMatrixNV = () + FragmentShaderSampleInterlockEXT = () + FragmentShaderShadingRateInterlockEXT = () + ShaderSMBuiltinsNV = () + FragmentShaderPixelInterlockEXT = () + DemoteToHelperInvocation = () + DemoteToHelperInvocationEXT = () + BindlessTextureNV = () + SubgroupShuffleINTEL = () + SubgroupBufferBlockIOINTEL = () + SubgroupImageBlockIOINTEL = () + SubgroupImageMediaBlockIOINTEL = () + RoundToInfinityINTEL = () + FloatingPointModeINTEL = () + IntegerFunctions2INTEL = () + FunctionPointersINTEL = () + IndirectReferencesINTEL = () + AsmINTEL = () + AtomicFloat32MinMaxEXT = () + AtomicFloat64MinMaxEXT = () + AtomicFloat16MinMaxEXT = () + VectorComputeINTEL = () + VectorAnyINTEL = () + ExpectAssumeKHR = () + SubgroupAvcMotionEstimationINTEL = () + SubgroupAvcMotionEstimationIntraINTEL = () + SubgroupAvcMotionEstimationChromaINTEL = () + VariableLengthArrayINTEL = () + FunctionFloatControlINTEL = () + FPGAMemoryAttributesINTEL = () + FPFastMathModeINTEL = () + ArbitraryPrecisionIntegersINTEL = () + ArbitraryPrecisionFloatingPointINTEL = () + UnstructuredLoopControlsINTEL = () + FPGALoopControlsINTEL = () + KernelAttributesINTEL = () + FPGAKernelAttributesINTEL = () + FPGAMemoryAccessesINTEL = () + FPGAClusterAttributesINTEL = () + LoopFuseINTEL = () + FPGABufferLocationINTEL = () + ArbitraryPrecisionFixedPointINTEL = () + USMStorageClassesINTEL = () + IOPipesINTEL = () + BlockingPipesINTEL = () + FPGARegINTEL = () + DotProductInputAll = () + DotProductInputAllKHR = () + DotProductInput4x8Bit = () + DotProductInput4x8BitKHR = () + DotProductInput4x8BitPacked = () + DotProductInput4x8BitPackedKHR = () + DotProduct = () + DotProductKHR = () + BitInstructions = () + AtomicFloat32AddEXT = () + AtomicFloat64AddEXT = () + LongConstantCompositeINTEL = () + OptNoneINTEL = () + AtomicFloat16AddEXT = () + DebugInfoModuleINTEL = () class RayFlagsShift(SPIRVEnum): - OpaqueKHR = 0 - NoOpaqueKHR = 1 - TerminateOnFirstHitKHR = 2 - SkipClosestHitShaderKHR = 3 - CullBackFacingTrianglesKHR = 4 - CullFrontFacingTrianglesKHR = 5 - CullOpaqueKHR = 6 - CullNoOpaqueKHR = 7 - SkipTrianglesKHR = 8 - SkipAABBsKHR = 9 + OpaqueKHR = () + NoOpaqueKHR = () + TerminateOnFirstHitKHR = () + SkipClosestHitShaderKHR = () + CullBackFacingTrianglesKHR = () + CullFrontFacingTrianglesKHR = () + CullOpaqueKHR = () + CullNoOpaqueKHR = () + SkipTrianglesKHR = () + SkipAABBsKHR = () class RayFlagsMask(SPIRVEnum): - MaskNone = 0 - OpaqueKHR = 1 - NoOpaqueKHR = 2 - TerminateOnFirstHitKHR = 4 - SkipClosestHitShaderKHR = 8 - CullBackFacingTrianglesKHR = 16 - CullFrontFacingTrianglesKHR = 32 - CullOpaqueKHR = 64 - CullNoOpaqueKHR = 128 - SkipTrianglesKHR = 256 - SkipAABBsKHR = 512 + MaskNone = () + OpaqueKHR = () + NoOpaqueKHR = () + TerminateOnFirstHitKHR = () + SkipClosestHitShaderKHR = () + CullBackFacingTrianglesKHR = () + CullFrontFacingTrianglesKHR = () + CullOpaqueKHR = () + CullNoOpaqueKHR = () + SkipTrianglesKHR = () + SkipAABBsKHR = () class RayQueryIntersection(SPIRVEnum): - RayQueryCandidateIntersectionKHR = 0 - RayQueryCommittedIntersectionKHR = 1 + RayQueryCandidateIntersectionKHR = () + RayQueryCommittedIntersectionKHR = () class RayQueryCommittedIntersectionType(SPIRVEnum): - RayQueryCommittedIntersectionNoneKHR = 0 - RayQueryCommittedIntersectionTriangleKHR = 1 - RayQueryCommittedIntersectionGeneratedKHR = 2 + RayQueryCommittedIntersectionNoneKHR = () + RayQueryCommittedIntersectionTriangleKHR = () + RayQueryCommittedIntersectionGeneratedKHR = () class RayQueryCandidateIntersectionType(SPIRVEnum): - RayQueryCandidateIntersectionTriangleKHR = 0 - RayQueryCandidateIntersectionAABBKHR = 1 + RayQueryCandidateIntersectionTriangleKHR = () + RayQueryCandidateIntersectionAABBKHR = () class FragmentShadingRateShift(SPIRVEnum): - Vertical2Pixels = 0 - Vertical4Pixels = 1 - Horizontal2Pixels = 2 - Horizontal4Pixels = 3 + Vertical2Pixels = () + Vertical4Pixels = () + Horizontal2Pixels = () + Horizontal4Pixels = () class FragmentShadingRateMask(SPIRVEnum): - MaskNone = 0 - Vertical2Pixels = 1 - Vertical4Pixels = 2 - Horizontal2Pixels = 4 - Horizontal4Pixels = 8 + MaskNone = () + Vertical2Pixels = () + Vertical4Pixels = () + Horizontal2Pixels = () + Horizontal4Pixels = () class FPDenormMode(SPIRVEnum): - Preserve = 0 - FlushToZero = 1 + Preserve = () + FlushToZero = () class FPOperationMode(SPIRVEnum): - IEEE = 0 - ALT = 1 + IEEE = () + ALT = () class QuantizationModes(SPIRVEnum): - TRN = 0 - TRN_ZERO = 1 - RND = 2 - RND_ZERO = 3 - RND_INF = 4 - RND_MIN_INF = 5 - RND_CONV = 6 - RND_CONV_ODD = 7 + TRN = () + TRN_ZERO = () + RND = () + RND_ZERO = () + RND_INF = () + RND_MIN_INF = () + RND_CONV = () + RND_CONV_ODD = () class OverflowModes(SPIRVEnum): - WRAP = 0 - SAT = 1 - SAT_ZERO = 2 - SAT_SYM = 3 + WRAP = () + SAT = () + SAT_ZERO = () + SAT_SYM = () class PackedVectorFormat(SPIRVEnum): - PackedVectorFormat4x8Bit = 0 - PackedVectorFormat4x8BitKHR = 0 - - -Op = ( - { - "OpNop": 0, - "OpUndef": 1, - "OpSourceContinued": 2, - "OpSource": 3, - "OpSourceExtension": 4, - "OpName": 5, - "OpMemberName": 6, - "OpString": 7, - "OpLine": 8, - "OpExtension": 10, - "OpExtInstImport": 11, - "OpExtInst": 12, - "OpMemoryModel": 14, - "OpEntryPoint": 15, - "OpExecutionMode": 16, - "OpCapability": 17, - "OpTypeVoid": 19, - "OpTypeBool": 20, - "OpTypeInt": 21, - "OpTypeFloat": 22, - "OpTypeVector": 23, - "OpTypeMatrix": 24, - "OpTypeImage": 25, - "OpTypeSampler": 26, - "OpTypeSampledImage": 27, - "OpTypeArray": 28, - "OpTypeRuntimeArray": 29, - "OpTypeStruct": 30, - "OpTypeOpaque": 31, - "OpTypePointer": 32, - "OpTypeFunction": 33, - "OpTypeEvent": 34, - "OpTypeDeviceEvent": 35, - "OpTypeReserveId": 36, - "OpTypeQueue": 37, - "OpTypePipe": 38, - "OpTypeForwardPointer": 39, - "OpConstantTrue": 41, - "OpConstantFalse": 42, - "OpConstant": 43, - "OpConstantComposite": 44, - "OpConstantSampler": 45, - "OpConstantNull": 46, - "OpSpecConstantTrue": 48, - "OpSpecConstantFalse": 49, - "OpSpecConstant": 50, - "OpSpecConstantComposite": 51, - "OpSpecConstantOp": 52, - "OpFunction": 54, - "OpFunctionParameter": 55, - "OpFunctionEnd": 56, - "OpFunctionCall": 57, - "OpVariable": 59, - "OpImageTexelPointer": 60, - "OpLoad": 61, - "OpStore": 62, - "OpCopyMemory": 63, - "OpCopyMemorySized": 64, - "OpAccessChain": 65, - "OpInBoundsAccessChain": 66, - "OpPtrAccessChain": 67, - "OpArrayLength": 68, - "OpGenericPtrMemSemantics": 69, - "OpInBoundsPtrAccessChain": 70, - "OpDecorate": 71, - "OpMemberDecorate": 72, - "OpDecorationGroup": 73, - "OpGroupDecorate": 74, - "OpGroupMemberDecorate": 75, - "OpVectorExtractDynamic": 77, - "OpVectorInsertDynamic": 78, - "OpVectorShuffle": 79, - "OpCompositeConstruct": 80, - "OpCompositeExtract": 81, - "OpCompositeInsert": 82, - "OpCopyObject": 83, - "OpTranspose": 84, - "OpSampledImage": 86, - "OpImageSampleImplicitLod": 87, - "OpImageSampleExplicitLod": 88, - "OpImageSampleDrefImplicitLod": 89, - "OpImageSampleDrefExplicitLod": 90, - "OpImageSampleProjImplicitLod": 91, - "OpImageSampleProjExplicitLod": 92, - "OpImageSampleProjDrefImplicitLod": 93, - "OpImageSampleProjDrefExplicitLod": 94, - "OpImageFetch": 95, - "OpImageGather": 96, - "OpImageDrefGather": 97, - "OpImageRead": 98, - "OpImageWrite": 99, - "OpImage": 100, - "OpImageQueryFormat": 101, - "OpImageQueryOrder": 102, - "OpImageQuerySizeLod": 103, - "OpImageQuerySize": 104, - "OpImageQueryLod": 105, - "OpImageQueryLevels": 106, - "OpImageQuerySamples": 107, - "OpConvertFToU": 109, - "OpConvertFToS": 110, - "OpConvertSToF": 111, - "OpConvertUToF": 112, - "OpUConvert": 113, - "OpSConvert": 114, - "OpFConvert": 115, - "OpQuantizeToF16": 116, - "OpConvertPtrToU": 117, - "OpSatConvertSToU": 118, - "OpSatConvertUToS": 119, - "OpConvertUToPtr": 120, - "OpPtrCastToGeneric": 121, - "OpGenericCastToPtr": 122, - "OpGenericCastToPtrExplicit": 123, - "OpBitcast": 124, - "OpSNegate": 126, - "OpFNegate": 127, - "OpIAdd": 128, - "OpFAdd": 129, - "OpISub": 130, - "OpFSub": 131, - "OpIMul": 132, - "OpFMul": 133, - "OpUDiv": 134, - "OpSDiv": 135, - "OpFDiv": 136, - "OpUMod": 137, - "OpSRem": 138, - "OpSMod": 139, - "OpFRem": 140, - "OpFMod": 141, - "OpVectorTimesScalar": 142, - "OpMatrixTimesScalar": 143, - "OpVectorTimesMatrix": 144, - "OpMatrixTimesVector": 145, - "OpMatrixTimesMatrix": 146, - "OpOuterProduct": 147, - "OpDot": 148, - "OpIAddCarry": 149, - "OpISubBorrow": 150, - "OpUMulExtended": 151, - "OpSMulExtended": 152, - "OpAny": 154, - "OpAll": 155, - "OpIsNan": 156, - "OpIsInf": 157, - "OpIsFinite": 158, - "OpIsNormal": 159, - "OpSignBitSet": 160, - "OpLessOrGreater": 161, - "OpOrdered": 162, - "OpUnordered": 163, - "OpLogicalEqual": 164, - "OpLogicalNotEqual": 165, - "OpLogicalOr": 166, - "OpLogicalAnd": 167, - "OpLogicalNot": 168, - "OpSelect": 169, - "OpIEqual": 170, - "OpINotEqual": 171, - "OpUGreaterThan": 172, - "OpSGreaterThan": 173, - "OpUGreaterThanEqual": 174, - "OpSGreaterThanEqual": 175, - "OpULessThan": 176, - "OpSLessThan": 177, - "OpULessThanEqual": 178, - "OpSLessThanEqual": 179, - "OpFOrdEqual": 180, - "OpFUnordEqual": 181, - "OpFOrdNotEqual": 182, - "OpFUnordNotEqual": 183, - "OpFOrdLessThan": 184, - "OpFUnordLessThan": 185, - "OpFOrdGreaterThan": 186, - "OpFUnordGreaterThan": 187, - "OpFOrdLessThanEqual": 188, - "OpFUnordLessThanEqual": 189, - "OpFOrdGreaterThanEqual": 190, - "OpFUnordGreaterThanEqual": 191, - "OpShiftRightLogical": 194, - "OpShiftRightArithmetic": 195, - "OpShiftLeftLogical": 196, - "OpBitwiseOr": 197, - "OpBitwiseXor": 198, - "OpBitwiseAnd": 199, - "OpNot": 200, - "OpBitFieldInsert": 201, - "OpBitFieldSExtract": 202, - "OpBitFieldUExtract": 203, - "OpBitReverse": 204, - "OpBitCount": 205, - "OpDPdx": 207, - "OpDPdy": 208, - "OpFwidth": 209, - "OpDPdxFine": 210, - "OpDPdyFine": 211, - "OpFwidthFine": 212, - "OpDPdxCoarse": 213, - "OpDPdyCoarse": 214, - "OpFwidthCoarse": 215, - "OpEmitVertex": 218, - "OpEndPrimitive": 219, - "OpEmitStreamVertex": 220, - "OpEndStreamPrimitive": 221, - "OpControlBarrier": 224, - "OpMemoryBarrier": 225, - "OpAtomicLoad": 227, - "OpAtomicStore": 228, - "OpAtomicExchange": 229, - "OpAtomicCompareExchange": 230, - "OpAtomicCompareExchangeWeak": 231, - "OpAtomicIIncrement": 232, - "OpAtomicIDecrement": 233, - "OpAtomicIAdd": 234, - "OpAtomicISub": 235, - "OpAtomicSMin": 236, - "OpAtomicUMin": 237, - "OpAtomicSMax": 238, - "OpAtomicUMax": 239, - "OpAtomicAnd": 240, - "OpAtomicOr": 241, - "OpAtomicXor": 242, - "OpPhi": 245, - "OpLoopMerge": 246, - "OpSelectionMerge": 247, - "OpLabel": 248, - "OpBranch": 249, - "OpBranchConditional": 250, - "OpSwitch": 251, - "OpKill": 252, - "OpReturn": 253, - "OpReturnValue": 254, - "OpUnreachable": 255, - "OpLifetimeStart": 256, - "OpLifetimeStop": 257, - "OpGroupAsyncCopy": 259, - "OpGroupWaitEvents": 260, - "OpGroupAll": 261, - "OpGroupAny": 262, - "OpGroupBroadcast": 263, - "OpGroupIAdd": 264, - "OpGroupFAdd": 265, - "OpGroupFMin": 266, - "OpGroupUMin": 267, - "OpGroupSMin": 268, - "OpGroupFMax": 269, - "OpGroupUMax": 270, - "OpGroupSMax": 271, - "OpReadPipe": 274, - "OpWritePipe": 275, - "OpReservedReadPipe": 276, - "OpReservedWritePipe": 277, - "OpReserveReadPipePackets": 278, - "OpReserveWritePipePackets": 279, - "OpCommitReadPipe": 280, - "OpCommitWritePipe": 281, - "OpIsValidReserveId": 282, - "OpGetNumPipePackets": 283, - "OpGetMaxPipePackets": 284, - "OpGroupReserveReadPipePackets": 285, - "OpGroupReserveWritePipePackets": 286, - "OpGroupCommitReadPipe": 287, - "OpGroupCommitWritePipe": 288, - "OpEnqueueMarker": 291, - "OpEnqueueKernel": 292, - "OpGetKernelNDrangeSubGroupCount": 293, - "OpGetKernelNDrangeMaxSubGroupSize": 294, - "OpGetKernelWorkGroupSize": 295, - "OpGetKernelPreferredWorkGroupSizeMultiple": 296, - "OpRetainEvent": 297, - "OpReleaseEvent": 298, - "OpCreateUserEvent": 299, - "OpIsValidEvent": 300, - "OpSetUserEventStatus": 301, - "OpCaptureEventProfilingInfo": 302, - "OpGetDefaultQueue": 303, - "OpBuildNDRange": 304, - "OpImageSparseSampleImplicitLod": 305, - "OpImageSparseSampleExplicitLod": 306, - "OpImageSparseSampleDrefImplicitLod": 307, - "OpImageSparseSampleDrefExplicitLod": 308, - "OpImageSparseSampleProjImplicitLod": 309, - "OpImageSparseSampleProjExplicitLod": 310, - "OpImageSparseSampleProjDrefImplicitLod": 311, - "OpImageSparseSampleProjDrefExplicitLod": 312, - "OpImageSparseFetch": 313, - "OpImageSparseGather": 314, - "OpImageSparseDrefGather": 315, - "OpImageSparseTexelsResident": 316, - "OpNoLine": 317, - "OpAtomicFlagTestAndSet": 318, - "OpAtomicFlagClear": 319, - "OpImageSparseRead": 320, - "OpSizeOf": 321, - "OpTypePipeStorage": 322, - "OpConstantPipeStorage": 323, - "OpCreatePipeFromPipeStorage": 324, - "OpGetKernelLocalSizeForSubgroupCount": 325, - "OpGetKernelMaxNumSubgroups": 326, - "OpTypeNamedBarrier": 327, - "OpNamedBarrierInitialize": 328, - "OpMemoryNamedBarrier": 329, - "OpModuleProcessed": 330, - "OpExecutionModeId": 331, - "OpDecorateId": 332, - "OpGroupNonUniformElect": 333, - "OpGroupNonUniformAll": 334, - "OpGroupNonUniformAny": 335, - "OpGroupNonUniformAllEqual": 336, - "OpGroupNonUniformBroadcast": 337, - "OpGroupNonUniformBroadcastFirst": 338, - "OpGroupNonUniformBallot": 339, - "OpGroupNonUniformInverseBallot": 340, - "OpGroupNonUniformBallotBitExtract": 341, - "OpGroupNonUniformBallotBitCount": 342, - "OpGroupNonUniformBallotFindLSB": 343, - "OpGroupNonUniformBallotFindMSB": 344, - "OpGroupNonUniformShuffle": 345, - "OpGroupNonUniformShuffleXor": 346, - "OpGroupNonUniformShuffleUp": 347, - "OpGroupNonUniformShuffleDown": 348, - "OpGroupNonUniformIAdd": 349, - "OpGroupNonUniformFAdd": 350, - "OpGroupNonUniformIMul": 351, - "OpGroupNonUniformFMul": 352, - "OpGroupNonUniformSMin": 353, - "OpGroupNonUniformUMin": 354, - "OpGroupNonUniformFMin": 355, - "OpGroupNonUniformSMax": 356, - "OpGroupNonUniformUMax": 357, - "OpGroupNonUniformFMax": 358, - "OpGroupNonUniformBitwiseAnd": 359, - "OpGroupNonUniformBitwiseOr": 360, - "OpGroupNonUniformBitwiseXor": 361, - "OpGroupNonUniformLogicalAnd": 362, - "OpGroupNonUniformLogicalOr": 363, - "OpGroupNonUniformLogicalXor": 364, - "OpGroupNonUniformQuadBroadcast": 365, - "OpGroupNonUniformQuadSwap": 366, - "OpCopyLogical": 400, - "OpPtrEqual": 401, - "OpPtrNotEqual": 402, - "OpPtrDiff": 403, - "OpTerminateInvocation": 4416, - "OpSubgroupBallotKHR": 4421, - "OpSubgroupFirstInvocationKHR": 4422, - "OpSubgroupAllKHR": 4428, - "OpSubgroupAnyKHR": 4429, - "OpSubgroupAllEqualKHR": 4430, - "OpSubgroupReadInvocationKHR": 4432, - "OpTraceRayKHR": 4445, - "OpExecuteCallableKHR": 4446, - "OpConvertUToAccelerationStructureKHR": 4447, - "OpIgnoreIntersectionKHR": 4448, - "OpTerminateRayKHR": 4449, - "OpSDot": 4450, - "OpSDotKHR": 4450, - "OpUDot": 4451, - "OpUDotKHR": 4451, - "OpSUDot": 4452, - "OpSUDotKHR": 4452, - "OpSDotAccSat": 4453, - "OpSDotAccSatKHR": 4453, - "OpUDotAccSat": 4454, - "OpUDotAccSatKHR": 4454, - "OpSUDotAccSat": 4455, - "OpSUDotAccSatKHR": 4455, - "OpTypeRayQueryKHR": 4472, - "OpRayQueryInitializeKHR": 4473, - "OpRayQueryTerminateKHR": 4474, - "OpRayQueryGenerateIntersectionKHR": 4475, - "OpRayQueryConfirmIntersectionKHR": 4476, - "OpRayQueryProceedKHR": 4477, - "OpRayQueryGetIntersectionTypeKHR": 4479, - "OpGroupIAddNonUniformAMD": 5000, - "OpGroupFAddNonUniformAMD": 5001, - "OpGroupFMinNonUniformAMD": 5002, - "OpGroupUMinNonUniformAMD": 5003, - "OpGroupSMinNonUniformAMD": 5004, - "OpGroupFMaxNonUniformAMD": 5005, - "OpGroupUMaxNonUniformAMD": 5006, - "OpGroupSMaxNonUniformAMD": 5007, - "OpFragmentMaskFetchAMD": 5011, - "OpFragmentFetchAMD": 5012, - "OpReadClockKHR": 5056, - "OpImageSampleFootprintNV": 5283, - "OpGroupNonUniformPartitionNV": 5296, - "OpWritePackedPrimitiveIndices4x8NV": 5299, - "OpReportIntersectionKHR": 5334, - "OpReportIntersectionNV": 5334, - "OpIgnoreIntersectionNV": 5335, - "OpTerminateRayNV": 5336, - "OpTraceNV": 5337, - "OpTraceMotionNV": 5338, - "OpTraceRayMotionNV": 5339, - "OpTypeAccelerationStructureKHR": 5341, - "OpTypeAccelerationStructureNV": 5341, - "OpExecuteCallableNV": 5344, - "OpTypeCooperativeMatrixNV": 5358, - "OpCooperativeMatrixLoadNV": 5359, - "OpCooperativeMatrixStoreNV": 5360, - "OpCooperativeMatrixMulAddNV": 5361, - "OpCooperativeMatrixLengthNV": 5362, - "OpBeginInvocationInterlockEXT": 5364, - "OpEndInvocationInterlockEXT": 5365, - "OpDemoteToHelperInvocation": 5380, - "OpDemoteToHelperInvocationEXT": 5380, - "OpIsHelperInvocationEXT": 5381, - "OpConvertUToImageNV": 5391, - "OpConvertUToSamplerNV": 5392, - "OpConvertImageToUNV": 5393, - "OpConvertSamplerToUNV": 5394, - "OpConvertUToSampledImageNV": 5395, - "OpConvertSampledImageToUNV": 5396, - "OpSamplerImageAddressingModeNV": 5397, - "OpSubgroupShuffleINTEL": 5571, - "OpSubgroupShuffleDownINTEL": 5572, - "OpSubgroupShuffleUpINTEL": 5573, - "OpSubgroupShuffleXorINTEL": 5574, - "OpSubgroupBlockReadINTEL": 5575, - "OpSubgroupBlockWriteINTEL": 5576, - "OpSubgroupImageBlockReadINTEL": 5577, - "OpSubgroupImageBlockWriteINTEL": 5578, - "OpSubgroupImageMediaBlockReadINTEL": 5580, - "OpSubgroupImageMediaBlockWriteINTEL": 5581, - "OpUCountLeadingZerosINTEL": 5585, - "OpUCountTrailingZerosINTEL": 5586, - "OpAbsISubINTEL": 5587, - "OpAbsUSubINTEL": 5588, - "OpIAddSatINTEL": 5589, - "OpUAddSatINTEL": 5590, - "OpIAverageINTEL": 5591, - "OpUAverageINTEL": 5592, - "OpIAverageRoundedINTEL": 5593, - "OpUAverageRoundedINTEL": 5594, - "OpISubSatINTEL": 5595, - "OpUSubSatINTEL": 5596, - "OpIMul32x16INTEL": 5597, - "OpUMul32x16INTEL": 5598, - "OpConstantFunctionPointerINTEL": 5600, - "OpFunctionPointerCallINTEL": 5601, - "OpAsmTargetINTEL": 5609, - "OpAsmINTEL": 5610, - "OpAsmCallINTEL": 5611, - "OpAtomicFMinEXT": 5614, - "OpAtomicFMaxEXT": 5615, - "OpAssumeTrueKHR": 5630, - "OpExpectKHR": 5631, - "OpDecorateString": 5632, - "OpDecorateStringGOOGLE": 5632, - "OpMemberDecorateString": 5633, - "OpMemberDecorateStringGOOGLE": 5633, - "OpVmeImageINTEL": 5699, - "OpTypeVmeImageINTEL": 5700, - "OpTypeAvcImePayloadINTEL": 5701, - "OpTypeAvcRefPayloadINTEL": 5702, - "OpTypeAvcSicPayloadINTEL": 5703, - "OpTypeAvcMcePayloadINTEL": 5704, - "OpTypeAvcMceResultINTEL": 5705, - "OpTypeAvcImeResultINTEL": 5706, - "OpTypeAvcImeResultSingleReferenceStreamoutINTEL": 5707, - "OpTypeAvcImeResultDualReferenceStreamoutINTEL": 5708, - "OpTypeAvcImeSingleReferenceStreaminINTEL": 5709, - "OpTypeAvcImeDualReferenceStreaminINTEL": 5710, - "OpTypeAvcRefResultINTEL": 5711, - "OpTypeAvcSicResultINTEL": 5712, - "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL": 5713, - "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL": 5714, - "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL": 5715, - "OpSubgroupAvcMceSetInterShapePenaltyINTEL": 5716, - "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL": 5717, - "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL": 5718, - "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL": 5719, - "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL": 5720, - "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL": 5721, - "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL": 5722, - "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL": 5723, - "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL": 5724, - "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL": 5725, - "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL": 5726, - "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL": 5727, - "OpSubgroupAvcMceSetAcOnlyHaarINTEL": 5728, - "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL": 5729, - "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL": 5730, - "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL": 5731, - "OpSubgroupAvcMceConvertToImePayloadINTEL": 5732, - "OpSubgroupAvcMceConvertToImeResultINTEL": 5733, - "OpSubgroupAvcMceConvertToRefPayloadINTEL": 5734, - "OpSubgroupAvcMceConvertToRefResultINTEL": 5735, - "OpSubgroupAvcMceConvertToSicPayloadINTEL": 5736, - "OpSubgroupAvcMceConvertToSicResultINTEL": 5737, - "OpSubgroupAvcMceGetMotionVectorsINTEL": 5738, - "OpSubgroupAvcMceGetInterDistortionsINTEL": 5739, - "OpSubgroupAvcMceGetBestInterDistortionsINTEL": 5740, - "OpSubgroupAvcMceGetInterMajorShapeINTEL": 5741, - "OpSubgroupAvcMceGetInterMinorShapeINTEL": 5742, - "OpSubgroupAvcMceGetInterDirectionsINTEL": 5743, - "OpSubgroupAvcMceGetInterMotionVectorCountINTEL": 5744, - "OpSubgroupAvcMceGetInterReferenceIdsINTEL": 5745, - "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL": 5746, - "OpSubgroupAvcImeInitializeINTEL": 5747, - "OpSubgroupAvcImeSetSingleReferenceINTEL": 5748, - "OpSubgroupAvcImeSetDualReferenceINTEL": 5749, - "OpSubgroupAvcImeRefWindowSizeINTEL": 5750, - "OpSubgroupAvcImeAdjustRefOffsetINTEL": 5751, - "OpSubgroupAvcImeConvertToMcePayloadINTEL": 5752, - "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL": 5753, - "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL": 5754, - "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL": 5755, - "OpSubgroupAvcImeSetWeightedSadINTEL": 5756, - "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL": 5757, - "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL": 5758, - "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL": 5759, - "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL": 5760, - "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL": 5761, - "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL": 5762, - "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL": 5763, - "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL": 5764, - "OpSubgroupAvcImeConvertToMceResultINTEL": 5765, - "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL": 5766, - "OpSubgroupAvcImeGetDualReferenceStreaminINTEL": 5767, - "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL": 5768, - "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL": 5769, - "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL": 5770, - "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL": 5771, - "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL": 5772, - "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL": 5773, - "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL": 5774, - "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL": 5775, - "OpSubgroupAvcImeGetBorderReachedINTEL": 5776, - "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL": 5777, - "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL": 5778, - "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL": 5779, - "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL": 5780, - "OpSubgroupAvcFmeInitializeINTEL": 5781, - "OpSubgroupAvcBmeInitializeINTEL": 5782, - "OpSubgroupAvcRefConvertToMcePayloadINTEL": 5783, - "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL": 5784, - "OpSubgroupAvcRefSetBilinearFilterEnableINTEL": 5785, - "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL": 5786, - "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL": 5787, - "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL": 5788, - "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL": 5789, - "OpSubgroupAvcRefConvertToMceResultINTEL": 5790, - "OpSubgroupAvcSicInitializeINTEL": 5791, - "OpSubgroupAvcSicConfigureSkcINTEL": 5792, - "OpSubgroupAvcSicConfigureIpeLumaINTEL": 5793, - "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL": 5794, - "OpSubgroupAvcSicGetMotionVectorMaskINTEL": 5795, - "OpSubgroupAvcSicConvertToMcePayloadINTEL": 5796, - "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL": 5797, - "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL": 5798, - "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL": 5799, - "OpSubgroupAvcSicSetBilinearFilterEnableINTEL": 5800, - "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL": 5801, - "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL": 5802, - "OpSubgroupAvcSicEvaluateIpeINTEL": 5803, - "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL": 5804, - "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL": 5805, - "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL": 5806, - "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL": 5807, - "OpSubgroupAvcSicConvertToMceResultINTEL": 5808, - "OpSubgroupAvcSicGetIpeLumaShapeINTEL": 5809, - "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL": 5810, - "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL": 5811, - "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL": 5812, - "OpSubgroupAvcSicGetIpeChromaModeINTEL": 5813, - "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL": 5814, - "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL": 5815, - "OpSubgroupAvcSicGetInterRawSadsINTEL": 5816, - "OpVariableLengthArrayINTEL": 5818, - "OpSaveMemoryINTEL": 5819, - "OpRestoreMemoryINTEL": 5820, - "OpArbitraryFloatSinCosPiINTEL": 5840, - "OpArbitraryFloatCastINTEL": 5841, - "OpArbitraryFloatCastFromIntINTEL": 5842, - "OpArbitraryFloatCastToIntINTEL": 5843, - "OpArbitraryFloatAddINTEL": 5846, - "OpArbitraryFloatSubINTEL": 5847, - "OpArbitraryFloatMulINTEL": 5848, - "OpArbitraryFloatDivINTEL": 5849, - "OpArbitraryFloatGTINTEL": 5850, - "OpArbitraryFloatGEINTEL": 5851, - "OpArbitraryFloatLTINTEL": 5852, - "OpArbitraryFloatLEINTEL": 5853, - "OpArbitraryFloatEQINTEL": 5854, - "OpArbitraryFloatRecipINTEL": 5855, - "OpArbitraryFloatRSqrtINTEL": 5856, - "OpArbitraryFloatCbrtINTEL": 5857, - "OpArbitraryFloatHypotINTEL": 5858, - "OpArbitraryFloatSqrtINTEL": 5859, - "OpArbitraryFloatLogINTEL": 5860, - "OpArbitraryFloatLog2INTEL": 5861, - "OpArbitraryFloatLog10INTEL": 5862, - "OpArbitraryFloatLog1pINTEL": 5863, - "OpArbitraryFloatExpINTEL": 5864, - "OpArbitraryFloatExp2INTEL": 5865, - "OpArbitraryFloatExp10INTEL": 5866, - "OpArbitraryFloatExpm1INTEL": 5867, - "OpArbitraryFloatSinINTEL": 5868, - "OpArbitraryFloatCosINTEL": 5869, - "OpArbitraryFloatSinCosINTEL": 5870, - "OpArbitraryFloatSinPiINTEL": 5871, - "OpArbitraryFloatCosPiINTEL": 5872, - "OpArbitraryFloatASinINTEL": 5873, - "OpArbitraryFloatASinPiINTEL": 5874, - "OpArbitraryFloatACosINTEL": 5875, - "OpArbitraryFloatACosPiINTEL": 5876, - "OpArbitraryFloatATanINTEL": 5877, - "OpArbitraryFloatATanPiINTEL": 5878, - "OpArbitraryFloatATan2INTEL": 5879, - "OpArbitraryFloatPowINTEL": 5880, - "OpArbitraryFloatPowRINTEL": 5881, - "OpArbitraryFloatPowNINTEL": 5882, - "OpLoopControlINTEL": 5887, - "OpFixedSqrtINTEL": 5923, - "OpFixedRecipINTEL": 5924, - "OpFixedRsqrtINTEL": 5925, - "OpFixedSinINTEL": 5926, - "OpFixedCosINTEL": 5927, - "OpFixedSinCosINTEL": 5928, - "OpFixedSinPiINTEL": 5929, - "OpFixedCosPiINTEL": 5930, - "OpFixedSinCosPiINTEL": 5931, - "OpFixedLogINTEL": 5932, - "OpFixedExpINTEL": 5933, - "OpPtrCastToCrossWorkgroupINTEL": 5934, - "OpCrossWorkgroupCastToPtrINTEL": 5938, - "OpReadPipeBlockingINTEL": 5946, - "OpWritePipeBlockingINTEL": 5947, - "OpFPGARegINTEL": 5949, - "OpRayQueryGetRayTMinKHR": 6016, - "OpRayQueryGetRayFlagsKHR": 6017, - "OpRayQueryGetIntersectionTKHR": 6018, - "OpRayQueryGetIntersectionInstanceCustomIndexKHR": 6019, - "OpRayQueryGetIntersectionInstanceIdKHR": 6020, - "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR": 6021, - "OpRayQueryGetIntersectionGeometryIndexKHR": 6022, - "OpRayQueryGetIntersectionPrimitiveIndexKHR": 6023, - "OpRayQueryGetIntersectionBarycentricsKHR": 6024, - "OpRayQueryGetIntersectionFrontFaceKHR": 6025, - "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR": 6026, - "OpRayQueryGetIntersectionObjectRayDirectionKHR": 6027, - "OpRayQueryGetIntersectionObjectRayOriginKHR": 6028, - "OpRayQueryGetWorldRayDirectionKHR": 6029, - "OpRayQueryGetWorldRayOriginKHR": 6030, - "OpRayQueryGetIntersectionObjectToWorldKHR": 6031, - "OpRayQueryGetIntersectionWorldToObjectKHR": 6032, - "OpAtomicFAddEXT": 6035, - "OpTypeBufferSurfaceINTEL": 6086, - "OpTypeStructContinuedINTEL": 6090, - "OpConstantCompositeContinuedINTEL": 6091, - "OpSpecConstantCompositeContinuedINTEL": 6092, - }, -) + PackedVectorFormat4x8Bit = () + PackedVectorFormat4x8BitKHR = () class GLSLOpcodes(SPIRVEnum): - Round = 1 - RoundEven = 2 - Trunc = 3 - FAbs = 4 - SAbs = 5 - FSign = 6 - SSign = 7 - Floor = 8 - Ceil = 9 - Fract = 10 - Radians = 11 - Degrees = 12 - Sin = 13 - Cos = 14 - Tan = 15 - Asin = 16 - Acos = 17 - Atan = 18 - Sinh = 19 - Cosh = 20 - Tanh = 21 - Asinh = 22 - Acosh = 23 - Atanh = 24 - Atan2 = 25 - Pow = 26 - Exp = 27 - Log = 28 - Exp2 = 29 - Log2 = 30 - Sqrt = 31 - InverseSqrt = 32 - Determinant = 33 - MatrixInverse = 34 - Modf = 35 - ModfStruct = 36 - FMin = 37 - UMin = 38 - SMin = 39 - Fmax = 40 - UMax = 41 - SMax = 42 - FClamp = 43 - UClamp = 44 - SClamp = 45 - FMix = 46 - UNDEF = 47 # Why is this not defined in the spec? - Step = 48 - SmoothStep = 49 - Fma = 50 - Frexp = 51 - FrexpStruct = 52 - Ldexp = 53 - PackSnorm4x8 = 54 - PackUnorm4x8 = 55 - PackSnorm2x16 = 56 - PackUnorm2x16 = 57 - PackHalf2x16 = 58 - PackDouble2x32 = 59 - UnpackSnorm2x16 = 60 - UnpackUnorm2x16 = 61 - UnpackHalf2x16 = 62 - UnpackSnorm4x8 = 63 - UnpackUnorm4x8 = 64 - UnpackDouble2x32 = 65 - Length = 66 - Distance = 67 - Cross = 68 - Normalize = 69 - FaceForward = 70 - Reflect = 71 - Refract = 72 - FindILsb = 73 - FindSMsb = 74 - FindUMsb = 75 - InterpolateAtCentroid = 76 - InterpolateAtSample = 77 - InterpolateAtOffset = 78 - NMin = 79 - NMax = 80 - NClamp = 81 + Round = () + RoundEven = () + Trunc = () + FAbs = () + SAbs = () + FSign = () + SSign = () + Floor = () + Ceil = () + Fract = () + Radians = () + Degrees = () + Sin = () + Cos = () + Tan = () + Asin = () + Acos = () + Atan = () + Sinh = () + Cosh = () + Tanh = () + Asinh = () + Acosh = () + Atanh = () + Atan2 = () + Pow = () + Exp = () + Log = () + Exp2 = () + Log2 = () + Sqrt = () + InverseSqrt = () + Determinant = () + MatrixInverse = () + Modf = () + ModfStruct = () + FMin = () + UMin = () + SMin = () + Fmax = () + UMax = () + SMax = () + FClamp = () + UClamp = () + SClamp = () + FMix = () + UNDEF = () # Why is this not defined in the spec? + Step = () + SmoothStep = () + Fma = () + Frexp = () + FrexpStruct = () + Ldexp = () + PackSnorm4x8 = () + PackUnorm4x8 = () + PackSnorm2x16 = () + PackUnorm2x16 = () + PackHalf2x16 = () + PackDouble2x32 = () + UnpackSnorm2x16 = () + UnpackUnorm2x16 = () + UnpackHalf2x16 = () + UnpackSnorm4x8 = () + UnpackUnorm4x8 = () + UnpackDouble2x32 = () + Length = () + Distance = () + Cross = () + Normalize = () + FaceForward = () + Reflect = () + Refract = () + FindILsb = () + FindSMsb = () + FindUMsb = () + InterpolateAtCentroid = () + InterpolateAtSample = () + InterpolateAtOffset = () + NMin = () + NMax = () + NClamp = () diff --git a/src/extension.py b/src/extension.py index 041b644..30f6eb8 100644 --- a/src/extension.py +++ b/src/extension.py @@ -1,23 +1,21 @@ from src import OpCode from src import Statement -from src import Type from src import VoidOp -from utils.patched_dataclass import dataclass +from src.patched_dataclass import dataclass @dataclass -class OpExtension(OpCode, VoidOp): - name: str = None +class OpExtension(VoidOp): + name: str @dataclass class OpExtInstImport(OpCode): - name: str = None + name: str @dataclass class OpExtInst(Statement): - type: Type = None - extension_set: OpExtInstImport = None - instruction: OpCode = None - operands: tuple[Statement] = None + extension_set: OpExtInstImport + instruction: OpCode + operands: tuple[OpCode, ...] diff --git a/src/function.py b/src/function.py index 4ff933d..99d4f7a 100644 --- a/src/function.py +++ b/src/function.py @@ -1,8 +1,13 @@ import random +from ast import Constant from typing import Optional from typing import TYPE_CHECKING -from src import FuzzLeaf +from typing_extensions import Self + +from src import AbortFuzzing +from src import FuzzLeafMixin +from src import FuzzResult from src import OpCode from src import Untyped from src import VoidOp @@ -12,86 +17,97 @@ if TYPE_CHECKING: from src.context import Context from src.operators.memory.memory_access import OpVariable, Statement -from src.types.concrete_types import OpTypeBool, OpTypeFunction, Type -from utils.patched_dataclass import dataclass +from src.types.concrete_types import ( + EmptyType, + OpTypeBool, + OpTypeFunction, + OpTypeVoid, + Type, +) +from src.patched_dataclass import dataclass +@dataclass class FunctionOperator(Statement): ... +@dataclass class OpFunction(OpCode): - context: "Context" = None - return_type: Type = None - function_control_mask: FunctionControlMask = None - function_type: OpTypeFunction = None - - def __init__( - self, - return_type: Type = None, - function_type: OpTypeFunction = None, - ) -> None: - self.return_type: Type = return_type - self.function_control_mask: FunctionControlMask = random.SystemRandom().choice( - list(FunctionControlMask) + return_type: Type + function_control_mask: FunctionControlMask + function_type: OpTypeFunction + + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + op_function: Self = cls( + context.current_function_type.return_type, + random.SystemRandom().choice(list(FunctionControlMask)), + context.current_function_type, + ) + child_context = context.make_child_context(op_function) + instructions: list[Statement] = fuzz_block(child_context, None) + return FuzzResult( + op_function, + [ + *instructions, + OpReturn.fuzz(child_context).opcode, + OpFunctionEnd.fuzz(child_context).opcode, + ], ) - self.function_type: OpTypeFunction = function_type - super().__init__() - - def fuzz(self, context: "Context") -> list[OpCode]: - self.context = context.make_child_context(self) - instructions: list[Statement] = fuzz_block(self.context, None) - return [ - self, - *instructions, - *OpReturn().fuzz(self.context), - *OpFunctionEnd().fuzz(self.context), - ] @dataclass -class OpFunctionParameter(FuzzLeaf): - type: Type = None +class OpFunctionParameter(FuzzLeafMixin): + type: Type -class OpFunctionEnd(FuzzLeaf, VoidOp): - pass +@dataclass +class OpFunctionEnd(FuzzLeafMixin, VoidOp): + ... -class OpReturn(FunctionOperator, OpCode, Untyped, VoidOp): +@dataclass +class OpReturn(FunctionOperator, Untyped, VoidOp): # operand: Statement = None - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: target_type = context.function.function_type.return_type # self.operand = None - return [self] + return FuzzResult(cls(type=EmptyType())) +@dataclass class OpFunctionCall(OpCode): - return_type: Type = None - function: OpFunction = None - arguments: list[OpCode] = None + return_type: Type + function: OpFunction + arguments: list[OpCode] -class OpLabel(FuzzLeaf, Untyped): - pass +@dataclass +class OpLabel(FuzzLeafMixin, Untyped, OpCode): + ... +@dataclass class ControlFlowOperator(Statement): ... +@dataclass class OpSelectionMerge(ControlFlowOperator, Untyped, VoidOp): - exit_label: OpLabel = None - selection_control: SelectionControlMask = None + exit_label: OpLabel + selection_control: SelectionControlMask - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: if context.get_depth() > context.config.limits.max_depth: - return [] - self.exit_label = OpLabel().fuzz(context)[0] - self.selection_control = SelectionControlMask.NONE - if_block = fuzz_block(context, self.exit_label) - else_block = fuzz_block(context, self.exit_label) + raise AbortFuzzing + exit_label = OpLabel.fuzz(context).opcode + selection_control = SelectionControlMask.NONE + if_block = fuzz_block(context, exit_label) + else_block = fuzz_block(context, exit_label) true_label = if_block[0] false_label = else_block[0] try: @@ -102,11 +118,18 @@ def fuzz(self, context: "Context") -> list[OpCode]: ) ) except IndexError: - return [] + raise AbortFuzzing op_branch = OpBranchConditional( condition=condition, true_label=true_label, false_label=false_label ) - return [self, op_branch, *if_block, *else_block, self.exit_label] + return FuzzResult( + cls( + type=EmptyType(), + exit_label=exit_label, + selection_control=selection_control, + ), + [op_branch, *if_block, *else_block, exit_label], + ) # class OpLoopMerge(ControlFlowOperator, Untyped, VoidOp): @@ -155,55 +178,56 @@ def fuzz(self, context: "Context") -> list[OpCode]: @dataclass -class OpBranchConditional(FuzzLeaf, Untyped, VoidOp): - condition: Statement = None - true_label: OpLabel = None - false_label: OpLabel = None +class OpBranchConditional(FuzzLeafMixin, Untyped, VoidOp): + condition: Statement + true_label: OpLabel + false_label: OpLabel @dataclass -class OpBranch(FuzzLeaf, Untyped, VoidOp): - label: OpLabel = None +class OpBranch(FuzzLeafMixin, Untyped, VoidOp): + label: OpLabel def fuzz_block(context: "Context", exit_label: Optional[OpLabel]) -> tuple[OpCode]: - block_label: OpLabel = OpLabel().fuzz(context)[0] + block_label: OpLabel = OpLabel.fuzz(context).opcode instructions: list[OpCode] = [] variables: list[OpVariable] = [] block_context = context.make_child_context() # TODO this is terrible, there must be a better way - import src.operators.arithmetic.scalar_arithmetic - import src.operators.arithmetic.linear_algebra - import src.operators.logic - import src.operators.bitwise - import src.operators.conversions - import src.operators.composite + # import src.operators.arithmetic.scalar_arithmetic + # import src.operators.arithmetic.linear_algebra + # import src.operators.logic + # import src.operators.bitwise + # import src.operators.conversions + # import src.operators.composite - if context.config.strategy.enable_ext_glsl_std_450: - import src.operators.arithmetic.glsl + # if context.config.strategy.enable_ext_glsl_std_450: + # import src.operators.arithmetic.glsl while random.SystemRandom().random() < context.config.strategy.p_statement: - opcodes: list[OpCode] = Statement().fuzz(block_context) + try: + fuzzed_opcode: FuzzResult = Statement.fuzz(block_context) + except AbortFuzzing: + continue nested_block = False - for statement in opcodes: - if isinstance(statement, OpSelectionMerge): - nested_block = True - break - if isinstance(statement, Statement) and not nested_block: - block_context.symbol_table.append(statement) - if not isinstance(statement, (OpVariable, OpReturn)): - instructions.append(statement) - if isinstance(statement, OpVariable): - variables.append(statement) - if nested_block: - nested_block_variables = filter( - lambda s: isinstance(s, OpVariable), opcodes - ) - nested_block_instructions = filter( - lambda s: not isinstance(s, OpVariable), opcodes - ) - variables += nested_block_variables - instructions += nested_block_instructions + if isinstance(fuzzed_opcode.opcode, OpSelectionMerge): + nested_block = True + for side_effect in fuzzed_opcode.side_effects: + match side_effect: + case Type() | Constant(): + context.add_to_tvc(side_effect) + case OpVariable(): + variables.append(side_effect) + case _: + instructions.append(side_effect) + continue + if isinstance(fuzzed_opcode.opcode, Statement) and not nested_block: + block_context.symbol_table.append(fuzzed_opcode.opcode) + if not isinstance(fuzzed_opcode.opcode, (OpVariable, OpReturn)): + instructions.append(fuzzed_opcode.opcode) + if isinstance(fuzzed_opcode.opcode, OpVariable): + variables.append(fuzzed_opcode.opcode) if exit_label: instructions.append(OpBranch(label=exit_label)) return tuple([block_label, *variables, *instructions]) diff --git a/src/fuzzing_server.py b/src/fuzzing_server.py index 70a5952..f40bb61 100644 --- a/src/fuzzing_server.py +++ b/src/fuzzing_server.py @@ -39,6 +39,8 @@ from src.shader_utils import assemble_shader from src.shader_utils import SPIRVShader from src.shader_utils import validate_spirv_file +from src.types.concrete_types import OpTypeFunction +from src.types.concrete_types import OpTypeVoid if TYPE_CHECKING: from run import SPIRVSmithConfig @@ -53,10 +55,6 @@ logging.getLogger("werkzeug").disabled = True -def get_BQ_client() -> bigquery.Client: - return bigquery.Client.from_service_account_json("infra/spirvsmith_gcp.json") - - terminate = False paused = False @@ -144,11 +142,11 @@ def start(self): MP_pool.close() MP_pool.join() thread_pool_executor.shutdown() - Monitor().info(event=Event.TERMINATED) + Monitor(self.config).info(event=Event.TERMINATED) break if not paused: shader: SPIRVShader = self.gen_shader() - + shader.export(f"out/{shader.id}.spasm") with tempfile.NamedTemporaryFile() as tmp: if assemble_shader(shader, tmp.name) and validate_spirv_file( shader, tmp.name @@ -160,7 +158,7 @@ def start(self): insert_new_shader_into_BQ, shader, self.generator_id ) if paused: - Monitor().info(event=Event.PAUSED) + Monitor(self.config).info(event=Event.PAUSED) def gen_shader(self) -> SPIRVShader: # execution_model = random.SystemRandom().choice(list(ExecutionModel)) @@ -169,31 +167,38 @@ def gen_shader(self) -> SPIRVShader: # ) execution_model = ExecutionModel.GLCompute context = Context.create_global_context(execution_model, self.config) + void_type = OpTypeVoid() + main_type = OpTypeFunction(return_type=void_type, parameter_types=()) + context.main_type = main_type + context.tvc[void_type] = void_type.id + context.tvc[main_type] = main_type.id + if self.config.strategy.enable_ext_glsl_std_450: - context.extension_sets["GLSL"] = OpExtInstImport(name="GLSL.std.450") + context.extension_sets["GLSL.std.450"] = OpExtInstImport( + name="GLSL.std.450" + ) # Generate random types and constants to be used by the program context.gen_types() context.gen_constants() context.gen_global_variables() # Populate function bodies and recondition - program: list[OpCode] = context.gen_program() - program: list[OpCode] = recondition(context, program) + program: list[OpCode] = recondition(context, context.gen_program()) FuzzDelegator.reset_parametrizations() # Remap IDs id_gen = id_generator() for ext in context.extension_sets.values(): - ext.id = next(id_gen) + ext.id = str(next(id_gen)) new_tvc = {} for tvc in context.tvc.keys(): - tvc.id = next(id_gen) + tvc.id = str(next(id_gen)) new_tvc[tvc] = tvc.id context.tvc = new_tvc for opcode in program: opcode.id = next(id_gen) - interfaces: Sequence[OpVariable] = context.get_interfaces() + interfaces: tuple[OpVariable, ...] = context.get_interfaces() entry_point = OpEntryPoint( execution_model=execution_model, function=context.main_fn, @@ -211,9 +216,13 @@ def gen_shader(self) -> SPIRVShader: # TODO extra operands if execution_model == ExecutionModel.GLCompute: execution_mode = ExecutionMode.LocalSize + extra_operands = (1, 1, 1) else: execution_mode = ExecutionMode.OriginUpperLeft - op_execution_mode = OpExecutionMode(entry_point.function, execution_mode) + extra_operands = () + op_execution_mode = OpExecutionMode( + entry_point.function, execution_mode, extra_operands + ) return SPIRVShader( capabilities, memory_model, diff --git a/src/misc.py b/src/misc.py index 3c534b0..641251c 100644 --- a/src/misc.py +++ b/src/misc.py @@ -1,7 +1,7 @@ -from dataclasses import dataclass +from dataclasses import field from typing import Sequence -from src import FuzzLeaf +from src import FuzzLeafMixin from src import OpCode from src import VoidOp from src.enums import AddressingModel @@ -10,75 +10,54 @@ from src.enums import ExecutionModel from src.enums import MemoryModel from src.function import OpFunction +from src.patched_dataclass import dataclass from src.types.concrete_types import Type class OpNop(OpCode): - pass + ... +@dataclass class OpUndef(OpCode): - type: Type = None + type: Type +@dataclass class OpSizeOf(OpCode): - pointer: Type = None - type: Type = None + pointer: Type + type: Type - def get_required_capabilities(self) -> list[Capability]: + @staticmethod + def get_required_capabilities() -> list[Capability]: return [Capability.Addresses] -class OpEntryPoint(FuzzLeaf, VoidOp): - execution_model: ExecutionModel = None - function: OpFunction = None - name: str = None - interfaces: Sequence[OpCode] = None - - def __init__( - self, - execution_model: ExecutionModel, - function: OpFunction, - name: str, - interfaces: Sequence[OpCode], - ) -> None: - self.execution_model = execution_model - self.function = function - self.name = name - self.interfaces = interfaces - super().__init__() - - -class OpMemoryModel(FuzzLeaf, VoidOp): - addressing_model: AddressingModel = None - memory_model: MemoryModel = None - - def __init__( - self, addressing_model: AddressingModel, memory_model: MemoryModel - ) -> None: - self.addressing_model = addressing_model - self.memory_model = memory_model - super().__init__() - - def get_required_capabilities(self) -> list[Capability]: - return [Capability.Shader] +@dataclass +class OpEntryPoint(FuzzLeafMixin, VoidOp): + execution_model: ExecutionModel + function: OpFunction + name: str + interfaces: tuple[OpCode, ...] @dataclass -class OpExecutionMode(FuzzLeaf, VoidOp): - function: OpFunction = None - execution_mode: ExecutionMode = None +class OpMemoryModel(FuzzLeafMixin, VoidOp): + addressing_model: AddressingModel + memory_model: MemoryModel - def __init__(self, function: OpFunction, execution_mode: ExecutionMode) -> None: - self.function = function - self.execution_mode = execution_mode - super().__init__() + @staticmethod + def get_required_capabilities() -> list[Capability]: + return [Capability.Shader] @dataclass -class OpCapability(FuzzLeaf, VoidOp): - capability: Capability = None +class OpExecutionMode(FuzzLeafMixin, VoidOp): + function: OpFunction + execution_mode: ExecutionMode + extra_operands: tuple[int, ...] + - def __init__(self, capability: Capability) -> None: - self.capability = capability - super().__init__() +@dataclass +class OpCapability(FuzzLeafMixin, VoidOp): + capability: Capability diff --git a/src/monitor.py b/src/monitor.py index 140a221..9d297f0 100644 --- a/src/monitor.py +++ b/src/monitor.py @@ -1,8 +1,13 @@ import logging from enum import Enum +from typing import Optional +from typing import TYPE_CHECKING import daiquiri +if TYPE_CHECKING: + from run import SPIRVSmithConfig + from src.utils import get_spirvsmith_version LOG_VERSION: str = get_spirvsmith_version() @@ -33,17 +38,18 @@ class Event(Enum): class Monitor: - def __init__(self) -> None: + def __init__(self, config: Optional["SPIRVSmithConfig"] = None) -> None: outputs = [ daiquiri.output.Stream( formatter=daiquiri.formatter.ColorFormatter( fmt=("[%(levelname)s] [%(asctime)s] %(message)s") ) - ), - daiquiri.output.Datadog(), + ) ] + if config and config.misc.upload_logs: + outputs.append(daiquiri.output.Datadog()) daiquiri.setup( - level=logging.INFO, + level=logging.WARNING, outputs=outputs, ) diff --git a/src/operators/__init__.py b/src/operators/__init__.py index 2ea0a5e..7cf1b60 100644 --- a/src/operators/__init__.py +++ b/src/operators/__init__.py @@ -1,10 +1,11 @@ from types import NoneType from typing import get_args -from typing import Optional from typing import TYPE_CHECKING +from typing_extensions import Self + from src import Constant -from src import OpCode +from src import FuzzResult from src import Signed from src import Statement from src.constants import OpConstantComposite @@ -22,26 +23,25 @@ class GLSLExtensionOperator: class UnaryOperatorFuzzMixin: - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: ( source_type, destination_type, source_constraint, destination_constraint, - ) = get_args(self.__class__.__orig_bases__[1]) - source_signed = None + ) = get_args(cls.__orig_bases__[1]) + source_signed: bool = None if not issubclass(source_constraint, NoneType): - source_signed = issubclass(source_constraint, Signed) + source_signed: bool = issubclass(source_constraint, Signed) destination_signed = None if not issubclass(destination_constraint, NoneType): destination_signed = issubclass(destination_constraint, Signed) - operand: Optional[Operand] = context.get_random_operand( - self.OPERAND_SELECTION_PREDICATE(source_type, source_signed) + operand: Operand = context.get_random_operand( + cls.OPERAND_SELECTION_PREDICATE(source_type, source_signed) ) - if operand is None: - return [] if not issubclass(destination_type, NoneType): - inner_type = destination_type().fuzz(context)[-1] + inner_type = destination_type.fuzz(context).opcode if destination_signed is not None: inner_type.signed = int(destination_signed) context.add_to_tvc(inner_type) @@ -50,60 +50,46 @@ def fuzz(self, context: "Context") -> list[OpCode]: if hasattr(operand, "width"): inner_type.width = operand.get_base_type().width if isinstance(operand.type, (OpConstantComposite, OpTypeVector)): - self.type = OpTypeVector().fuzz(context)[-1] - self.type.type = inner_type - self.type.size = len(operand.type) - context.add_to_tvc(self.type) - else: - self.type = inner_type + inner_type = OpTypeVector(type=inner_type, size=len(operand.type)) + context.add_to_tvc(inner_type) else: - self.type = operand.type - self.operand1 = operand - if isinstance(self, GLSLExtensionOperator): - return [ + inner_type = operand.type + if issubclass(cls, GLSLExtensionOperator): + return FuzzResult( OpExtInst( - type=self.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, - operands=tuple([self.operand1]), + type=inner_type, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, + operands=(operand,), ) - ] - return [self] - - def __str__(self) -> str: - return f"{self.__class__.__name__}({self.operand1})" - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.operand1})" + ) + return FuzzResult(cls(type=inner_type, operand1=operand), [inner_type]) class BinaryOperatorFuzzMixin: - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: ( source_type, destination_type, source_constraint, destination_constraint, - ) = get_args(self.__class__.__orig_bases__[1]) + ) = get_args(cls.__orig_bases__[1]) source_signed = None if not issubclass(source_constraint, NoneType): source_signed = issubclass(source_constraint, Signed) destination_signed = None if not issubclass(destination_constraint, NoneType): destination_signed = issubclass(destination_constraint, Signed) - operand1: Optional[Operand] = context.get_random_operand( - self.OPERAND_SELECTION_PREDICATE(source_type, source_signed) + operand1: Operand = context.get_random_operand( + cls.OPERAND_SELECTION_PREDICATE(source_type, source_signed) ) - if operand1 is None: - return [] - operand2: Optional[Operand] = context.get_random_operand( - self.OPERAND_SELECTION_PREDICATE(source_type, source_signed), + operand2: Operand = context.get_random_operand( + cls.OPERAND_SELECTION_PREDICATE(source_type, source_signed), constraint=operand1, ) - if operand2 is None: - return [] if not issubclass(destination_type, NoneType): - inner_type = destination_type().fuzz(context)[-1] + inner_type = destination_type.fuzz(context).opcode if destination_signed is not None: inner_type.signed = int(destination_signed) context.add_to_tvc(inner_type) @@ -112,29 +98,19 @@ def fuzz(self, context: "Context") -> list[OpCode]: if hasattr(operand1, "width"): inner_type.width = operand1.get_base_type().width if isinstance(operand1.type, (OpConstantComposite, OpTypeVector)): - self.type = OpTypeVector().fuzz(context)[-1] - self.type.type = inner_type - self.type.size = len(operand1.type) - context.add_to_tvc(self.type) - else: - self.type = inner_type + inner_type = OpTypeVector(type=inner_type, size=len(operand1.type)) + context.add_to_tvc(inner_type) else: - self.type = operand1.type - self.operand1 = operand1 - self.operand2 = operand2 - if isinstance(self, GLSLExtensionOperator): - return [ + inner_type = operand1.type + if issubclass(cls, GLSLExtensionOperator): + return FuzzResult( OpExtInst( - type=self.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, - operands=tuple([self.operand1, self.operand2]), + type=inner_type, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, + operands=(operand1, operand2), ) - ] - return [self] - - def __str__(self) -> str: - return f"{self.__class__.__name__}({self.operand1})({self.operand2})" - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.operand1})({self.operand2})" + ) + return FuzzResult( + cls(type=inner_type, operand1=operand1, operand2=operand2), [inner_type] + ) diff --git a/src/operators/arithmetic/__init__.py b/src/operators/arithmetic/__init__.py index 6443987..3a70437 100644 --- a/src/operators/arithmetic/__init__.py +++ b/src/operators/arithmetic/__init__.py @@ -1,14 +1,14 @@ from typing import Callable +from typing import ClassVar from typing import Generic from typing import Optional from typing import TypeVar from src import Statement -from src import Type from src.operators import Operand +from src.patched_dataclass import dataclass from src.predicates import HasValidBaseTypeAndSign -from src.predicates import IsOfType -from src.types.abstract_types import ArithmeticType +from src.predicates import IsArithmeticType S = TypeVar("S") @@ -17,26 +17,27 @@ DC = TypeVar("DC") +@dataclass class ArithmeticOperator(Statement, Generic[S, D, SC, DC]): - OPERAND_SELECTION_PREDICATE: Callable[ - [Operand], bool - ] = lambda _, target_type, signed: lambda op: IsOfType(ArithmeticType)( + OPERAND_SELECTION_PREDICATE: ClassVar[ + Callable[[Operand], bool] + ] = lambda target_type, signed: lambda op: IsArithmeticType( op ) and HasValidBaseTypeAndSign( op, target_type, signed ) +@dataclass class UnaryArithmeticOperator( ArithmeticOperator[S, Optional[D], Optional[SC], Optional[DC]] ): - type: Type = None - operand1: Operand = None + operand1: Operand +@dataclass class BinaryArithmeticOperator( ArithmeticOperator[S, Optional[D], Optional[SC], Optional[DC]] ): - type: Type = None - operand1: Operand = None - operand2: Operand = None + operand1: Operand + operand2: Operand diff --git a/src/operators/arithmetic/glsl.py b/src/operators/arithmetic/glsl.py index bc5b498..6d8d0cc 100644 --- a/src/operators/arithmetic/glsl.py +++ b/src/operators/arithmetic/glsl.py @@ -1,5 +1,8 @@ from typing import TYPE_CHECKING +from typing_extensions import Self + +from src import FuzzResult from src import OpCode from src import Signed from src import Unsigned @@ -11,6 +14,7 @@ from src.operators import UnaryOperatorFuzzMixin from src.operators.arithmetic import BinaryArithmeticOperator from src.operators.arithmetic import UnaryArithmeticOperator +from src.patched_dataclass import dataclass from src.predicates import And from src.predicates import HasLength from src.predicates import HasType @@ -36,6 +40,7 @@ # ... +@dataclass class RoundEven( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -44,6 +49,7 @@ class RoundEven( ... +@dataclass class Trunc( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -52,6 +58,7 @@ class Trunc( ... +@dataclass class FAbs( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -60,6 +67,7 @@ class FAbs( ... +@dataclass class SAbs( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, Signed, None], @@ -68,6 +76,7 @@ class SAbs( ... +@dataclass class FSign( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -76,6 +85,7 @@ class FSign( ... +@dataclass class SSign( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, Signed, None], @@ -84,6 +94,7 @@ class SSign( ... +@dataclass class Floor( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -92,6 +103,7 @@ class Floor( ... +@dataclass class Ceil( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -100,6 +112,7 @@ class Ceil( ... +@dataclass class Fract( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -108,6 +121,7 @@ class Fract( ... +@dataclass class Degrees( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -116,6 +130,7 @@ class Degrees( ... +@dataclass class Sin( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -124,6 +139,7 @@ class Sin( ... +@dataclass class Cos( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -132,6 +148,7 @@ class Cos( ... +@dataclass class Tan( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -140,6 +157,7 @@ class Tan( ... +@dataclass class Asin( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -148,6 +166,7 @@ class Asin( ... +@dataclass class Acos( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -156,6 +175,7 @@ class Acos( ... +@dataclass class Atan( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -164,6 +184,7 @@ class Atan( ... +@dataclass class Sinh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -172,6 +193,7 @@ class Sinh( ... +@dataclass class Cosh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -180,6 +202,7 @@ class Cosh( ... +@dataclass class Tanh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -188,6 +211,7 @@ class Tanh( ... +@dataclass class Asinh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -196,6 +220,7 @@ class Asinh( ... +@dataclass class Acosh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -204,6 +229,7 @@ class Acosh( ... +@dataclass class Atanh( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -212,6 +238,7 @@ class Atanh( ... +@dataclass class Atan2( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -220,6 +247,7 @@ class Atan2( ... +@dataclass class Pow( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -228,6 +256,7 @@ class Pow( ... +@dataclass class Exp( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -236,6 +265,7 @@ class Exp( ... +@dataclass class Log( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -244,6 +274,7 @@ class Log( ... +@dataclass class Exp2( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -252,6 +283,7 @@ class Exp2( ... +@dataclass class Log2( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -260,6 +292,7 @@ class Log2( ... +@dataclass class Sqrt( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -268,6 +301,7 @@ class Sqrt( ... +@dataclass class InverseSqrt( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -276,24 +310,25 @@ class InverseSqrt( ... +@dataclass class Determinant( UnaryArithmeticOperator[None, None, None, None], GLSLExtensionOperator ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand = context.get_random_operand( lambda x: IsMatrixType(x) and len(x.type) == len(x.type.type) ) - if not operand: - return [] result_type = operand.get_base_type() - return [ + return FuzzResult( OpExtInst( type=result_type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand,), - ) - ] + ), + [result_type], + ) # class MatrixInverse( @@ -306,36 +341,36 @@ def fuzz(self, context: "Context") -> list[OpCode]: # return [ # OpExtInst( # type=operand.type, -# extension_set=context.extension_sets["GLSL"], +# extension_set=context.extension_sets["GLSL.std.450"], # instruction=self.__class__, # operands=(operand,), # ) # ] +@dataclass class ModfStruct( UnaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) - if not operand: - return [] - result_type = OpTypeStruct() - result_type.types = (operand.type, operand.type) - context.add_to_tvc(result_type) - return [ + result_type = OpTypeStruct(types=(operand.type, operand.type)) + return FuzzResult( OpExtInst( type=result_type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand,), - ) - ] + ), + [result_type], + ) +@dataclass class FMin( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -344,6 +379,7 @@ class FMin( ... +@dataclass class UMin( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Unsigned, None], @@ -352,6 +388,7 @@ class UMin( ... +@dataclass class SMin( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Signed, None], @@ -360,6 +397,7 @@ class SMin( ... +@dataclass class FMax( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -368,6 +406,7 @@ class FMax( ... +@dataclass class UMax( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Unsigned, None], @@ -376,6 +415,7 @@ class UMax( ... +@dataclass class SMax( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Signed, None], @@ -385,94 +425,95 @@ class SMax( # TODO: we need a ternary arithmetic operator classification, workaround for now +@dataclass class FClamp( BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) +@dataclass class UClamp( BinaryArithmeticOperator[OpTypeInt, None, Unsigned, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfUnsignedIntegerBaseType), IsScalarSignedInteger) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) +@dataclass class SClamp( BinaryArithmeticOperator[OpTypeInt, None, Signed, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfSignedIntegerBaseType), IsScalarSignedInteger) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) +@dataclass class FMix( BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) +@dataclass class Step( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -489,77 +530,70 @@ class Step( # operand1 = context.get_random_operand( # Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) # ) -# if not operand1: -# return [] # operand2 = context.get_random_operand(HasType(operand1.type)) # operand3 = context.get_random_operand(HasType(operand1.type)) # return [ # OpExtInst( # type=operand1.type, -# extension_set=context.extension_sets["GLSL"], +# extension_set=context.extension_sets["GLSL.std.450"], # instruction=self.__class__, # operands=(operand1, operand2, operand3), # ) # ] -class Fma( - BinaryArithmeticOperator[OpTypeFloat, None, None, None], - GLSLExtensionOperator, -): - def fuzz(self, context: "Context") -> list[OpCode]: - operand1 = context.get_random_operand( - Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) - ) - if not operand1: - return [] - operand2 = context.get_random_operand(HasType(operand1.type)) - operand3 = context.get_random_operand(HasType(operand1.type)) - ext_inst = OpExtInst( - type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, - operands=(operand1, operand2, operand3), - ) - # Required for determinism - context.add_annotation( - OpDecorate(target=ext_inst, decoration=Decoration.NoContraction) - ) - return [ext_inst] +# @dataclass +# class Fma( +# BinaryArithmeticOperator[OpTypeFloat, None, None, None], +# GLSLExtensionOperator, +# ): +# @classmethod +# def fuzz(cls, context: "Context") -> FuzzResult[Self]: +# operand1 = context.get_random_operand( +# Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) +# ) +# operand2 = context.get_random_operand(HasType(operand1.type)) +# operand3 = context.get_random_operand(HasType(operand1.type)) +# ext_inst = OpExtInst( +# type=operand1.type, +# extension_set=context.extension_sets["GLSL.std.450"], +# instruction=cls, +# operands=(operand1, operand2, operand3), +# ) +# # Required for determinism +# context.add_annotation( +# OpDecorate(target=ext_inst, decoration=Decoration.NoContraction) +# ) +# return FuzzResult(ext_inst) +@dataclass class FrexpStruct( UnaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) - if not operand: - return [] - struct_type = OpTypeStruct() inner_type1 = operand.type - int_type = OpTypeInt() - int_type.width = 32 - int_type.signed = 1 if IsVectorType(operand): - inner_type2 = OpTypeVector() - inner_type2.type = int_type - inner_type2.size = len(inner_type1) + inner_type2 = OpTypeVector(OpTypeInt(32, 1), len(inner_type1)) else: - inner_type2 = int_type + inner_type2 = OpTypeInt(32, 1) + struct_type = OpTypeStruct((inner_type1, inner_type2)) context.add_to_tvc(inner_type2) - struct_type.types = (inner_type1, inner_type2) context.add_to_tvc(struct_type) - return [ + return FuzzResult( OpExtInst( type=struct_type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand,), - ) - ] + ), + [struct_type], + ) # # # # # # # # # # # # # # # # @@ -570,71 +604,74 @@ def fuzz(self, context: "Context") -> list[OpCode]: # # # # # # # # # # # # # # # # +@dataclass class Length( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - if not operand: - return [] - result_type = OpTypeFloat().fuzz(context)[-1] - return [ + result_type = OpTypeFloat(32) + return FuzzResult( OpExtInst( type=result_type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand,), - ) - ] + ), + [result_type], + ) +@dataclass class Distance( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) - result_type = OpTypeFloat().fuzz(context)[-1] - return [ + result_type = OpTypeFloat(32) + return FuzzResult( OpExtInst( type=result_type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=( operand1, operand2, ), - ) - ] + ), + [result_type], + ) +@dataclass class Cross( BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( And(IsVectorType, IsOfFloatBaseType, HasLength(3)) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2), ) - ] + ) +@dataclass class Normalize( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -643,26 +680,29 @@ class Normalize( ... +@dataclass class FaceForward( BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) +@dataclass class Reflect( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -676,6 +716,7 @@ class Reflect( # ... +@dataclass class FindILsb( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, None, None], @@ -684,6 +725,7 @@ class FindILsb( ... +@dataclass class FindSMsb( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, Signed, None], @@ -692,6 +734,7 @@ class FindSMsb( ... +@dataclass class FindUMsb( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, Unsigned, None], @@ -725,6 +768,7 @@ class FindUMsb( # ... +@dataclass class NMin( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -733,6 +777,7 @@ class NMin( ... +@dataclass class NMax( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None], @@ -741,23 +786,23 @@ class NMax( ... +@dataclass class NClamp( BinaryArithmeticOperator[OpTypeFloat, None, None, None], GLSLExtensionOperator, ): - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand( Or(And(IsVectorType, IsOfFloatBaseType), IsScalarFloat) ) - if not operand1: - return [] operand2 = context.get_random_operand(HasType(operand1.type)) operand3 = context.get_random_operand(HasType(operand1.type)) - return [ + return FuzzResult( OpExtInst( type=operand1.type, - extension_set=context.extension_sets["GLSL"], - instruction=self.__class__, + extension_set=context.extension_sets["GLSL.std.450"], + instruction=cls, operands=(operand1, operand2, operand3), ) - ] + ) diff --git a/src/operators/arithmetic/linear_algebra.py b/src/operators/arithmetic/linear_algebra.py index e09d2ca..3c30977 100644 --- a/src/operators/arithmetic/linear_algebra.py +++ b/src/operators/arithmetic/linear_algebra.py @@ -2,10 +2,11 @@ TYPE_CHECKING, ) -from src import OpCode -from src.operators import Operand -from src.operators.arithmetic import BinaryArithmeticOperator +from typing_extensions import Self +from src import FuzzResult +from src.operators.arithmetic import BinaryArithmeticOperator +from src.patched_dataclass import dataclass if TYPE_CHECKING: from src.context import Context @@ -21,7 +22,6 @@ ) from src.types.concrete_types import ( - OpTypeFloat, OpTypeMatrix, OpTypeVector, ) @@ -31,100 +31,64 @@ # This is because trying to encompass their logic in the mixin would be way too complex: +@dataclass class OpVectorTimesScalar(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeVector = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - if not operand1: - return [] operand2 = context.get_random_operand(IsScalarFloat) - if not operand2: - return [] - self.type = operand1.type - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + return FuzzResult(cls(type=operand1.type, operand1=operand1, operand2=operand2)) +@dataclass class OpMatrixTimesScalar(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeMatrix = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsMatrixType, IsOfFloatBaseType)) - if not operand1: - return [] operand2 = context.get_random_operand(IsScalarFloat) - if not operand2: - return [] - self.type = operand1.type - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + return FuzzResult(cls(type=operand1.type, operand1=operand1, operand2=operand2)) +@dataclass class OpVectorTimesMatrix(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeVector = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: # We pick the matrix first here because we tend to have more vectors than matrices operand2 = context.get_random_operand(And(IsMatrixType, IsOfFloatBaseType)) - if not operand2: - return [] # The vector must have as many element as the matrix has rows operand1 = context.get_random_operand( And(IsVectorType, IsOfFloatBaseType, HasLength(len(operand2.type.type))) ) - if not operand1: - return [] - self.type = OpTypeVector() - self.type.type = operand1.get_base_type() - self.type.size = len(operand2.type) - context.add_to_tvc(self.type) - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + result_type = OpTypeVector( + type=operand1.get_base_type(), size=len(operand2.type) + ) + return FuzzResult( + cls(type=result_type, operand1=operand1, operand2=operand2), [result_type] + ) +@dataclass class OpMatrixTimesVector(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeVector = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsMatrixType, IsOfFloatBaseType)) - if not operand1: - return [] # The vector must have as many elements as the matrix has columns operand2 = context.get_random_operand( And(IsVectorType, IsOfFloatBaseType, HasLength(len(operand1.type))) ) - if not operand2: - return [] - self.type = OpTypeVector() - self.type.type = operand1.get_base_type() - self.type.size = len(operand1.type.type) - context.add_to_tvc(self.type) - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + result_type = OpTypeVector( + type=operand1.get_base_type(), size=len(operand1.type.type) + ) + return FuzzResult( + cls(type=result_type, operand1=operand1, operand2=operand2), [result_type] + ) +@dataclass class OpMatrixTimesMatrix(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeMatrix = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsMatrixType, IsOfFloatBaseType)) - if not operand1: - return [] # operand2 must have the same number of columns that operand1 has # rows, tricky case if we got unlucky and picked for operand1 # a matrix that could be multiplied by operand2 in the symmetric case @@ -145,8 +109,6 @@ def fuzz(self, context: "Context") -> list[OpCode]: or HaveSameTypeLength(x, operand1.type) ) ) - if not operand2: - return [] # Handle the symmetric case # len(operand1.type) != len(operand2.type.type) @@ -157,45 +119,29 @@ def fuzz(self, context: "Context") -> list[OpCode]: # The resulting matrix has the same number of rows as operand1 # and same number of columns as operand2 - self.type = OpTypeMatrix() - # Rows - self.type.type = operand1.type.type - # Columns - self.type.size = len(operand2.type) - context.add_to_tvc(self.type) - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + result_type = OpTypeMatrix(type=operand1.type.type, size=len(operand2.type)) + return FuzzResult( + cls(type=result_type, operand1=operand1, operand2=operand2), [result_type] + ) +@dataclass class OpOuterProduct(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeMatrix = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - if not operand1: - return [] operand2 = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - self.type = OpTypeMatrix() - self.type.type = operand1.type - self.type.size = len(operand2.type) - context.add_to_tvc(self.type) - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + result_type = OpTypeMatrix(type=operand1.type, size=len(operand2.type)) + return FuzzResult( + cls(type=result_type, operand1=operand1, operand2=operand2), [result_type] + ) +@dataclass class OpDot(BinaryArithmeticOperator[None, None, None, None]): - type: OpTypeFloat = None - operand1: Operand = None - operand2: Operand = None - - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: operand1 = context.get_random_operand(And(IsVectorType, IsOfFloatBaseType)) - if not operand1: - return [] operand2 = context.get_random_operand( And( IsVectorType, @@ -203,7 +149,6 @@ def fuzz(self, context: "Context") -> list[OpCode]: HasLength(len(operand1.type)), ) ) - self.type = operand1.get_base_type() - self.operand1 = operand1 - self.operand2 = operand2 - return [self] + return FuzzResult( + cls(type=operand1.get_base_type(), operand1=operand1, operand2=operand2) + ) diff --git a/src/operators/arithmetic/scalar_arithmetic.py b/src/operators/arithmetic/scalar_arithmetic.py index 0d87186..41bf9c0 100644 --- a/src/operators/arithmetic/scalar_arithmetic.py +++ b/src/operators/arithmetic/scalar_arithmetic.py @@ -4,100 +4,117 @@ from src.operators import UnaryOperatorFuzzMixin from src.operators.arithmetic import BinaryArithmeticOperator from src.operators.arithmetic import UnaryArithmeticOperator +from src.patched_dataclass import dataclass from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeInt +@dataclass class OpSNegate( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeInt, None, Signed, None] ): ... +@dataclass class OpFNegate( UnaryOperatorFuzzMixin, UnaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpIAdd( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpFAdd( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpISub( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpFSub( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpIMul( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpFMul( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpUDiv( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Unsigned, None] ): ... +@dataclass class OpSDiv( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Signed, None] ): ... +@dataclass class OpFDiv( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpUMod( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Unsigned, None] ): ... +@dataclass class OpSRem( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Signed, None] ): ... +@dataclass class OpSMod( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeInt, None, Signed, None] ): ... +@dataclass class OpFRem( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): ... +@dataclass class OpFMod( BinaryOperatorFuzzMixin, BinaryArithmeticOperator[OpTypeFloat, None, None, None] ): diff --git a/src/operators/bitwise.py b/src/operators/bitwise.py index 9f7bdf9..c1290f8 100644 --- a/src/operators/bitwise.py +++ b/src/operators/bitwise.py @@ -1,19 +1,17 @@ from typing import Callable +from typing import ClassVar from typing import Generic from typing import Optional from typing import TypeVar from src import Statement -from src.constants import Constant from src.operators import BinaryOperatorFuzzMixin +from src.operators import Operand from src.operators import UnaryOperatorFuzzMixin +from src.patched_dataclass import dataclass from src.predicates import HasValidBaseTypeAndSign -from src.predicates import IsOfType -from src.types.abstract_types import ArithmeticType +from src.predicates import IsArithmeticType from src.types.concrete_types import OpTypeInt -from src.types.concrete_types import Type - -Operand = Statement | Constant S = TypeVar("S") D = TypeVar("D") @@ -21,69 +19,78 @@ DC = TypeVar("DC") +@dataclass class BitwiseOperator(Statement, Generic[S, D, SC, DC]): - OPERAND_SELECTION_PREDICATE: Callable[ - [Operand], bool - ] = lambda _, target_type, signed: lambda op: IsOfType(ArithmeticType)( + OPERAND_SELECTION_PREDICATE: ClassVar[ + Callable[[Operand], bool] + ] = lambda target_type, signed: lambda op: IsArithmeticType( op ) and HasValidBaseTypeAndSign( op, target_type, signed ) +@dataclass class UnaryBitwiseOperator(BitwiseOperator[S, Optional[D], Optional[SC], Optional[DC]]): - type: Type = None - operand1: Operand = None + operand1: Operand +@dataclass class BinaryBitwiseOperator( BitwiseOperator[S, Optional[D], Optional[SC], Optional[DC]] ): - type: Type = None - operand1: Operand = None - operand2: Operand = None + operand1: Operand + operand2: Operand +@dataclass class OpShiftRightLogical( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpShiftRightArithmetic( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpShiftLeftLogical( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpBitwiseOr( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpBitwiseXor( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpBitwiseAnd( BinaryOperatorFuzzMixin, BinaryBitwiseOperator[OpTypeInt, None, None, None] ): ... +@dataclass class OpNot(UnaryOperatorFuzzMixin, UnaryBitwiseOperator[OpTypeInt, None, None, None]): ... +@dataclass class OpBitCount( UnaryOperatorFuzzMixin, UnaryBitwiseOperator[OpTypeInt, None, None, None] ): diff --git a/src/operators/composite.py b/src/operators/composite.py index 7da63cb..f3c717b 100644 --- a/src/operators/composite.py +++ b/src/operators/composite.py @@ -3,10 +3,12 @@ from math import log2 from typing import TYPE_CHECKING -from src import OpCode +from typing_extensions import Self + +from src import FuzzResult from src import Statement -from src import Type from src.operators import Operand +from src.patched_dataclass import dataclass from src.predicates import And from src.predicates import HasBaseType from src.predicates import HasType @@ -22,120 +24,111 @@ from src.context import Context +@dataclass class CompositeOperator(Statement): ... +@dataclass class OpVectorExtractDynamic(CompositeOperator): - type: Type = None - vector: Statement = None - index: Statement = None + vector: Operand + index: Operand - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: vector = context.get_random_operand(IsVectorType) - if vector is None: - return [] - - self.type = vector.get_base_type() - self.vector = vector - self.index = context.get_random_operand(IsScalarInteger) - return [self] + index = context.get_random_operand(IsScalarInteger) + return FuzzResult(cls(type=vector.get_base_type(), vector=vector, index=index)) +@dataclass class OpVectorInsertDynamic(CompositeOperator): - type: Type = None - vector: Statement = None - component: Statement = None - index: Statement = None + vector: Operand + component: Operand + index: Operand - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: vector = context.get_random_operand(IsVectorType) - if vector is None: - return [] component = context.get_random_operand(HasType(vector.get_base_type())) - if component is None: - return [] - self.type = vector.type - self.vector = vector - self.component = component - self.index = context.get_random_operand(IsScalarInteger) - return [self] + return FuzzResult( + cls( + type=vector.type, + vector=vector, + component=component, + index=context.get_random_operand(IsScalarInteger), + ) + ) +@dataclass class OpVectorShuffle(CompositeOperator): - type: Type = None - vector1: Statement = None - vector2: Statement = None - components: tuple[int] = None + vector1: Operand + vector2: Operand + components: tuple[int, ...] - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: vector1 = context.get_random_operand(IsVectorType) - if vector1 is None: - return [] vector2 = context.get_random_operand( And(IsVectorType, HasBaseType(vector1.get_base_type())) ) - if vector2 is None: - return [] - self.type = OpTypeVector() - self.type.type = vector1.get_base_type() - self.type.size = min( - 4, 2 ** (ceil(log2(len(vector1.type) + len(vector2.type)))) + inner_type = OpTypeVector( + type=vector1.get_base_type(), + size=min(4, 2 ** (ceil(log2(len(vector1.type) + len(vector2.type))))), ) - context.add_to_tvc(self.type) - self.vector1 = vector1 - self.vector2 = vector2 - self.components = tuple( + context.add_to_tvc(inner_type) + components = tuple( [ - random.SystemRandom().randint(0, self.type.size - 1) - for _ in range(self.type.size) + random.SystemRandom().randint(0, len(inner_type) - 1) + for _ in range(len(inner_type)) ] ) - return [self] + return FuzzResult( + cls( + type=inner_type, vector1=vector1, vector2=vector2, components=components + ) + ) # class OpCompositeConstruct: # ... +@dataclass class OpCompositeExtract(CompositeOperator): - type: Type = None - composite: Operand = None - indexes: tuple[int] = None + composite: Operand + indexes: tuple[int, ...] - def fuzz(self, context: "Context") -> list[OpCode]: - composite = context.get_random_operand(IsCompositeType) - if composite is None: - return [] + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + composite: Operand = context.get_random_operand(IsCompositeType) if IsMatrixType(composite): indexes = ( random.SystemRandom().randint(0, len(composite.type) - 1), random.SystemRandom().randint(0, len(composite.type.type) - 1), ) - self.type = composite.get_base_type() + inner_type = composite.get_base_type() else: indexes = (random.SystemRandom().randint(0, len(composite.type) - 1),) - self.type = ( + inner_type = ( composite.type.types[indexes[0]] if IsStructType(composite) else composite.get_base_type() ) - self.composite = composite - self.indexes = indexes - return [self] + return FuzzResult(cls(type=inner_type, composite=composite, indexes=indexes)) +@dataclass class OpCompositeInsert(CompositeOperator): - type: Type = None - object: Statement = None - composite: Statement = None - indexes: tuple[int] = None + object: Operand + composite: Operand + indexes: tuple[int, ...] - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: composite = context.get_random_operand(IsCompositeType) - if composite is None: - return [] if IsMatrixType(composite): indexes = ( random.SystemRandom().randint(0, len(composite.type) - 1), @@ -152,42 +145,39 @@ def fuzz(self, context: "Context") -> list[OpCode]: else composite.get_base_type() ) target_object = context.get_random_operand(HasType(target_type)) - if not target_object: - return [] - self.type = composite.type - self.object = target_object - self.composite = composite - self.indexes = indexes - return [self] + return FuzzResult( + cls( + type=composite.type, + object=target_object, + composite=composite, + indexes=indexes, + ) + ) +@dataclass class OpCopyObject(CompositeOperator): - type: Type = None - object: Statement = None + object: Operand - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: target_object = context.get_random_operand(lambda _: True) - if target_object is None: - return [] - self.type = target_object.type - self.object = target_object - return [self] + return FuzzResult(cls(type=target_object.type, object=target_object)) +@dataclass class OpTranspose(CompositeOperator): - type: Type = None - object: Statement = None + object: Operand - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: target_object = context.get_random_operand(IsMatrixType) - if target_object is None: - return [] - self.type = OpTypeMatrix() - self.type.type = OpTypeVector() - self.type.type.type = target_object.get_base_type() - self.type.type.size = len(target_object.type) - self.type.size = len(target_object.type.type) - context.add_to_tvc(self.type.type) - context.add_to_tvc(self.type) - self.object = target_object - return [self] + inner_type = OpTypeMatrix( + type=OpTypeVector( + type=target_object.get_base_type(), size=len(target_object.type) + ), + size=len(target_object.type.type), + ) + context.add_to_tvc(inner_type.type) + context.add_to_tvc(inner_type) + return FuzzResult(cls(type=inner_type, object=target_object)) diff --git a/src/operators/conversions.py b/src/operators/conversions.py index ec45f07..d3ea69d 100644 --- a/src/operators/conversions.py +++ b/src/operators/conversions.py @@ -1,4 +1,5 @@ from typing import Callable +from typing import ClassVar from typing import Generic from typing import Optional from typing import TypeVar @@ -6,16 +7,13 @@ from src import Signed from src import Statement from src import Unsigned -from src.constants import Constant +from src.operators import Operand from src.operators import UnaryOperatorFuzzMixin +from src.patched_dataclass import dataclass from src.predicates import HasValidBaseTypeAndSign -from src.predicates import IsOfType -from src.types.abstract_types import ArithmeticType +from src.predicates import IsArithmeticType from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeInt -from src.types.concrete_types import Type - -Operand = Statement | Constant S = TypeVar("S") D = TypeVar("D") @@ -23,21 +21,23 @@ DC = TypeVar("DC") +@dataclass class ConversionOperator(Statement, Generic[S, D, SC, DC]): - OPERAND_SELECTION_PREDICATE: Callable[ - [Statement], bool - ] = lambda _, target_type, signed: lambda op: IsOfType(ArithmeticType)( + OPERAND_SELECTION_PREDICATE: ClassVar[ + Callable[[Operand], bool] + ] = lambda target_type, signed: lambda op: IsArithmeticType( op ) and HasValidBaseTypeAndSign( op, target_type, signed ) +@dataclass class UnaryConversionOperator(ConversionOperator[S, D, Optional[SC], Optional[DC]]): - type: Type = None - operand1: Operand = None + operand1: Operand +@dataclass class OpConvertFToU( UnaryOperatorFuzzMixin, UnaryConversionOperator[OpTypeFloat, OpTypeInt, None, Unsigned], @@ -45,6 +45,7 @@ class OpConvertFToU( ... +@dataclass class OpConvertFToS( UnaryOperatorFuzzMixin, UnaryConversionOperator[OpTypeFloat, OpTypeInt, None, Signed], @@ -52,6 +53,7 @@ class OpConvertFToS( ... +@dataclass class OpConvertSToF( UnaryOperatorFuzzMixin, UnaryConversionOperator[OpTypeInt, OpTypeFloat, Signed, None], @@ -59,6 +61,7 @@ class OpConvertSToF( ... +@dataclass class OpConvertUToF( UnaryOperatorFuzzMixin, UnaryConversionOperator[OpTypeInt, OpTypeFloat, Unsigned, None], diff --git a/src/operators/logic.py b/src/operators/logic.py index 4702f73..67a6e12 100644 --- a/src/operators/logic.py +++ b/src/operators/logic.py @@ -1,4 +1,6 @@ +from dataclasses import field from typing import Callable +from typing import ClassVar from typing import Generic from typing import Optional from typing import TypeVar @@ -8,16 +10,16 @@ from src import Unsigned from src.constants import Constant from src.operators import BinaryOperatorFuzzMixin +from src.operators import Operand from src.operators import UnaryOperatorFuzzMixin +from src.patched_dataclass import dataclass from src.predicates import HasValidBaseTypeAndSign +from src.predicates import IsArithmeticType from src.predicates import IsOfType -from src.types.abstract_types import ArithmeticType +from src.predicates import Or from src.types.concrete_types import OpTypeBool from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeInt -from src.types.concrete_types import Type - -Operand = Statement | Constant S = TypeVar("S") D = TypeVar("D") @@ -25,11 +27,12 @@ DC = TypeVar("DC") +@dataclass class LogicalOperator(Statement, Generic[S, D, SC, DC]): - OPERAND_SELECTION_PREDICATE: Callable[ - [Operand], bool - ] = lambda _, target_type, signed: lambda op: IsOfType( - (OpTypeBool, ArithmeticType) + OPERAND_SELECTION_PREDICATE: ClassVar[ + Callable[[Operand], bool] + ] = lambda target_type, signed: lambda op: Or( + IsArithmeticType, IsOfType(OpTypeBool) )( op ) and HasValidBaseTypeAndSign( @@ -37,17 +40,17 @@ class LogicalOperator(Statement, Generic[S, D, SC, DC]): ) +@dataclass class UnaryLogicalOperator(LogicalOperator[S, Optional[D], Optional[SC], Optional[DC]]): - type: Type = None - operand1: Operand = None + operand1: Operand +@dataclass class BinaryLogicalOperator( LogicalOperator[S, Optional[D], Optional[SC], Optional[DC]] ): - type: Type = None - operand1: Operand = None - operand2: Operand = None + operand1: Operand + operand2: Operand # class OpAny(UnaryLogicalOperatorFuzzMixin, UnaryLogicalOperator[OpTypeBool]): @@ -57,42 +60,49 @@ class BinaryLogicalOperator( # ... +@dataclass class OpLogicalEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeBool, OpTypeBool, None, None] ): ... +@dataclass class OpLogicalNotEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeBool, OpTypeBool, None, None] ): ... +@dataclass class OpLogicalOr( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeBool, OpTypeBool, None, None] ): ... +@dataclass class OpLogicalAnd( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeBool, OpTypeBool, None, None] ): ... +@dataclass class OpLogicalNot( UnaryOperatorFuzzMixin, UnaryLogicalOperator[OpTypeBool, OpTypeBool, None, None] ): ... +@dataclass class OpIEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, None, None] ): ... +@dataclass class OpINotEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, None, None] ): @@ -106,12 +116,14 @@ class OpUGreaterThan( ... +@dataclass class OpSGreaterThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Signed, None] ): ... +@dataclass class OpUGreaterThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Unsigned, None], @@ -119,12 +131,14 @@ class OpUGreaterThanEqual( ... +@dataclass class OpSGreaterThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Signed, None] ): ... +@dataclass class OpULessThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Unsigned, None], @@ -132,12 +146,14 @@ class OpULessThan( ... +@dataclass class OpSLessThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Signed, None] ): ... +@dataclass class OpULessThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Unsigned, None], @@ -145,78 +161,91 @@ class OpULessThanEqual( ... +@dataclass class OpSLessThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeInt, OpTypeBool, Signed, None] ): ... +@dataclass class OpFOrdEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFOrdNotEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordNotEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFOrdLessThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordLessThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFOrdGreaterThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordGreaterThan( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFOrdLessThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordLessThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFOrdGreaterThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): ... +@dataclass class OpFUnordGreaterThanEqual( BinaryOperatorFuzzMixin, BinaryLogicalOperator[OpTypeFloat, OpTypeBool, None, None] ): diff --git a/src/operators/memory/__init__.py b/src/operators/memory/__init__.py index 7417541..178dfbd 100644 --- a/src/operators/memory/__init__.py +++ b/src/operators/memory/__init__.py @@ -1,5 +1,7 @@ from src import Statement +from src.patched_dataclass import dataclass +@dataclass class MemoryOperator(Statement): ... diff --git a/src/operators/memory/memory_access.py b/src/operators/memory/memory_access.py index eae7641..7754d16 100644 --- a/src/operators/memory/memory_access.py +++ b/src/operators/memory/memory_access.py @@ -1,9 +1,15 @@ import random +from dataclasses import field +from typing import Callable from typing import TYPE_CHECKING +from typing_extensions import Self + from src.constants import OpConstant +from src.operators import Operand from src.operators.memory import MemoryOperator from src.operators.memory.variable import OpVariable +from src.patched_dataclass import dataclass from src.predicates import HasType from src.predicates import IsCompositeType from src.predicates import IsMatrixType @@ -15,24 +21,28 @@ if TYPE_CHECKING: from src.context import Context from src import ( + AbortFuzzing, + FuzzResult, OpCode, Statement, Untyped, VoidOp, ) from src.types.concrete_types import ( + EmptyType, OpTypeInt, OpTypePointer, Type, ) +@dataclass class OpLoad(MemoryOperator): - type: Type = None - variable: OpVariable = None + variable: OpVariable # memory_operands: Optional[???] - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: variable: OpVariable = random.SystemRandom().choice( list( filter( @@ -41,42 +51,35 @@ def fuzz(self, context: "Context") -> list[OpCode]: ) ) ) - self.type: Type = variable.type.type - self.variable = variable - return [self] + return FuzzResult(cls(type=variable.type.type, variable=variable)) -class OpStore(MemoryOperator, OpCode, Untyped, VoidOp): - pointer: OpTypePointer = None - object: OpCode = None +@dataclass +class OpStore(MemoryOperator, Untyped, VoidOp): + pointer: OpTypePointer + object: OpCode # memory_operands: Optional[???] - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: pointer: OpTypePointer = context.get_random_operand(IsPointerType) - if not pointer: - return [] - target_object: Statement = context.get_random_operand( - HasType(pointer.type.type) - ) - if not target_object: - return [] - self.pointer = pointer - self.object = target_object - return [self] + target_object: Operand = context.get_random_operand(HasType(pointer.type.type)) + return FuzzResult(cls(type=EmptyType(), pointer=pointer, object=target_object)) +@dataclass class OpAccessChain(MemoryOperator): - type: Type = None - base: OpVariable = None - indexes: tuple[OpConstant] = [] + base: OpVariable + indexes: tuple[OpConstant, ...] - def fuzz(self, context: "Context") -> list[OpCode]: - predicate = lambda var: IsCompositeType(var.type) + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + predicate: Callable[[OpVariable], bool] = lambda var: IsCompositeType(var.type) base: OpVariable = random.SystemRandom().choice( list(filter(predicate, context.get_storage_buffers())) ) if base is None: - return [] + raise AbortFuzzing composite_pointer = base.type if IsMatrixType(composite_pointer): indexes = ( @@ -93,12 +96,11 @@ def fuzz(self, context: "Context") -> list[OpCode]: if IsStructType(composite_pointer) else composite_pointer.get_base_type() ) - self.type = OpTypePointer() - self.type.storage_class = base.storage_class - self.type.type = pointer_inner_type - context.add_to_tvc(self.type) - self.base = base - self.indexes: tuple[OpConstant] = tuple( + pointer_type = OpTypePointer( + storage_class=base.storage_class, type=pointer_inner_type + ) + context.add_to_tvc(pointer_type) + indexes: tuple[OpConstant] = tuple( [ context.create_on_demand_numerical_constant( OpTypeInt, value=idx, width=32, signed=0 @@ -106,7 +108,7 @@ def fuzz(self, context: "Context") -> list[OpCode]: for idx in indexes ] ) - return [self] + return FuzzResult(cls(type=pointer_type, base=base, indexes=indexes)) # class OpArrayLength(OpCode): diff --git a/src/operators/memory/variable.py b/src/operators/memory/variable.py index 2571725..63f1c4a 100644 --- a/src/operators/memory/variable.py +++ b/src/operators/memory/variable.py @@ -1,14 +1,20 @@ import random +from dataclasses import fields from typing import TYPE_CHECKING -from src.operators.memory import MemoryOperator +from typing_extensions import Self +from src.operators.memory import MemoryOperator +from src.patched_dataclass import dataclass if TYPE_CHECKING: from src.context import Context from src.enums import StorageClass from src import ( + AbortFuzzing, + FuzzResult, OpCode, + Type, ) from src.types.concrete_types import ( OpTypeBool, @@ -17,13 +23,20 @@ ) +@dataclass class OpVariable(MemoryOperator): - context: "Context" = None - type: OpTypePointer = None - storage_class: StorageClass = None + storage_class: StorageClass - def fuzz(self, context: "Context") -> list[OpCode]: + def hashing_members(self): + return tuple( + [x.name for x in fields(self.__class__) if x.name not in {"id", "context"}] + ) + def get_base_type(self) -> Type: + return self.type.get_base_type() + + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: if context.function: storage_class = StorageClass.Function else: @@ -32,10 +45,8 @@ def fuzz(self, context: "Context") -> list[OpCode]: if context.is_compute_shader() else StorageClass.Input ) - self.context = context - dynamic = False try: - self.type = random.SystemRandom().choice( + variable_type = random.SystemRandom().choice( list( filter( lambda t: isinstance(t, OpTypePointer) @@ -52,18 +63,15 @@ def fuzz(self, context: "Context") -> list[OpCode]: ) ) except IndexError: - dynamic = True if context.function: - return [] - self.type = OpTypePointer() - self.type.storage_class = storage_class + raise AbortFuzzing target_storage_class = ( StorageClass.StorageBuffer if context.is_compute_shader() else StorageClass.Input ) if storage_class == target_storage_class: - self.type.type = random.SystemRandom().choice( + pointer_inner_type = random.SystemRandom().choice( list( filter( lambda tvc: isinstance(tvc, (OpTypeStruct)) @@ -73,7 +81,7 @@ def fuzz(self, context: "Context") -> list[OpCode]: ) ) else: - self.type.type = random.SystemRandom().choice( + pointer_inner_type = random.SystemRandom().choice( list( filter( lambda tvc: isinstance(tvc, (OpTypeStruct)), @@ -81,7 +89,9 @@ def fuzz(self, context: "Context") -> list[OpCode]: ) ) ) - self.storage_class = storage_class - if dynamic: - return [self.type, self] - return [self] + variable_type = OpTypePointer( + storage_class=storage_class, type=pointer_inner_type + ) + return FuzzResult( + cls(type=variable_type, storage_class=storage_class), [variable_type] + ) diff --git a/src/optimiser_fuzzer.py b/src/optimiser_fuzzer.py index 5b34309..b414623 100644 --- a/src/optimiser_fuzzer.py +++ b/src/optimiser_fuzzer.py @@ -1,3 +1,4 @@ +import signal import subprocess import tempfile from concurrent.futures import ThreadPoolExecutor @@ -77,17 +78,19 @@ def _fuzz_optimiser(shader: "SPIRVShader", filename: str): capture_output=True, ) if process.returncode != 0: - Monitor().error( + Monitor(shader.context.config).error( event=Event.OPTIMIZER_FAILURE, extra={ "stderr": process.stderr.decode("utf-8"), + "stdout": process.stdout.decode("utf-8"), + "is_segfault": process.returncode == -signal.SIGSEGV, "cli_args": str(process.args), "shader_id": shader.id, "spirv-opt_flags": spirv_opt_flags, }, ) else: - Monitor().info( + Monitor(shader.context.config).info( event=Event.OPTIMIZER_SUCCESS, extra={"shader_id": shader.id, "spirv-opt_flags": spirv_opt_flags}, ) diff --git a/src/patched_dataclass.py b/src/patched_dataclass.py new file mode 100644 index 0000000..df7f9cd --- /dev/null +++ b/src/patched_dataclass.py @@ -0,0 +1,12 @@ +from dataclasses import dataclass + + +dataclass = dataclass( + init=True, + repr=False, + eq=False, + order=False, + unsafe_hash=False, + frozen=False, + slots=True, +) diff --git a/src/predicates.py b/src/predicates.py index 80d3a59..104ea13 100644 --- a/src/predicates.py +++ b/src/predicates.py @@ -35,6 +35,7 @@ IsStructType = IsOfType(OpTypeStruct) IsPointerType = IsOfType(OpTypePointer) IsCompositeType = IsOfType((OpTypeMatrix, OpTypeVector, OpTypeStruct, OpTypeArray)) +IsArithmeticType = IsOfType((OpTypeFloat, OpTypeInt, OpTypeVector)) IsScalarInteger = IsOfType(OpTypeInt) IsScalarFloat = IsOfType(OpTypeFloat) diff --git a/src/recondition.py b/src/recondition.py index 532cf3a..efea36c 100644 --- a/src/recondition.py +++ b/src/recondition.py @@ -79,13 +79,9 @@ def recondition(context: Context, opcode: VectorAccessOutOfBoundsVulnerableOpCod ) if index_type.signed: - mod = OpSMod + op_mod = OpSMod(index_type, operand1, operand2) else: - mod = OpUMod - op_mod = mod() - op_mod.type = index_type - op_mod.operand1 = operand1 - op_mod.operand2 = operand2 + op_mod = OpUMod(index_type, operand1, operand2) opcode.index = op_mod return [op_mod] @@ -106,9 +102,9 @@ def recondition( """Recondition |x| > 1 scalars using x := x - floor(x).""" op_fract = OpExtInst( type=opcode.operand1.type, - extension_set=context.extension_sets["GLSL"], + extension_set=context.extension_sets["GLSL.std.450"], instruction=Fract, - operands=[opcode.operand1], + operands=(opcode.operand1,), ) opcode.operand1 = op_fract return [op_fract] @@ -133,19 +129,16 @@ def recondition( # Operands will always be floats op_abs = OpExtInst( type=opcode.operand1.type, - extension_set=context.extension_sets["GLSL"], + extension_set=context.extension_sets["GLSL.std.450"], instruction=FAbs, - operands=[opcode.operand1], + operands=(opcode.operand1,), ) const_one = context.create_on_demand_numerical_constant(OpTypeFloat, value=1.0) if IsVectorType(opcode.operand1): const_one = context.create_on_demand_vector_constant( inner_constant=const_one, size=len(opcode.operand1.type) ) - op_add = OpFAdd() - op_add.type = opcode.operand1.type - op_add.operand1 = op_abs - op_add.operand2 = const_one + op_add = OpFAdd(opcode.operand1.type, op_abs, const_one) opcode.operand1 = op_add return [op_abs, op_add] @@ -183,23 +176,11 @@ def recondition( const_one = context.create_on_demand_vector_constant( inner_constant=const_one, size=len(opcode.operand1.type) ) - op_sub1 = sub() - op_sub1.type = opcode.operand1.type - op_sub1.operand1 = opcode.operand1 - op_sub1.operand2 = opcode.operand2 - op_add1 = add() - op_add1.type = opcode.operand1.type - op_add1.operand1 = op_sub1 - op_add1.operand2 = const_one - - op_sub2 = sub() - op_sub2.type = opcode.operand2.type - op_sub2.operand1 = opcode.operand2 - op_sub2.operand2 = opcode.operand1 - op_add2 = add() - op_add2.type = opcode.operand2.type - op_add2.operand1 = op_sub2 - op_add2.operand2 = const_one + op_sub1 = sub(opcode.operand1.type, opcode.operand1, opcode.operand2) + op_add1 = add(opcode.operand1.type, op_sub1, const_one) + + op_sub2 = sub(opcode.operand2.type, opcode.operand2, opcode.operand1) + op_add2 = add(opcode.operand2.type, op_sub2, const_one) opcode.operand1 = op_add1 opcode.operand2 = op_add2 @@ -225,28 +206,28 @@ def recondition( """ match opcode.__name__: case "FClamp": - op_min = FMin() - op_max = FMax() + op_min = FMin + op_max = FMax case "UClamp": - op_min = UMin() - op_max = UMax() + op_min = UMin + op_max = UMax case "SClamp": - op_min = SMin() - op_max = SMax() + op_min = SMin + op_max = SMax case "NClamp": - op_min = NMin() - op_max = NMax() + op_min = NMin + op_max = NMax op_min = OpExtInst( type=opcode.operand2.type, - extension_set=context.extension_sets["GLSL"], - instruction=op_min.__class__, - operands=[opcode.operand2, opcode.operand3], + extension_set=context.extension_sets["GLSL.std.450"], + instruction=op_min, + operands=(opcode.operand2, opcode.operand3), ) op_max = OpExtInst( type=opcode.operand2.type, - extension_set=context.extension_sets["GLSL"], - instruction=op_max.__class__, - operands=[opcode.operand2, opcode.operand3], + extension_set=context.extension_sets["GLSL.std.450"], + instruction=op_max, + operands=(opcode.operand2, opcode.operand3), ) opcode.operand2 = op_min opcode.operand3 = op_max @@ -272,27 +253,25 @@ def recondition( y := |y| % sizeof(base_type(x)) """ base_type = opcode.operand2.get_base_type() + const = context.create_on_demand_numerical_constant( + base_type.__class__, + value=base_type.width, + width=base_type.width, + signed=base_type.signed, + ) op_abs = None if base_type.signed: # TODO the Abs shouldn't be necessary but SPIRV-Cross generates undefined MSL otherwise. # See https://github.com/KhronosGroup/SPIRV-Cross/issues/1933 op_abs = OpExtInst( type=opcode.operand2.type, - extension_set=context.extension_sets["GLSL"], + extension_set=context.extension_sets["GLSL.std.450"], instruction=SAbs, - operands=[opcode.operand2], + operands=(opcode.operand2,), ) - op_mod = OpSMod() + op_mod = OpSMod(opcode.operand2.type, op_abs, const) else: - op_mod = OpUMod() - op_mod.type = opcode.operand2.type - op_mod.operand1 = op_abs if op_abs else opcode.operand2 - op_mod.operand2 = context.create_on_demand_numerical_constant( - base_type.__class__, - value=base_type.width, - width=base_type.width, - signed=base_type.signed, - ) + op_mod = OpUMod(opcode.operand2.type, opcode.operand2, const) if IsVectorType(opcode.operand1): op_mod.operand2 = context.create_on_demand_vector_constant( inner_constant=op_mod.operand2, size=len(opcode.operand1.type) diff --git a/src/shader_brokerage.py b/src/shader_brokerage.py index 6e95381..a4c6fef 100644 --- a/src/shader_brokerage.py +++ b/src/shader_brokerage.py @@ -6,10 +6,14 @@ from google.cloud import bigquery from google.cloud import storage +import sys -STORAGE_CLIENT = storage.Client.from_service_account_json("infra/spirvsmith_gcp.json") -BQ_CLIENT = bigquery.Client.from_service_account_json("infra/spirvsmith_gcp.json") -BUCKET = STORAGE_CLIENT.get_bucket("spirv_shaders_bucket") +if "pytest" not in sys.modules: + STORAGE_CLIENT = storage.Client.from_service_account_json( + "infra/spirvsmith_gcp.json" + ) + BQ_CLIENT = bigquery.Client.from_service_account_json("infra/spirvsmith_gcp.json") + BUCKET = STORAGE_CLIENT.get_bucket("spirv_shaders_bucket") def upload_shader_to_gcs(shader: "SPIRVShader") -> None: @@ -20,7 +24,7 @@ def upload_shader_to_gcs(shader: "SPIRVShader") -> None: def download_shader_from_gcs(shader_id: str) -> "SPIRVShader": blob = BUCKET.blob(f"{shader_id}.pkl") - pickled_shader: str = blob.download_as_bytes() + pickled_shader: bytes = blob.download_as_bytes() return pickle.loads(pickled_shader) diff --git a/src/shader_parser.py b/src/shader_parser.py new file mode 100644 index 0000000..4832077 --- /dev/null +++ b/src/shader_parser.py @@ -0,0 +1,169 @@ +from dataclasses import fields +from inspect import isclass +from typing import Optional + +from src import OpCode +from src.context import Context +from src.enums import AddressingModel +from src.enums import Capability +from src.enums import ExecutionModel +from src.enums import MemoryModel +from src.enums import SPIRVEnum +from src.misc import OpCapability +from src.misc import OpEntryPoint +from src.misc import OpExecutionMode +from src.misc import OpMemoryModel +from src.shader_utils import SPIRVShader +from src.types.concrete_types import EmptyType +from src.utils import get_opcode_class_from_name + + +def attempt_numeric_coercion(string: str) -> int | float | str: + if string.isnumeric() or string.replace("-", "").isnumeric(): + return int(string) + try: + val = float(string) + return val + except (TypeError, ValueError): + return string + + +def resolve_operands( + opcode_class: type[OpCode], + operands: list[str], + opcode_lookup_table: dict[str, OpCode], +) -> tuple[OpCode | str | int | float, ...]: + resolved_operands: list[OpCode | str | int | float] = [] + enum_idx: int = 0 + for operand in operands: + if operand.startswith("%"): + resolved_operands.append(opcode_lookup_table[operand]) + else: + resolved_operand: int | float | str = attempt_numeric_coercion(operand) + if isinstance(resolved_operand, str): + try: + resolved_operand: OpCode = get_opcode_class_from_name(operand) + except KeyError: + enums: list[type[SPIRVEnum]] = [ + x.type + for x in fields(opcode_class) + if isclass(x.type) and issubclass(x.type, SPIRVEnum) + ][enum_idx:] + if enums: + enum_class: type[SPIRVEnum] = enums[0] + try: + if resolved_operand == "None": + resolved_operand = "NONE" + resolved_operand = enum_class(resolved_operand) + except ValueError: + pass + else: + enum_idx += 1 + else: + resolved_operand = resolved_operand.replace('"', "") + resolved_operands.append(resolved_operand) + typed_operands: tuple[OpCode] = tuple(resolved_operands) + if opcode_class.__name__ == "OpTypeStruct": + typed_operands = (typed_operands,) + if opcode_class.__name__ == "OpReturn": + typed_operands = (EmptyType(),) + if opcode_class.__name__ == "OpStore": + typed_operands = (EmptyType(), *typed_operands) + elif opcode_class.__name__ == "OpConstantComposite": + typed_operands = (typed_operands[0], typed_operands[1:]) + elif opcode_class.__name__ in { + "OpCompositeExtract", + "OpExecutionMode", + "OpAccessChain", + "OpDecorate", + }: + typed_operands = (*typed_operands[:2], typed_operands[2:]) + elif opcode_class.__name__ in { + "OpExtInst", + "OpVectorShuffle", + "OpCompositeInsert", + "OpEntryPoint", + "OpMemberDecorate", + }: + typed_operands = (*typed_operands[:3], typed_operands[3:]) + return typed_operands + + +def parse_spirv_assembly_file(filename: str) -> SPIRVShader: + with open(filename, "r") as fr: + lines: list[list[str]] = list( + map(lambda l: l.strip().split(" "), fr.readlines()) + ) + capabilities: list[OpCapability] = [] + global_context: Context = Context.create_global_context( + ExecutionModel.GLCompute, None + ) + current_context = global_context + deferred_lines: list[list[str]] = [] + opcode_lookup_table: dict[str, OpCode] = {} + opcodes: list[OpCode] = [] + current_opcode: Optional[OpCode] = None + for line in lines: + match line: + case [";", *_]: + continue + case ["OpCapability", capability]: + capabilities.append(OpCapability(Capability(capability))) + case ["OpMemoryModel", addressing_model, memory_model]: + memory_model: OpMemoryModel = OpMemoryModel( + AddressingModel(addressing_model), MemoryModel(memory_model) + ) + case [ + "OpEntryPoint" | "OpExecutionMode" | "OpDecorate" | "OpMemberDecorate", + *_, + ]: + deferred_lines.append(line) + case [opcode_id, "=", opcode_name, *operands]: + opcode_class: type[OpCode] = get_opcode_class_from_name(opcode_name) + resolved_operands: tuple[OpCode] = resolve_operands( + opcode_class, operands, opcode_lookup_table + ) + current_opcode = opcode_class(*resolved_operands) + current_opcode.id = opcode_id.replace("%", "") + opcode_lookup_table[opcode_id] = current_opcode + case [opcode_name, *operands]: + opcode_class: type[OpCode] = get_opcode_class_from_name(opcode_name) + resolved_operands: tuple[OpCode] = resolve_operands( + opcode_class, operands, opcode_lookup_table + ) + current_opcode = opcode_class(*resolved_operands) + if current_opcode is not None: + # Massive hacks ahead to avoid the double import trap + if current_opcode.__class__.__name__.startswith( + ("OpType", "OpConstant", "OpVariable") + ): + current_context.add_to_tvc(current_opcode) + elif current_opcode.__class__.__name__ == "OpExtInstImport": + current_context.extension_sets[current_opcode.name] = current_opcode + else: + current_context.symbol_table.append(current_opcode) + if current_opcode.__class__.__name__ == "OpFunction": + current_context = current_context.make_child_context(current_opcode) + current_context.current_function_type = current_opcode.function_type + opcodes.append(current_opcode) + current_opcode = None + for [opcode_name, *operands] in deferred_lines: + opcode_class: type[OpCode] = get_opcode_class_from_name(opcode_name) + resolved_operands: tuple[OpCode] = resolve_operands( + opcode_class, operands, opcode_lookup_table + ) + opcode: OpCode = opcode_class(*resolved_operands) + if opcode_name in {"OpDecorate", "OpMemberDecorate"}: + current_context.add_annotation(opcode) + elif opcode_name == "OpEntryPoint": + entry_point: OpEntryPoint = opcode + elif opcode_name == "OpExecutionMode": + execution_mode: OpExecutionMode = opcode + return SPIRVShader( + capabilities=capabilities, + memory_model=memory_model, + entry_point=entry_point, + execution_mode=execution_mode, + opcodes=opcodes, + context=current_context.get_global_context(), + ) diff --git a/src/shader_utils.py b/src/shader_utils.py index 9cc45dc..fbf09b9 100644 --- a/src/shader_utils.py +++ b/src/shader_utils.py @@ -9,7 +9,9 @@ from src import OpCode from src.context import Context -from src.enums import StorageClass +from src.enums import ( + StorageClass, +) from src.misc import OpCapability from src.misc import OpEntryPoint from src.misc import OpExecutionMode @@ -19,6 +21,7 @@ from src.operators.memory.variable import OpVariable from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeInt +from src.utils import get_opcode_class_from_name @dataclass @@ -43,24 +46,13 @@ def export(self, filename: str) -> None: f.write("; Schema: 0\n") for capability in self.capabilities: f.write(capability.to_spasm(self.context)) - f.write("\n") for ext in self.context.extension_sets.values(): f.write(ext.to_spasm(self.context)) - f.write("\n") f.write(self.memory_model.to_spasm(self.context)) - f.write("\n") f.write(self.entry_point.to_spasm(self.context)) - f.write("\n") - # TODO - # f.write(self.execution_mode.to_spasm(self.context)) - # f.write("\n") - f.write( - f"OpExecutionMode %{self.execution_mode.function.id} {self.execution_mode.execution_mode} 1 1 1" - ) - f.write("\n") - for annotation in self.context.annotations: + f.write(self.execution_mode.to_spasm(self.context)) + for annotation in self.context.get_global_context().annotations.keys(): f.write(annotation.to_spasm(self.context)) - f.write("\n") for tvc, _ in self.context.tvc.items(): if ( isinstance(tvc, OpVariable) @@ -68,10 +60,8 @@ def export(self, filename: str) -> None: ): continue f.write(tvc.to_spasm(self.context)) - f.write("\n") for opcode in self.opcodes: f.write(opcode.to_spasm(self.context)) - f.write("\n") # class CrossLanguage(Enum): @@ -118,7 +108,7 @@ def assemble_shader(shader: SPIRVShader, filename: str, silent: bool = False) -> capture_output=True, ) if process.returncode != 0 and not silent: - Monitor().error( + Monitor(shader.context.config).error( event=Event.ASSEMBLER_FAILURE, extra={ "stderr": process.stderr.decode("utf-8"), @@ -127,7 +117,7 @@ def assemble_shader(shader: SPIRVShader, filename: str, silent: bool = False) -> }, ) elif not silent: - Monitor().info( + Monitor(shader.context.config).info( event=Event.ASSEMBLER_SUCCESS, extra={"shader_id": shader.id} ) @@ -150,7 +140,7 @@ def validate_spirv_file( capture_output=True, ) if process.returncode != 0 and not silent: - Monitor().error( + Monitor(shader.context.config).error( event=Event.VALIDATOR_OPT_FAILURE if opt else Event.VALIDATOR_FAILURE, extra={ "stderr": process.stderr.decode("utf-8"), @@ -159,7 +149,7 @@ def validate_spirv_file( }, ) elif not silent: - Monitor().info( + Monitor(shader.context.config).info( event=Event.VALIDATOR_OPT_SUCCESS if opt else Event.VALIDATOR_SUCCESS, extra={"shader_id": shader.id}, ) @@ -179,7 +169,7 @@ def optimise_spirv_file(shader: SPIRVShader, filename: str) -> bool: capture_output=True, ) if process.returncode != 0: - Monitor().error( + Monitor(shader.context.config).error( event=Event.OPTIMIZER_FAILURE, extra={ "stderr": process.stderr.decode("utf-8"), @@ -188,7 +178,9 @@ def optimise_spirv_file(shader: SPIRVShader, filename: str) -> bool: }, ) else: - Monitor().info(event=Event.OPTIMIZER_SUCCESS, extra={"shader_id": shader.id}) + Monitor(shader.context.config).info( + event=Event.OPTIMIZER_SUCCESS, extra={"shader_id": shader.id} + ) return process.returncode == 0 @@ -267,7 +259,7 @@ def create_amber_file(shader: SPIRVShader, filename: str) -> None: ) ) case _: - Monitor().error( + Monitor(shader.context.config).error( event=Event.INVALID_TYPE_AMBER_BUFFER, extra={ "shader_id": shader.id, diff --git a/src/types/abstract_types.py b/src/types/abstract_types.py index 609a822..9cf5397 100644 --- a/src/types/abstract_types.py +++ b/src/types/abstract_types.py @@ -1,30 +1,34 @@ +from typing import Generic +from typing import TypeVar + from src import Type +from src.patched_dataclass import dataclass +@dataclass class ScalarType(Type): ... -class NumericalType(Type): - ... - - +@dataclass class ContainerType(Type): ... -class ArithmeticType(Type): - ... - - # TODO I fucking hate this type, look into reworking the whole type system +@dataclass class MiscType(Type): ... -class UniformContainerType(ContainerType): - ... +T = TypeVar("T", bound=Type) + + +@dataclass +class UniformContainerType(Generic[T], ContainerType): + type: T +@dataclass class MixedContainerType(ContainerType): ... diff --git a/src/types/concrete_types.py b/src/types/concrete_types.py index 4390308..c0e3a84 100644 --- a/src/types/concrete_types.py +++ b/src/types/concrete_types.py @@ -1,67 +1,84 @@ import random +from dataclasses import field +from typing import NoReturn from typing import TYPE_CHECKING -from src import FuzzLeaf +from typing_extensions import Self + +from src import AbortFuzzing +from src import FuzzLeafMixin +from src import FuzzResult from src import OpCode from src import ReparametrizationError from src.enums import Capability from src.enums import StorageClass +from src.patched_dataclass import dataclass if TYPE_CHECKING: from src.context import Context from src.types.abstract_types import ( - ArithmeticType, ContainerType, MiscType, MixedContainerType, - NumericalType, ScalarType, Type, UniformContainerType, ) -class OpTypeVoid(FuzzLeaf, MiscType): +@dataclass +class EmptyType(MiscType): + @classmethod + def fuzz(cls, context: "Context") -> NoReturn: + MiscType.set_zero_probability(cls, context) + raise AbortFuzzing + + +@dataclass +class OpTypeVoid(FuzzLeafMixin, MiscType): ... -class OpTypeBool(FuzzLeaf, ScalarType): +@dataclass +class OpTypeBool(FuzzLeafMixin, ScalarType): def get_base_type(self): return self -class OpTypeInt(ScalarType, NumericalType, ArithmeticType): - width: int = None - signed: int = None +@dataclass +class OpTypeInt(ScalarType): + width: int + signed: int - def fuzz(self, context: "Context") -> list[OpCode]: - self.width = 2**5 # TODO other widths with capabilities - self.signed = int(bool(random.getrandbits(1))) - return [self] + @classmethod + def fuzz(cls, _: "Context") -> FuzzResult[Self]: + return FuzzResult(cls(width=2**5, signed=int(bool(random.getrandbits(1))))) def get_base_type(self): return self -class OpTypeFloat(ScalarType, NumericalType, ArithmeticType): - width: int = None +@dataclass +class OpTypeFloat(ScalarType): + width: int - def fuzz(self, context: "Context") -> list[OpCode]: - self.width = 2**5 # TODO other widths with capabilities - return [self] + @classmethod + def fuzz(cls, _: "Context") -> FuzzResult[Self]: + return FuzzResult(cls(width=2**5), []) def get_base_type(self): return self -class OpTypeVector(UniformContainerType, ArithmeticType): - type: Type = None - size: int = None +@dataclass +class OpTypeVector(UniformContainerType[ScalarType]): + size: int - def fuzz(self, context: "Context") -> list[OpCode]: - self.type = ScalarType().fuzz(context)[0] - self.size = random.SystemRandom().choice([2, 3, 4]) - return [self.type, self] + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + fuzzed_inner_type: ScalarType = ScalarType.fuzz(context).opcode + size: int = random.SystemRandom().choice([2, 3, 4]) + return FuzzResult(cls(type=fuzzed_inner_type, size=size), [fuzzed_inner_type]) def __len__(self): return self.size @@ -70,29 +87,32 @@ def get_base_type(self): return self.type.get_base_type() -class OpTypeMatrix(UniformContainerType): - type: OpTypeVector = None - size: int = None +@dataclass +class OpTypeMatrix(UniformContainerType[OpTypeVector]): + size: int - def fuzz(self, context: "Context") -> list[OpCode]: - matrix_type = OpTypeVector().fuzz(context)[-1] - matrix_type.type = OpTypeFloat().fuzz(context)[0] - self.type = matrix_type - self.size = random.SystemRandom().choice([2, 3, 4]) # 8, 16]) - return [matrix_type.type, matrix_type, self] + @classmethod + def fuzz(cls, _: "Context") -> FuzzResult[Self]: + n_columns: int = random.SystemRandom().choice([2, 3, 4]) + n_rows: int = random.SystemRandom().choice([2, 3, 4]) + float_type: OpTypeFloat = OpTypeFloat(width=32) + vector_type: OpTypeVector = OpTypeVector(type=float_type, size=n_rows) + return FuzzResult( + cls(type=vector_type, size=n_columns), [float_type, vector_type] + ) def __len__(self): return self.size - def get_required_capabilities(self) -> list[Capability]: + @staticmethod + def get_required_capabilities() -> list[Capability]: return [Capability.Matrix] - def get_base_type(self): + def get_base_type(self) -> ScalarType: return self.type.get_base_type() # class OpTypeImage(UniformContainerType): -# type: Type = None # dim: Dim = None # depth: int = None # arrayed: int = None @@ -120,18 +140,20 @@ def get_base_type(self): # return [self.type, self] -class OpTypeArray(UniformContainerType): - type: Type = None - length: OpCode = None - - def fuzz(self, context: "Context") -> list[OpCode]: +@dataclass +class OpTypeArray(UniformContainerType[ScalarType]): + length: OpCode - self.type = ScalarType().fuzz(context)[0] - - self.length = context.create_on_demand_numerical_constant( + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + fuzzed_inner_type: ScalarType = ScalarType.fuzz(context).opcode + length = context.create_on_demand_numerical_constant( OpTypeInt, value=random.SystemRandom().randint(1, 32), width=32, signed=0 ) - return [self.type, self.length.type, self.length, self] + return FuzzResult( + cls(type=fuzzed_inner_type, length=length), + [fuzzed_inner_type], + ) def __len__(self): return self.length.value @@ -141,68 +163,69 @@ def get_base_type(self): # class OpTypeRuntimeArray(UniformContainerType): -# type: Type = None # def fuzz(self, context: "Context") -> list[OpCode]: # self.type = ScalarType().fuzz(context)[0] # return [self.type, self] +@dataclass class OpTypeStruct(MixedContainerType): - types: tuple[Type] = None + types: tuple[Type, ...] - def fuzz(self, context: "Context") -> list[OpCode]: - self.types = [] + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + struct_types = [] side_effect_types = [] for _ in range(random.SystemRandom().randint(2, 5)): # TODO relax parameter type constraint - parameter_type = ( - random.SystemRandom().choice([NumericalType])().fuzz(context) + fuzzed_parameter_type: FuzzResult = ( + random.SystemRandom().choice([OpTypeFloat, OpTypeInt]).fuzz(context) ) - if parameter_type == []: - continue - self.types.append(parameter_type[-1]) - side_effect_types += parameter_type - self.types = tuple(self.types) - return [*side_effect_types, *self.types, self] + struct_types.append(fuzzed_parameter_type.opcode) + side_effect_types += fuzzed_parameter_type.side_effects + side_effect_types.append(fuzzed_parameter_type.opcode) + return FuzzResult(cls(types=tuple(struct_types)), side_effect_types) def __len__(self): return len(self.types) -class OpTypePointer(UniformContainerType): - storage_class: StorageClass = None - type: Type = None +@dataclass +class OpTypePointer(MixedContainerType): + storage_class: StorageClass + type: Type - def fuzz(self, context: "Context") -> list[OpCode]: - self.storage_class = StorageClass.StorageBuffer - fuzzed_type = ( - random.SystemRandom().choice([ScalarType, ContainerType])().fuzz(context) + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: + fuzzed_type: FuzzResult = ( + random.SystemRandom().choice([ScalarType, ContainerType]).fuzz(context) + ) + return FuzzResult( + cls(type=fuzzed_type.opcode, storage_class=StorageClass.StorageBuffer), + fuzzed_type.side_effects + [fuzzed_type.opcode], ) - self.type = fuzzed_type[-1] - return [*fuzzed_type, self] +@dataclass class OpTypeFunction(MiscType): - return_type: Type = None - parameter_types: tuple[Type] = None + return_type: Type + parameter_types: tuple[Type, ...] = field(default_factory=tuple) - def fuzz(self, context: "Context") -> list[OpCode]: + @classmethod + def fuzz(cls, context: "Context") -> FuzzResult[Self]: if len(context.get_function_types()) >= context.config.limits.n_functions: - MiscType.set_zero_probability(self.__class__) + MiscType.set_zero_probability(cls, context) raise ReparametrizationError # return_type = random.SystemRandom().choice([ScalarType, ContainerType])().fuzz(context) - return_type = [OpTypeVoid()] - self.return_type = return_type[-1] - self.parameter_types = [] - all_types = return_type + return_type = OpTypeVoid() + parameter_types = [] for _ in range(random.SystemRandom().randint(4, 7)): parameter_type = ( - random.SystemRandom() - .choice([ScalarType, ContainerType])() - .fuzz(context) + random.SystemRandom().choice([ScalarType, ContainerType]).fuzz(context) ) - self.parameter_types.append(parameter_type[-1]) - all_types += parameter_type - self.parameter_types = tuple(self.parameter_types) - return [*all_types, self] + parameter_types.append(parameter_type.opcode) + return FuzzResult( + cls(return_type=return_type, parameter_types=tuple(parameter_types)), + parameter_types, + ) diff --git a/src/utils.py b/src/utils.py index 9bcd5c4..6e9ec57 100644 --- a/src/utils.py +++ b/src/utils.py @@ -2,6 +2,8 @@ import git +from src import OpCode + def get_spirvsmith_version() -> str: if os.getenv("CI"): @@ -11,3 +13,32 @@ def get_spirvsmith_version() -> str: filter(None, repo.tags), key=lambda t: t.commit.committed_datetime ) return tags[-1].name + + +def get_opcode_class_from_name(opcode_name: str) -> OpCode: + import src.operators.arithmetic.scalar_arithmetic + import src.operators.arithmetic.linear_algebra + import src.operators.arithmetic.glsl + import src.operators.memory.memory_access + import src.operators.memory.variable + import src.operators.bitwise + import src.operators.composite + import src.operators.conversions + import src.operators.logic + import src.annotations + import src.constants + import src.extension + import src.function + + subclasses: set[OpCode] = set() + find_subclasses_dfs(subclasses, OpCode) + opcode_lookup: dict[str, OpCode] = dict( + zip(map(lambda cls: cls.__name__, subclasses), subclasses) + ) + return opcode_lookup[opcode_name] + + +def find_subclasses_dfs(subclasses: set[OpCode], cls: OpCode) -> None: + for subclass in cls.__subclasses__(): + subclasses.add(subclass) + find_subclasses_dfs(subclasses, subclass) diff --git a/tests/__init__.py b/tests/__init__.py index 1b1f248..5e525a1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,4 +1,29 @@ import logging +from typing import TYPE_CHECKING + +from src import Type +from src.constants import OpConstant +from src.constants import OpConstantComposite + +if TYPE_CHECKING: + from src.context import Context +from src.types.concrete_types import OpTypeVector logging.disable(logging.CRITICAL) + + +def create_vector_const( + context: "Context", inner_type: Type, size: int = 4, value: int = 42 +) -> OpConstant: + const: OpConstant = context.create_on_demand_numerical_constant( + inner_type, value=value, width=32 + ) + + vector_type = OpTypeVector(type=const.type, size=size) + vector_const = OpConstantComposite( + type=vector_type, constituents=tuple([const] * size) + ) + context.add_to_tvc(vector_type) + context.add_to_tvc(vector_const) + return vector_const diff --git a/tests/test_arithmetic.py b/tests/test_arithmetic.py index 6f532db..f9d9f3a 100644 --- a/tests/test_arithmetic.py +++ b/tests/test_arithmetic.py @@ -3,9 +3,7 @@ from run import SPIRVSmithConfig from src import FuzzDelegator -from src import Type from src.constants import OpConstant -from src.constants import OpConstantComposite from src.context import Context from src.enums import ExecutionModel from src.monitor import Monitor @@ -15,33 +13,17 @@ from src.operators.arithmetic.linear_algebra import OpVectorTimesMatrix from src.operators.arithmetic.linear_algebra import OpVectorTimesScalar from src.types.concrete_types import OpTypeFloat -from src.types.concrete_types import OpTypeVector +from tests import create_vector_const N = 1000 -monitor = Monitor() config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False - - -def create_vector_const(context: Context, inner_type: Type, size: int = 4): - const: OpConstant = context.create_on_demand_numerical_constant( - inner_type, value=42, width=32 - ) - - vector_type = OpTypeVector() - vector_type.type = const.type - vector_type.size = size - context.add_to_tvc(vector_type) - - vector_const = OpConstantComposite() - vector_const.type = vector_type - vector_const.constituents = tuple([const for _ in range(size)]) - context.add_to_tvc(vector_const) - return vector_const +config.misc.upload_logs = False +monitor = Monitor(config) class TestArithmetic(unittest.TestCase): @@ -50,15 +32,15 @@ def setUp(self): config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_vector_times_scalar_preserves_type(self): const: OpConstant = create_vector_const(self.context, OpTypeFloat) - vector_times_scalar: OpVectorTimesScalar = OpVectorTimesScalar().fuzz( + vector_times_scalar: OpVectorTimesScalar = OpVectorTimesScalar.fuzz( self.context - )[-1] + ).opcode self.assertEqual(vector_times_scalar.type, const.type) @@ -66,7 +48,7 @@ def test_outer_product_has_correct_shape(self): create_vector_const(self.context, OpTypeFloat, size=4) create_vector_const(self.context, OpTypeFloat, size=2) - outer_product: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + outer_product: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode # columns self.assertEqual(len(outer_product.type), len(outer_product.operand2.type)) @@ -78,13 +60,13 @@ def test_vector_times_matrix_has_correct_shape(self): create_vector_const(self.context, OpTypeFloat, size=2) # Here we get either: mat2x2, mat2x4, mat4x2, mat4x4 - outer_product: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + outer_product: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode self.context.symbol_table.append(outer_product) # This should always find operands - vector_times_matrix: OpVectorTimesMatrix = OpVectorTimesMatrix().fuzz( + vector_times_matrix: OpVectorTimesMatrix = OpVectorTimesMatrix.fuzz( self.context - )[-1] + ).opcode # The resulting vector must have as many elements as the matrix has columns self.assertEqual(len(vector_times_matrix.type), len(outer_product.type)) @@ -94,13 +76,13 @@ def test_matrix_times_vector_has_correct_shape(self): create_vector_const(self.context, OpTypeFloat, size=2) # Here we get either: mat2x2, mat2x4, mat4x2, mat4x4 - outer_product: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + outer_product: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode self.context.symbol_table.append(outer_product) # This should always find operands - matrix_times_vector: OpMatrixTimesVector = OpMatrixTimesVector().fuzz( + matrix_times_vector: OpMatrixTimesVector = OpMatrixTimesVector.fuzz( self.context - )[-1] + ).opcode # The resulting vector must have as many elements as the matrix has rows self.assertEqual(len(matrix_times_vector.type), len(outer_product.type.type)) @@ -110,20 +92,20 @@ def test_matrix_times_matrix_has_correct_shape(self): create_vector_const(self.context, OpTypeFloat, size=2) # Here we get either: mat2x2, mat2x4, mat4x2, mat4x4 - outer_product1: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + outer_product1: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode self.context.symbol_table.append(outer_product1) # We do this to avoid having two outer products that - # eeturn a mat2x4/mat4x2 which will fail the test + # return a mat2x4/mat4x2 which will fail the test outer_product2 = copy.deepcopy(outer_product1) - while outer_product2 == outer_product1: - outer_product2: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + while outer_product2.type == outer_product1.type: + outer_product2: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode self.context.symbol_table.append(outer_product2) # This should always find operands - matrix_times_matrix: OpMatrixTimesMatrix = OpMatrixTimesMatrix().fuzz( + matrix_times_matrix: OpMatrixTimesMatrix = OpMatrixTimesMatrix.fuzz( self.context - )[-1] + ).opcode # The left matrix should have as many columns as the right matrix has rows self.assertEqual( diff --git a/tests/test_composite.py b/tests/test_composite.py index f31bacf..044520c 100644 --- a/tests/test_composite.py +++ b/tests/test_composite.py @@ -3,7 +3,6 @@ from run import SPIRVSmithConfig from src import FuzzDelegator -from src import Type from src.constants import OpConstant from src.constants import OpConstantComposite from src.context import Context @@ -18,73 +17,68 @@ from src.operators.composite import OpVectorExtractDynamic from src.operators.composite import OpVectorInsertDynamic from src.types.concrete_types import OpTypeFloat -from src.types.concrete_types import OpTypeVector +from src.types.concrete_types import OpTypeInt +from tests import create_vector_const N = 1000 -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) -def create_vector_const(context: Context, inner_type: Type, size: int = 4): - const: OpConstant = context.create_on_demand_numerical_constant( - inner_type, value=42, width=32 - ) - - vector_type = OpTypeVector() - vector_type.type = const.type - vector_type.size = size - context.add_to_tvc(vector_type) - - vector_const = OpConstantComposite() - vector_const.type = vector_type - vector_const.constituents = tuple([const for _ in range(size)]) - context.add_to_tvc(vector_const) - return vector_const - - -class TestArithmetic(unittest.TestCase): +class TestComposite(unittest.TestCase): def setUp(self): FuzzDelegator.reset_parametrizations() config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_vector_dynamic_extract_has_correct_type(self): + index_const: OpConstant = self.context.create_on_demand_numerical_constant( + OpTypeInt + ) vec_const: OpConstantComposite = create_vector_const(self.context, OpTypeFloat) - - vector_extract: OpVectorExtractDynamic = OpVectorExtractDynamic().fuzz( + vector_extract: OpVectorExtractDynamic = OpVectorExtractDynamic.fuzz( self.context - )[-1] + ).opcode self.assertEqual(vector_extract.type, vec_const.get_base_type()) + self.assertEqual(vector_extract.index, index_const) def test_vector_insert_preserves_type(self): + index_const: OpConstant = self.context.create_on_demand_numerical_constant( + OpTypeInt + ) vec_const: OpConstantComposite = create_vector_const(self.context, OpTypeFloat) - vector_insert: OpVectorInsertDynamic = OpVectorInsertDynamic().fuzz( + vector_insert: OpVectorInsertDynamic = OpVectorInsertDynamic.fuzz( self.context - )[-1] + ).opcode self.assertEqual(vector_insert.type, vec_const.type) + self.assertEqual(vector_insert.index, index_const) def test_composite_extract_has_correct_type(self): vec_const: OpConstantComposite = create_vector_const(self.context, OpTypeFloat) - vector_extract: OpCompositeExtract = OpCompositeExtract().fuzz(self.context)[-1] + vector_extract: OpCompositeExtract = OpCompositeExtract.fuzz( + self.context + ).opcode self.assertEqual(vector_extract.type, vec_const.get_base_type()) def test_composite_insert_preserves_type(self): vec_const: OpConstantComposite = create_vector_const(self.context, OpTypeFloat) - vector_insert: OpCompositeInsert = OpCompositeInsert().fuzz(self.context)[-1] + vector_insert: OpCompositeInsert = OpCompositeInsert.fuzz(self.context).opcode self.assertEqual(vector_insert.type, vec_const.type) @@ -92,10 +86,10 @@ def test_transpose_has_correct_shape(self): create_vector_const(self.context, OpTypeFloat, size=4) create_vector_const(self.context, OpTypeFloat, size=2) - outer_product: OpOuterProduct = OpOuterProduct().fuzz(self.context)[-1] + outer_product: OpOuterProduct = OpOuterProduct.fuzz(self.context).opcode self.context.symbol_table.append(outer_product) - transpose: OpTranspose = OpTranspose().fuzz(self.context)[-1] + transpose: OpTranspose = OpTranspose.fuzz(self.context).opcode self.assertEqual(len(transpose.type), len(outer_product.type.type)) self.assertEqual(len(transpose.type.type), len(outer_product.type)) diff --git a/tests/test_constants.py b/tests/test_constants.py index 7cdd5b7..76d520c 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -13,35 +13,37 @@ from src.types.concrete_types import OpTypeInt N = 5000 -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) -class TestMemory(unittest.TestCase): +class TestConstants(unittest.TestCase): def setUp(self): FuzzDelegator.reset_parametrizations() config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_fuzzing_bool_constants(self): - bool_constant1 = OpConstantTrue().fuzz(self.context) - bool_constant2 = OpConstantFalse().fuzz(self.context) - self.assertEqual(bool_constant1[0], OpTypeBool()) - self.assertEqual(bool_constant2[0], OpTypeBool()) + bool_constant1 = OpConstantTrue.fuzz(self.context) + bool_constant2 = OpConstantFalse.fuzz(self.context) + self.assertEqual(bool_constant1.opcode.type, OpTypeBool()) + self.assertEqual(bool_constant2.opcode.type, OpTypeBool()) def test_fuzzing_numerical_constants_montecarlo(self): signedness_counter = {0: 0, 1: 0} constants = [] for _ in range(N): - const = OpConstant().fuzz(self.context)[-1] + const = OpConstant.fuzz(self.context).opcode if isinstance(const.type, OpTypeInt): signedness_counter[const.type.signed] += 1 constants.append(const) diff --git a/tests/test_context.py b/tests/test_context.py index 8e0fb01..ad19f2c 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -8,8 +8,9 @@ from src.enums import ExecutionModel from src.monitor import Monitor from src.operators.arithmetic.scalar_arithmetic import OpISub -from src.types.abstract_types import ArithmeticType +from src.predicates import IsArithmeticType from src.types.abstract_types import MiscType +from src.types.abstract_types import ScalarType from src.types.concrete_types import OpTypeBool from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeFunction @@ -17,13 +18,15 @@ from src.types.concrete_types import OpTypeVector N = 500 -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) class TestContext(unittest.TestCase): @@ -32,7 +35,7 @@ def setUp(self): config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_context_registers_all_constants(self): @@ -40,13 +43,7 @@ def test_context_registers_all_constants(self): self.context.create_on_demand_numerical_constant(OpTypeInt, value=1) self.assertEqual( - len( - list( - self.context.get_constants( - lambda sym: (isinstance(sym.type, ArithmeticType)) - ) - ) - ), + len(list(self.context.get_constants(IsArithmeticType))), 2, ) @@ -59,13 +56,7 @@ def test_constants_of_same_value_and_type_should_be_conflated_int(self): ) self.assertTrue( - len( - list( - self.context.get_constants( - lambda sym: (isinstance(sym.type, ArithmeticType)) - ) - ) - ), + len(list(self.context.get_constants(IsArithmeticType))), 1, ) self.assertEqual(constant1, constant2) @@ -77,66 +68,44 @@ def test_context_same_types_should_be_conflated_bool(self): self.context.tvc[bool_type1] = bool_type1.id self.context.tvc[bool_type2] = bool_type2.id - self.assertEqual(len(self.context.tvc), 3) + self.assertEqual(len(self.context.tvc), 1) def test_context_same_types_should_be_conflated_int(self): - int_type1 = OpTypeInt() - int_type1.width = 32 - int_type1.signed = 1 - - int_type2 = OpTypeInt() - int_type2.width = 32 - int_type2.signed = 1 + int_type1 = OpTypeInt(32, 1) + int_type2 = OpTypeInt(32, 1) self.context.tvc[int_type1] = int_type1.id self.context.tvc[int_type2] = int_type2.id - self.assertEqual(len(self.context.tvc), 3) + self.assertEqual(len(self.context.tvc), 1) def test_context_same_types_should_be_conflated_vector1(self): - int_type = OpTypeInt() - int_type.width = 32 - int_type.signed = 1 + int_type = OpTypeInt(32, 1) self.context.tvc[int_type] = int_type.id - vec_type1 = OpTypeVector() - vec_type1.size = 4 - vec_type1.type = int_type - - vec_type2 = OpTypeVector() - vec_type2.size = 4 - vec_type2.type = int_type + vec_type1 = OpTypeVector(int_type, 4) + vec_type2 = OpTypeVector(int_type, 4) self.context.tvc[vec_type1] = vec_type1.id self.context.tvc[vec_type2] = vec_type2.id - self.assertEqual(len(self.context.tvc), 4) + self.assertEqual(len(self.context.tvc), 2) def test_context_same_types_should_be_conflated_vector2(self): - int_type1 = OpTypeInt() - int_type1.width = 32 - int_type1.signed = 1 - - int_type2 = OpTypeInt() - int_type2.width = 32 - int_type2.signed = 1 + int_type1 = OpTypeInt(32, 1) + int_type2 = OpTypeInt(32, 1) self.context.tvc[int_type1] = int_type1.id self.context.tvc[int_type2] = int_type2.id - vec_type1 = OpTypeVector() - vec_type1.size = 4 - vec_type1.type = int_type1 - - vec_type2 = OpTypeVector() - vec_type2.size = 4 - vec_type2.type = int_type2 + vec_type1 = OpTypeVector(int_type1, 4) + vec_type2 = OpTypeVector(int_type2, 4) self.context.tvc[vec_type1] = vec_type1.id self.context.tvc[vec_type2] = vec_type2.id - self.assertEqual(len(self.context.tvc), 4) + self.assertEqual(len(self.context.tvc), 2) def test_context_variables_in_different_scopes_should_not_be_conflated(self): pass @@ -145,7 +114,7 @@ def test_context_finds_all_arithmetic_operands(self): constant1 = self.context.create_on_demand_numerical_constant(OpTypeInt, 0) constant2 = self.context.create_on_demand_numerical_constant(OpTypeInt, 1) - operator = OpISub().fuzz(self.context)[-1] + operator = OpISub.fuzz(self.context).opcode self.assertTrue( operator.operand1 == constant1 or operator.operand1 == constant2 @@ -157,7 +126,7 @@ def test_context_finds_all_arithmetic_operands_monte_carlo(self): counter = {constant1: 0, constant2: 0} for _ in range(N): - operator = OpISub().fuzz(self.context)[-1] + operator = OpISub.fuzz(self.context).opcode counter[operator.operand1] += 1 counter[operator.operand2] += 1 @@ -173,26 +142,19 @@ def test_depth_is_correct(self): def test_numerical_types_distributed_correctly(self): self.context.config.limits.n_types = N - self.context.config.strategy.w_scalar_type = 0 - self.context.config.strategy.w_numerical_type = 1 self.context.config.strategy.w_container_type = 0 - self.context.config.strategy.w_arithmetic_type = 0 - - Type().parametrize(self.context) - Type.get_parametrization()[MiscType.__name__] = 0 - - # All possible numerical types - type1: Type = OpTypeInt().fuzz(self.context)[-1] - type1.signed = 0 - type2: Type = OpTypeInt().fuzz(self.context)[-1] - type2.signed = 1 + Type.parametrize(self.context) + Type.set_zero_probability(MiscType, self.context) + ScalarType.set_zero_probability(OpTypeBool, self.context) - type3: Type = OpTypeFloat().fuzz(self.context)[-1] + type1: Type = OpTypeInt(32, 0) + type2: Type = OpTypeInt(32, 1) + type3: Type = OpTypeFloat(32) counter = {type1: 0, type2: 0, type3: 0} - types = [Type().fuzz(self.context)[-1] for _ in range(N)] + types = [Type.fuzz(self.context).opcode for _ in range(N)] for type in types: counter[type] += 1 @@ -204,13 +166,11 @@ def test_numerical_types_distributed_correctly(self): def test_correct_number_of_function_types_created(self): self.context.config.limits.n_types = N self.context.config.strategy.w_scalar_type = 1 - self.context.config.strategy.w_numerical_type = 1 self.context.config.strategy.w_container_type = 1 - self.context.config.strategy.w_arithmetic_type = 1 self.context.config.limits.n_functions = 5 - Type().parametrize(self.context) + Type.parametrize(self.context) self.context.gen_types() diff --git a/tests/test_memory.py b/tests/test_memory.py index daf4673..5b26648 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -9,13 +9,15 @@ from src.monitor import Monitor from src.operators.memory.memory_access import OpLoad -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) class TestMemory(unittest.TestCase): @@ -24,12 +26,12 @@ def setUp(self): config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_opload_finds_global_variable(self): self.context.config.limits.n_types = 100 self.context.gen_types() variable = self.context.create_on_demand_variable(StorageClass.StorageBuffer) - op_load: OpLoad = OpLoad().fuzz(self.context)[-1] + op_load: OpLoad = OpLoad.fuzz(self.context).opcode self.assertEqual(op_load.variable, variable) diff --git a/tests/test_parser.py b/tests/test_parser.py new file mode 100644 index 0000000..b9077d5 --- /dev/null +++ b/tests/test_parser.py @@ -0,0 +1,103 @@ +import copy +import unittest +from dataclasses import fields +from tempfile import NamedTemporaryFile + +from run import SPIRVSmithConfig +from src import FuzzDelegator +from src.context import Context +from src.enums import ExecutionModel +from src.fuzzing_server import ShaderGenerator +from src.monitor import Monitor +from src.shader_parser import parse_spirv_assembly_file +from src.shader_utils import SPIRVShader + +config = SPIRVSmithConfig() +init_strategy = copy.deepcopy(config.strategy) +init_limits = copy.deepcopy(config.limits) + +config.misc.broadcast_generated_shaders = False +config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) + + +class TestParser(unittest.TestCase): + def setUp(self): + FuzzDelegator.reset_parametrizations() + config.limits = copy.deepcopy(init_limits) + config.strategy = copy.deepcopy(init_strategy) + self.context: Context = Context.create_global_context( + ExecutionModel.GLCompute, config + ) + + def test_parser_fully_reconstructs_tvc(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertSetEqual( + set(shader.context.tvc.keys()), set(parsed_shader.context.tvc.keys()) + ) + + def test_parser_fully_reconstructs_operands(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + # print(shader.opcodes) + # print(list(map(hash, shader.opcodes))) + # print(parsed_shader.opcodes) + # print(list(map(hash, parsed_shader.opcodes))) + self.assertListEqual(shader.opcodes, parsed_shader.opcodes) + + def test_parser_fully_reconstructs_annotatons(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertSetEqual( + set(shader.context.annotations.keys()), + set(parsed_shader.context.annotations.keys()), + ) + + def test_parser_reconstructs_entry_point(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertEqual(shader.entry_point, parsed_shader.entry_point) + + def test_parser_reconstructs_execution_mode(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertEqual(shader.execution_mode, parsed_shader.execution_mode) + + def test_parser_reconstructs_memory_model(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertEqual(shader.memory_model, parsed_shader.memory_model) + + def test_parser_reconstructs_capabilities(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as tmp: + shader.export(tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(tmp.name) + self.assertListEqual(shader.capabilities, parsed_shader.capabilities) + + def test_parsed_shader_generates_same_assembly_file(self): + shader: SPIRVShader = ShaderGenerator(config, None).gen_shader() + with NamedTemporaryFile(suffix=".spasm") as orig_tmp: + shader.export(orig_tmp.name) + parsed_shader: SPIRVShader = parse_spirv_assembly_file(orig_tmp.name) + with NamedTemporaryFile(suffix=".spasm") as parsed_tmp: + parsed_shader.export(parsed_tmp.name) + with open(orig_tmp.name, "r") as orig_file: + with open(parsed_tmp.name, "r") as parsed_file: + original_lines = list(map(str.strip, orig_file.readlines())) + parsed_lines = list(map(str.strip, parsed_file.readlines())) + self.assertListEqual(original_lines, parsed_lines) diff --git a/tests/test_recondition.py b/tests/test_recondition.py index 3202fd0..5c99276 100644 --- a/tests/test_recondition.py +++ b/tests/test_recondition.py @@ -13,13 +13,15 @@ from src.types.concrete_types import OpTypeInt from src.types.concrete_types import OpTypeVector -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) class TestRecondition(unittest.TestCase): @@ -28,34 +30,27 @@ def setUp(self): config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_vector_access_is_reconditioned(self): - int_type = OpTypeInt() - int_type.width = 32 - int_type.signed = 1 - self.context.tvc[int_type] = int_type.id + int_type = OpTypeInt(32, 1) + vec_type = OpTypeVector(int_type, 4) - vec_type = OpTypeVector() - vec_type.size = 4 - vec_type.type = int_type + self.context.tvc[int_type] = int_type.id self.context.tvc[vec_type] = vec_type.id index = self.context.create_on_demand_numerical_constant( OpTypeInt, value=5, signed=1, width=32 ) - self.context.tvc[index] = index.id + vec_constant = OpConstantComposite( + vec_type, tuple([index for _ in range(len(vec_type))]) + ) - vec_constant = OpConstantComposite() - vec_constant.type = vec_type - vec_constant.constituents = tuple([index for _ in range(len(vec_type))]) - self.context.tvc[vec_type] = vec_type.id + self.context.tvc[vec_constant] = vec_constant.id + self.context.tvc[index] = index.id - vec_access = OpVectorExtractDynamic() - vec_access.type = int_type - vec_access.vector = vec_constant - vec_access.index = index + vec_access = OpVectorExtractDynamic(int_type, vec_constant, index) opcodes = [int_type, vec_type, index, vec_constant, vec_access] @@ -68,43 +63,29 @@ def test_vector_access_is_reconditioned(self): self.assertEqual(vec_access.index, reconditioned[4]) def test_two_vector_accesses_are_reconditioned(self): - context: Context = Context.create_global_context( - ExecutionModel.GLCompute, SPIRVSmithConfig(), monitor - ) + int_type = OpTypeInt(32, 1) + vec_type = OpTypeVector(int_type, 4) - int_type = OpTypeInt() - int_type.width = 32 - int_type.signed = 1 - context.tvc[int_type] = int_type.id - - vec_type = OpTypeVector() - vec_type.size = 4 - vec_type.type = int_type - context.tvc[vec_type] = vec_type.id + self.context.tvc[int_type] = int_type.id + self.context.tvc[vec_type] = vec_type.id - index = context.create_on_demand_numerical_constant( + index = self.context.create_on_demand_numerical_constant( OpTypeInt, value=5, signed=1, width=32 ) - context.tvc[index] = index.id + vec_constant = OpConstantComposite( + vec_type, tuple([index for _ in range(len(vec_type))]) + ) - vec_constant = OpConstantComposite() - vec_constant.type = vec_type - vec_constant.constituents = tuple([index for _ in range(len(vec_type))]) - context.tvc[vec_type] = vec_type.id + self.context.tvc[vec_constant] = vec_constant.id + self.context.tvc[index] = index.id - vec_access1 = OpVectorExtractDynamic() - vec_access1.type = int_type - vec_access1.vector = vec_constant - vec_access1.index = index + vec_access1 = OpVectorExtractDynamic(int_type, vec_constant, index) - vec_access2 = OpVectorExtractDynamic() - vec_access2.type = int_type - vec_access2.vector = vec_constant - vec_access2.index = index + vec_access2 = OpVectorExtractDynamic(int_type, vec_constant, index) opcodes = [int_type, vec_type, index, vec_constant, vec_access1, vec_access2] - reconditioned = recondition(context, opcodes) + reconditioned = recondition(self.context, opcodes) self.assertEqual(len(reconditioned), 8) self.assertTrue(isinstance(reconditioned[4], OpSMod)) diff --git a/tests/test_types.py b/tests/test_types.py index 0351830..fdd01f0 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -3,7 +3,6 @@ from run import SPIRVSmithConfig from src import FuzzDelegator -from src import Type from src.constants import OpConstant from src.constants import OpConstantComposite from src.context import Context @@ -13,44 +12,27 @@ from src.predicates import HaveSameType from src.types.concrete_types import OpTypeFloat from src.types.concrete_types import OpTypeInt -from src.types.concrete_types import OpTypeVector +from tests import create_vector_const N = 1000 -monitor = Monitor() + config = SPIRVSmithConfig() init_strategy = copy.deepcopy(config.strategy) init_limits = copy.deepcopy(config.limits) config.misc.broadcast_generated_shaders = False config.misc.start_web_server = False +config.misc.upload_logs = False +monitor = Monitor(config) -def create_vector_const( - context: Context, inner_type: Type, size: int = 4, value: int = 42 -): - const: OpConstant = context.create_on_demand_numerical_constant( - inner_type, value=value, width=32 - ) - - vector_type = OpTypeVector() - vector_type.type = const.type - vector_type.size = size - context.add_to_tvc(vector_type) - - vector_const = OpConstantComposite() - vector_const.type = vector_type - vector_const.constituents = tuple([const for _ in range(size)]) - context.add_to_tvc(vector_const) - return vector_const - - -class TestArithmetic(unittest.TestCase): +class TestTypes(unittest.TestCase): def setUp(self): FuzzDelegator.reset_parametrizations() config.limits = copy.deepcopy(init_limits) config.strategy = copy.deepcopy(init_strategy) self.context: Context = Context.create_global_context( - ExecutionModel.GLCompute, config, monitor + ExecutionModel.GLCompute, config ) def test_ints_same_width_and_signedness_are_equal(self): diff --git a/utils/patched_dataclass.py b/utils/patched_dataclass.py deleted file mode 100644 index 5e769de..0000000 --- a/utils/patched_dataclass.py +++ /dev/null @@ -1,6 +0,0 @@ -from dataclasses import dataclass - - -dataclass = dataclass( - init=True, repr=False, eq=False, order=False, unsafe_hash=False, frozen=False -)