From 9f3f8734927601a78f3454a5d1accea51e4cfd90 Mon Sep 17 00:00:00 2001 From: eopXD Date: Mon, 2 Jan 2023 22:51:56 -0800 Subject: [PATCH] Add the intrinsic generator framework This is a collective work from SiFive developers. Please checkout the CONTRIBUTORS file for the full list. On the other hand, this is a project released by SiFive under the Apache 2.0 license, please checkout LICENSE for the full terms and conditions. Signed-off-by: eop Chen Co-authored-by: Zakk Chen Co-authored-by: Kito Cheng Co-authored-by: Brandon Wu Co-authored-by: Han-Kuan Chen Co-authored-by: Hsiangkai Wang Co-authored-by: Jerry Zhang Jian --- rvv-intrinsic-generator/.gitignore | 105 ++++ rvv-intrinsic-generator/.pylintrc | 430 ++++++++++++++ rvv-intrinsic-generator/.style.yapf | 3 + rvv-intrinsic-generator/CONTRIBUTORS | 11 + rvv-intrinsic-generator/LICENSE | 203 +++++++ rvv-intrinsic-generator/Makefile | 263 +++++++++ rvv-intrinsic-generator/Makefile.api | 40 ++ rvv-intrinsic-generator/Makefile.api.llvm | 33 ++ rvv-intrinsic-generator/README.md | 20 + rvv-intrinsic-generator/overview.adoc | 72 +++ rvv-intrinsic-generator/requirements.txt | 4 + .../rvv_intrinsic_gen/__init__.py | 0 .../rvv_intrinsic_gen/constants.py | 35 ++ .../rvv_intrinsic_gen/enums.py | 166 ++++++ .../rvv_intrinsic_gen/generator.py | 440 ++++++++++++++ .../rvv_intrinsic_gen/inst.py | 545 ++++++++++++++++++ .../rvv_intrinsic_gen/intrinsic_decorator.py | 189 ++++++ .../rvv_intrinsic_gen/main.py | 163 ++++++ .../templates/binary_intcarry_template.py | 124 ++++ .../templates/binary_nop_template.py | 98 ++++ .../templates/binary_op_template.py | 145 +++++ .../templates/binary_wop_template.py | 135 +++++ .../templates/cmp_template.py | 80 +++ .../templates/cvt_op_template.py | 134 +++++ .../get_set_diff_lmul_op_template.py | 97 ++++ .../templates/load_template.py | 82 +++ .../templates/mac_template.py | 169 ++++++ .../templates/mask_load_store_template.py | 64 ++ .../templates/mask_template.py | 116 ++++ .../templates/misc_op_template.py | 86 +++ .../templates/permute_template.py | 104 ++++ .../templates/reduction_template.py | 87 +++ .../templates/reint_op_template.py | 109 ++++ .../templates/seg_load_template.py | 92 +++ .../templates/seg_store_template.py | 88 +++ .../templates/setvl_template.py | 53 ++ .../templates/store_template.py | 74 +++ .../templates/unary_op_template.py | 202 +++++++ .../templates/vtype_template.py | 31 + .../rvv_intrinsic_gen/utils.py | 213 +++++++ 40 files changed, 5105 insertions(+) create mode 100644 rvv-intrinsic-generator/.gitignore create mode 100644 rvv-intrinsic-generator/.pylintrc create mode 100644 rvv-intrinsic-generator/.style.yapf create mode 100644 rvv-intrinsic-generator/CONTRIBUTORS create mode 100644 rvv-intrinsic-generator/LICENSE create mode 100644 rvv-intrinsic-generator/Makefile create mode 100644 rvv-intrinsic-generator/Makefile.api create mode 100644 rvv-intrinsic-generator/Makefile.api.llvm create mode 100644 rvv-intrinsic-generator/README.md create mode 100644 rvv-intrinsic-generator/overview.adoc create mode 100644 rvv-intrinsic-generator/requirements.txt create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/__init__.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/constants.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/enums.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/generator.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/inst.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/intrinsic_decorator.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/main.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_intcarry_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_nop_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_wop_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cmp_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cvt_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/get_set_diff_lmul_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/load_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mac_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_load_store_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/misc_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/permute_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reduction_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reint_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_load_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_store_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/setvl_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/store_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/unary_op_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/templates/vtype_template.py create mode 100644 rvv-intrinsic-generator/rvv_intrinsic_gen/utils.py diff --git a/rvv-intrinsic-generator/.gitignore b/rvv-intrinsic-generator/.gitignore new file mode 100644 index 000000000..75cd0ca78 --- /dev/null +++ b/rvv-intrinsic-generator/.gitignore @@ -0,0 +1,105 @@ +public +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/rvv-intrinsic-generator/.pylintrc b/rvv-intrinsic-generator/.pylintrc new file mode 100644 index 000000000..ae0b04986 --- /dev/null +++ b/rvv-intrinsic-generator/.pylintrc @@ -0,0 +1,430 @@ +# This Pylint rcfile contains a best-effort configuration to uphold the +# best-practices and style described in the Google Python style guide: +# https://google.github.io/styleguide/pyguide.html +# +# Its canonical open-source location is: +# https://google.github.io/styleguide/pylintrc + +[MASTER] + +# Files or directories to be skipped. They should be base names, not paths. +ignore=third_party + +# Files or directories matching the regex patterns are skipped. The regex +# matches against base names, not paths. +ignore-patterns= + +# Pickle collected data for later comparisons. +persistent=no + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=abstract-method, + apply-builtin, + arguments-differ, + attribute-defined-outside-init, + backtick, + bad-option-value, + basestring-builtin, + buffer-builtin, + c-extension-no-member, + consider-using-enumerate, + cmp-builtin, + cmp-method, + coerce-builtin, + coerce-method, + delslice-method, + div-method, + duplicate-code, + eq-without-hash, + execfile-builtin, + file-builtin, + filter-builtin-not-iterating, + fixme, + getslice-method, + global-statement, + hex-method, + idiv-method, + implicit-str-concat, + import-error, + import-self, + import-star-module-level, + inconsistent-return-statements, + input-builtin, + intern-builtin, + invalid-str-codec, + locally-disabled, + long-builtin, + long-suffix, + map-builtin-not-iterating, + misplaced-comparison-constant, + missing-function-docstring, + metaclass-assignment, + next-method-called, + next-method-defined, + no-absolute-import, + no-else-break, + no-else-continue, + no-else-raise, + no-else-return, + no-init, # added + no-member, + no-name-in-module, + no-self-use, + nonzero-method, + oct-method, + old-division, + old-ne-operator, + old-octal-literal, + old-raise-syntax, + parameter-unpacking, + print-statement, + raising-string, + range-builtin-not-iterating, + raw_input-builtin, + rdiv-method, + reduce-builtin, + relative-import, + reload-builtin, + round-builtin, + setslice-method, + signature-differs, + standarderror-builtin, + suppressed-message, + sys-max-int, + too-few-public-methods, + too-many-ancestors, + too-many-arguments, + too-many-boolean-expressions, + too-many-branches, + too-many-instance-attributes, + too-many-locals, + too-many-nested-blocks, + too-many-public-methods, + too-many-return-statements, + too-many-statements, + trailing-newlines, + unichr-builtin, + unicode-builtin, + unnecessary-pass, + unpacking-in-except, + useless-else-on-loop, + useless-object-inheritance, + useless-suppression, + using-cmp-argument, + wrong-import-order, + xrange-builtin, + zip-builtin-not-iterating, + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# Good variable names which should always be accepted, separated by a comma +good-names=main,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl + +# Regular expression matching correct function names +function-rgx=^(?:(?PsetUp|tearDown|setUpModule|tearDownModule)|(?P_?[A-Z][a-zA-Z0-9]*)|(?P_?[a-z][a-z0-9_]*))$ + +# Regular expression matching correct variable names +variable-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct constant names +const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ + +# Regular expression matching correct attribute names +attr-rgx=^_{0,2}[a-z][a-z0-9_]*$ + +# Regular expression matching correct argument names +argument-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=^[a-z][a-z0-9_]*$ + +# Regular expression matching correct class names +class-rgx=^_?[A-Z][a-zA-Z0-9]*$ + +# Regular expression matching correct module names +module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$ + +# Regular expression matching correct method names +method-rgx=(?x)^(?:(?P_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P_{0,2}[a-z][a-z0-9_]*))$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=10 + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt +# lines made too long by directives to pytype. + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=(?x)( + ^\s*(\#\ )??$| + ^\s*(from\s+\S+\s+)?import\s+.+$) + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=yes + +# Maximum number of lines in a module +max-module-lines=99999 + +# String used as indentation unit. The internal Google style guide mandates 2 +# spaces. Google's externaly-published style guide says 4, consistent with +# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google +# projects (like TensorFlow). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=TODO + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=yes + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_) + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging,absl.logging,tensorflow.io.logging + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub, + TERMIOS, + Bastion, + rexec, + sets + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant, absl + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls, + class_ + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=StandardError, + Exception, + BaseException + diff --git a/rvv-intrinsic-generator/.style.yapf b/rvv-intrinsic-generator/.style.yapf new file mode 100644 index 000000000..64ab7f0ee --- /dev/null +++ b/rvv-intrinsic-generator/.style.yapf @@ -0,0 +1,3 @@ +[style] +based_on_style = yapf +indent_width = 2 diff --git a/rvv-intrinsic-generator/CONTRIBUTORS b/rvv-intrinsic-generator/CONTRIBUTORS new file mode 100644 index 000000000..bc13cbd87 --- /dev/null +++ b/rvv-intrinsic-generator/CONTRIBUTORS @@ -0,0 +1,11 @@ +The RISC-V Vector intrinsics generator is contributed by the following SiFive +developers. In alphabetical order, + +Brandon Wu +Eop Chen +HanKuan Chen +HsiangKai Wang +Jerry Zhang Jian +Kito Cheng +Yi-Hsiu Hsu +Zakk Chen diff --git a/rvv-intrinsic-generator/LICENSE b/rvv-intrinsic-generator/LICENSE new file mode 100644 index 000000000..cf00cdc0a --- /dev/null +++ b/rvv-intrinsic-generator/LICENSE @@ -0,0 +1,203 @@ +Copyright 2022 The RISC-V Vecctor Intrinsic Generator Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 The RISC-V Vecctor Intrinsic Generator Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/rvv-intrinsic-generator/Makefile b/rvv-intrinsic-generator/Makefile new file mode 100644 index 000000000..2af03436c --- /dev/null +++ b/rvv-intrinsic-generator/Makefile @@ -0,0 +1,263 @@ +############################################################################### +# Copyright 2022 SiFive Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +############################################################################### +# Utilities +############################################################################### +# Check that given variables are set and all have non-empty values, +# die with an error otherwise. +# +# Params: +# 1. Variable name(s) to test. +# 2. (optional) Error message to print. +check_defined = \ + $(strip $(foreach 1,$1, \ + $(call __check_defined,$1,$(strip $(value 2))))) +__check_defined = \ + $(if $(value $1),, \ + $(error Undefined $1$(if $2, ($2)))) + +# Replace softfloat float-point types with LLVM compatible floating-point types +replace_float = \ + sed -i 's/float16_t/_Float16/g' $(1)/*; \ + sed -i 's/float32_t/float/g' $(1)/*; \ + sed -i 's/float64_t/double/g' $(1)/* + +############################################################################### +# Variables +############################################################################### +# Path to the rvv_intrinsic_gen folder +RVV_INTRINSIC_GEN_PATH := $(CURDIR)/rvv_intrinsic_gen +# Vendor specific folder +VENDOR_PATH ?= +# Absolute vendor path +ABS_VENDOR_PATH := $(abspath $(VENDOR_PATH)) +# Python paths for module import +PYTHONPATHS = $(RVV_INTRINSIC_GEN_PATH):$(ABS_VENDOR_PATH) +# Requires Python3.6 or higher +PY3 := PYTHONPATH=$$PYTHONPATH:$(PYTHONPATHS) python3 +# Main entry script of the generator +MAIN := rvv_intrinsic_gen.main +# Main output directory is default to golden +OUTPUT_DIR := golden +# Derives output directory for each set of intrinsics +# Output directory for non-policy intrinsics +DIR := $(abspath $(OUTPUT_DIR)) +# Output directory for policy intrinsics +POLICY_DIR := $(DIR)/policy_funcs +# Derived variable to trigger option --vendor-inst +ifdef VENDOR_INST +TRIGGER_VENDOR_INST := --vendor-inst $(VENDOR_INST) +else +TRIGGER_VENDOR_INST := +endif + +############################################################################### +# Functions +############################################################################### +# Generate file $(2).md under $(1). The files contains all RVV intrinsic +# function prototypes, all in one file. +# $(1): Output path (relative) +# $(2): Output file name +# $(3): Generator mode +# $(4): Additional flags +define gen_doc + mkdir -p $(1) + rm -rf $(1)/$(2).md + $(PY3) -m $(MAIN) --gen $(3) --out $(1)/$(2).md $(4) $(TRIGGER_VENDOR_INST) +endef + +# Generate grouped files under $(1). Each file contains a group of RVV +# intrinsic prototypes. +# $(1): Output path (relative) +# $(2): Output folder name +# $(3): Generator mode +# $(4): Additional flags +define gen_docs + mkdir -p $(1) + rm $(1)/$(2) -rf + mkdir -p $(1)/$(2) + $(PY3) -m $(MAIN) --gen $(3) --out $(1)/$(2) $(4) $(TRIGGER_VENDOR_INST) +endef + +define gen_tests + rm $(1)/*.c -f + $(PY3) -m $(MAIN) --gen $(2) --out $(1) $(3) $(TRIGGER_VENDOR_INST) +endef + +############################################################################### +# Basic Targets +############################################################################### +# If VENDOR_GENERATOR_SCRIPT is defined, also trigger it in all. +# NOTE: A possible enhancement to this is allow multiple targets be added here +ifdef VENDOR_GENERATOR_SCRIPT +all: gen-document gen-test vendor-generator +else +all: gen-document gen-test +endif + +gen-document: non-overloaded-doc non-overloaded-docs overloaded-doc overloaded-docs +gen-test: non-overloaded-test overloaded-test llvm-non-overloaded-test llvm-overloaded-test + +# Generate all-in-one document for non-overloaded intrinsics +non-overloaded-doc: + $(call gen_doc,$(DIR),intrinsic_funcs,$@,) + $(call gen_doc,$(POLICY_DIR),intrinsic_funcs,$@,--has-policy) + +# Generate grouped documents for non-overloaded intrinsics +non-overloaded-docs: + $(call gen_docs,$(DIR),intrinsic_funcs,$@,) + $(call gen_docs,$(POLICY_DIR),intrinsic_funcs,$@,--has-policy) + +# Generate all-in-one document for overloaded intrinsics +overloaded-doc: + $(call gen_doc,$(DIR),overloaded_intrinsic_funcs,$@,) + $(call gen_doc,$(POLICY_DIR),overloaded_intrinsic_funcs,$@,--has-policy) + +# Generate grouped documents for overloaded intrinsics +overloaded-docs: + $(call gen_docs,$(DIR),overloaded_intrinsic_funcs,$@,) + $(call gen_docs,$(POLICY_DIR),overloaded_intrinsic_funcs,$@,--has-policy) + +# Generate non-overloaded intrinsic testing C source files +non-overloaded-test: + $(call gen_tests,$(DIR)/api-testing,non-overloaded-test,) + +# Generate overloaded intrinsic testing C source files +overloaded-test: + $(call gen_tests,$(DIR)/overloaded-api-testing,overloaded-test,) + +# Generate non-overloaded intrinsic testing C source files +llvm-non-overloaded-test: + $(call gen_tests,$(DIR)/llvm-api-tests,non-overloaded-test,--llvm) + $(call gen_tests,$(POLICY_DIR)/llvm-api-tests,non-overloaded-test,--llvm --has-policy) + $(call replace_float, $(DIR)/llvm-api-tests) + $(call replace_float, $(POLICY_DIR)/llvm-api-tests) + +# Generate overloaded intrinsic testing C source files +llvm-overloaded-test: + $(call gen_tests,$(DIR)/llvm-overloaded-tests,overloaded-test,--llvm) + $(call gen_tests,$(POLICY_DIR)/llvm-overloaded-tests,overloaded-test,--llvm --has-policy) + $(call replace_float, $(DIR)/llvm-overloaded-tests) + $(call replace_float, $(POLICY_DIR)/llvm-overloaded-tests) + +############################################################################### +# Golden Targets +############################################################################### +# This is essentially the same with 'make all' as ${OUTPUT_DIR} is default to +# `golden`, but removes golden/ first. +gen-golden: + rm -rf ${DIR} + make all OUTPUT_DIR=${OUTPUT_DIR} + +# Update and commit all files under golden +git-commit-golden: + make git-commit-golden-doc OUTPUT_DIR=${OUTPUT_DIR} + make git-commit-golden-test OUTPUT_DIR=${OUTPUT_DIR} + +# Update and commit all documents under golden +git-commit-golden-doc: + make gen-document OUTPUT_DIR=${OUTPUT_DIR} + git add ${DIR}/* + git commit -m "[Auto-gen] Update documents under ${OUTPUT_DIR}. (make git-commit-golden-doc)" + +# Update and commit all testing C source files under golden +git-commit-golden-test: + make gen-test + git add ${DIR}/* + git commit -m "[Auto-gen] Update tests under ${OUTPUT_DIR}. (make git-commit-golden-test)" + +# Runs diff with golden, requires ${TEST_DIR} to be provided. +GOLDEN_DIR = ${DIR} +TEST_DIR = .tmp +diff-golden: + $(call check_defined, TEST_DIR, output directory for documents/tests generation) + rm -rf ${abspath ${TEST_DIR}} + make OUTPUT_DIR=${TEST_DIR} + diff -qr ${TEST_DIR} ${GOLDEN_DIR} + +############################################################################### +# Testing Targets +############################################################################### +# Test golden/api-testing with testing-report +run-api-testing: + make run-test \ + API_DIR=golden/api-testing \ + API_MAKEFILE=Makefile.api \ + TESTING_REPORT_SCRIPT=testing-report + +# Test golden/overloaded-api-testing with testing-report +run-overloaded-api-testing: + make run-test \ + API_DIR=golden/overloaded-api-testing \ + API_MAKEFILE=Makefile.api \ + TESTING_REPORT_SCRIPT=testing-report + +# A parameterized target to run testing through testing-report. +# Makes target 'test' of ${API_MAKEFILE} with ${TESTING_REPORT_SCRIPT} under +# ${API_DIR}. Requires ${API_DIR}, ${API_MAKEFILE}, ${TESTING_REPORT_SCRIPT} +# to be provided. +run-test: + $(call check_defined, API_DIR, directory containing the C source file tests) + $(call check_defined, API_MAKEFILE, makefile for testing the files in API_DIR) + $(call check_defined, TESTING_REPORT_SCRIPT, script to generate testing report) + + if [ ! -d "${CURDIR}/${API_DIR}" ]; then \ + echo "Directory '${CURDIR}/${API_DIR}' does not exist"; \ + fi + if [ ! -f "${CURDIR}/${API_MAKEFILE}" ]; then \ + echo "File '${CURDIR}/${API_MAKEFILE}' does not exist"; \ + fi + if [ ! -f "${CURDIR}/${TESTING_REPORT_SCRIPT}" ]; then \ + echo "File '${CURDIR}/${TESTING_REPORT_SCRIPT}' does not exist"; \ + fi + make -C ${CURDIR}/${API_DIR} clean -f ${CURDIR}/${API_MAKEFILE} + make -C ${CURDIR}/${API_DIR} \ + BASE_DIR=${CURDIR}/${API_DIR} \ + TESTING_REPORT_SCRIPT=${CURDIR}/${TESTING_REPORT_SCRIPT} \ + CC=/sifive/tools/riscv-tools/riscv64-unknown-elf-toolsuite-13.0.0-2022.04.2-x86_64-linux-redhat8/bin/riscv64-unknown-elf-clang \ + -f ${CURDIR}/${API_MAKEFILE} + +############################################################################### +# Custom Vendor Generator Target +############################################################################### +VENDOR_GENERATOR_OUTPUT ?= +vendor-generator: + $(PY3) -m $(MAIN) --out $(DIR)/$(VENDOR_GENERATOR_OUTPUT) \ + $(TRIGGER_VENDOR_INST) \ + --vendor-generator-script $(VENDOR_GENERATOR_SCRIPT) \ + --vendor-generator-name $(VENDOR_GENERATOR_NAME) + +############################################################################### +# Formating Targets +############################################################################### +# Run pylint for all Python scripts +lint: + pylint --rcfile .pylintrc --recursive yes rvv_intrinsic_gen/*.py + pylint --rcfile .pylintrc --recursive yes rvv_intrinsic_gen/*/*.py + +# Run yapf for all Python scripts +yapf-format: + yapf --in-place --recursive rvv_intrinsic_gen/*.py + yapf --in-place --recursive rvv_intrinsic_gen/*/*.py + +yapf-check: + yapf --quiet --recursive rvv_intrinsic_gen/*.py + yapf --quiet --recursive rvv_intrinsic_gen/*/*.py + +# Run pytype for all Python scripts +type-check: + pytype . --pythonpath $(PYTHONPATHS) diff --git a/rvv-intrinsic-generator/Makefile.api b/rvv-intrinsic-generator/Makefile.api new file mode 100644 index 000000000..036ab47ac --- /dev/null +++ b/rvv-intrinsic-generator/Makefile.api @@ -0,0 +1,40 @@ +############################################################################### +# Copyright 2022 SiFive Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +CFLAGS?=-O -Werror=implicit-function-declaration +EXTRA_CFLAGS?=-march=rv64gcv_zvfh -menable-experimental-extensions + +TEST_MULTILIB:=rv32gcv-ilp32d,rv64gcv-lp64d + +TEST_FILES:=$(wildcard $(BASE_DIR)/*.c) +TEST_LOGS:=$(subst .c,.log,$(notdir $(TEST_FILES))) + +TESTSUITE_NAME?=Report +TESTING_REPORT_SCRIPT?=$(BASE_DIR)/../testing-report + +# TESTING_REPORT_SCRIPT should link to `rvv_intrinsic_gen/testing-report` +all: $(TEST_LOGS) + $(TESTING_REPORT_SCRIPT) --gen-junit-report --testsuite $(TESTSUITE_NAME) + +test: + echo $(TEST_FILES) + echo $(basename $(TEST_FILES)) + +clean: + rm *.log -f + +%.log: $(BASE_DIR)/%.c + -$(CC) $< -S -o /dev/null $(CFLAGS) $(EXTRA_CFLAGS) &> $@ diff --git a/rvv-intrinsic-generator/Makefile.api.llvm b/rvv-intrinsic-generator/Makefile.api.llvm new file mode 100644 index 000000000..1de0ca94a --- /dev/null +++ b/rvv-intrinsic-generator/Makefile.api.llvm @@ -0,0 +1,33 @@ +############################################################################### +# Copyright 2022 SiFive Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +CC:=clang +BASE_DIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +CFLAGS:=-O0 -Werror=implicit-function-declaration -I $(BASE_DIR) +EXTRA_CFLAGS:=--target=riscv64-unknown-elf-gnu -march=-march=rv64gcv_zvfh -menable-experimental-extensions -S -DFLMUL=1 + +TEST_FILES:=$(wildcard *.c) +TEST_LOGS:=$(subst .c,.log,$(TEST_FILES)) + +all: $(TEST_LOGS) + $(BASE_DIR)/testing-report + @echo "Test DONE" + +clean: + rm *.log -f + +%.log: %.c + -$(CC) $< -S -o /dev/null $(CFLAGS) $(EXTRA_CFLAGS) > $@ 2>&1 diff --git a/rvv-intrinsic-generator/README.md b/rvv-intrinsic-generator/README.md new file mode 100644 index 000000000..00302e5a5 --- /dev/null +++ b/rvv-intrinsic-generator/README.md @@ -0,0 +1,20 @@ +# RISC-V Vector Intrinsics Generator + +This generator generates the golden for the RISC-V Vector C intrinsic prototypes. Please checkout [overview.doc](./overview.adoc) for an overview of the generator and how to use it. + +## How to use + +```bash +git clone git@github.com:riscv-non-isa/rvv-intrinsic-generator.git +cd rvv-intrinsic-generator +python3 -m pip install -r requirements.txt +make gen-document +``` + +For more functionality, please checkout the [Makefile](./Makefile). + +## Note + +[LICENSE](./LICENSE) + +[CONTRIBUTORS](./CONTRIBUTORS) diff --git a/rvv-intrinsic-generator/overview.adoc b/rvv-intrinsic-generator/overview.adoc new file mode 100644 index 000000000..bca4645cd --- /dev/null +++ b/rvv-intrinsic-generator/overview.adoc @@ -0,0 +1,72 @@ += Overview of the RISC-V Vector intrinsics generator + +The RISC-V Vector intrinsic generator serves as the generator to generate all +RISC-V V intrinsic function prototypes. Although not required, it is expected +for the developer to have knowledge of the RISC-V Vector extension [0] while +reading through and modify the code. + +== Classes + +There are a few classes that might help you understand the project faster. + +=== Generator (`rvv_intrinsic_gen/generator.py`) + +This is the base class of a `Generator`. Other derived generators, namely +`DocGenerator`, `OverloadedDocGenerator`, `APITestGenerator`, and `Grouper` +are also defined under the same module. + +Notable functions are `function_group` and `func`. + +- The `function_group` method is called under `inst.py`, where the instructions +are listed out as raw data, with template attached, aside from other static +information (e.g. SEW, LMUL) that will form an intrinsic function. +- The `func` method is called under template modules (under +`rvv_intrinsic_gen/template`) containing the `render` function that slightly +alters some information before sending into `func`. Essentially `func` glues +the function name, return type, and function arguments together to form an +intrinsic function. + +=== TypeHelper (`rvv_intrinsic_gen/utils.py`) + +Given the SEW and LMUL during object construction, the class provides utility +to return strings of different data types that will be used in an intrinsic +function. The methods are in abbreviation, but some explanation here will +give you the taste to interpret the rest. + +- `v` is the vector type given the data type (that may be integer or float), +SEW, and LMUL +- `s` is the scalar type given the data type (that may be integer or float), +SEW, and LMUL +- `vm1` is the vector type but with LMUL fixed to `m1`. This is used in +vector reduction intrinsics because the `vd` register will always be `m1`. +Please refer to v-spec for exact detail. +- `uiv` is the unsigned integer vector type. +- `qv` is the quadra vector type and `ov` is the octa vector type. They are +used for the vector integer extension instructions. + +The `TypeHelper` is used under the template modules when getting the +appropriate data type for a intrinsic function. + +=== IntrinsicDecorator (`rvv_intrinsic_gen/intrinsic_decorator.py`) + +Given the attributes (collected by the `ExtraAttr` class under +`rvv_intrinsic_gen/enums.py`) upon construction, the decorator provides +appropriate masked function parameters for a intrinsic function. It also +helps decorate the function suffix if attributes specifies to be with +policy behavior specified or masked. + +== How the generator works + +The entry for execution is under `rvv_intrinsic_gen/main.py`. A generator +will be specified and forward to `inst.py::gen` the actual generation. +Under `inst.py::gen`, each call to `function_group` will be similar instruction +that shares the same SEW, LMUL, data type, and decorator. + +Through `function_group`, the information will be fed into the corresponding +template and rendered into the actual intrinsic function. + +== How to extend within this repository + +- You can add your own generator, customizing what you will do upon a +"`function_group`" and "`func`". +- You can add more instructions under `inst.py::gen`. diff --git a/rvv-intrinsic-generator/requirements.txt b/rvv-intrinsic-generator/requirements.txt new file mode 100644 index 000000000..3299a96b8 --- /dev/null +++ b/rvv-intrinsic-generator/requirements.txt @@ -0,0 +1,4 @@ +junitparser==2.6.0 +pylint==2.14.1 +yapf +pytype diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/__init__.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/constants.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/constants.py new file mode 100644 index 000000000..15915a6f6 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/constants.py @@ -0,0 +1,35 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +This file collects constant values. +""" + +LMULS = ["f8", "f4", "f2", 1, 2, 4, 8] +WLMULS = ["f8", "f4", "f2", 1, 2, 4] +NCVTLMULS = ["f4", "f2", 1, 2, 4, 8] +SEWS = [8, 16, 32, 64] +WSEWS = [8, 16, 32] +FSEWS = [16, 32, 64] +WFSEWS = [16, 32] +NSEWS = [16, 32, 64] +TYPES = ["float", "int", "uint"] +ITYPES = ["int", "uint"] +FTYPES = ["float"] +MTYPES = ["bool"] +MLENS = [1, 2, 4, 8, 16, 32, 64] +REF_DOC_URL = "../rvv-intrinsic-api.md" +REF_RFC_URL = "../rvv-intrinsic-rfc.md" diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/enums.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/enums.py new file mode 100644 index 000000000..7cd8e2e16 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/enums.py @@ -0,0 +1,166 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +This file stores enum classes and InstInfo that collects them. +""" +import enum + + +# First letter of InstType is return type. +class InstType(enum.Enum): + """ + Enum of instruction mnemonics. + """ + V = 0 + X = 1 + F = 2 + I = 3 + + VV = 11 + VX = 12 + VF = 13 + VM = 14 + XV = 15 + FV = 16 + VI = 17 + + VVV = 21 + VVX = 22 + VVF = 23 + VXX = 24 + VVI = 25 + + VVVM = 31 + VVXM = 32 + VVFM = 33 + + WVV = 41 + WVX = 42 + WVF = 43 + WVI = 44 + WWV = 45 + WWX = 46 + WWF = 47 + + WV = 51 + QV = 52 + OV = 53 + + VWV = 61 + VWX = 62 + VWF = 63 + + MM = 71 + MMM = 72 + + V1VV1 = 81 + W1VW1 = 82 + + SETVL = 100 + SETVLMAX = 101 + REINT = 102 + VUNDEF = 103 + LMUL_EXT = 104 + LMUL_TRUNC = 105 + VGET = 106 + VSET = 107 + + UNKNOWN = -1 + + +class MemType(enum.Enum): + """ + Enum of memory instruction type. + """ + NO_MEM = 0 + LOAD = 1 + STORE = 2 + AMO = 3 + + +class ExtraAttr: + """ + Enum of extra attributes of the intrinsic. + """ + NO_ATTR = 0 + MAC = 1 << 0 + REDUCE = 1 << 1 + MERGE = 1 << 2 + CONVERT = 1 << 3 + INT_EXTENSION = 1 << 4 + FIRST_FAULT = 1 << 5 + IS_MASK = 1 << 6 + NEED_MASKOFF = 1 << 7 + NEED_MERGE = 1 << 8 + IS_TA = 1 << 9 + IS_TU = 1 << 10 + IS_TAMA = 1 << 11 + IS_TAMU = 1 << 12 + IS_TUMA = 1 << 13 + IS_TUMU = 1 << 14 + IS_MA = 1 << 15 + IS_MU = 1 << 16 + IS_RED_TUMA = 1 << 17 + IS_RED_TAMA = 1 << 18 + + +class InstInfo: + """ + Structure that stores the information of the intrinsic. + """ + + def __init__(self, + SEW, + LMUL, + OP, + inst_type=InstType.UNKNOWN, + mem_type=MemType.NO_MEM, + extra_attr=ExtraAttr.NO_ATTR): + #pylint: disable=invalid-name + self.SEW = SEW + self.LMUL = LMUL + self.OP = OP + self.inst_type = inst_type + self.mem_type = mem_type + self.extra_attr = extra_attr + + def load_p(self): + return self.mem_type == MemType.LOAD + + def store_p(self): + return self.mem_type == MemType.STORE + + def mem_p(self): + return self.load_p() or self.store_p() + + @staticmethod + def get(args, + decorator, + inst_type, + mem_type=MemType.NO_MEM, + extra_attr=ExtraAttr.NO_ATTR): + if decorator is None: + # vsetvl and vsetvlmax + return InstInfo(args["SEW"], args["LMUL"], args["OP"], inst_type, + mem_type, extra_attr) + elif "SEW" in args: + return InstInfo(args["SEW"], args["LMUL"], args["OP"], inst_type, + mem_type, extra_attr | decorator.flags) + else: + # For mask operation + return InstInfo(0, 0, args["OP"], inst_type, mem_type, + extra_attr | decorator.flags) diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/generator.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/generator.py new file mode 100644 index 000000000..3c3661221 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/generator.py @@ -0,0 +1,440 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Generator classes that controls structures of the output. +""" +import os +import collections +import re + + +class Generator(): + """ + Base class for all generators. + """ + has_tail_policy = False + + def __init__(self): + self.generated_functions_set = set() + pass + + def write(self, text): + pass + + def write_title(self, text, link): + pass + + def inst_group_prologue(self): + return "" + + def inst_group_epilogue(self): + return "" + + def func(self, inst_info, name, return_type, **kwargs): + # pylint: disable=unused-argument + # FIXME: inst_info is currently only used by RIFGenerator. + self.generated_functions_set.add(name) + args = ", ".join(map(lambda a: f"{a[1]} {a[0]}", kwargs.items())) + # "T * name" to "T *name" + args = args.replace("* ", "*") + s = f"{return_type} {name} ({args});\n" + return s + + def function_group(self, template, title, link, op_list, type_list, sew_list, + lmul_list, decorator_list): + # pylint: disable=unused-argument + # NOTE: 'title' and 'link' are only used in DocGenerator and + # OverloadedDocGenerator. Probably need some decoupling here. + template.render( + G=self, + op_list=op_list, + type_list=type_list, + sew_list=sew_list, + lmul_list=lmul_list, + decorator_list=decorator_list) + + def start_group(self, group_name): + pass + + @staticmethod + def func_name(name): + name = name.replace("_uint", "_u") + name = name.replace("_int", "_i") + name = name.replace("_float", "_f") + name = name.replace("_bool", "_b") + return name + + # Some instructions don't have an overloaded version intrinsics because the + # reduced representation of the intrinsics is not expressable. Take vle8 as + # an example. Both intrinsics below share the same type of parameters, hence + # the LMUL is not derivable through the function parameters and has to be + # specified. + # vle8_v_i8m1 (const int8_t *base, size_t vl); + # vle8_v_i8m2 (const int8_t *base, size_t vl); + @staticmethod + def is_support_overloaded(name, **kwargs): + for p in ["m", "tu", "tamu", "tumu", "tuma", "tam", "tum"]: + if name.split("_")[-1] == p: + return True + if name.find("vmv_s_x") != -1 and name.split("_")[-1] == "ta": + return False + if name.find("vfmv_s_f") != -1 and name.split("_")[-1] == "ta": + return False + # vle/vse does not support overloading + load_ops = [ + "vl(s)?ei?[0-9]+(ff)?_v_.*", "vl(s)?seg[0-9]ei?[0-9]+(ff)?_v_.*" + ] + for p in load_ops: + if re.match(p, name) and name[-2:] != "_m": + return False + unsupported_op = [ + "setvl", "vundefined", "viota", "vmclr", "vmset_", "vid", "vmv_v_x", + "vfmv_v_f", "vread_csr", "vwrite_csr", "vcreate", "vlm_v" + ] + if any(i in name for i in unsupported_op): + if name[-2:] != "_m": + return False + + if name.startswith("sf_vc"): + any_vector_type = False + for arg_type in kwargs.values(): + if arg_type.startswith("v"): + any_vector_type = True + + if not any_vector_type: + return False + + return True + + # the input name should be process by func_name(name) + @staticmethod + def get_overloaded_op_name(name): + sn = name.split("_") + if name.startswith("sf_"): + if name.startswith("sf_vfwcvt") or name.startswith("sf_vfncvt"): + overloaded_name = "_".join(sn[0:3]) + else: + overloaded_name = "_".join(sn[0:-1]) + elif name in ["vread_csr", "vwrite_csr", "vlmul_trunc", "vlmul_ext"]: + overloaded_name = name + elif name.find("cvt") != -1: + if name.find("cvt_rod") != -1 or name.find("cvt_rtz") != -1: + overloaded_name = "_".join(sn[0:3]) + else: + overloaded_name = "_".join(sn[0:2]) + elif any(op in name for op in ["reinterpret", "vget"]): + overloaded_name = "_".join([sn[0], sn[-1]]) + elif any(op in name for op in ["vlmul_ext", "vlmul_trunc"]): + overloaded_name = "_".join([sn[0], sn[1], sn[-1]]) + elif any(op in name for op in [ + "vzext", "vsext", "vwadd", "vwsub", "vfwadd", "vfwsub", "vwadd", + "vwsub", "vfwadd", "vfwsub", "vmv", "vfmv" + ]): + # 2. compiler can not distinguish *.wx and *.vx, need encode them in + # suffix, for example: + # vuint32m1_t vwaddu (vuint32m1_t op1, uint16_t op2); // vwaddu.wx + # vuint64m2_t vwaddu (vuint32m1_t op1, uint32_t op2); // vwaddu.vx + # 3. the signature of vmv series are similar, for example + # vmv_v_v_i8mf8 -> vint8mf8_t vmv(vint8mf8_t src, size_t vl) + # vmv_x_s_i8mf8_i8 -> int8_t vmv(vint8mf8_t src) + overloaded_name = "_".join(sn[0:2]) + else: + overloaded_name = sn[0] + # append policy suffix if need + if sn[-1] in [ + "ta", "tu", "tama", "tuma", "tamu", "tumu", "ma", "mu", "tam", "tum" + ]: + overloaded_name += "_" + sn[-1] + return overloaded_name + + # Report how many functions are generated by the generator + def report_summary(self): + print(f"Generator generated \x1b[1;31m{len(self.generated_functions_set)} \ + \x1b[0mfunctions") + + +class DocGenerator(Generator): + """ + Derived generator for document that collects function definitions. + """ + + def __init__(self, f, is_all_in_one, has_tail_policy): + super().__init__() + self.is_all_in_one = is_all_in_one + self.has_tail_policy = has_tail_policy + if self.is_all_in_one: + self.fd = f + else: + self.folder = f + if not os.path.exists(self.folder): + os.makedirs(self.folder) + if not os.path.isdir(self.folder): + raise Exception("%s not dir, but it must be a dir.") + self.group_counter = 0 + self.fd = None + + def write(self, text): + self.fd.write(text) + + def write_title(self, text, link): + self.fd.write("\n### [" + text + "](" + link + "):\n") + + def inst_group_prologue(self): + s = "\n**Prototypes:**\n``` C\n" + self.write(s) + return s + + def inst_group_epilogue(self): + s = "```\n" + self.write(s) + return s + + def function_group(self, template, title, link, op_list, type_list, sew_list, + lmul_list, decorator_list): + self.write_title(title, link) + if self.has_tail_policy and len(decorator_list) == 0: + s = "This operation don't have Policy Intrinsic Functions.\n" + self.write(s) + return + super().function_group(template, title, link, op_list, type_list, sew_list, + lmul_list, decorator_list) + + def func(self, inst_info, name, return_type, **kwargs): + name = Generator.func_name(name) + s = super().func(inst_info, name, return_type, **kwargs) + self.write(s) + + def start_group(self, group_name): + # pylint: disable=consider-using-with + # NOTE: If is_all_in_one is False, separate files of the grouped intrinsics + # will be created, therefore we are allowing overriding the file descriptor + # here. + super().start_group(group_name) + if not self.is_all_in_one: + file_name = f"{self.group_counter:02d}_{group_name}.md" + file_name = file_name.replace(" ", "_") + file_name = file_name.replace("/", "_") + file_name = file_name.replace("(", "") + file_name = file_name.replace(")", "") + file_name = file_name.lower() + self.group_counter += 1 + + if self.fd is not None: + self.fd.close() + self.fd = open( + os.path.join(self.folder, file_name), "w", encoding="utf-8") + self.write(f"\n## {group_name}:\n") + + +class OverloadedDocGenerator(DocGenerator): + """ + Derived generator for documents that collects overloaded function definitions + """ + + def func(self, inst_info, name, return_type, **kwargs): + name = Generator.func_name(name) + if Generator.is_support_overloaded(name, **kwargs): + name = Generator.get_overloaded_op_name(name) + super().func(inst_info, name, return_type, **kwargs) + + +def vector_type_p(t): + return t.startswith("vint") or \ + t.startswith("vuint") or \ + t.startswith("vfloat") + + +class APITestGenerator(Generator): + """ + Derived generator for api unit tests. + """ + + def __init__(self, f, is_overloaded, is_llvm, has_tail_policy): + super().__init__() + self.is_overloaded = is_overloaded + self.folder = f + self.llvm = is_llvm + self.has_tail_policy = has_tail_policy + if not os.path.exists(self.folder): + os.makedirs(self.folder) + if not os.path.isdir(self.folder): + raise Exception("%s not dir, but it must be a dir.") + self.fd = None + self.test_files = [] + # test file name candidates which are declared in inst.py, it could have + # different op name + self.test_file_names = [] + + def write_file_header(self, has_float_type): + #pylint: disable=line-too-long + int_llvm_header = (r"""// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -triple riscv64 -target-feature +v -disable-O0-optnone \ +// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ +// RUN: FileCheck --check-prefix=CHECK-RV64 %s + +""") + float_llvm_header = (r"""// REQUIRES: riscv-registered-target +// RUN: %clang_cc1 -triple riscv64 -target-feature +v -target-feature +zfh \ +// RUN: -target-feature +experimental-zvfh -disable-O0-optnone \ +// RUN: -emit-llvm %s -o - | opt -S -passes=mem2reg | \ +// RUN: FileCheck --check-prefix=CHECK-RV64 %s + +""") + if self.llvm: + if has_float_type: + self.fd.write(float_llvm_header) + else: + self.fd.write(int_llvm_header) + else: + self.fd.write("#include \n") + self.fd.write("#include \n\n") + if not self.llvm: + self.fd.write("typedef _Float16 float16_t;\n") + self.fd.write("typedef float float32_t;\n") + self.fd.write("typedef double float64_t;\n") + + def func(self, inst_info, name, return_type, **kwargs): + if self.is_overloaded and not Generator.is_support_overloaded( + name, **kwargs): + return + + name = Generator.func_name(name) + overloaded_func_name = Generator.get_overloaded_op_name(name) + test_file_name = f"{overloaded_func_name.split('_')[0]}.c" + + if self.is_overloaded: + func_name = overloaded_func_name + else: + func_name = name + + if test_file_name not in self.test_files: + mode = "w" + header = True + else: + mode = "a" + header = False + if self.fd is not None: + self.fd.close() + + self.test_files.append(test_file_name) + # pylint: disable=consider-using-with + # NOTE(FIXME): For APITestGenerator, every function will own an individual + # C source file. Overriding here is acceptable but shows the problem that + # the long-living file descriptor is not useful in every generator. + self.fd = open( + os.path.join(self.folder, test_file_name), mode, encoding="utf-8") + + func_decl = super().func(inst_info, "test_" + name, return_type, **kwargs) + func_decl = func_decl.replace(" (", "(") + + # NOTE(FIXME): This logic is dependent to `TYPES` under constant.py. + # Hardcoded that if an an intrinsic has a floating-point type variant, the + # variant will be enumerated before the integer type variant. To fix this + # righteously, there should be a function to determine if an intrinsic + # has a floating-point variant and have the header emission depend on it. + has_float_type = func_decl.find("vfloat") != -1 + # NOTE(FIXME): This is logic as a hard fix to test case header emission. + has_float_type_variant_inst = [ + "macc", "nmacc", "msac", "nmsac", "madd", "nmadd", "msub", "nmsub", + "wmacc", "wnmacc", "wmsac", "wnmsac", "eq", "ne", "lt", "le", "gt", + "ge", "merge", "mv", "reinterpret" + ] + + for i in has_float_type_variant_inst: + if i in func_decl: + has_float_type = True + + if header: + self.write_file_header(has_float_type) + + def output_call_arg(arg_name, type_name): + if ((name.startswith("vget") or name.startswith("vset")) \ + and ((arg_name == "index" and type_name == "size_t"))) \ + or arg_name.startswith("bit_field") or arg_name.startswith("simm"): + return "0" + return arg_name + + # Write test func body. + # Write test func. func_decl has end of ";" and "\n" + self.fd.write(func_decl[:-2]) + self.fd.write(" {\n") + + self.fd.write(f" return {func_name}(") + call_args = ", ".join( + map(lambda a: output_call_arg(a[0], a[1]), kwargs.items())) + self.fd.write(call_args) + self.fd.write(");\n") + self.fd.write("}\n\n") + + def function_group(self, template, title, link, op_list, type_list, sew_list, + lmul_list, decorator_list): + self.test_file_names = op_list + template.render( + G=self, + op_list=op_list, + type_list=type_list, + sew_list=sew_list, + lmul_list=lmul_list, + decorator_list=decorator_list) + + +class Grouper(Generator): + """ + Derived generator for structured grouping in testing-report (testing script) + """ + + op_list = [] + + def __init__(self): + super().__init__() + self.func_group = {} # Func_name -> (group, sub-group). + self.groups = collections.OrderedDict() # Set of group name. + self.current_group = None + self.current_sub_group = None + + def start_group(self, group_name): + self.current_group = group_name + if group_name not in self.groups: + self.groups[group_name] = [] + + def func(self, inst_info, name, return_type, **kwargs): + + func_name = Generator.func_name(name) + overloaded_func_name = Generator.get_overloaded_op_name(name) + test_file_name = overloaded_func_name.split("_")[0] + + grp_info = (self.current_group, self.current_sub_group) + + self.func_group[test_file_name] = grp_info + self.func_group[func_name] = grp_info + self.func_group[overloaded_func_name] = grp_info + + def query_group_desc(self, func_name): + return self.func_group[func_name] + + def function_group(self, template, title, link, op_list, type_list, sew_list, + lmul_list, decorator_list): + self.op_list = op_list + self.groups[self.current_group].append(title) + self.current_sub_group = title + template.render( + G=self, + op_list=op_list, + type_list=type_list, + sew_list=sew_list, + lmul_list=lmul_list, + decorator_list=decorator_list) diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/inst.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/inst.py new file mode 100644 index 000000000..253cc95bd --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/inst.py @@ -0,0 +1,545 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Declares the intrinsics and links to the templates for its realization into +function prototype. The documents are generated under the sequence and +grouping. +""" + +from intrinsic_decorator import IntrinsicDecorators +from templates import vtype_template +from templates import setvl_template +from templates import load_template +from templates import seg_load_template +from templates import store_template +from templates import seg_store_template +from templates import binary_op_template +from templates import binary_wop_template +from templates import binary_nop_template +from templates import binary_intcarry_template +from templates import cmp_template +from templates import mac_template +from templates import unary_op_template +from templates import cvt_op_template +from templates import misc_op_template +from templates import reint_op_template +from templates import get_set_diff_lmul_op_template +from templates import reduction_template +from templates import mask_template +from templates import mask_load_store_template +from templates import permute_template +from constants import LMULS,WLMULS,NCVTLMULS,SEWS,WSEWS,FSEWS,WFSEWS,NSEWS,\ + TYPES,ITYPES,FTYPES,MTYPES,MLENS,REF_DOC_URL,REF_RFC_URL + + +def gen(g): + decorators = IntrinsicDecorators(g.has_tail_policy) + g.start_group("RVV C Type System") + + # dump all vector type + g.write_title("RVV C extension types", REF_RFC_URL + "#data-types") + vtype_template.render(G=g, type_list=TYPES, sew_list=SEWS, lmul_list=LMULS) + + g.write_title("RVV C extension mask types", REF_RFC_URL + "#mask-types") + g.write("- The Syntax is `vbool_t`\n%s" % + "".join(map(lambda x: f" - `vbool{x}_t`\n", MLENS))) + + #################################################################### + g.start_group("Configuration-Setting and Utility Functions") + + g.function_group(setvl_template, "Set `vl` and `vtype` Functions", + REF_DOC_URL + "#set-vl-and-vtype-functions", ["setvl"], [], + SEWS, LMULS, []) + + g.function_group(setvl_template, "Set the vl to VLMAX with specific vtype", + REF_DOC_URL + "#set-vl-to-vlmax-with-specific-vtype", + ["setvlmax"], [], SEWS, LMULS, []) + + #################################################################### + g.start_group("Vector Loads and Stores Functions") + + g.function_group(load_template, "Vector Unit-Stride Load Functions", + REF_DOC_URL + "#74-vector-unit-stride-operations", ["vle"], + TYPES, SEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group(store_template, "Vector Unit-Stride Store Functions", + REF_DOC_URL + "#74-vector-unit-stride-operations", ["vse"], + TYPES, SEWS, LMULS, decorators.has_masking_no_maskedoff) + + g.function_group(load_template, "Vector Strided Load Functions", + REF_DOC_URL + "#75-vector-strided-loadstore-operations", + ["vlse"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(store_template, "Vector Strided Store Functions", + REF_DOC_URL + "#75-vector-strided-loadstore-operations", + ["vsse"], TYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff) + + g.function_group(load_template, "Vector Indexed Load Functions", + REF_DOC_URL + "#76-vector-indexed-loadstore-operations", + ["vloxei", "vluxei"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(store_template, "Vector Indexed Store Functions", + REF_DOC_URL + "#76-vector-indexed-loadstore-operations", + ["vsoxei", "vsuxei"], TYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff) + + g.function_group( + load_template, "Unit-stride Fault-Only-First Loads Functions", + REF_DOC_URL + "#77-unit-stride-fault-only-first-loads-operations", + ["vleff"], TYPES, SEWS, LMULS, decorators.has_masking_maskedoff_policy) + + #################################################################### + + g.start_group("Vector Load/Store Segment Instructions (Zvlsseg)") + + g.function_group(seg_load_template, + "Vector Unit-Stride Segment Load Functions", "", + ["vlseg", "vlsegff"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(seg_store_template, + "Vector Unit-Stride Segment Store Functions", "", ["vsseg"], + TYPES, SEWS, LMULS, decorators.has_masking_no_maskedoff) + + g.function_group(seg_load_template, "Vector Strided Segment Load Functions", + "", ["vlsseg"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(seg_store_template, "Vector Strided Segment Store Functions", + "", ["vssseg"], TYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff) + + g.function_group(seg_load_template, "Vector Indexed Segment Load Functions", + "", ["vloxseg", "vluxseg"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(seg_store_template, "Vector Indexed Segment Store Functions", + "", ["vsoxseg", "vsuxseg"], TYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff) + + #################################################################### + + g.start_group("Vector Integer Arithmetic Functions") + + g.function_group( + binary_op_template, + "Vector Single-Width Integer Add and Subtract Functions", + REF_DOC_URL + "#121-vector-single-width-integer-add-and-subtract", + ["add", "sub", "rsub", "neg"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_wop_template, "Vector Widening Integer Add/Subtract Functions", + REF_DOC_URL + "#122-vector-widening-integer-addsubtract-operations", + ["wadd", "wsub"], ITYPES, WSEWS, WLMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(unary_op_template, "Vector Integer Extension Functions", + REF_DOC_URL + "#123-vector-integer-extension-operations", + ["zext", "sext"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + if g.has_tail_policy: + g.function_group( + binary_intcarry_template, + "Vector Integer Add-with-Carry / Subtract-with-Borrow Functions", + REF_DOC_URL + + "#124-vector-integer-add-with-carry--subtract-with-borrow-operations", + ["adc", "sbc"], ITYPES, SEWS, LMULS, decorators.has_no_masking_policy) + + g.function_group( + binary_intcarry_template, + "Vector Integer Add-with-Carry / Subtract-with-Borrow Functions", + REF_DOC_URL + + "#124-vector-integer-add-with-carry--subtract-with-borrow-operations", + ["madc", "msbc"], ITYPES, SEWS, LMULS, decorators.has_no_masking) + else: + g.function_group( + binary_intcarry_template, + "Vector Integer Add-with-Carry / Subtract-with-Borrow Functions", + REF_DOC_URL + + "#124-vector-integer-add-with-carry--subtract-with-borrow-operations", + ["adc", "sbc", "madc", "msbc"], ITYPES, SEWS, LMULS, + decorators.has_no_masking) + + g.function_group(binary_op_template, "Vector Bitwise Logical Functions", + REF_DOC_URL + "#125-vector-bitwise-logical-operations", + ["and", "or", "xor"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(unary_op_template, "Vector Bitwise Logical Functions", + REF_DOC_URL + "#125-vector-bitwise-logical-operations", + ["not"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, "Vector Single-Width Bit Shift Functions", + REF_DOC_URL + "#126-vector-single-width-bit-shift-operations", + ["sll", "srl", "sra"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_nop_template, "Vector Narrowing Integer Right Shift Functions", + REF_DOC_URL + "#127-vector-narrowing-integer-right-shift-operations", + ["nsrl", "nsra"], ITYPES, WSEWS, WLMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(cmp_template, "Vector Integer Comparison Functions", + REF_DOC_URL + "#128-vector-integer-comparison-operations", + ["eq", "ne", "lt", "le", "gt", "ge"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy_mu_ma) + + g.function_group(binary_op_template, "Vector Integer Min/Max Functions", + REF_DOC_URL + "#129-vector-integer-minmax-operations", + ["min", "max"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, "Vector Single-Width Integer Multiply Functions", + REF_DOC_URL + "#1210-vector-single-width-integer-multiply-operations", + ["mul", "mulh", "mulhsu"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(binary_op_template, "Vector Integer Divide Functions", + REF_DOC_URL + "#1211-vector-integer-divide-operations", + ["div", "rem"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_wop_template, "Vector Widening Integer Multiply Functions", + REF_DOC_URL + "#1212-vector-widening-integer-multiply-operations", + ["wmul", "wmulsu"], ITYPES, WSEWS, WLMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + mac_template, "Vector Single-Width Integer Multiply-Add Functions", + REF_DOC_URL + "#1213-vector-single-width-integer-multiply-add-operations", + ["macc", "nmsac", "madd", "nmsub"], ITYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff_policy) + + g.function_group( + mac_template, "Vector Widening Integer Multiply-Add Functions", + REF_DOC_URL + "#1214-vector-widening-integer-multiply-add-operations", + ["wmacc", "wmaccsu", "wmaccus"], ITYPES, WSEWS, WLMULS, + decorators.has_masking_no_maskedoff_policy) + + g.function_group(unary_op_template, "Vector Integer Merge Functions", + REF_DOC_URL + "#1216-vector-integer-merge-operations", + ["merge"], ITYPES, SEWS, LMULS, + decorators.has_no_masking_policy) + + g.function_group(unary_op_template, "Vector Integer Move Functions", + REF_DOC_URL + "#1217-vector-integer-move-operations", ["mv"], + ITYPES, SEWS, LMULS, decorators.has_no_masking_policy) + + #################################################################### + g.start_group("Vector Fixed-Point Arithmetic Functions") + + g.function_group( + binary_op_template, + "Vector Single-Width Saturating Add and Subtract Functions", + REF_DOC_URL + "#131-vector-single-width-saturating-add-and-subtract", + ["sadd", "ssub"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, + "Vector Single-Width Averaging Add and Subtract Functions", + REF_DOC_URL + "#132-vector-single-width-averaging-add-and-subtract", + ["aadd", "asub"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, + "Vector Single-Width Fractional Multiply with Rounding and Saturation" + + " Functions", REF_DOC_URL + + "#133-vector-single-width-fractional-multiply-with-rounding-and-" + + "saturation", ["smul"], ["int"], SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, "Vector Single-Width Scaling Shift Functions", + REF_DOC_URL + "#134-vector-single-width-scaling-shift-operations", + ["ssrl", "ssra"], ITYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_nop_template, "Vector Narrowing Fixed-Point Clip Functions", + REF_DOC_URL + "#135-vector-narrowing-fixed-point-clip-operations", + ["nclip"], ITYPES, WSEWS, WLMULS, decorators.has_masking_maskedoff_policy) + + #################################################################### + g.start_group("Vector Floating-Point Functions") + + g.function_group( + binary_op_template, + "Vector Single-Width Floating-Point Add/Subtract Functions", REF_DOC_URL + + "#142-vector-single-width-floating-point-addsubtract-operations", + ["fadd", "fsub", "frsub", "fneg"], FTYPES, FSEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_wop_template, + "Vector Widening Floating-Point Add/Subtract Functions", REF_DOC_URL + + "#143-vector-widening-floating-point-addsubtract-operations", + ["fwadd", "fwsub"], FTYPES, WFSEWS, WLMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, + "Vector Single-Width Floating-Point Multiply/Divide Functions", + REF_DOC_URL + + "#144-vector-single-width-floating-point-multiplydivide-operations", + ["fmul", "fdiv", "frdiv"], FTYPES, FSEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_wop_template, "Vector Widening Floating-Point Multiply Functions", + REF_DOC_URL + "#145-vector-widening-floating-point-multiply-operations", + ["fwmul"], FTYPES, WFSEWS, WLMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + mac_template, + "Vector Single-Width Floating-Point Fused Multiply-Add Functions", + REF_DOC_URL + + "#146-vector-single-width-floating-point-fused-multiply-add-operations", + ["macc", "nmacc", "msac", "nmsac", "madd", "nmadd", "msub", "nmsub"], + FTYPES, FSEWS, LMULS, decorators.has_masking_no_maskedoff_policy) + + g.function_group( + mac_template, + "Vector Widening Floating-Point Fused Multiply-Add Functions", + REF_DOC_URL + + "#147-vector-widening-floating-point-fused-multiply-add-operations", + ["wmacc", "wnmacc", "wmsac", "wnmsac"], FTYPES, WFSEWS, WLMULS, + decorators.has_masking_no_maskedoff_policy) + + g.function_group( + unary_op_template, "Vector Floating-Point Square-Root Functions", + REF_DOC_URL + "#148-vector-floating-point-square-root-operations", + ["sqrt"], FTYPES, FSEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + unary_op_template, + "Vector Floating-Point Reciprocal Square-Root Estimate Functions", + REF_DOC_URL + + "#149-vector-floating-point-reciprocal-square-root-estimate-operations", + ["rsqrt7"], FTYPES, FSEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + unary_op_template, "Vector Floating-Point Reciprocal Estimate Functions", + REF_DOC_URL + + "#1410-vector-floating-point-reciprocal-estimate-operations", ["rec7"], + FTYPES, FSEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, "Vector Floating-Point MIN/MAX Functions", + REF_DOC_URL + "#1411-vector-floating-point-minmax-operations", + ["fmin", "fmax"], FTYPES, FSEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + binary_op_template, "Vector Floating-Point Sign-Injection Functions", + REF_DOC_URL + "#1412-vector-floating-point-sign-injection-operations", + ["fsgnj", "fsgnjn", "fsgnjx"], FTYPES, FSEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group( + unary_op_template, "Vector Floating-Point Absolute Value Functions", + REF_DOC_URL + "#1412-vector-floating-point-sign-injection-operations", + ["abs"], FTYPES, FSEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + cmp_template, "Vector Floating-Point Compare Functions", + REF_DOC_URL + "#1413-vector-floating-point-compare-operations", + ["eq", "ne", "lt", "le", "gt", "ge"], FTYPES, FSEWS, LMULS, + decorators.has_masking_maskedoff_policy_mu_ma) + + g.function_group( + unary_op_template, "Vector Floating-Point Classify Functions", + REF_DOC_URL + "#1414-vector-floating-point-classify-operations", + ["class"], FTYPES, FSEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group(unary_op_template, "Vector Floating-Point Merge Functions", + REF_DOC_URL + "#1415-vector-floating-point-merge-operations", + ["merge"], FTYPES, FSEWS, LMULS, + decorators.has_no_masking_policy) + + g.function_group(unary_op_template, "Vector Floating-Point Move Functions", + REF_DOC_URL + "#1416-vector-floating-point-move-operations", + ["mv"], FTYPES, FSEWS, LMULS, + decorators.has_no_masking_policy) + + g.function_group( + cvt_op_template, + "Single-Width Floating-Point/Integer Type-Convert Functions", + REF_DOC_URL + + "#1417-single-width-floating-pointinteger-type-convert-operations", + ["cvt"], "", SEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + cvt_op_template, "Widening Floating-Point/Integer Type-Convert Functions", + REF_DOC_URL + + "#1418-widening-floating-pointinteger-type-convert-operations", ["wcvt"], + "", WSEWS, WLMULS, decorators.has_masking_maskedoff_policy) + + g.function_group( + cvt_op_template, + "Narrowing Floating-Point/Integer Type-Convert Functions", REF_DOC_URL + + "#1419-narrowing-floating-pointinteger-type-convert-operations", ["ncvt"], + "", NSEWS, NCVTLMULS, decorators.has_masking_maskedoff_policy) + + #################################################################### + g.start_group("Vector Reduction Functions") + + g.function_group( + reduction_template, "Vector Single-Width Integer Reduction Functions", + REF_DOC_URL + "#151-vector-single-width-integer-reduction-operations", + ["redsum", "redmax", "redmin", "redand", "redor", "redxor"], ITYPES, SEWS, + LMULS, decorators.has_masking_no_maskedoff_reduction_policy) + + g.function_group( + reduction_template, "Vector Widening Integer Reduction Functions", + REF_DOC_URL + "##152-vector-widening-integer-reduction-operations", + ["wredsum"], ITYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff_reduction_policy) + + g.function_group( + reduction_template, + "Vector Single-Width Floating-Point Reduction Functions", REF_DOC_URL + + "#153-vector-single-width-floating-point-reduction-operations", + ["redosum", "redusum", "redmax", "redmin"], FTYPES, FSEWS, LMULS, + decorators.has_masking_no_maskedoff_reduction_policy) + + g.function_group( + reduction_template, "Vector Widening Floating-Point Reduction Functions", + REF_DOC_URL + "#154-vector-widening-floating-point-reduction-operations", + ["wredosum", "wredusum"], FTYPES, FSEWS, LMULS, + decorators.has_masking_no_maskedoff_reduction_policy) + + #################################################################### + g.start_group("Vector Mask Functions") + + g.function_group(mask_load_store_template, "Vector Mask Load/Store Functions", + REF_DOC_URL + "#74-vector-unit-stride-operations", + ["vlm", "vsm"], MTYPES, MLENS, [1], + decorators.has_no_masking) + + g.function_group(mask_template, "Vector Mask-Register Logical Functions", + REF_DOC_URL + "#161-vector-mask-register-logical-operations", + [ + "and", "nand", "andn", "xor", "or", "nor", "orn", "xnor", + "mv", "clr", "set", "not" + ], MTYPES, MLENS, [1], decorators.has_no_masking) + + g.function_group(mask_template, "Vector count population in mask Functions", + REF_DOC_URL + "#162-vector-count-population-in-mask-vcpopm", + ["cpop"], MTYPES, MLENS, [1], + decorators.has_masking_no_maskedoff) + + g.function_group(mask_template, "Find-first-set mask bit Functions", + REF_DOC_URL + "#163-vfirst-find-first-set-mask-bit", + ["first"], MTYPES, MLENS, [1], + decorators.has_masking_no_maskedoff) + + g.function_group(mask_template, "Set-before-first mask bit Functions", + REF_DOC_URL + "#164-vmsbfm-set-before-first-mask-bit", + ["sbf"], MTYPES, MLENS, [1], + decorators.has_masking_maskedoff_policy_mu_ma) + + g.function_group(mask_template, "Set-including-first mask bit Functions", + REF_DOC_URL + "#165-vmsifm-set-including-first-mask-bit", + ["sif"], MTYPES, MLENS, [1], + decorators.has_masking_maskedoff_policy_mu_ma) + + g.function_group(mask_template, "Set-only-first mask bit Functions", + REF_DOC_URL + "#166-vmsofm-set-only-first-mask-bit", ["sof"], + MTYPES, MLENS, [1], + decorators.has_masking_maskedoff_policy_mu_ma) + + g.function_group(mask_template, "Vector Iota Functions", + REF_DOC_URL + "#168-vector-iota-operations", ["iota"], + MTYPES, SEWS, LMULS, decorators.has_masking_maskedoff_policy) + + g.function_group(mask_template, "Vector Element Index Functions", + REF_DOC_URL + "#169-vector-element-index-operations", ["id"], + MTYPES, SEWS, LMULS, decorators.has_masking_maskedoff_policy) + + #################################################################### + g.start_group("Vector Permutation Functions") + + g.function_group(permute_template, + "Integer and Floating-Point Scalar Move Functions", + REF_DOC_URL + "#171-integer-scalar-move-operations", ["mv"], + TYPES, SEWS, LMULS, decorators.has_no_masking_policy) + + g.function_group(permute_template, "Vector Slideup and Slidedown Functions", + REF_DOC_URL + "#173-vector-slide-operations", + ["slideup", "slidedown"], TYPES, SEWS, LMULS, + decorators.has_masking_no_maskedoff_policy_vslide) + + g.function_group( + permute_template, "Vector Slide1up and Slide1down Functions", + REF_DOC_URL + "#173-vector-slide1up-and-slide1down-functions", + ["slide1up", "slide1down"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(binary_op_template, "Vector Register Gather Functions", + REF_DOC_URL + "#174-vector-register-gather-operations", + ["rgather", "rgatherei16"], TYPES, SEWS, LMULS, + decorators.has_masking_maskedoff_policy) + + g.function_group(permute_template, "Vector Compress Functions", + REF_DOC_URL + "#175-vector-compress-operations", + ["compress"], TYPES, SEWS, LMULS, + decorators.has_no_masking_policy) + + #################################################################### + g.start_group("Miscellaneous Vector Functions") + + g.function_group(reint_op_template, "Reinterpret Cast Conversion Functions", + REF_DOC_URL + "#reinterpret-cast-conversion-functions", + ["reinterpret"], "", SEWS, LMULS, decorators.has_no_masking) + + g.function_group( + misc_op_template, "Vector LMUL Extension Functions", + REF_DOC_URL + "vector-lmul-extension-and-truncation-functions", + ["vlmul_ext_v"], TYPES, SEWS, LMULS, decorators.has_no_masking) + + g.function_group( + misc_op_template, "Vector LMUL Truncation Functions", + REF_DOC_URL + "vector-lmul-extension-and-truncation-functions", + ["vlmul_trunc_v"], TYPES, SEWS, LMULS, decorators.has_no_masking) + + g.function_group(misc_op_template, "Vector Initialization Functions", + REF_DOC_URL + "#vector-initialization-functions", + ["vundefined"], TYPES, SEWS, LMULS, + decorators.has_no_masking) + + g.function_group(get_set_diff_lmul_op_template, "Vector Insertion Functions", + REF_DOC_URL + "#vector-insertion-functions", ["vset"], TYPES, + SEWS, LMULS, decorators.has_no_masking) + + g.function_group(get_set_diff_lmul_op_template, "Vector Extraction Functions", + REF_DOC_URL + "#vector-extraction-functions", ["vget"], + TYPES, SEWS, LMULS, decorators.has_no_masking) + + #################################################################### diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/intrinsic_decorator.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/intrinsic_decorator.py new file mode 100644 index 000000000..f12fad36e --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/intrinsic_decorator.py @@ -0,0 +1,189 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +File for InstructionDecorator and lists of objects of different Instances of +them. +""" +import collections +from enums import ExtraAttr + + +class IntrinsicDecorator(): + """ + Helper for intrinsics. Provides mask, maskedoff, destination arguments when + needed. Also helps decorate the intrinsics with appropriate suffix (masked or + policy suffix), depending on the provided attributes. + """ + is_mask = False + has_maskedoff_name = False + + def __init__(self, flags=ExtraAttr.NO_ATTR): + self.is_mask = (flags & ExtraAttr.IS_MASK) != 0 + self.need_maskedoff = (flags & ExtraAttr.NEED_MASKOFF) != 0 + self.has_maskedoff_name = (flags & ExtraAttr.NEED_MERGE) != 0 + self.flags = flags + if flags & ExtraAttr.IS_TA: + self.func_suffix = "_ta" + elif flags & ExtraAttr.IS_TU: + self.func_suffix = "_tu" + elif flags & ExtraAttr.IS_MA: + self.func_suffix = "_ma" + elif flags & ExtraAttr.IS_MU: + self.func_suffix = "_mu" + elif flags & ExtraAttr.IS_TAMA: + self.func_suffix = "_tama" + elif flags & ExtraAttr.IS_TAMU: + self.func_suffix = "_tamu" + elif flags & ExtraAttr.IS_TUMA: + self.func_suffix = "_tuma" + elif flags & ExtraAttr.IS_TUMU: + self.func_suffix = "_tumu" + elif self.is_mask and flags & ExtraAttr.IS_RED_TUMA: + self.func_suffix = "_tum" + elif self.is_mask and flags & ExtraAttr.IS_RED_TAMA: + self.func_suffix = "_tam" + elif self.is_mask: + self.func_suffix = "_m" + else: + self.func_suffix = "" + + def write_text_header(self, g): + if self.is_mask: + g.write("// masked functions\n") + + def mask_args(self, mask_type, maskoff_type=None, nf=None): + if self.is_mask and self.need_maskedoff: + assert maskoff_type is not None + d = collections.OrderedDict() + d["mask"] = mask_type + if nf is None: + d["maskedoff"] = maskoff_type + else: + for i in range(nf): + d[f"maskedoff{i}"] = maskoff_type + return d + elif self.is_mask: + return {"mask": mask_type} + + return {} + + def dest_args(self, dest_type): + if self.func_suffix in ["_ta", "_tama"] and self.has_maskedoff_name: + return {"dest": dest_type} + if self.func_suffix in ["_ta", "_tama", "_tam"]: + return {} + elif self.has_maskedoff_name is True and not self.need_maskedoff: + return {"maskedoff": dest_type} + return {"dest": dest_type} + + def tu_dest_args(self, dest_type, nf=None): + if self.has_maskedoff_name and not self.need_maskedoff: + assert dest_type is not None + d = collections.OrderedDict() + if nf is None: + d["maskedoff"] = dest_type + else: + for i in range(nf): + d[f"maskedoff{i}"] = dest_type + return d + return {} + + +class IntrinsicDecorators(): + """ + Collection of lists of InstructionDecorator instances. The instances are used + to help intrinsic rendering. + """ + + def __init__(self, has_tail_policy): + # pylint: disable=unused-variable + # NOTE: The variables here are all used under inst.py, disabling the warning + self.has_no_masking = [IntrinsicDecorator()] + self.has_masking_maskedoff = [ + IntrinsicDecorator(), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MASKOFF) + ] + self.has_masking_no_maskedoff = [ + IntrinsicDecorator(), + IntrinsicDecorator(ExtraAttr.IS_MASK) + ] + if has_tail_policy: + self.has_no_masking_policy = [ + IntrinsicDecorator(ExtraAttr.NEED_MERGE | ExtraAttr.IS_TU), + IntrinsicDecorator(ExtraAttr.IS_TA) + ] + self.has_masking_maskedoff_policy = [ + IntrinsicDecorator(ExtraAttr.NEED_MERGE | ExtraAttr.IS_TU), + IntrinsicDecorator(ExtraAttr.IS_TA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.NEED_MASKOFF | ExtraAttr.IS_TUMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.NEED_MASKOFF | ExtraAttr.IS_TUMU), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.IS_TAMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.NEED_MASKOFF | ExtraAttr.IS_TAMU) + ] + self.has_masking_maskedoff_policy_mu_ma = [ + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.IS_MA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.NEED_MASKOFF | ExtraAttr.IS_MU) + ] + self.has_masking_no_maskedoff_policy = [ + IntrinsicDecorator(ExtraAttr.IS_TU | ExtraAttr.NEED_MERGE), + IntrinsicDecorator(ExtraAttr.IS_TA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TUMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TUMU), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.IS_TAMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TAMU), + ] + self.has_masking_no_maskedoff_policy_vslide = [ + IntrinsicDecorator(ExtraAttr.IS_TU | ExtraAttr.NEED_MERGE), + IntrinsicDecorator(ExtraAttr.IS_TA | ExtraAttr.NEED_MERGE), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TUMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TUMU), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TAMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_TAMU), + ] + self.has_masking_no_maskedoff_reduction_policy = [ + IntrinsicDecorator(ExtraAttr.IS_TU | ExtraAttr.NEED_MERGE), + IntrinsicDecorator(ExtraAttr.IS_TA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.NEED_MERGE + | ExtraAttr.IS_RED_TUMA), + IntrinsicDecorator(ExtraAttr.IS_MASK | ExtraAttr.IS_RED_TAMA), + ] + self.has_no_masking = [] + self.has_masking_maskedoff = [] + self.has_masking_no_maskedoff = [] + else: + # no tail policy use the same decorator + self.has_no_masking_policy = self.has_no_masking + + self.has_masking_maskedoff_policy = self.has_masking_maskedoff + self.has_masking_maskedoff_policy_mu_ma = self.has_masking_maskedoff + + self.has_masking_no_maskedoff_policy = self.has_masking_no_maskedoff + self.has_masking_no_maskedoff_policy_vslide =\ + self.has_masking_no_maskedoff + self.has_masking_no_maskedoff_reduction_policy =\ + self.has_masking_no_maskedoff diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/main.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/main.py new file mode 100644 index 000000000..8af82be30 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/main.py @@ -0,0 +1,163 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Main entry of the generator +""" + +import argparse +import sys +import os +import importlib.util +import inspect +import inst +import generator + + +def get_gen_from_vendor(vendor_inst_filepath): + if vendor_inst_filepath is None: + return None + if not os.path.isfile(vendor_inst_filepath): + print("File does not exist in path of --vendor-inst, ignoring the option") + return None + spec = importlib.util.spec_from_file_location("", vendor_inst_filepath) + vendor_module = importlib.util.module_from_spec(spec) + vendor_module.__package__ = __package__ + + if spec is None or spec.loader is None: + print("Cannot load module with spec") + + spec.loader.exec_module(vendor_module) # pytype: disable=attribute-error + if not hasattr(vendor_module, "gen"): + print("File does not have a attribute named 'gen'") + return None + if not inspect.isfunction(vendor_module.gen): + print("The attribute in file is not a function") + print("Please specify a function that takes a Generator") + return None + + return vendor_module.gen + + +def get_generator_from_vendor(vendor_generator_filepath, + vendor_generator_class_name): + if vendor_generator_filepath is None or\ + vendor_generator_class_name is None: + return None + if not os.path.isfile(vendor_generator_filepath): + print("File does not exist in path of --vendor-generator-script,", + "ignoring the option") + return None + spec = importlib.util.spec_from_file_location("", vendor_generator_filepath) + vendor_module = importlib.util.module_from_spec(spec) + vendor_module.__package__ = __package__ + + if spec is None or spec.loader is None: + print("Cannot load module with spec") + spec.loader.exec_module(vendor_module) # pytype: disable=attribute-error + if not hasattr(vendor_module, vendor_generator_class_name): + print("File does not have a attribute named", + f"'{vendor_generator_class_name}'") + return None + return getattr(vendor_module, vendor_generator_class_name) + + +def main(): + + class GenTypes: + NON_OVERLOADED_DOC = 0 + NON_OVERLOADED_DOCS = 1 + OVERLOADED_DOC = 2 + OVERLOADED_DOCS = 3 + NON_OVERLOADED_TEST = 4 + OVERLOADED_TEST = 5 + + parser = argparse.ArgumentParser() + parser.add_argument( + "--gen", + default="doc", + choices=[ + "non-overloaded-doc", "non-overloaded-docs", "overloaded-doc", + "overloaded-docs", "non-overloaded-test", "overloaded-test" + ]) + parser.add_argument("--llvm", default=False, action="store_true") + parser.add_argument("--has-policy", default=False, action="store_true") + parser.add_argument("--vendor-inst") + parser.add_argument("--vendor-generator-script") + parser.add_argument("--vendor-generator-name") + parser.add_argument("--out") + args = parser.parse_args() + + vendor_gen = get_gen_from_vendor(args.vendor_inst) + if vendor_gen is not None: + print("Recognized 'gen' function through --vendor-inst path", + f"'{args.vendor_inst}'") + vendor_generator =\ + get_generator_from_vendor(args.vendor_generator_script, + args.vendor_generator_name) + # If a vendor generator is specified, the --gen option will be ignored + if vendor_generator is not None: + print("Recognized generator through --vendor-generator-script path", + f"'{args.vendor_generator_script}'") + print(f"Triggering the generator {args.vendor_generator_name}") + with open(args.out, "w", encoding="utf-8") as f: + g = vendor_generator(f, args.has_policy) + inst.gen(g) + if vendor_gen is not None: + vendor_gen(g) + g.report_summary() + return + + mode = getattr(GenTypes, args.gen.replace("-", "_").upper()) + + if mode in [GenTypes.NON_OVERLOADED_DOC, GenTypes.OVERLOADED_DOC]: + with open(args.out, "w", encoding="utf-8") as f: + if mode == GenTypes.NON_OVERLOADED_DOC: + g = generator.DocGenerator(f, True, args.has_policy) + elif mode == GenTypes.OVERLOADED_DOC: + g = generator.OverloadedDocGenerator(f, True, args.has_policy) + else: + assert False + + inst.gen(g) + if vendor_gen is not None: + vendor_gen(g) + g.report_summary() + return + elif mode == GenTypes.NON_OVERLOADED_DOCS: + g = generator.DocGenerator(args.out, False, args.has_policy) + elif mode == GenTypes.OVERLOADED_DOCS: + g = generator.OverloadedDocGenerator(args.out, False, args.has_policy) + elif mode == GenTypes.NON_OVERLOADED_TEST: + g = generator.APITestGenerator(args.out, False, args.llvm, args.has_policy) + + elif mode == GenTypes.OVERLOADED_TEST: + g = generator.APITestGenerator(args.out, True, args.llvm, args.has_policy) + else: + assert False + + inst.gen(g) + if vendor_gen is not None: + vendor_gen(g) + g.report_summary() + return + + +if __name__ == "__main__": + if not (sys.version_info.major == 3 and sys.version_info.minor >= 6): + print("This script requires Python 3.6 or higher!") + sys.exit(1) + main() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_intcarry_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_intcarry_template.py new file mode 100644 index 000000000..7c0f4703a --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_intcarry_template.py @@ -0,0 +1,124 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering Add-With-Carry and Subtract-With-Borrow instructions +to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + type_helper = TypeHelper(**args) + v = type_helper.v + s = type_helper.s + m = type_helper.m + if "sbc" in args["OP"]: + carry = {"borrowin": m} + else: + carry = {"carryin": m} + + inst_info_vvm = InstInfo.get(args, decorator, InstType.VVVM) + inst_info_vxm = InstInfo.get(args, decorator, InstType.VVXM) + + if not "m" in args["OP"]: + G.func( + inst_info=inst_info_vvm, + name="v{OP}_vvm_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=v, + **decorator.tu_dest_args(v), + op1=v, + op2=v, + **carry, + vl=type_helper.size_t) + G.func( + inst_info=inst_info_vxm, + name="v{OP}_vxm_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=v, + **decorator.tu_dest_args(v), + op1=v, + op2=s, + **carry, + vl=type_helper.size_t) + + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + type_helper = TypeHelper(**args) + v = type_helper.v + s = type_helper.s + m = type_helper.m + if "sbc" in args["OP"]: + carry = {"borrowin": m} + else: + carry = {"carryin": m} + + inst_info_vvm = InstInfo.get(args, None, InstType.VVVM) + inst_info_vxm = InstInfo.get(args, None, InstType.VVXM) + + inst_info_vv = InstInfo.get(args, None, InstType.VVV) + inst_info_vx = InstInfo.get(args, None, InstType.VVX) + + # madc or msbc + if "m" in args["OP"]: + args["MLEN"] = type_helper.mlen + G.func( + inst_info_vvm, + name="v{OP}_vvm_{TYPE}{SEW}m{LMUL}_b{MLEN}".format_map(args) + + decorator.func_suffix, + return_type=m, + op1=v, + op2=v, + **carry, + vl=type_helper.size_t) + G.func( + inst_info_vxm, + name="v{OP}_vxm_{TYPE}{SEW}m{LMUL}_b{MLEN}".format_map(args) + + decorator.func_suffix, + return_type=m, + op1=v, + op2=s, + **carry, + vl=type_helper.size_t) + G.func( + inst_info_vv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}_b{MLEN}".format_map(args) + + decorator.func_suffix, + return_type=m, + op1=v, + op2=v, + vl=type_helper.size_t) + G.func( + inst_info_vx, + name="v{OP}_vx_{TYPE}{SEW}m{LMUL}_b{MLEN}".format_map(args) + + decorator.func_suffix, + return_type=m, + op1=v, + op2=s, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_nop_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_nop_template.py new file mode 100644 index 000000000..5a11bc57f --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_nop_template.py @@ -0,0 +1,98 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering Narrowing Integer Right Shift Add-With-Carry and +Narrowing Fixed-Point Clip instructions to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import basic_constraint +from enums import InstInfo +from enums import InstType + + +def must_int_type(**kargs): + return kargs["TYPE"] in ["int", "uint"] and basic_constraint(**kargs) + + +# narrowing op template +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + constraint=must_int_type, + OP=op_list, + TYPE=type_list, + SEW=sew_list, + LMUL=lmul_list, + OP2=["v", "s"]): + data_type = args["TYPE"] + op = args["OP"] + op2 = args["OP2"] + + if op2 == "s": + if data_type == "float": + args["OP2"] = "f" + inst_type = InstType.VWF + else: + args["OP2"] = "x" + inst_type = InstType.VWX + else: + inst_type = InstType.VWV + + if op == "nclip" and data_type == "uint": + args["OP"] = op + "u" + + if ((op == "nsrl" and data_type == "int") or + (op == "nsra" and data_type == "uint")): + # unsupported cases: unsigned sra is unsupported, signed srl + # is unsupported + continue + type_helper = TypeHelper(**args) + + inst_info = InstInfo.get(args, decorator, inst_type) + + if op in ["nsrl", "nsra", "nclip"]: + G.func( + inst_info, + name="v{OP}_w{OP2}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + return_type=type_helper.v, + op1=type_helper.wv, + shift=(f"vuint{args['SEW']}m{args['LMUL']}_t" + if op2 == "v" else "size_t"), + vl=type_helper.size_t) + else: + G.func( + inst_info, + name="v{OP}_w{OP2}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + return_type=type_helper.v, + op1=type_helper.wv, + op2=(type_helper.v if op2 == "v" else type_helper.s), + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_op_template.py new file mode 100644 index 000000000..55cc91760 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_op_template.py @@ -0,0 +1,145 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering binary operand instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import get_string_lmul +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + OP=op_list, + TYPE=type_list, + SEW=sew_list, + LMUL=lmul_list, + OP2=["v", "s"]): + data_type = args["TYPE"] + op = args["OP"] + sew = args["SEW"] + op2 = args["OP2"] + + if op2 == "s": + if data_type == "float" and op != "rgather": + args["OP2"] = "f" + else: + args["OP2"] = "x" + if data_type == "uint" and op in [ + "max", "min", "mulh", "div", "rem", "sadd", "ssub", "aadd", "asub" + ]: + args["OP"] = op + "u" + + type_helper = TypeHelper(**args) + + if (op in ["mulhsu", "ssra", "sra"] and data_type == "uint") or \ + (op in ["ssrl", "srl"] and data_type == "int"): + # Unsigned mulhsu and ssra are unsupported, signed ssrl is unsupported + continue + if (op2 == "v") and op in ["rsub", "frsub", "frdiv"]: + # rsub and rdiv only support vs version + continue + if op2 == "s" and (op == "rgatherei16" or "neg" in op): + # rgatheri16/neg only support vv version + continue + if op == "rgather": + v_op2 = type_helper.uiv + s_op2 = type_helper.size_t + elif op == "rgatherei16": + elmul = type_helper.get_elmul(16, sew) + if elmul == 0: + continue + elmul_str = get_string_lmul(elmul, 1) + v_op2 = f"vuint16m{elmul_str}_t" + elif "neg" in op and data_type == "uint": + continue + elif ("mulhsu" in op and data_type == "int"): + v_op2 = type_helper.uiv + s_op2 = type_helper.uis + else: + v_op2 = type_helper.v + s_op2 = type_helper.s + + inst_info_vv = InstInfo.get(args, decorator, InstType.VVV) + inst_info_vx = InstInfo.get(args, decorator, InstType.VVX) + inst_info_vf = InstInfo.get(args, decorator, InstType.VVF) + inst_info_v = InstInfo.get(args, decorator, InstType.VV) + if args["OP2"] == "v": + inst_info = inst_info_vv + elif args["OP2"] == "x": + inst_info = inst_info_vx + elif args["OP2"] == "f": + inst_info = inst_info_vf + else: + raise Exception("Unknown op2 type.") + + if op in ["ssra", "sra", "ssrl", "srl", "sll"]: + G.func( + inst_info, + name="v{OP}_v{OP2}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + shift=(f"vuint{args['SEW']}m{args['LMUL']}_t" + if op2 == "v" else "size_t"), + vl=type_helper.size_t) + elif op in ["neg", "fneg"]: + G.func( + inst_info_v, + name="v{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + vl=type_helper.size_t) + elif "rgather" == op: + G.func( + InstInfo.get(args, decorator, InstType.VVV), + name="v{OP}_v{OP2}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + index=(v_op2 if op2 == "v" else s_op2), + vl=type_helper.size_t) + else: + G.func( + inst_info, + name="v{OP}_v{OP2}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + op2=(v_op2 if op2 == "v" else s_op2), + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_wop_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_wop_template.py new file mode 100644 index 000000000..8c05bee80 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/binary_wop_template.py @@ -0,0 +1,135 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering Widening Integer/Floating-Point Add/Subtract/Multiply +instructions to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + data_type = args["TYPE"] + op = args["OP"] + + type_helper = TypeHelper(**args) + + if op == "wmul" and data_type == "uint": + args["OP"] = op + "u" + + if op in ["wadd", "wsub"] and data_type == "uint": + args["OP"] = op + "u" + + inst_info_wvv = InstInfo.get(args, decorator, InstType.WVV) + inst_info_wvx = InstInfo.get(args, decorator, InstType.WVX) + inst_info_wvf = InstInfo.get(args, decorator, InstType.WVF) + inst_info_wwv = InstInfo.get(args, decorator, InstType.WWV) + inst_info_wwx = InstInfo.get(args, decorator, InstType.WWX) + inst_info_wwf = InstInfo.get(args, decorator, InstType.WWF) + + args["LMUL"] = args["WLMUL"] + args["SEW"] = args["WSEW"] + if data_type == "float": + args["SCALAR"] = "f" + inst_info_wws = inst_info_wwf + inst_info_wvs = inst_info_wvf + else: + args["SCALAR"] = "x" + inst_info_wws = inst_info_wwx + inst_info_wvs = inst_info_wvx + + if op == "wmulsu": + if data_type != "int": + # unsupported cases: wmulsu only support int type + pass + else: #data_type == "int" + G.func( + inst_info_wvv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.v, + op2=type_helper.uiv, + vl=type_helper.size_t) + G.func( + inst_info_wvs, + name="v{OP}_v{SCALAR}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.v, + op2=type_helper.uis, + vl=type_helper.size_t) + else: + G.func( + inst_info_wvv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.v, + op2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_wvs, + name="v{OP}_v{SCALAR}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.v, + op2=type_helper.s, + vl=type_helper.size_t) + + if "add" in op or "sub" in op: + # integer/floating wadd and wsub support "2*sew = 2*sew op SEW" + G.func( + inst_info_wwv, + name="v{OP}_wv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.wv, + op2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_wws, + name="v{OP}_w{SCALAR}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.wv), + **decorator.tu_dest_args(type_helper.wv), + op1=type_helper.wv, + op2=type_helper.s, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cmp_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cmp_template.py new file mode 100644 index 000000000..4b806be0a --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cmp_template.py @@ -0,0 +1,80 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering comparison instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + OP=op_list, + TYPE=type_list, + SEW=sew_list, + LMUL=lmul_list, + OP2=["v", "s"]): + data_type = args["TYPE"] + op = args["OP"] + op2 = args["OP2"] + + type_helper = TypeHelper(**args) + + args["MLEN"] = type_helper.mlen + + if data_type == "float": + if op2 == "s": + args["OP2"] = "f" + inst_type = InstType.VVF + else: + inst_type = InstType.VVV + op = "mf" + op + else: + if op2 == "s": + args["OP2"] = "x" + inst_type = InstType.VVX + else: + inst_type = InstType.VVV + op = "ms" + op + if args["OP"] not in ["eq", "ne"] and data_type == "uint": + op = op + "u" + + args["OP"] = op + inst_info = InstInfo.get(args, decorator, inst_type) + + G.func( + inst_info, + name="v{OP}_v{OP2}_{TYPE}{SEW}m{LMUL}_b{MLEN}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.m, + **decorator.mask_args(type_helper.m, type_helper.m), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + op2=(type_helper.v if op2 == "v" else type_helper.s), + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cvt_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cvt_op_template.py new file mode 100644 index 000000000..df6958814 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/cvt_op_template.py @@ -0,0 +1,134 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering type-convert instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType +from enums import ExtraAttr + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name, unused-argument + # FIXME: Renaming 'G' to 'g' all in once later. + # FIXME: Argument 'type_list' is unused but required for interface + # consistency. We can prune it in the future. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + # Variable in list means + # [dst_type, dst_type_short, src_type, src_type_short] + convert_set = [["int", "x", "float", "f"], ["int", "x", "int", "x"], + ["uint", "x", "uint", "x"], ["uint", "xu", "float", "f"], + ["float", "f", "int", "x"], ["float", "f", "uint", "xu"], + ["float", "f", "float", "f"]] + for args in prod( + OP=op_list, SEW=sew_list, TYPES=convert_set, LMUL=lmul_list): + op = args["OP"] + + type_helper = TypeHelper(**args) + args["TYPES0"] = args["TYPES"][0] + args["TYPES1"] = args["TYPES"][1] + args["TYPES2"] = args["TYPES"][2] + args["TYPES3"] = args["TYPES"][3] + + if (op == "cvt" and args["TYPES1"] == args["TYPES3"]): + continue + + args["MIDDLE"] = "v" + factor = "" + if op == "wcvt": + factor = "W" + if op == "ncvt": + factor = "N" + args["MIDDLE"] = "w" + + args["LLMUL"] = args[factor + "LMUL"] + args["LSEW"] = args[factor + "SEW"] + + if args["TYPES1"] == "f" or args["TYPES3"] == "f": + args["OP"] = "f" + args["OP"] + + if args["TYPES0"] == "uint": + args["D_TYPE"] = "u" + elif args["TYPES1"] == "x": + args["D_TYPE"] = "i" + else: + args["D_TYPE"] = "f" + + if op == "wcvt" and \ + (args["TYPES0"] == "uint" and args["TYPES2"] == "uint"): + args["OP"] += "u" + + extra_attr = ExtraAttr.CONVERT + inst_info = InstInfo.get( + args, decorator, InstType.VV, extra_attr=extra_attr) + + src_type = "v{TYPES2}{SEW}m{LMUL}_t".format_map(args) + rt = "v{TYPES0}{LSEW}m{LLMUL}_t".format_map(args) + if not type_helper.valid_vtype(rt) or\ + not type_helper.valid_vtype(src_type): + continue + func_name = \ + "v{OP}_{TYPES1}_{TYPES3}_{MIDDLE}_{D_TYPE}{LSEW}m{LLMUL}".format_map\ + (args) + G.func( + inst_info, + name=func_name + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, rt), + **decorator.tu_dest_args(rt), + src=src_type, + vl=type_helper.size_t) + if args["TYPES1"] != args["TYPES3"] and args["TYPES3"] == "f": + args["OP"] = args["OP"] + "_rtz" + inst_info = InstInfo.get( + args, decorator, InstType.VV, extra_attr=extra_attr) + func_name =\ + "v{OP}_{TYPES1}_{TYPES3}_{MIDDLE}_{D_TYPE}{LSEW}m{LLMUL}".format_map\ + (args) + G.func( + inst_info, + name=func_name + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, rt), + **decorator.tu_dest_args(rt), + src=src_type, + vl=type_helper.size_t) + + if op == "ncvt" and args["TYPES1"] == "f" and args["TYPES3"] == "f": + args["OP"] = args["OP"] + "_rod" + inst_info = \ + InstInfo.get(args, decorator, InstType.VV, extra_attr=extra_attr) + func_name = \ + "v{OP}_{TYPES1}_{TYPES3}_{MIDDLE}_{D_TYPE}{LSEW}m{LLMUL}".format_map\ + (args) + G.func( + inst_info, + name=func_name + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, rt), + **decorator.tu_dest_args(rt), + src=src_type, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/get_set_diff_lmul_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/get_set_diff_lmul_op_template.py new file mode 100644 index 000000000..4124fef53 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/get_set_diff_lmul_op_template.py @@ -0,0 +1,97 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering Vector Insertion and Extraction intrinsics. They are +intrinsics defined and do not have a corresponding instruction in RVV. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import basic_constraint +from enums import InstInfo +from enums import InstType + + +def not_fractional_lmul(lmul): + return str(lmul)[0] != "f" + + +def common_constraint(**kargs): + return not_fractional_lmul(kargs["LMUL"]) \ + and not_fractional_lmul(kargs["SRC_LMUL"]) + + +def vget_constraint(**kargs): + return basic_constraint(**kargs) \ + and common_constraint(**kargs) \ + and int(kargs["LMUL"]) < int(kargs["SRC_LMUL"]) + + +def vset_constraint(**kargs): + return basic_constraint(**kargs) \ + and common_constraint(**kargs) \ + and int(kargs["LMUL"]) > int(kargs["SRC_LMUL"]) + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + + assert len(op_list) + vget = True + if op_list[0] == "vget": + constraint = vget_constraint + elif op_list[0] == "vset": + constraint = vset_constraint + vget = False + else: + raise Exception("Unknown operation") + + for args in prod( + OP=op_list, + SEW=sew_list, + TYPE=type_list, + LMUL=lmul_list, + SRC_LMUL=lmul_list, + constraint=constraint): + + type_helper = TypeHelper(**args) + src_type = "v{TYPE}{SEW}m{SRC_LMUL}_t".format_map(args) + + func_name = "{OP}_v_{TYPE}{SEW}m{SRC_LMUL}_{TYPE}{SEW}m{LMUL}".format_map( + args) + if vget: + G.func( + InstInfo.get(args, decorator, InstType.VGET), + name=func_name, + return_type=type_helper.v, + src=src_type, + index=type_helper.size_t) + else: + G.func( + InstInfo.get(args, decorator, InstType.VSET), + name=func_name, + return_type=type_helper.v, + dest=type_helper.v, + index=type_helper.size_t, + val=src_type) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/load_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/load_template.py new file mode 100644 index 000000000..bfbb56667 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/load_template.py @@ -0,0 +1,82 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering load instructions to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import get_string_lmul +import collections +from enums import InstInfo +from enums import InstType +from enums import MemType +from enums import ExtraAttr + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + OP=op_list, TYPE=type_list, SEW=sew_list, EEW=sew_list, LMUL=lmul_list): + op = args["OP"] + sew = args["SEW"] + eew = args["EEW"] + + type_helper = TypeHelper(**args) + + extra_addr_args = collections.OrderedDict() + inst_type = InstType.VX + extra_attr = ExtraAttr.NO_ATTR + if op in ["vlse"]: + extra_addr_args["bstride"] = "ptrdiff_t" + inst_type = InstType.VXX + if op in ["vloxei", "vluxei"]: + elmul = type_helper.get_elmul(eew, sew) + if elmul == 0: + continue + elmul_str = get_string_lmul(elmul, 1) + extra_addr_args["bindex"] = f"vuint{eew}m{elmul_str}_t" + inst_type = InstType.VV + + if op == "vleff": + extra_attr |= ExtraAttr.FIRST_FAULT + args["OP"] = "vle" + str(eew) + "ff" + extra_addr_args["new_vl"] = "size_t *" + else: + args["OP"] = op + str(eew) + + if op not in ["vloxei", "vluxei"] and sew != eew: + continue + inst_info =\ + InstInfo.get(args, decorator, inst_type, MemType.LOAD, extra_attr) + G.func( + inst_info, + name=\ + "{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + base="const {TYPE}{SEW}_t *".format_map(args), + **extra_addr_args, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mac_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mac_template.py new file mode 100644 index 000000000..2e224db9f --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mac_template.py @@ -0,0 +1,169 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering multiply-add instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType +from enums import ExtraAttr + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + data_type = args["TYPE"] + op = args["OP"] + + if data_type == "float": + args["S_TYPE"] = "f" + args["OP"] = "f" + op + inst_type = InstType.VVF + else: + args["S_TYPE"] = "x" + inst_type = InstType.VVX + + if op in ["wmacc", "qmacc"] and data_type == "uint": + args["OP"] = args["OP"] + "u" + + inst_info_vs = InstInfo.get( + args, decorator, inst_type, extra_attr=ExtraAttr.MAC) + inst_info_vv = InstInfo.get( + args, decorator, InstType.VVV, extra_attr=ExtraAttr.MAC) + inst_info_vx = InstInfo.get( + args, decorator, InstType.VVX, extra_attr=ExtraAttr.MAC) + + type_helper = TypeHelper(**args) + if (("maccsu" in op) or ("maccus" in op)) and data_type == "uint": + # maccsu and maccus only support int type + continue + elif (("w" in op) or ("q" in op)) and ("int" in data_type): + if "q" in op: + w_vtype = type_helper.qv + args["SEW"] = args["QSEW"] + args["LMUL"] = args["QLMUL"] + else: + w_vtype = type_helper.wv + args["SEW"] = args["WSEW"] + args["LMUL"] = args["WLMUL"] + + rt = w_vtype + if "maccsu" in op: + G.func( + inst_info_vv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=rt, + vs1=type_helper.siv, + vs2=type_helper.uiv, + vl=type_helper.size_t) + G.func( + inst_info_vx, + name="v{OP}_vx_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=rt, + rs1=type_helper.sis, + vs2=type_helper.uiv, + vl=type_helper.size_t) + elif "maccus" in op: + G.func( + inst_info_vx, + name="v{OP}_vx_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=rt, + rs1=type_helper.uis, + vs2=type_helper.siv, + vl=type_helper.size_t) + elif "macc" in op: + G.func( + inst_info_vv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=rt, + vs1=type_helper.v, + vs2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_vs, + name="v{OP}_v{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=rt, + rs1=type_helper.s, + vs2=type_helper.v, + vl=type_helper.size_t) + elif data_type == "float" and "w" in op: + G.func( + inst_info_vv, + name="v{OP}_vv_{TYPE}{WSEW}m{WLMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=type_helper.wv, + vs1=type_helper.v, + vs2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_vs, + name="v{OP}_v{S_TYPE}_{TYPE}{WSEW}m{WLMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.wv, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=type_helper.wv, + vs1=type_helper.s, + vs2=type_helper.v, + vl=type_helper.size_t) + else: + G.func( + inst_info_vv, + name="v{OP}_vv_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=type_helper.v, + vs1=type_helper.v, + vs2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_vs, + name="v{OP}_v{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + vd=type_helper.v, + rs1=type_helper.s, + vs2=type_helper.v, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_load_store_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_load_store_template.py new file mode 100644 index 000000000..c76f773c3 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_load_store_template.py @@ -0,0 +1,64 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering load/store instructions of mask registers to their +corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name, unused-argument + # FIXME: Renaming 'G' to 'g' all in once later. + # FIXME: Argument 'lmul_list' is unused but required for interface + # consistency. We can prune it in the future. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + # treat sew_list as MLEN + for args in prod(OP=op_list, TYPE=type_list, MLEN=sew_list): + op = args["OP"] + type_helper = TypeHelper(**args) + + load_p = op == "vlm" + + inst_info = InstInfo.get(args, decorator, InstType.V) + + if load_p: + base_type = "const uint8_t *" + G.func( + inst_info, + name="vlm_v_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.m, + base=base_type, + vl=type_helper.size_t) + else: + base_type = "uint8_t *" + G.func( + inst_info, + name="vsm_v_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.void, + base=base_type, + value=type_helper.m, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_template.py new file mode 100644 index 000000000..4759c568b --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/mask_template.py @@ -0,0 +1,116 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering mask instructions to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + # treat sew_list as MLEN + for args in prod(OP=op_list, TYPE=type_list, MLEN=sew_list): + op = args["OP"] + if op not in ["cpop", "first"]: + args["OP"] = "m" + args["OP"] + type_helper = TypeHelper(**args) + + if op in ["iota", "id"]: + continue + + inst_info_mm = InstInfo.get(args, decorator, InstType.MMM) + inst_info_m = InstInfo.get(args, decorator, InstType.MM) + + if op in ["mv", "not"]: # unary operator + G.func( + inst_info_m, + name="v{OP}_m_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.m, + op1=type_helper.m, + vl=type_helper.size_t) + elif op in ["clr", "set"]: # nullary operator + G.func( + inst_info_m, + name="v{OP}_m_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.m, + vl=type_helper.size_t) + elif op in ["sbf", "sif", "sof"]: + G.func( + inst_info_m, + name="v{OP}_m_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.m, + **decorator.mask_args(type_helper.m, type_helper.m), + op1=type_helper.m, + vl=type_helper.size_t) + elif op == "cpop": + G.func( + inst_info_m, + name="v{OP}_m_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.ulong, + **decorator.mask_args(type_helper.m), + op1=type_helper.m, + vl=type_helper.size_t) + elif op == "first": + G.func( + inst_info_m, + name="v{OP}_m_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.long, + **decorator.mask_args(type_helper.m), + op1=type_helper.m, + vl=type_helper.size_t) + else: # binary operator + G.func( + inst_info_mm, + name="v{OP}_mm_b{MLEN}".format_map(args) + decorator.func_suffix, + return_type=type_helper.m, + **decorator.mask_args(type_helper.m), + op1=type_helper.m, + op2=type_helper.m, + vl=type_helper.size_t) + + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + op = args["OP"] + type_helper = TypeHelper(**args) + if op == "iota": + G.func( + InstInfo.get(args, decorator, InstType.MM), + name=\ + "viota_m_u{SEW}m{LMUL}".format_map(args) + decorator.func_suffix, + return_type=type_helper.uiv, + **decorator.mask_args(type_helper.m, type_helper.uiv), + **decorator.tu_dest_args(type_helper.uiv), + op1=type_helper.m, + vl=type_helper.size_t) + if op == "id": + G.func( + InstInfo.get(args, decorator, InstType.VM), + name="vid_v_u{SEW}m{LMUL}".format_map(args) + decorator.func_suffix, + return_type=type_helper.uiv, + **decorator.mask_args(type_helper.m, type_helper.uiv), + **decorator.tu_dest_args(type_helper.uiv), + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/misc_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/misc_op_template.py new file mode 100644 index 000000000..e65fe9255 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/misc_op_template.py @@ -0,0 +1,86 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering LMUL extension, LMUL truncation, and intitialization +function to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import get_float_lmul +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + if "vlmul_ext_v" in op_list or "vlmul_trunc_v" in op_list: + break + decorator.write_text_header(G) + + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + type_helper = TypeHelper(**args) + if args["OP"] not in ["vundefined"]: + break + if args["TYPE"] == "float" and args["SEW"] == 8: + continue + if args["OP"] == "vundefined": + inst_type = InstType.VUNDEF + G.func( + InstInfo.get(args, decorator, inst_type), + name="{OP}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v) + + for decorator in decorator_list: + if not ("vlmul_ext_v" in op_list or "vlmul_trunc_v" in op_list): + break + for args in prod( + OP=op_list, + TYPE=type_list, + SEW=sew_list, + LMUL=lmul_list, + DST_LMUL=lmul_list): + op = args["OP"] + src_lmul = args["LMUL"] + dst_lmul = args["DST_LMUL"] + if op == "vlmul_trunc_v": + inst_type = InstType.LMUL_TRUNC + if get_float_lmul(src_lmul) <= get_float_lmul(dst_lmul): + continue + if op == "vlmul_ext_v": + inst_type = InstType.LMUL_EXT + if get_float_lmul(src_lmul) >= get_float_lmul(dst_lmul): + continue + type_helper = TypeHelper(**args) + dst_type = "v{TYPE}{SEW}m{DST_LMUL}_t".format_map(args) + if not type_helper.valid_vtype(dst_type): + continue + args["TYPE1"] = args["TYPE"][0] + func_name = "{OP}_{TYPE1}{SEW}m{LMUL}_{TYPE1}{SEW}m{DST_LMUL}".format_map( + args) + G.func( + InstInfo.get(args, decorator, inst_type), + name=func_name + decorator.func_suffix, + return_type=dst_type, + op1=type_helper.v) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/permute_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/permute_template.py new file mode 100644 index 000000000..722547d76 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/permute_template.py @@ -0,0 +1,104 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering permutation instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + data_type = args["TYPE"] + op = args["OP"] + + if data_type == "float" and\ + op not in ["compress", "slideup", "slidedown"]: + args["S_TYPE"] = "f" + args["OP"] = "f" + args["OP"] + sv_inst_type = InstType.FV + vs_inst_type = InstType.VF + vvs_inst_type = InstType.VVF + else: + args["S_TYPE"] = "x" + sv_inst_type = InstType.XV + vs_inst_type = InstType.VX + vvs_inst_type = InstType.VVX + + type_helper = TypeHelper(**args) + + if op == "mv": + if decorator.func_suffix == "": + G.func( + InstInfo.get(args, decorator, sv_inst_type), + name="v{OP}_{S_TYPE}_s_{TYPE}{SEW}m{LMUL}_{TYPE}{SEW}".format_map( + args), + return_type=type_helper.s, + src=type_helper.v) + G.func( + InstInfo.get(args, decorator, vs_inst_type), + name="v{OP}_s_{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.dest_args(type_helper.v), + src=type_helper.s, + vl=type_helper.size_t) + elif op in ["slide1up", "slide1down"]: + G.func( + InstInfo.get(args, decorator, vvs_inst_type), + name="v{OP}_v{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + src=type_helper.v, + value=type_helper.s, + vl=type_helper.size_t) + elif op in ["slideup", "slidedown"]: + G.func( + InstInfo.get(args, decorator, InstType.VVX), + name="v{OP}_v{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.dest_args(type_helper.v), + src=type_helper.v, + offset=type_helper.size_t, + vl=type_helper.size_t) + elif op == "compress": + G.func( + InstInfo.get(args, decorator, InstType.VVV), + name="v{OP}_vm_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + mask=type_helper.m, + **decorator.dest_args(type_helper.v), + src=type_helper.v, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reduction_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reduction_template.py new file mode 100644 index 000000000..a6f194e8d --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reduction_template.py @@ -0,0 +1,87 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering reduction instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType +from enums import ExtraAttr + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + data_type = args["TYPE"] + op = args["OP"] + sew = args["SEW"] + + type_helper = TypeHelper(**args) + + if data_type == "float": + args["OP"] = "f" + op + if data_type == "uint" and op in ["redmax", "redmin", "wredsum"]: + args["OP"] = args["OP"] + "u" + + if "w" in op: + s = type_helper.wvm1 + args["WSEW"] = 2 * sew + inst_type = InstType.W1VW1 + else: + inst_type = InstType.V1VV1 + s = type_helper.vm1 + + if not type_helper.valid_vtype(s): + continue + + inst_info = InstInfo.get( + args, decorator, inst_type, extra_attr=ExtraAttr.REDUCE) + if (data_type == "float" and + op in ["redosum","redusum","redmax","redmin","wredosum","wredusum"])\ + or ("int" in data_type): + if "w" in op: + G.func( + inst_info, + name="v{OP}_vs_{TYPE}{SEW}m{LMUL}_{TYPE}{WSEW}m1".format_map(args) + + decorator.func_suffix, + return_type=s, + **decorator.mask_args(type_helper.m), + **decorator.dest_args(s), + vector=type_helper.v, + scalar=s, + vl=type_helper.size_t) + else: + G.func( + inst_info, + name="v{OP}_vs_{TYPE}{SEW}m{LMUL}_{TYPE}{SEW}m1".format_map(args) + + decorator.func_suffix, + return_type=s, + **decorator.mask_args(type_helper.m), + **decorator.dest_args(s), + vector=type_helper.v, + scalar=s, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reint_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reint_op_template.py new file mode 100644 index 000000000..0bd4ccb8e --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/reint_op_template.py @@ -0,0 +1,109 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering reinterpret cast conversion functions to their +corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name, unused-argument + # FIXME: Renaming 'G' to 'g' all in once later. + # FIXME: Argument 'type_list' is unused but required for interface + # consistency. We can prune it in the future. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + + G.write("// Reinterpret between different type under the same SEW/LMUL\n") + # Variable in list means + # [dst type, dst short type, src type, src short type] + convert_set = [["float", "f", "int", "i"], ["float", "f", "uint", "u"], + ["uint", "u", "int", "i"], ["int", "i", "uint", "u"], + ["int", "i", "float", "f"], ["uint", "u", "float", "f"]] + + for args in prod( + OP=op_list, SEW=sew_list, TYPES=convert_set, LMUL=lmul_list): + sew = args["SEW"] + + type_helper = TypeHelper(**args) + args["TYPES0"] = args["TYPES"][0] + args["TYPES1"] = args["TYPES"][1] + args["TYPES2"] = args["TYPES"][2] + args["TYPES3"] = args["TYPES"][3] + + if (args["TYPES1"] == "f" or args["TYPES3"] == "f") and sew == 8: + continue + + if (args["TYPES1"] == "bf" or args["TYPES3"] == "bf") and sew != 16: + continue + + rt = "v{TYPES0}{SEW}m{LMUL}_t".format_map(args) + if not type_helper.valid_vtype(rt): + continue + func_name =\ + "v{OP}_v_{TYPES3}{SEW}m{LMUL}_{TYPES1}{SEW}m{LMUL}".format_map(args) + src_type = "v{TYPES2}{SEW}m{LMUL}_t".format_map(args) + G.func( + InstInfo.get(args, decorator, InstType.REINT), + name=func_name + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, rt), + src=src_type) + + G.write("// Reinterpret between different SEW under the same LMUL\n") + # Variable in list means + # [dst type, dst short type, src type, src short type] + convert_set = [["int", "i", "int", "i"], ["uint", "u", "uint", "u"]] + + for args in prod( + OP=op_list, + SEW=sew_list, + DST_SEW=sew_list, + TYPES=convert_set, + LMUL=lmul_list): + sew = args["SEW"] + dst_sew = args["DST_SEW"] + if sew == dst_sew: + continue + + type_helper = TypeHelper(**args) + args["TYPES0"] = args["TYPES"][0] + args["TYPES1"] = args["TYPES"][1] + args["TYPES2"] = args["TYPES"][2] + args["TYPES3"] = args["TYPES"][3] + + rt = "v{TYPES0}{DST_SEW}m{LMUL}_t".format_map(args) + if not type_helper.valid_vtype(rt): + continue + func_name =\ + "v{OP}_v_{TYPES3}{SEW}m{LMUL}_{TYPES1}{DST_SEW}m{LMUL}".format_map(args) + src_type = "v{TYPES2}{SEW}m{LMUL}_t".format_map(args) + G.func( + InstInfo.get(args, decorator, InstType.REINT), + name=func_name + decorator.func_suffix, + return_type=rt, + **decorator.mask_args(type_helper.m, rt), + src=src_type) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_load_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_load_template.py new file mode 100644 index 000000000..2d35e8a68 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_load_template.py @@ -0,0 +1,92 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering segment load instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import seg_constraint +from utils import TypeHelper +from utils import get_string_lmul +from utils import seg_arg +import collections +from enums import InstInfo +from enums import InstType +from enums import MemType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + nf_list = range(2, 9) + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + constraint=seg_constraint, + OP=op_list, + TYPE=type_list, + SEW=sew_list, + EEW=sew_list, + LMUL=lmul_list, + NF=nf_list): + op = args["OP"] + nf = str(args["NF"]) + sew = args["SEW"] + eew = args["EEW"] + + type_helper = TypeHelper(**args) + + if op not in ["vloxseg", "vluxseg"] and sew != eew: + continue + + extra_addr_args = collections.OrderedDict() + inst_type = InstType.VX + + if op in ["vlsseg"]: + extra_addr_args["bstride"] = "ptrdiff_t" + inst_type = InstType.VXX + if op in ["vloxseg", "vluxseg"]: + elmul = type_helper.get_elmul(eew, sew) + if elmul == 0: + continue + elmul_str = get_string_lmul(elmul, 1) + extra_addr_args["bindex"] = f"vuint{eew}m{elmul_str}_t" + args["OP"] = op + nf + "ei" + str(eew) + inst_type = InstType.VV + elif op == "vlsegff": + args["OP"] = "vlseg" + nf + "e" + str(eew) + "ff" + extra_addr_args["new_vl"] = "size_t *" + else: + args["OP"] = op + nf + "e" + str(eew) + + inst_info = InstInfo.get(args, decorator, inst_type, MemType.LOAD) + G.func( + inst_info, + name="{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.void, + **seg_arg(type_helper.v, int(nf), ptr_t=True), + **decorator.mask_args(type_helper.m, type_helper.v, int(nf)), + **decorator.tu_dest_args(type_helper.v, int(nf)), + base="const {TYPE}{SEW}_t *".format_map(args), + **extra_addr_args, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_store_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_store_template.py new file mode 100644 index 000000000..b00a40814 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/seg_store_template.py @@ -0,0 +1,88 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering segment store instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import seg_constraint +from utils import TypeHelper +from utils import get_string_lmul +from utils import seg_arg +import collections +from enums import InstInfo +from enums import InstType +from enums import MemType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + nf_list = range(2, 9) + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + constraint=seg_constraint, + OP=op_list, + TYPE=type_list, + SEW=sew_list, + EEW=sew_list, + LMUL=lmul_list, + NF=nf_list): + op = args["OP"] + nf = str(args["NF"]) + sew = args["SEW"] + eew = args["EEW"] + + if op not in ["vsoxseg", "vsuxseg"] and sew != eew: + continue + + type_helper = TypeHelper(**args) + + extra_addr_args = collections.OrderedDict() + inst_type = InstType.VX + if op in ["vssseg"]: + extra_addr_args["bstride"] = "ptrdiff_t" + inst_type = InstType.VXX + + if op in ["vsoxseg", "vsuxseg"]: + elmul = type_helper.get_elmul(eew, sew) + if elmul == 0: + continue + elmul_str = get_string_lmul(elmul, 1) + extra_addr_args["bindex"] = f"vuint{eew}m{elmul_str}_t" + args["OP"] = op + nf + "ei" + str(eew) + inst_type = InstType.VV + else: + args["OP"] = op + nf + "e" + str(eew) + + inst_info = InstInfo.get(args, decorator, inst_type, MemType.STORE) + G.func( + inst_info, + name="{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.void, + **decorator.mask_args(type_helper.m, type_helper.v, int(nf)), + base="{TYPE}{SEW}_t *".format_map(args), + **extra_addr_args, + **seg_arg(type_helper.v, int(nf)), + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/setvl_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/setvl_template.py new file mode 100644 index 000000000..782724497 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/setvl_template.py @@ -0,0 +1,53 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering vsetvl to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name, unused-argument + # FIXME: Renaming 'G' to 'g' all in once later. + # FIXME: Argument 'type_list', 'decorator_list' is unused but required for + # interface consistency. We can prune it in the future. + G.inst_group_prologue() + for args in prod(OP=op_list, SEW=sew_list, LMUL=lmul_list): + op = args["OP"] + + type_helper = TypeHelper(**args) + + if op == "readvl": + G.func(name="v{OP}".format_map(args), return_type=type_helper.size_t) + elif op == "setvlmax": + G.func( + InstInfo.get(args, None, InstType.SETVLMAX), + name="v{OP}_e{SEW}m{LMUL}".format_map(args), + return_type=type_helper.size_t) + else: + G.func( + InstInfo.get(args, None, InstType.SETVL), + name="v{OP}_e{SEW}m{LMUL}".format_map(args), + return_type=type_helper.size_t, + avl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/store_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/store_template.py new file mode 100644 index 000000000..44c25383a --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/store_template.py @@ -0,0 +1,74 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering store instructions to their corresponding intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from utils import get_string_lmul +import collections +from enums import InstInfo +from enums import InstType +from enums import MemType + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod( + OP=op_list, TYPE=type_list, SEW=sew_list, EEW=sew_list, LMUL=lmul_list): + op = args["OP"] + sew = args["SEW"] + eew = args["EEW"] + + type_helper = TypeHelper(**args) + + extra_addr_args = collections.OrderedDict() + inst_type = InstType.VX + if op in ["vsse"]: + extra_addr_args["bstride"] = "ptrdiff_t" + inst_type = InstType.VXX + if op in ["vsoxei", "vsuxei"]: + elmul = type_helper.get_elmul(eew, sew) + if elmul == 0: + continue + elmul_str = get_string_lmul(elmul, 1) + extra_addr_args["bindex"] = f"vuint{eew}m{elmul_str}_t" + inst_type = InstType.VV + args["OP"] = op + str(eew) + + if op not in ["vsoxei", "vsuxei"] and sew != eew: + continue + + inst_info = InstInfo.get(args, decorator, inst_type, MemType.STORE) + G.func( + inst_info, + name="{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.void, + **decorator.mask_args(type_helper.m, type_helper.v), + base="{TYPE}{SEW}_t *".format_map(args), + **extra_addr_args, + value=type_helper.v, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/unary_op_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/unary_op_template.py new file mode 100644 index 000000000..6d55468b8 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/unary_op_template.py @@ -0,0 +1,202 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering unary operand instructions to their corresponding +intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod +from utils import TypeHelper +from enums import InstInfo +from enums import InstType +from enums import ExtraAttr +import copy + + +def render(G, op_list, type_list, sew_list, lmul_list, decorator_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for decorator in decorator_list: + decorator.write_text_header(G) + for args in prod(OP=op_list, TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + data_type = args["TYPE"] + op = args["OP"] + + if op in ["zext", "sext"]: + break + + if data_type == "float": + args["S_TYPE"] = "f" + args["OP"] = "f" + args["OP"] + inst_type_vvsm = InstType.VVFM + inst_type_vs = InstType.VF + else: + args["S_TYPE"] = "x" + inst_type_vvsm = InstType.VVXM + inst_type_vs = InstType.VX + + type_helper = TypeHelper(**args) + + if op == "merge": + extra_attr = ExtraAttr.MERGE + else: + extra_attr = ExtraAttr.NO_ATTR + + inst_info_vv = InstInfo.get( + args, decorator, InstType.VV, extra_attr=extra_attr) + inst_info_vs = InstInfo.get( + args, decorator, inst_type_vs, extra_attr=extra_attr) + inst_info_vvsm = InstInfo.get( + args, decorator, inst_type_vvsm, extra_attr=extra_attr) + + # Special rule for vfmv_v_v, we don"t have vfmv.v.v but vmv.v.v can used + # for float type, accrdoing current naming scheming it + # should be vmv_v_v, same for vmerge.vvm. + vv_args = args + if data_type == "float" and op in ["mv", "merge"]: + vv_args = copy.deepcopy(args) + vv_args["OP"] = op + + if op == "merge": + G.func( + InstInfo.get( + vv_args, decorator, InstType.VVVM, extra_attr=extra_attr), + name="v{OP}_vvm_{TYPE}{SEW}m{LMUL}".format_map(vv_args) + + decorator.func_suffix, + return_type=type_helper.v, + mask=type_helper.m, + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + op2=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_vvsm, + name="v{OP}_v{S_TYPE}m_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + mask=type_helper.m, + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + op2=type_helper.s, + vl=type_helper.size_t) + elif op == "mv": + G.func( + InstInfo.get(vv_args, decorator, InstType.VV), + name="v{OP}_v_v_{TYPE}{SEW}m{LMUL}".format_map(vv_args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.tu_dest_args(type_helper.v), + src=type_helper.v, + vl=type_helper.size_t) + G.func( + inst_info_vs, + name="v{OP}_v_{S_TYPE}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.tu_dest_args(type_helper.v), + src=type_helper.s, + vl=type_helper.size_t) + elif op in ["sqrt", "rsqrt7", "rec7", "abs"]: + assert data_type == "float" + G.func( + inst_info_vv, + name="v{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + vl=type_helper.size_t) + elif op == "class": + assert data_type == "float" + G.func( + inst_info_vv, + name="v{OP}_v_u{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.uiv, + **decorator.mask_args(type_helper.m, type_helper.uiv), + **decorator.tu_dest_args(type_helper.uiv), + op1=type_helper.v, + vl=type_helper.size_t) + elif op == "not": + G.func( + inst_info_vv, + name="v{OP}_v_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=type_helper.v, + **decorator.mask_args(type_helper.m, type_helper.v), + **decorator.tu_dest_args(type_helper.v), + op1=type_helper.v, + vl=type_helper.size_t) + else: + assert False, "Unknown instruction" + + # handle Vector Integer Extension + for args in prod( + OP=op_list, TYPE=type_list, SEW=sew_list, EXT=[2, 4, 8], + LMUL=lmul_list): + op = args["OP"] + data_type = args["TYPE"] + ext = args["EXT"] + + if not op in ["zext", "sext"]: + break + if data_type == "uint" and op == "sext": + continue + if data_type == "int" and op == "zext": + continue + + type_helper = TypeHelper(**args) + + args["OP"] = f"{op}_vf{ext}" + + if ext == 2: + prefix_lowercase = "w" + prefix_uppercase = "W" + inst_type = InstType.WV + elif ext == 4: + prefix_lowercase = "q" + prefix_uppercase = "Q" + inst_type = InstType.QV + else: + prefix_lowercase = "o" + prefix_uppercase = "O" + inst_type = InstType.OV + + args["SEW"] = args[prefix_uppercase + "SEW"] + args["LMUL"] = args[prefix_uppercase + "LMUL"] + + rt_type = getattr(type_helper, prefix_lowercase + "v") + if not type_helper.valid_vtype(rt_type): + continue + + inst_info_v = InstInfo.get( + args, decorator, inst_type, extra_attr=ExtraAttr.INT_EXTENSION) + + G.func( + inst_info_v, + name="v{OP}_{TYPE}{SEW}m{LMUL}".format_map(args) + + decorator.func_suffix, + return_type=rt_type, + **decorator.mask_args(type_helper.m, rt_type), + **decorator.tu_dest_args(rt_type), + op1=type_helper.v, + vl=type_helper.size_t) + + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/vtype_template.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/vtype_template.py new file mode 100644 index 000000000..93bb097d5 --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/templates/vtype_template.py @@ -0,0 +1,31 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Template for rendering all possible vector types in RVV intrinsics. +""" + +#pylint: disable=relative-beyond-top-level +from utils import prod + + +def render(G, type_list, sew_list, lmul_list): + #pylint: disable=invalid-name + # FIXME: Renaming 'G' to 'g' all in once later. + G.inst_group_prologue() + for args in prod(TYPE=type_list, SEW=sew_list, LMUL=lmul_list): + G.write("v{TYPE}{SEW}m{LMUL}_t\n".format_map(args)) + G.inst_group_epilogue() diff --git a/rvv-intrinsic-generator/rvv_intrinsic_gen/utils.py b/rvv-intrinsic-generator/rvv_intrinsic_gen/utils.py new file mode 100644 index 000000000..7887c3a6a --- /dev/null +++ b/rvv-intrinsic-generator/rvv_intrinsic_gen/utils.py @@ -0,0 +1,213 @@ +""" +-------------------------------------------------------------------------------- +Copyright 2022 SiFive Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------------- + +Utility on handling RVV types +""" + +import itertools +import re + +ELEN = 64 + + +# ex. f8 -> 0.125 +def get_float_lmul(num): + if isinstance(num, str) and num[0] == "f": + return float(1 / float(num[1:])) + else: + return float(num) + + +# ex. 0.125 -> f8 +def get_string_lmul(num, factor): + result = get_float_lmul(num) * factor + if result < 1.0: + return f"f{int(1 / result)}" + else: + return int(result) + + +class TypeHelper: + """ + The 'TypeHelper' class provides appropriate types for function parameters and + return type. + """ + size_t = "size_t" + void = "void" + intptr_t = "intptr_t" + ptrdiff_t = "ptrdiff_t" + ulong = "unsigned long" + long = "long" + boolean = "uint8_t" + const_int = "const int" + int = "int" + + def __init__(self, **kargs): + self.args = kargs + + @property + def get_float_lmul(self): + lmul = self.args["LMUL"] + return get_float_lmul(lmul) + + def get_elmul(self, eew, sew): + elmul = (eew / sew) * get_float_lmul(self.args["LMUL"]) + if elmul > 8.0 or elmul < (1 / 8): + return 0 + return elmul + + @property + def mlen(self): + if "MLEN" in self.args: + return self.args["MLEN"] + else: + return int(self.args["SEW"] / self.get_float_lmul) + + @property + def m(self): + if "MLEN" in self.args: + return f"vbool{self.args['MLEN']}_t" + else: + return f"vbool{int(self.args['SEW'] / self.get_float_lmul)}_t" + + def valid_vtype(self, vtype): + p = "v(bool|int|uint|float|bfloat)(?P[0-9]+)m(?Pf?[0-9])_t" + i = re.match(p, vtype) + if i is None: + return False + sew = i.group("SEW") + lmul = i.group("LMUL") + # assume ELEN = 64 + if vtype[:6] == "vfloat": + if sew not in ["16", "32", "64"]: + return False + elif vtype[:7] == "vbfloat": + if sew not in ["16"]: + return False + else: + if sew not in ["8", "16", "32", "64"]: + return False + if lmul not in ["f8", "f4", "f2", "1", "2", "4", "8"]: + return False + if get_float_lmul(lmul) < int(sew) / ELEN: + return False + return True + + @property + def v(self): + return "v{TYPE}{SEW}m{LMUL}_t".format_map(self.args) + + @property + def vm1(self): + return "v{TYPE}{SEW}m1_t".format_map(self.args) + + @property + def uiv(self): + return "vuint{SEW}m{LMUL}_t".format_map(self.args) + + @property + def siv(self): + return "vint{SEW}m{LMUL}_t".format_map(self.args) + + @property + def s(self): + return "{TYPE}{SEW}_t".format_map(self.args) + + @property + def uis(self): + return "uint{SEW}_t".format_map(self.args) + + @property + def sis(self): + return "int{SEW}_t".format_map(self.args) + + @property + def wv(self): + return "v{TYPE}{WSEW}m{WLMUL}_t".format_map(self.args) + + @property + def wvm1(self): + return "v{TYPE}{WSEW}m1_t".format_map(self.args) + + @property + def ws(self): + return "{TYPE}{WSEW}_t".format_map(self.args) + + @property + def qv(self): + return "v{TYPE}{QSEW}m{QLMUL}_t".format_map(self.args) + + @property + def ov(self): + return "v{TYPE}{OSEW}m{OLMUL}_t".format_map(self.args) + + +def seg_constraint(**kargs): + return ((get_float_lmul(kargs["LMUL"]) * kargs["NF"]) <= + 8) and basic_constraint(**kargs) + + +def seg_arg(v, nf, ptr_t=False): + args = {} + for i in range(nf): + if ptr_t: + vt = f"{v} *" + else: + vt = v + args[f"v{i}"] = vt + return args + + +def basic_constraint(**kargs): + if "TYPE" in kargs: + if kargs["TYPE"] == "float" and kargs["SEW"] == 8: + return False + if "SEW" in kargs and "LMUL" in kargs and kargs["SEW"] is not None and kargs[ + "LMUL"] is not None: + if "TYPE" not in kargs: + kargs["TYPE"] = "int" + type_helper = TypeHelper(**kargs) + if not type_helper.valid_vtype(type_helper.v): + return False + return True + + +# Return list of dict +# prod(a=[1,2], b=[4,5]) +# return [{a:"1", b : "4"}, {a:"1", b : "5"}, +# {a:"2", b : "4"}, {a:"2", b : "5"}] +def prod(constraint=basic_constraint, **kargs): + for k, v in kargs.items(): + if len(v) == 0: + kargs[k] = [None] + result = [] + for i in itertools.product(*kargs.values()): + temp = dict(zip(kargs.keys(), i)) + for k in ["LMUL", "SEW"]: + if k in temp and temp[k]: + temp["W" + k] = get_string_lmul(temp[k], 2) + temp["Q" + k] = get_string_lmul(temp[k], 4) + temp["O" + k] = get_string_lmul(temp[k], 8) + temp["N" + k] = get_string_lmul(temp[k], 0.5) + if constraint(**temp): + result.append(temp) + + # Put float in front of int + if "TYPE" in result[0]: + result = sorted(result, key=lambda d: d["TYPE"]) + + return result