diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2545cb58c06c0..fbdf01375e7bf 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6647,8 +6647,10 @@ void SPIRVTranslator::ConstructJob(Compilation &C, const JobAction &JA, TranslatorArgs.push_back("-o"); TranslatorArgs.push_back(Output.getFilename()); - if (getToolChain().getTriple().isSYCLDeviceEnvironment()) - TranslatorArgs.push_back("-spirv-no-deref-attr"); + if (getToolChain().getTriple().isSYCLDeviceEnvironment()) { + TranslatorArgs.push_back("-spirv-max-version=1.0"); + TranslatorArgs.push_back("-spirv-ext=+all"); + } for (auto I : Inputs) { TranslatorArgs.push_back(I.getFilename()); } diff --git a/clang/lib/Driver/ToolChains/SYCL.cpp b/clang/lib/Driver/ToolChains/SYCL.cpp index 0bc1aab5aefe9..807ccb37c3907 100644 --- a/clang/lib/Driver/ToolChains/SYCL.cpp +++ b/clang/lib/Driver/ToolChains/SYCL.cpp @@ -39,7 +39,8 @@ const char *SYCL::Linker::constructLLVMSpirvCommand(Compilation &C, CmdArgs.push_back("-o"); CmdArgs.push_back(OutputFileName); } else { - CmdArgs.push_back("-spirv-no-deref-attr"); + CmdArgs.push_back("-spirv-max-version=1.0"); + CmdArgs.push_back("-spirv-ext=+all"); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } diff --git a/clang/test/Driver/sycl-offload-intelfpga.cpp b/clang/test/Driver/sycl-offload-intelfpga.cpp index 6efbf292b1c69..72bb8f738ab66 100644 --- a/clang/test/Driver/sycl-offload-intelfpga.cpp +++ b/clang/test/Driver/sycl-offload-intelfpga.cpp @@ -21,7 +21,7 @@ // CHK-FPGA-LINK: clang-offload-bundler{{.*}} "-type=o" "-targets=fpga-fpga_aocr-intel-{{.*}}-sycldevice" "-inputs=[[INPUT]]" "-check-section" // CHK-FPGA-LINK: clang-offload-bundler{{.*}} "-type=o" "-targets=host-x86_64-unknown-linux-gnu,sycl-spir64_fpga-unknown-{{.*}}-sycldevice" "-inputs=[[INPUT]]" "-outputs=[[OUTPUT1:.+\.o]],[[OUTPUT2:.+\.o]]" "-unbundle" // CHK-FPGA-LINK: llvm-link{{.*}} "[[OUTPUT2]]" "-o" "[[OUTPUT3:.+\.bc]]" -// CHK-FPGA-LINK: llvm-spirv{{.*}} "-spirv-no-deref-attr" "-o" "[[OUTPUT4:.+\.spv]]" "[[OUTPUT3]]" +// CHK-FPGA-LINK: llvm-spirv{{.*}} "-spirv-max-version=1.0" "-spirv-ext=+all" "-o" "[[OUTPUT4:.+\.spv]]" "[[OUTPUT3]]" // CHK-FPGA-EARLY: aoc{{.*}} "-o" "[[OUTPUT5:.+\.aocr]]" "[[OUTPUT4]]" "-sycl" "-rtl" // CHK-FPGA-IMAGE: aoc{{.*}} "-o" "[[OUTPUT5:.+\.aocx]]" "[[OUTPUT4]]" "-sycl" // CHK-FPGA-LINK: ld{{.*}} "-r" "[[INPUT]]" "-o" "[[OUTPUT6:.+\.o]]" diff --git a/clang/test/Driver/sycl.c b/clang/test/Driver/sycl.c index 6085c4a331dd9..7b48f85b9101d 100644 --- a/clang/test/Driver/sycl.c +++ b/clang/test/Driver/sycl.c @@ -6,9 +6,9 @@ // DEFAULT: "-triple" "spir64-unknown-{{.*}}-sycldevice"{{.*}} "-fsycl-is-device"{{.*}} "-emit-llvm-bc" // DEFAULT: "-internal-isystem" "{{.*lib.*clang.*include}}" -// DEFAULT-NOT: "{{.*}}llvm-spirv"{{.*}} "-spirv-no-deref-attr" +// DEFAULT-NOT: "{{.*}}llvm-spirv"{{.*}} "-spirv-max-version=1.0"{{.*}} "-spirv-ext=+all" // NO-BITCODE: "-triple" "spir64-unknown-{{.*}}-sycldevice"{{.*}} "-fsycl-is-device"{{.*}} "-emit-llvm-bc" -// NO-BITCODE: "{{.*}}llvm-spirv"{{.*}} "-spirv-no-deref-attr" +// NO-BITCODE: "{{.*}}llvm-spirv"{{.*}} "-spirv-max-version=1.0"{{.*}} "-spirv-ext=+all" // TARGET: "-triple" "spir64-unknown-linux-sycldevice"{{.*}} "-fsycl-is-device"{{.*}} "-emit-llvm-bc" // COMBINED: "-triple" "spir64-unknown-{{.*}}-sycldevice"{{.*}} "-fsycl-is-device"{{.*}} "-emit-llvm-bc" diff --git a/llvm-spirv/CMakeLists.txt b/llvm-spirv/CMakeLists.txt index 120874179453c..915fd670840a2 100644 --- a/llvm-spirv/CMakeLists.txt +++ b/llvm-spirv/CMakeLists.txt @@ -63,6 +63,8 @@ endif(LLVM_INCLUDE_TESTS) install( FILES ${LLVM_SPIRV_INCLUDE_DIRS}/LLVMSPIRVLib.h + ${LLVM_SPIRV_INCLUDE_DIRS}/LLVMSPIRVOpts.h + ${LLVM_SPIRV_INCLUDE_DIRS}/LLVMSPIRVExtensions.inc DESTINATION ${CMAKE_INSTALL_PREFIX}/include/LLVMSPIRVLib ) diff --git a/llvm-spirv/README.md b/llvm-spirv/README.md index ab844e705115b..17fb769ec38c2 100644 --- a/llvm-spirv/README.md +++ b/llvm-spirv/README.md @@ -18,7 +18,7 @@ The files/directories related to the translator: ## Build Instructions -Master branch of this repo is aimed to be buildable with the latest LLVM version. +The `master` branch of this repo is aimed to be buildable with the latest LLVM `master` or `trunk` revision. ### Build with pre-installed LLVM @@ -64,7 +64,8 @@ make llvm-spirv -j`nproc` ## Test instructions -All tests related to the translator are placed in the [test](test) directory. Optionally the tests can make use of spirv-val (part of SPIRV-Tools) in order to validate the generated SPIR-V against the official SPIR-V specification. +All tests related to the translator are placed in the [test](test) directory. A number of the tests require spirv-as (part of SPIR-V Tools) to run, but the remainder of the tests can still be run without this. Optionally the tests can make use of spirv-val (part of SPIRV-Tools) in order to validate the generated SPIR-V against the official SPIR-V specification. + In case tests are failing due to SPIRV-Tools not supporting certain SPIR-V features, please get an updated package. The `PKG_CONFIG_PATH` environmental variable can be used to let cmake point to a custom installation. Execute the following command inside the build directory to run translator tests: @@ -99,10 +100,52 @@ To translate between LLVM IR and SPIR-V: * `-spirv-text` - read/write SPIR-V in an internal textual format for debugging purpose. The textual format is not defined by SPIR-V spec. * `-help` - to see full list of options +### Handling SPIR-V versions generated by the translator + +There is one option to control the behavior of the translator with respect to +the version of the SPIR-V file which is being generated/consumed. + +* `-spirv-max-version=` - this option allows restricting the + SPIRV-LLVM-Translator **not** to generate a SPIR-V with a version which is + higher than the one specified via this option. + + If the `-r` option was also specified, the SPIRV-LLVM-Translator will reject + the input file and emit an error if the SPIR-V version in it is higher than + one specified via this option. + +Allowed values are `1.0`/`1.1`. + +More information can be found in +[SPIR-V versions and extensions handling](docs/SPIRVVersionsAndExtensionsHandling.rst) + +### Handling SPIR-V extensions generated by the translator + +By default, during SPIR-V generation, the translator doesn't use any extensions. +However, during SPIR-V consumption, the translator accepts input files that use +any known extensions. + +If certain extensions are required to be enabled or disabled, the following +command line option can be used: + +* ``--spirv-ext=`` - this options allows controlling which extensions are + allowed/disallowed + +Valid value for this option is comma-separated list of extension names prefixed +with ``+`` or ``-`` - plus means allow to use extension, minus means disallow +to use extension. There is one more special value which can be used as extension +name in this option: ``all`` - it affects all extension which are known to the +translator. + +If ``--spirv-ext`` contains the name of an extension which is not known for the +translator, it will emit an error. + +More information can be found in +[SPIR-V versions and extensions handling](docs/SPIRVVersionsAndExtensionsHandling.rst) + ## Branching strategy Code on the master branch in this repository is intended to be compatible with master/trunk branch of the [llvm](https://github.com/llvm-mirror/llvm) project. That is, for an OpenCL kernel compiled to llvm bitcode by the latest version(built with the latest git commit or svn revision) of Clang it should be possible to translate it to SPIR-V with the llvm-spirv tool. All new development should be done on the master branch. -To have versions compatible with released versions of LLVM and Clang, corresponding branches are created in this repository. For example, to build translator with LLVM 7.0 ([release_70](https://github.com/llvm-mirror/llvm/tree/release_70)) one should use [llvm_release_70](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/llvm_release_70) branch. +To have versions compatible with released versions of LLVM and Clang, corresponding branches are available in this repository. For example, to build the translator with LLVM 7.0 ([release_70](https://github.com/llvm-mirror/llvm/tree/release_70)) one should use the [llvm_release_70](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/tree/llvm_release_70) branch. As a general rule, commits from the master branch may be backported to the release branches as long as they do not depend on features from a later LLVM/Clang release and there are no objections from the maintainer(s). There is no guarantee that older release branches are proactively kept up to date with master, but you can request certain commits on older release branches by creating a pull request or raising an issue on GitHub. diff --git a/llvm-spirv/docs/SPIRVVersionsAndExtensionsHandling.rst b/llvm-spirv/docs/SPIRVVersionsAndExtensionsHandling.rst new file mode 100644 index 0000000000000..cdf11614fee25 --- /dev/null +++ b/llvm-spirv/docs/SPIRVVersionsAndExtensionsHandling.rst @@ -0,0 +1,243 @@ +======================================= +SPIR-V versions and extensions handling +======================================= + +.. contents:: + :local: + +Overview +======== + +This document describes how the translator makes decisions about using +instructions from different version of the SPIR-V core and extension +specifications. + +Being able to control the resulting SPIR-V version is important: the target +consumer might be quite old, without support for new SPIR-V versions and there +must be the possibility to control which version of the SPIR-V specification +that will be used during translation. + +SPIR-V extensions is another thing which must be controllable. Extensions +can update and re-define semantics and validation rules for existing SPIR-V +entries and it is important to ensure that the translator is able to generate +valid SPIR-V according to the core spec, without uses of any extensions if such +SPIR-V was requested by user. + +For example, without such infrastructure it is impossible to disable use of +``SPV_KHR_no_integer_wrap_decoration`` - it will be always generated if +corresponding LLVM IR counterparts are encountered in input module. + +It is worth mentioning that SPIR-V versions and extensions the handling of +SPIR-V versions and extension is mostly important for the SPIR-V generation +step. On the consumer side it is the responsibility of the consumer to analyze +the incoming SPIR-V file and reject it if it contains something that is not +supported by the consumer. + +However, translator simplifies this step for downstream users by checking +version and extensions in SPIR-V module during ``readSpirv``/``readSpirvModule`` +phases. + +SPIR-V Versions +=============== + +SPIR-V Generation step +---------------------- + +By default translator selects version of generated SPIR-V file based on features +used in this file. For example, if it contains ``dereferencable`` LLVM IR +attribute, ``MaxByteOffset`` decoration will be generated and resulting SPIR-V +version will be raised to 1.1. + +.. note:: + There is no documentation about which exact features from newest + SPIR-V spec versions will be used by the translator. If you are interested + when or why a particular SPIR-V instruction is generated, please check this + in the source code. Consider this as an implementation detail and if you + disagree with something, you can always open an issue or submit pull request + - contributions are welcome! + +There is one option to control the behavior of the translator with respect to +the version of the SPIR-V file which is being generated/consumed. + +* ``--spirv-max-version=`` - instructs the translator to generate SPIR-V file + corresponding to any spec version which is less than or equal to the + specified one. Behavior of the translator is the same as by default with only + one exception: resulting SPIR-V version cannot be raised higher than + specified by this option. + +Allowed values are ``1.0`` and ``1.1``. + +.. warning:: + These two options are mutually exclusive and cannot be specified at the + same time. + +If the translator encounters something that cannot be represented by set of +allowed SPIR-V versions (which might contain only one version), it does one of +the following things: + +* ignores LLVM IR entity in the input file. + + For example, ``dereferencable`` LLVM IR attribute can be ignored if it is not + allowed to generate SPIR-V 1.1 and higher. + +* tries to represent LLVM IR entity with allowed instructions. + + For example, ``OpPtrEqual`` can be used if SPIR-V 1.4 is not allowed and can + be emulated via ``OpConvertPtrToU`` + ``OpIEqual`` sequence. + +* emits error if LLVM IR entity cannot be ignored and cannot be emulated using + available instructions. + + For example, if global constructors/destructors + (represented by @llvm.global_ctors/@llvm.global_dtors) are present in a module + then the translator should emit error if it cannot use SPIR-V 1.1 and higher + where ``Initializer`` and ``Finalizer`` execution modes are described. + +SPIR-V Consumption step +----------------------- + +By default, translator consumes SPIR-V of any version which is supported. + +This behavior, however, can be controlled via the same switches described in +the previous section. + +If one of the switches present and translator encountered SPIR-V file +corresponding to a spec version which is not included into set of allowed +SPIR-V versions, translator emits error. + +SPIR-V Extensions +================= + +SPIR-V Generation step +---------------------- + +By default, translator doesn't use any extensions. If it required to enable +certain extension, the following command line option can be used: + +* ``--spirv-ext=`` - allows to control list of allowed/disallowed extensions. + +Valid value for this option is comma-separated list of extension names prefixed +with ``+`` or ``-`` - plus means allow to use extension, minus means disallow +to use extension. There is one more special value which can be used as extension +name in this option: ``all`` - it affects all extension which are known to the +translator. + +If ``--spirv-ext`` contains name of extension which is not know for the +translator, it will emit error. + +Examples: + +* ``--spirv-ext=+SPV_KHR_no_integer_wrap_decoration,+SPV_INTEL_subgroups`` +* ``--spirv-ext=+all,-SPV_INTEL_fpga_loop_controls`` + +.. warning:: + Extension name cannot be allowed and disallowed at the same time: for inputs + like ``--spirv-ext=+SPV_INTEL_subgroups,-SPV_INTEL_subgroups`` translator + will emit error about invalid arguments. + +.. note:: + Since by default during SPIR-V generation all extensions are disabled, this + means that ``-all,`` is implicitly added at the beggining of the + ``-spirv-ext`` value. + +If the translator encounters something that cannot be represented by set of +allowed SPIR-V extensions (which might be empty), it does one of the following +things: + +* ignores LLVM IR entity in the input file. + + For example, ``nsw``/``nuw`` LLVM IR attributes can be ignored if it is not + allowed to generate SPIR-V 1.4 and ``SPV_KHR_no_integer_wrap_decoration`` + extension is disallowed. + +* tries to represent LLVM IR entity with allowed instructions. + + Translator could translate calls to a new built-in functions defined by some + extensions as usual call instructions without using special SPIR-V + instructions. + + However, this could result in a strange SPIR-V and most likely will lead to + errors during consumption. Having that, translator should emit errors if it + encounters a call to a built-in function from an extension which must be + represented as a special SPIR-V instruction from extension which wasn't + allowed to be used. I.e. if translator knows that this certain LLVM IR entity + belongs to an extension functionality and this extension is disallowed, it + should emit error rather than emulating it. + +* emits error if LLVM IR entity cannot be ignored and cannot be emulated using + available instructions. + + For example, new built-in types defined by + ``cl_intel_device_side_avc_motion_estimation`` cannot be represented in SPIR-V + if ``SPV_INTEL_device_side_avc_motion_estimation`` is disallowed. + +SPIR-V Consumption step +----------------------- + +By default, translator consumes SPIR-V regardless of list extensions which are +used by the input file, i.e. all extensions are allowed by default during +consumption step. + +.. note:: + This is opposite to the generation step and this is done on purpose: to not + broke workflows of existing users of the translator. + +.. note:: + Since by default during SPIR-V consumption all extensions are enabled, this + means that ``+all,`` is implicitly added at the beggining of the + ``-spirv-ext`` value. + +This behavior, however, can be controlled via the same switches described in +the previous section. + +If ``--spirv-ext`` switch presents, translator will emit error if it finds out +that input SPIR-V file uses disallowed extension. + +.. note:: + If the translator encounters unknown extension in the input SPIR-V file, it + will emit error regardless of ``-spirv-ext`` option value. + +If one of the switches present and translator encountered SPIR-V file +corresponding to a spec version which is not included into set of allowed +SPIR-V versions, translator emits error. + +How to control translator behavior when using it as library +=========================================================== + +When using translator as library it can be controlled via bunch of alternative +APIs that have additional argument: ``TranslatorOpts`` object which +encapsulates information about available SPIR-V versions and extensions. + +List of new APIs is: ``readSpirvModule``, ``writeSpirv`` and ``readSpirv``. + +.. note:: + See ``LLVMSPIRVOpts.h`` for more details. + +How to get ``TranslatorOpts`` object +------------------------------------ + +1. Default constructor. Equal to: + + ``--spirv-max-version=MaxKnownVersion --spirv-ext=-all`` + + .. note:: + There is method ``TranslatorOpts::enableAllExtensions()`` that allows you + to quickly enable all known extensions if it is needed. + +2. Constructor which accepts all parameters + + Consumes both max SPIR-V version and optional map with extensions status + (i.e. which one is allowed and which one is disallowed) + +Extensions status map +^^^^^^^^^^^^^^^^^^^^^ + +This map is defined as ``std::map`` and it is intended to +show which extension is allowed to be used (``true`` as value) and which is not +(``false`` as value). + +.. note:: + If certain ``ExtensionID`` value is missed in the map, it automatically means + that extension is not allowed to be used. + + This implies that by default, all extensions are disallowed. diff --git a/llvm-spirv/include/LLVMSPIRVExtensions.inc b/llvm-spirv/include/LLVMSPIRVExtensions.inc new file mode 100644 index 0000000000000..869fef843c71e --- /dev/null +++ b/llvm-spirv/include/LLVMSPIRVExtensions.inc @@ -0,0 +1,15 @@ + +#ifndef EXT + #error "EXT macro must be defined" +#endif + +EXT(SPV_KHR_no_integer_wrap_decoration) +EXT(SPV_INTEL_subgroups) +EXT(SPV_INTEL_media_block_io) +EXT(SPV_INTEL_device_side_avc_motion_estimation) +EXT(SPV_INTEL_fpga_loop_controls) +EXT(SPV_INTEL_fpga_memory_attributes) +EXT(SPV_INTEL_unstructured_loop_controls) +EXT(SPV_INTEL_fpga_reg) +EXT(SPV_INTEL_blocking_pipes) +EXT(SPV_INTEL_function_pointers) diff --git a/llvm-spirv/include/LLVMSPIRVLib.h b/llvm-spirv/include/LLVMSPIRVLib.h index 1529c982f262e..0c775c1f98e57 100644 --- a/llvm-spirv/include/LLVMSPIRVLib.h +++ b/llvm-spirv/include/LLVMSPIRVLib.h @@ -41,6 +41,8 @@ #ifndef SPIRV_H #define SPIRV_H +#include "LLVMSPIRVOpts.h" + #include #include @@ -66,6 +68,7 @@ void initializePreprocessMetadataPass(PassRegistry &); #include "llvm/IR/Module.h" namespace SPIRV { + class SPIRVModule; /// \brief Check if a string contains SPIR-V binary. @@ -94,6 +97,12 @@ bool isSpirvText(std::string &Img); std::unique_ptr readSpirvModule(std::istream &IS, std::string &ErrMsg); +/// \brief Load SPIR-V from istream as a SPIRVModule. +/// \returns null on failure. +std::unique_ptr readSpirvModule(std::istream &IS, + const SPIRV::TranslatorOpts &Opts, + std::string &ErrMsg); + } // End namespace SPIRV namespace llvm { @@ -107,6 +116,16 @@ bool writeSpirv(Module *M, std::ostream &OS, std::string &ErrMsg); bool readSpirv(LLVMContext &C, std::istream &IS, Module *&M, std::string &ErrMsg); +/// \brief Translate LLVM module to SPIR-V and write to ostream. +/// \returns true if succeeds. +bool writeSpirv(Module *M, const SPIRV::TranslatorOpts &Opts, std::ostream &OS, + std::string &ErrMsg); + +/// \brief Load SPIR-V from istream and translate to LLVM module. +/// \returns true if succeeds. +bool readSpirv(LLVMContext &C, const SPIRV::TranslatorOpts &Opts, + std::istream &IS, Module *&M, std::string &ErrMsg); + /// \brief Convert a SPIRVModule into LLVM IR. /// \returns null on failure. std::unique_ptr diff --git a/llvm-spirv/include/LLVMSPIRVOpts.h b/llvm-spirv/include/LLVMSPIRVOpts.h new file mode 100644 index 0000000000000..1f5aa39855d91 --- /dev/null +++ b/llvm-spirv/include/LLVMSPIRVOpts.h @@ -0,0 +1,104 @@ +//===- LLVMSPIRVOpts.h - Specify options for translation --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// Copyright (c) 2019 Intel Corporation. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal with the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimers. +// Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimers in the documentation +// and/or other materials provided with the distribution. +// Neither the names of Advanced Micro Devices, Inc., nor the names of its +// contributors may be used to endorse or promote products derived from this +// Software without specific prior written permission. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH +// THE SOFTWARE. +// +//===----------------------------------------------------------------------===// +/// \file LLVMSPIRVOpts.h +/// +/// This files declares helper classes to handle SPIR-V versions and extensions. +/// +//===----------------------------------------------------------------------===// +#ifndef SPIRV_LLVMSPIRVOPTS_H +#define SPIRV_LLVMSPIRVOPTS_H + +#include +#include +#include + +namespace SPIRV { + +enum class VersionNumber : uint32_t { + // See section 2.3 of SPIR-V spec: Physical Layout of a SPIR_V Module and + // Instruction + SPIRV_1_0 = 0x00010000, + SPIRV_1_1 = 0x00010100, + // TODO: populate this enum with the latest versions (up to 1.4) once + // translator get support of correponding features + MinimumVersion = SPIRV_1_0, + MaximumVersion = SPIRV_1_1 +}; + +enum class ExtensionID : uint32_t { + First, +#define EXT(X) X, +#include "LLVMSPIRVExtensions.inc" +#undef EXT + Last, +}; + +/// \brief Helper class to manage SPIR-V translation +class TranslatorOpts { +public: + using ExtensionsStatusMap = std::map; + + TranslatorOpts() = default; + + TranslatorOpts(VersionNumber Max, const ExtensionsStatusMap &Map = {}) + : MaxVersion(Max), ExtStatusMap(Map) {} + + bool isAllowedToUseVersion(VersionNumber RequestedVersion) const { + return RequestedVersion <= MaxVersion; + } + + bool isAllowedToUseExtension(ExtensionID Extension) const { + auto I = ExtStatusMap.find(Extension); + if (ExtStatusMap.end() == I) + return false; + + return I->second; + } + + VersionNumber getMaxVersion() const { return MaxVersion; } + + void enableAllExtensions() { +#define EXT(X) ExtStatusMap[ExtensionID::X] = true; +#include "LLVMSPIRVExtensions.inc" +#undef EXT + } + +private: + VersionNumber MaxVersion = VersionNumber::MaximumVersion; + ExtensionsStatusMap ExtStatusMap; +}; + +} // namespace SPIRV + +#endif // SPIRV_LLVMSPIRVOPTS_H diff --git a/llvm-spirv/lib/SPIRV/LLVMToSPIRVDbgTran.cpp b/llvm-spirv/lib/SPIRV/LLVMToSPIRVDbgTran.cpp index 0c3399479ca10..5e218336ec5c1 100644 --- a/llvm-spirv/lib/SPIRV/LLVMToSPIRVDbgTran.cpp +++ b/llvm-spirv/lib/SPIRV/LLVMToSPIRVDbgTran.cpp @@ -160,6 +160,12 @@ void LLVMToSPIRVDbgTran::transLocationInfo() { unsigned LineNo = 0; unsigned Col = 0; for (const Instruction &I : BB) { + if (auto *II = dyn_cast(&I)) { + if (II->getIntrinsicID() == Intrinsic::dbg_label) { + // SPIR-V doesn't support llvm.dbg.label intrinsic translation + continue; + } + } const DebugLoc &DL = I.getDebugLoc(); if (!DL.get()) { if (DbgScope || InlinedAt) { // Emit DebugNoScope diff --git a/llvm-spirv/lib/SPIRV/OCLUtil.h b/llvm-spirv/lib/SPIRV/OCLUtil.h index b3fcac971a9d7..b246e0f4b3236 100644 --- a/llvm-spirv/lib/SPIRV/OCLUtil.h +++ b/llvm-spirv/lib/SPIRV/OCLUtil.h @@ -427,6 +427,13 @@ bool isSamplerTy(Type *Ty); // If so, it applies ContractionOff ExecutionMode to the kernel. void checkFpContract(BinaryOperator *B, SPIRVBasicBlock *BB); +template std::string toString(const T *Object) { + std::string S; + llvm::raw_string_ostream RSOS(S); + Object->print(RSOS); + RSOS.flush(); + return S; +} } // namespace OCLUtil /////////////////////////////////////////////////////////////////////////////// diff --git a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp index a617048df9c53..c36492ac69795 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVReader.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVReader.cpp @@ -383,12 +383,11 @@ Type *SPIRVToLLVM::transType(SPIRVType *T, bool IsClassMember) { case OpTypeArray: return mapType(T, ArrayType::get(transType(T->getArrayElementType()), T->getArrayLength())); - case OpTypePointer: { + case OpTypePointer: return mapType( T, PointerType::get( transType(T->getPointerElementType(), IsClassMember), SPIRSPIRVAddrSpaceMap::rmap(T->getPointerStorageClass()))); - } case OpTypeVector: return mapType(T, VectorType::get(transType(T->getVectorComponentType()), T->getVectorComponentCount())); @@ -504,10 +503,10 @@ std::string SPIRVToLLVM::transTypeToOCLTypeName(SPIRVType *T, bool IsSigned) { case OpTypePointer: { SPIRVType *ET = T->getPointerElementType(); if (isa(ET)) { - SPIRVTypeFunction *TF = static_cast(ET); + SPIRVTypeFunction *TF = static_cast(ET); std::string name = transTypeToOCLTypeName(TF->getReturnType()); name += " (*)("; - for(unsigned I = 0, E = TF->getNumParameters(); I < E; ++I) + for (unsigned I = 0, E = TF->getNumParameters(); I < E; ++I) name += transTypeToOCLTypeName(TF->getParameterType(I)) + ','; name.back() = ')'; // replace the last comma with a closing brace. return name; @@ -1714,8 +1713,8 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, case OpFunctionPointerINTEL: { SPIRVFunctionPointerINTEL *BC = - static_cast(BV); - SPIRVFunction* F = BC->getFunction(); + static_cast(BV); + SPIRVFunction *F = BC->getFunction(); BV->setName(F->getName()); return mapValue(BV, transFunction(F)); } @@ -1777,7 +1776,8 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, BV->getName(), BB)); } - case OpNot: { + case OpNot: + case OpLogicalNot: { SPIRVUnary *BC = static_cast(BV); return mapValue( BV, BinaryOperator::CreateNot(transValue(BC->getOperand(0), F, BB), @@ -1958,9 +1958,9 @@ Function *SPIRVToLLVM::transFunction(SPIRVFunction *BF) { /// LLVM convert builtin functions is translated to two instructions: /// y = i32 islessgreater(float x, float z) -> -/// y = i32 ZExt(bool LessGreater(float x, float z)) +/// y = i32 ZExt(bool LessOrGreater(float x, float z)) /// When translating back, for simplicity, a trunc instruction is inserted -/// w = bool LessGreater(float x, float z) -> +/// w = bool LessOrGreater(float x, float z) -> /// w = bool Trunc(i32 islessgreater(float x, float z)) /// Optimizer should be able to remove the redundant trunc/zext void SPIRVToLLVM::transOCLBuiltinFromInstPreproc( @@ -1976,9 +1976,7 @@ void SPIRVToLLVM::transOCLBuiltinFromInstPreproc( RetTy = VectorType::get( IntegerType::get( *Context, - Args[0]->getType()->getVectorComponentType()->isTypeFloat(64) - ? 64 - : 32), + Args[0]->getType()->getVectorComponentType()->getBitWidth()), BT->getVectorComponentCount()); else llvm_unreachable("invalid compare instruction"); @@ -2449,10 +2447,9 @@ void generateIntelFPGAAnnotation(const SPIRVEntry *E, Out << "{register:1}"; SPIRVWord Result = 0; - if (E->hasDecorate(DecorationMemoryINTEL)) { - Out << "{memory:" << E->getDecorationStringLiteral(DecorationMemoryINTEL) - << '}'; - } + if (E->hasDecorate(DecorationMemoryINTEL)) + Out << "{memory:" + << E->getDecorationStringLiteral(DecorationMemoryINTEL).front() << '}'; if (E->hasDecorate(DecorationBankwidthINTEL, 0, &Result)) Out << "{bankwidth:" << Result << '}'; if (E->hasDecorate(DecorationNumbanksINTEL, 0, &Result)) @@ -2467,11 +2464,14 @@ void generateIntelFPGAAnnotation(const SPIRVEntry *E, Out << "{max_replicates:" << Result << '}'; if (E->hasDecorate(DecorationSimpleDualPortINTEL)) Out << "{simple_dual_port:1}"; - if (E->hasDecorate(DecorationMergeINTEL)) - Out << "{merge:" << E->getDecorationStringLiteral(DecorationMergeINTEL) - << '}'; + if (E->hasDecorate(DecorationMergeINTEL)) { + Out << "{merge"; + for (auto Str : E->getDecorationStringLiteral(DecorationMergeINTEL)) + Out << ":" << Str; + Out << '}'; + } if (E->hasDecorate(DecorationUserSemantic)) - Out << E->getDecorationStringLiteral(DecorationUserSemantic); + Out << E->getDecorationStringLiteral(DecorationUserSemantic).front(); } void generateIntelFPGAAnnotationForStructMember( @@ -2486,6 +2486,7 @@ void generateIntelFPGAAnnotationForStructMember( Out << "{memory:" << E->getMemberDecorationStringLiteral(DecorationMemoryINTEL, MemberNumber) + .front() << '}'; if (E->hasMemberDecorate(DecorationBankwidthINTEL, 0, MemberNumber, &Result)) Out << "{bankwidth:" << Result << '}'; @@ -2503,14 +2504,18 @@ void generateIntelFPGAAnnotationForStructMember( Out << "{max_replicates:" << Result << '}'; if (E->hasMemberDecorate(DecorationSimpleDualPortINTEL, 0, MemberNumber)) Out << "{simple_dual_port:1}"; - if (E->hasMemberDecorate(DecorationMergeINTEL, 0, MemberNumber)) - Out << "{merge:" - << E->getMemberDecorationStringLiteral(DecorationMergeINTEL, - MemberNumber) - << '}'; + if (E->hasMemberDecorate(DecorationMergeINTEL, 0, MemberNumber)) { + Out << "{merge"; + for (auto Str : E->getMemberDecorationStringLiteral(DecorationMergeINTEL, + MemberNumber)) + Out << ":" << Str; + Out << '}'; + } + if (E->hasMemberDecorate(DecorationUserSemantic, 0, MemberNumber)) Out << E->getMemberDecorationStringLiteral(DecorationUserSemantic, - MemberNumber); + MemberNumber) + .front(); } void SPIRVToLLVM::transIntelFPGADecorations(SPIRVValue *BV, Value *V) { @@ -3052,8 +3057,9 @@ Instruction *SPIRVToLLVM::transOCLRelational(SPIRVInstruction *I, } std::unique_ptr readSpirvModule(std::istream &IS, + const SPIRV::TranslatorOpts &Opts, std::string &ErrMsg) { - std::unique_ptr BM(SPIRVModule::createSPIRVModule()); + std::unique_ptr BM(SPIRVModule::createSPIRVModule(Opts)); IS >> *BM; if (!BM->isModuleValid()) { @@ -3063,6 +3069,12 @@ std::unique_ptr readSpirvModule(std::istream &IS, return BM; } +std::unique_ptr readSpirvModule(std::istream &IS, + std::string &ErrMsg) { + SPIRV::TranslatorOpts DefaultOpts; + return readSpirvModule(IS, DefaultOpts, ErrMsg); +} + } // namespace SPIRV std::unique_ptr @@ -3084,7 +3096,16 @@ llvm::convertSpirvToLLVM(LLVMContext &C, SPIRVModule &BM, std::string &ErrMsg) { bool llvm::readSpirv(LLVMContext &C, std::istream &IS, Module *&M, std::string &ErrMsg) { - std::unique_ptr BM(readSpirvModule(IS, ErrMsg)); + SPIRV::TranslatorOpts DefaultOpts; + // As it is stated in the documentation, the translator accepts all SPIR-V + // extensions by default + DefaultOpts.enableAllExtensions(); + return llvm::readSpirv(C, DefaultOpts, IS, M, ErrMsg); +} + +bool llvm::readSpirv(LLVMContext &C, const SPIRV::TranslatorOpts &Opts, + std::istream &IS, Module *&M, std::string &ErrMsg) { + std::unique_ptr BM(readSpirvModule(IS, Opts, ErrMsg)); if (!BM) return false; diff --git a/llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp b/llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp index 0b9401df3d2ea..4ca2e72dbdffa 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVRegularizeLLVM.cpp @@ -182,7 +182,7 @@ void SPIRVRegularizeLLVM::lowerFuncPtr(Module *M) { auto AI = F.arg_begin(); if (hasFunctionPointerArg(&F, AI)) { auto OC = getSPIRVFuncOC(F.getName()); - if (OC != OpNop) // not a user-defined function + if (OC != OpNop) // builtin with a function pointer argument Work.push_back(std::make_pair(&F, OC)); } } diff --git a/llvm-spirv/lib/SPIRV/SPIRVToOCL.cpp b/llvm-spirv/lib/SPIRV/SPIRVToOCL.cpp index 7b5c02b7c046d..e3baa7b8de7ae 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVToOCL.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVToOCL.cpp @@ -302,7 +302,8 @@ void SPIRVToOCL::visitCallSPIRVPipeBuiltin(CallInst *CI, Op OC) { Args.erase(Args.begin(), Args.begin() + 1); if (!(OC == OpReadPipe || OC == OpWritePipe || - OC == OpReservedReadPipe || OC == OpReservedWritePipe)) + OC == OpReservedReadPipe || OC == OpReservedWritePipe || + OC == OpReadPipeBlockingINTEL || OC == OpWritePipeBlockingINTEL)) return DemangledName; auto &P = Args[Args.size() - 3]; diff --git a/llvm-spirv/lib/SPIRV/SPIRVToOCL12.cpp b/llvm-spirv/lib/SPIRV/SPIRVToOCL12.cpp index ae44138249f49..ddfaaea92848a 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVToOCL12.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVToOCL12.cpp @@ -151,7 +151,7 @@ void SPIRVToOCL12::visitCallSPIRVMemoryBarrier(CallInst *CI) { void SPIRVToOCL12::visitCallSPIRVControlBarrier(CallInst *CI) { AttributeList Attrs = CI->getCalledFunction()->getAttributes(); Attrs = Attrs.addAttribute(CI->getContext(), AttributeList::FunctionIndex, - Attribute::NoDuplicate); + Attribute::Convergent); mutateCallInstOCL( M, CI, [=](CallInst *, std::vector &Args) { @@ -229,7 +229,10 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicLoad(CallInst *CI, Op OC) { M, CI, [=](CallInst *, std::vector &Args) { Args.resize(1); - Args.push_back(getInt32(M, 0)); + // There is no atomic_load in OpenCL 1.2 spec. + // Emit this builtin via call of atomic_add(*p, 0). + Type *ptrElemTy = Args[0]->getType()->getPointerElementType(); + Args.push_back(Constant::getNullValue(ptrElemTy)); return OCL12SPIRVBuiltinMap::rmap(OpAtomicIAdd); }, &Attrs); @@ -242,7 +245,9 @@ Instruction *SPIRVToOCL12::visitCallSPIRVAtomicStore(CallInst *CI, Op OC) { [=](CallInst *, std::vector &Args, Type *&RetTy) { std::swap(Args[1], Args[3]); Args.resize(2); - RetTy = Type::getInt32Ty(M->getContext()); + // The type of the value pointed to by Pointer (1st argument) + // must be the same as Result Type. + RetTy = Args[0]->getType()->getPointerElementType(); return OCL12SPIRVBuiltinMap::rmap(OpAtomicExchange); }, [=](CallInst *CI) -> Instruction * { return CI; }, &Attrs); diff --git a/llvm-spirv/lib/SPIRV/SPIRVToOCL20.cpp b/llvm-spirv/lib/SPIRV/SPIRVToOCL20.cpp index b9857c0e0dcba..765591a52506a 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVToOCL20.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVToOCL20.cpp @@ -123,7 +123,7 @@ void SPIRVToOCL20::visitCallSPIRVMemoryBarrier(CallInst *CI) { void SPIRVToOCL20::visitCallSPIRVControlBarrier(CallInst *CI) { AttributeList Attrs = CI->getCalledFunction()->getAttributes(); Attrs = Attrs.addAttribute(CI->getContext(), AttributeList::FunctionIndex, - Attribute::NoDuplicate); + Attribute::Convergent); mutateCallInstOCL( M, CI, [=](CallInst *, std::vector &Args) { diff --git a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp index a95e938f1c406..63a8047e56bc0 100644 --- a/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp +++ b/llvm-spirv/lib/SPIRV/SPIRVWriter.cpp @@ -90,10 +90,6 @@ namespace SPIRV { cl::opt SPIRVMemToReg("spirv-mem2reg", cl::init(false), cl::desc("LLVM/SPIR-V translation enable mem2reg")); -cl::opt SPIRVNoDerefAttr( - "spirv-no-deref-attr", cl::init(false), - cl::desc("Do not translate 'dereferenceable' LLVM attribute to SPIR-V")); - static void foreachKernelArgMD( MDNode *MD, SPIRVFunction *BF, std::function @@ -261,19 +257,10 @@ SPIRVType *LLVMToSPIRV::transType(Type *T) { // (non-pointer) image or pipe type. if (T->isPointerTy()) { auto ET = T->getPointerElementType(); - bool IsFuncPtrAllowed = true; - // TODO: uncomment the line below once - // https://github.com/KhronosGroup/SPIRV-LLVM-Translator/pull/244 is merged. - // BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_function_pointers); - if (ET->isFunctionTy() && !IsFuncPtrAllowed) { - std::string S; - raw_string_ostream RSOS(S); - T->print(RSOS); - BM->getErrorLog().checkError(false, SPIRVEC_FunctionPointersDisallowed, - RSOS.str()); - BM->setInvalid(); + if (ET->isFunctionTy() && + !BM->checkExtension(ExtensionID::SPV_INTEL_function_pointers, + SPIRVEC_FunctionPointers, toString(T))) return nullptr; - } auto ST = dyn_cast(ET); auto AddrSpc = T->getPointerAddressSpace(); if (ST && !ST->isSized()) { @@ -507,7 +494,7 @@ SPIRVFunction *LLVMToSPIRV::transFunctionDecl(Function *F) { BA->addAttr(FunctionParameterAttributeZext); if (Attrs.hasAttribute(ArgNo + 1, Attribute::SExt)) BA->addAttr(FunctionParameterAttributeSext); - if (!SPIRVNoDerefAttr && + if (BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_1) && Attrs.hasAttribute(ArgNo + 1, Attribute::Dereferenceable)) BA->addDecorate(DecorationMaxByteOffset, Attrs.getAttribute(ArgNo + 1, Attribute::Dereferenceable) @@ -799,7 +786,10 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V, MemoryAccess.clear(); SPIRVValue *BSV = nullptr; - if(Function *F = dyn_cast(ST->getValueOperand())) { + if (Function *F = dyn_cast(ST->getValueOperand())) { + if (!BM->checkExtension(ExtensionID::SPV_INTEL_function_pointers, + SPIRVEC_FunctionPointers, toString(ST))) + return nullptr; // store of function pointer BSV = BM->addFunctionPointerINTELInst( transType(F->getType()), @@ -914,10 +904,13 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V, BB->getId(), // Continue Target LoopControl, Parameters, SuccessorTrue); } else { - // For unstructured loop we add a special loop control instruction. - // Simple example of unstructured loop is an infinite loop, that has - // no terminate instruction. - BM->addLoopControlINTELInst(LoopControl, Parameters, SuccessorTrue); + if (BM->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_unstructured_loop_controls)) { + // For unstructured loop we add a special loop control instruction. + // Simple example of unstructured loop is an infinite loop, that has + // no terminate instruction. + BM->addLoopControlINTELInst(LoopControl, Parameters, SuccessorTrue); + } } } return mapValue(V, BM->addBranchInst(SuccessorTrue, BB)); @@ -942,6 +935,9 @@ SPIRVValue *LLVMToSPIRV::transValueWithoutDecoration(Value *V, for (size_t I = 0, E = Phi->getNumIncomingValues(); I != E; ++I) { SPIRVValue *BV = nullptr; if (Function *F = dyn_cast(Phi->getIncomingValue(I))) { + if (!BM->checkExtension(ExtensionID::SPV_INTEL_function_pointers, + SPIRVEC_FunctionPointers, toString(Phi))) + return nullptr; BV = BM->addFunctionPointerINTELInst( transType(F->getType()), static_cast(transValue(F, BB)), BB); @@ -1148,7 +1144,7 @@ SPIRVValue *LLVMToSPIRV::oclTransSpvcCastSampler(CallInst *CI, } std::vector> -parseAnnotations(StringRef AnnotatedCode) { +tryParseIntelFPGAAnnotationString(StringRef AnnotatedCode) { std::vector> Decorates; size_t OpenBracketNum = AnnotatedCode.count('{'); @@ -1197,14 +1193,18 @@ parseAnnotations(StringRef AnnotatedCode) { void addIntelFPGADecorations( SPIRVEntry *E, std::vector> &Decorations) { + if (!E->getModule()->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_fpga_memory_attributes)) + return; + for (const auto &I : Decorations) { switch (I.first) { - case DecorationMemoryINTEL: - E->addDecorate(new SPIRVDecorateMemoryINTELAttr(E, I.second)); - break; case DecorationUserSemantic: E->addDecorate(new SPIRVDecorateUserSemanticAttr(E, I.second)); break; + case DecorationMemoryINTEL: + E->addDecorate(new SPIRVDecorateMemoryINTELAttr(E, I.second)); + break; case DecorationMergeINTEL: { StringRef Name = StringRef(I.second).split(':').first; StringRef Direction = StringRef(I.second).split(':').second; @@ -1235,16 +1235,20 @@ void addIntelFPGADecorations( void addIntelFPGADecorationsForStructMember( SPIRVEntry *E, SPIRVWord MemberNumber, std::vector> &Decorations) { + if (!E->getModule()->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_fpga_memory_attributes)) + return; + for (const auto &I : Decorations) { switch (I.first) { - case DecorationMemoryINTEL: - E->addMemberDecorate( - new SPIRVMemberDecorateMemoryINTELAttr(E, MemberNumber, I.second)); - break; case DecorationUserSemantic: E->addMemberDecorate( new SPIRVMemberDecorateUserSemanticAttr(E, MemberNumber, I.second)); break; + case DecorationMemoryINTEL: + E->addMemberDecorate( + new SPIRVMemberDecorateMemoryINTELAttr(E, MemberNumber, I.second)); + break; case DecorationMergeINTEL: { StringRef Name = StringRef(I.second).split(':').first; StringRef Direction = StringRef(I.second).split(':').second; @@ -1380,8 +1384,13 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, StringRef AnnotationString = cast(C->getOperand(0))->getAsCString(); - if (AnnotationString == kOCLBuiltinName::FPGARegIntel) - return BM->addFPGARegINTELInst(Ty, transValue(II->getOperand(0), BB), BB); + if (AnnotationString == kOCLBuiltinName::FPGARegIntel) { + if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_reg)) + return BM->addFPGARegINTELInst(Ty, transValue(II->getOperand(0), BB), + BB); + else + return transValue(II->getOperand(0), BB); + } return nullptr; } @@ -1399,8 +1408,15 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, StringRef AnnotationString = cast(C->getOperand(0))->getAsString(); - std::vector> Decorations = - parseAnnotations(AnnotationString); + std::vector> Decorations; + if (BB->getModule()->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_fpga_memory_attributes)) + // If it is allowed, let's try to parse annotation string to find + // IntelFPGA-specific decorations + Decorations = tryParseIntelFPGAAnnotationString(AnnotationString); + + // If we didn't find any IntelFPGA-specific decorations, let's add the whole + // annotation string as UserSemantic Decoration if (Decorations.empty()) { SV->addDecorate(new SPIRVDecorateUserSemanticAttr( SV, AnnotationString.substr(0, AnnotationString.size() - 1))); @@ -1428,9 +1444,15 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, SPIRVWord MemberNumber = dyn_cast(GI->getOperand(2))->getZExtValue(); - std::vector> Decorations = - parseAnnotations(AnnotationString); + std::vector> Decorations; + if (BB->getModule()->isAllowedToUseExtension( + ExtensionID::SPV_INTEL_fpga_memory_attributes)) + // If it is allowed, let's try to parse annotation string to find + // IntelFPGA-specific decorations + Decorations = tryParseIntelFPGAAnnotationString(AnnotationString); + // If we didn't find any IntelFPGA-specific decorations, let's add the + // whole annotation string as UserSemantic Decoration if (Decorations.empty()) { Ty->addMemberDecorate(new SPIRVMemberDecorateUserSemanticAttr( Ty, MemberNumber, AnnotationString)); @@ -1441,14 +1463,19 @@ SPIRVValue *LLVMToSPIRV::transIntrinsicInst(IntrinsicInst *II, } else { auto *Ty = transType(II->getType()); auto *BI = dyn_cast(II->getOperand(0)); - if (AnnotationString == kOCLBuiltinName::FPGARegIntel) - return BM->addFPGARegINTELInst(Ty, transValue(BI, BB), BB); + if (AnnotationString == kOCLBuiltinName::FPGARegIntel) { + if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_fpga_reg)) + return BM->addFPGARegINTELInst(Ty, transValue(BI, BB), BB); + else + return transValue(BI, BB); + } } return 0; } // We can just ignore/drop some intrinsics, like optimizations hint. case Intrinsic::invariant_start: case Intrinsic::invariant_end: + case Intrinsic::dbg_label: return nullptr; default: // Other LLVM intrinsics shouldn't get to SPIRV, because they @@ -1466,7 +1493,8 @@ SPIRVValue *LLVMToSPIRV::transCallInst(CallInst *CI, SPIRVBasicBlock *BB) { return transDirectCallInst(CI, BB); } -SPIRVValue *LLVMToSPIRV::transDirectCallInst(CallInst *CI, SPIRVBasicBlock *BB) { +SPIRVValue *LLVMToSPIRV::transDirectCallInst(CallInst *CI, + SPIRVBasicBlock *BB) { SPIRVExtInstSetKind ExtSetKind = SPIRVEIS_Count; SPIRVWord ExtOp = SPIRVWORD_MAX; llvm::Function *F = CI->getCalledFunction(); @@ -1500,6 +1528,10 @@ SPIRVValue *LLVMToSPIRV::transDirectCallInst(CallInst *CI, SPIRVBasicBlock *BB) SPIRVValue *LLVMToSPIRV::transIndirectCallInst(CallInst *CI, SPIRVBasicBlock *BB) { + if (!BM->checkExtension(ExtensionID::SPV_INTEL_function_pointers, + SPIRVEC_FunctionPointers, toString(CI))) + return nullptr; + return BM->addIndirectCallInst( transValue(CI->getCalledValue(), BB), transType(CI->getType()), transArguments(CI, BB, SPIRVEntry::createUnique(OpFunctionCall).get()), @@ -1509,9 +1541,6 @@ SPIRVValue *LLVMToSPIRV::transIndirectCallInst(CallInst *CI, bool LLVMToSPIRV::transAddressingMode() { Triple TargetTriple(M->getTargetTriple()); - SPIRVCKRT(isSupportedTriple(TargetTriple), InvalidTargetTriple, - "Actual target triple is " + M->getTargetTriple()); - if (TargetTriple.isArch32Bit()) BM->setAddressingModel(AddressingModelPhysical32); else @@ -1743,6 +1772,10 @@ LLVMToSPIRV::transBuiltinToInst(const std::string &DemangledName, if (OC == OpNop) return nullptr; + if (OpReadPipeBlockingINTEL <= OC && OC <= OpWritePipeBlockingINTEL && + !BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_blocking_pipes)) + return nullptr; + auto Inst = transBuiltinToInstWithoutDecoration(OC, CI, BB); addDecorations(Inst, Dec); return Inst; @@ -2020,8 +2053,32 @@ void addPassesForSPIRV(legacy::PassManager &PassMgr) { PassMgr.add(createSPIRVLowerMemmove()); } +bool isValidLLVMModule(Module *M, SPIRVErrorLog &ErrorLog) { + if (!M) + return false; + + Triple TT(M->getTargetTriple()); + if (!ErrorLog.checkError(isSupportedTriple(TT), SPIRVEC_InvalidTargetTriple, + "Actual target triple is " + M->getTargetTriple())) + return false; + + return true; +} + bool llvm::writeSpirv(Module *M, std::ostream &OS, std::string &ErrMsg) { - std::unique_ptr BM(SPIRVModule::createSPIRVModule()); + SPIRV::TranslatorOpts DefaultOpts; + // To preserve old behavior of the translator, let's enable all extensions + // by default in this API + DefaultOpts.enableAllExtensions(); + return llvm::writeSpirv(M, DefaultOpts, OS, ErrMsg); +} + +bool llvm::writeSpirv(Module *M, const SPIRV::TranslatorOpts &Opts, + std::ostream &OS, std::string &ErrMsg) { + std::unique_ptr BM(SPIRVModule::createSPIRVModule(Opts)); + if (!isValidLLVMModule(M, BM->getErrorLog())) + return false; + legacy::PassManager PassMgr; addPassesForSPIRV(PassMgr); if (hasLoopUnrollMetadata(M)) @@ -2037,6 +2094,9 @@ bool llvm::writeSpirv(Module *M, std::ostream &OS, std::string &ErrMsg) { bool llvm::regularizeLlvmForSpirv(Module *M, std::string &ErrMsg) { std::unique_ptr BM(SPIRVModule::createSPIRVModule()); + if (!isValidLLVMModule(M, BM->getErrorLog())) + return false; + legacy::PassManager PassMgr; addPassesForSPIRV(PassMgr); PassMgr.run(*M); diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp index 316c94aae4c57..4af7e2c36de99 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.cpp @@ -82,6 +82,10 @@ SPIRVWord SPIRVDecorateGeneric::getLiteral(size_t I) const { return Literals[I]; } +std::vector SPIRVDecorateGeneric::getVecLiteral() const { + return Literals; +} + size_t SPIRVDecorateGeneric::getLiteralCount() const { return Literals.size(); } void SPIRVDecorate::encode(spv_ostream &O) const { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h index 4987dbc2ec483..ea227bc77abeb 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVDecorate.h @@ -61,6 +61,7 @@ class SPIRVDecorateGeneric : public SPIRVAnnotationGeneric { SPIRVDecorateGeneric(Op OC); SPIRVWord getLiteral(size_t) const; + std::vector getVecLiteral() const; Decoration getDecorateKind() const; size_t getLiteralCount() const; /// Compare for kind and literal only. @@ -84,15 +85,15 @@ class SPIRVDecorateGeneric : public SPIRVAnnotationGeneric { switch (Dec) { case DecorationSpecId: if (getModule()->hasCapability(CapabilityKernel)) - return SPIRV_1_1; + return static_cast(VersionNumber::SPIRV_1_1); else - return SPIRV_1_0; + return static_cast(VersionNumber::SPIRV_1_0); case DecorationMaxByteOffset: - return SPIRV_1_1; + return static_cast(VersionNumber::SPIRV_1_1); default: - return SPIRV_1_0; + return static_cast(VersionNumber::SPIRV_1_0); } } @@ -140,7 +141,7 @@ class SPIRVDecorate : public SPIRVDecorateGeneric { switch (Dec) { case DecorationNoSignedWrap: case DecorationNoUnsignedWrap: - return getSet(SPV_KHR_no_integer_wrap_decoration); + return getSet(ExtensionID::SPV_KHR_no_integer_wrap_decoration); case DecorationRegisterINTEL: case DecorationMemoryINTEL: case DecorationNumbanksINTEL: @@ -151,9 +152,9 @@ class SPIRVDecorate : public SPIRVDecorateGeneric { case DecorationMaxReplicatesINTEL: case DecorationSimpleDualPortINTEL: case DecorationMergeINTEL: - return getSet(SPV_INTEL_fpga_memory_attributes); + return getSet(ExtensionID::SPV_INTEL_fpga_memory_attributes); case DecorationReferencedIndirectlyINTEL: - return getSet(SPV_INTEL_function_pointers); + return getSet(ExtensionID::SPV_INTEL_function_pointers); default: return SPIRVExtSet(); } @@ -247,7 +248,7 @@ class SPIRVMemberDecorate : public SPIRVDecorateGeneric { case DecorationMaxReplicatesINTEL: case DecorationSimpleDualPortINTEL: case DecorationMergeINTEL: - return getSet(SPV_INTEL_fpga_memory_attributes); + return getSet(ExtensionID::SPV_INTEL_fpga_memory_attributes); default: return SPIRVExtSet(); } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp index 89295a9d83dbf..31fd2d4dc4637 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.cpp @@ -335,30 +335,23 @@ bool SPIRVEntry::hasMemberDecorate(Decoration Kind, size_t Index, return true; } -std::string SPIRVEntry::getDecorationStringLiteral(Decoration Kind) const { - std::vector Literals; +std::vector +SPIRVEntry::getDecorationStringLiteral(Decoration Kind) const { auto Loc = Decorates.find(Kind); if (Loc == Decorates.end()) - return std::string(); + return {}; - for (SPIRVWord I = 0; I < Loc->second->getLiteralCount(); ++I) - Literals.push_back(Loc->second->getLiteral(I)); - - return getString(Literals.cbegin(), Literals.cend()); + return getVecString(Loc->second->getVecLiteral()); } -std::string +std::vector SPIRVEntry::getMemberDecorationStringLiteral(Decoration Kind, SPIRVWord MemberNumber) const { - std::vector Literals; auto Loc = MemberDecorates.find({MemberNumber, Kind}); if (Loc == MemberDecorates.end()) - return std::string(); - - for (SPIRVWord I = 0; I < Loc->second->getLiteralCount(); ++I) - Literals.push_back(Loc->second->getLiteral(I)); + return {}; - return getString(Literals.cbegin(), Literals.cend()); + return getVecString(Loc->second->getVecLiteral()); } // Get literals of all decorations of Kind at Index. diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h index b723dfe051c21..fd141e865927d 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEntry.h @@ -40,6 +40,7 @@ #ifndef SPIRV_LIBSPIRV_SPIRVENTRY_H #define SPIRV_LIBSPIRV_SPIRVENTRY_H +#include "LLVMSPIRVOpts.h" #include "SPIRVEnum.h" #include "SPIRVError.h" #include "SPIRVIsValidEnum.h" @@ -295,9 +296,10 @@ class SPIRVEntry { bool hasMemberDecorate(Decoration Kind, size_t Index = 0, SPIRVWord MemberNumber = 0, SPIRVWord *Result = 0) const; - std::string getDecorationStringLiteral(Decoration Kind) const; - std::string getMemberDecorationStringLiteral(Decoration Kind, - SPIRVWord MemberNumber) const; + std::vector getDecorationStringLiteral(Decoration Kind) const; + std::vector + getMemberDecorationStringLiteral(Decoration Kind, + SPIRVWord MemberNumber) const; std::set getDecorate(Decoration Kind, size_t Index = 0) const; bool hasId() const { return !(Attrib & SPIRVEA_NOID); } bool hasLine() const { return Line != nullptr; } @@ -382,7 +384,9 @@ class SPIRVEntry { void validateBuiltin(SPIRVWord, SPIRVWord) const; // By default assume SPIRV 1.0 as required version - virtual SPIRVWord getRequiredSPIRVVersion() const { return SPIRV_1_0; } + virtual SPIRVWord getRequiredSPIRVVersion() const { + return static_cast(VersionNumber::SPIRV_1_0); + } virtual std::vector getNonLiteralOperands() const { return std::vector(); @@ -644,10 +648,10 @@ class SPIRVExecutionMode : public SPIRVAnnotation { case ExecutionModeInitializer: case ExecutionModeSubgroupSize: case ExecutionModeSubgroupsPerWorkgroup: - return SPIRV_1_1; + return static_cast(VersionNumber::SPIRV_1_1); default: - return SPIRV_1_0; + return static_cast(VersionNumber::SPIRV_1_0); } } @@ -720,6 +724,9 @@ class SPIRVExtension : public SPIRVEntryNoId { public: SPIRVExtension(SPIRVModule *M, const std::string &SS); SPIRVExtension() {} + + std::string getExtensionName() const { return S; } + _SPIRV_DCL_ENCDEC private: std::string S; @@ -736,10 +743,10 @@ class SPIRVCapability : public SPIRVEntryNoId { case CapabilityNamedBarrier: case CapabilitySubgroupDispatch: case CapabilityPipeStorage: - return SPIRV_1_1; + return static_cast(VersionNumber::SPIRV_1_1); default: - return SPIRV_1_0; + return static_cast(VersionNumber::SPIRV_1_0); } } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h index ccd037b6bc043..220b7171a2151 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVEnum.h @@ -40,6 +40,7 @@ #ifndef SPIRV_LIBSPIRV_SPIRVENUM_H #define SPIRV_LIBSPIRV_SPIRVENUM_H +#include "LLVMSPIRVOpts.h" #include "SPIRVOpCode.h" #include "spirv.hpp" #include @@ -61,11 +62,6 @@ inline SPIRVWord mkWord(unsigned WordCount, Op OpCode) { const static unsigned KSpirvMemOrderSemanticMask = 0x1F; -enum SPIRVVersion : SPIRVWord { - SPIRV_1_0 = 0x00010000, - SPIRV_1_1 = 0x00010100 -}; - enum SPIRVGeneratorKind { SPIRVGEN_KhronosLLVMSPIRVTranslator = 6, SPIRVGEN_KhronosSPIRVAssembler = 7, @@ -113,28 +109,16 @@ typedef spv::GroupOperation SPIRVGroupOperationKind; typedef spv::Dim SPIRVImageDimKind; typedef std::vector SPIRVCapVec; -enum SPIRVExtensionKind { - SPV_KHR_no_integer_wrap_decoration, - SPV_INTEL_blocking_pipes, - SPV_INTEL_device_side_avc_motion_estimation, - SPV_INTEL_fpga_reg, - SPV_INTEL_fpga_memory_attributes, - SPV_INTEL_unstructured_loop_controls, - SPV_INTEL_function_pointers -}; +typedef std::set SPIRVExtSet; -typedef std::set SPIRVExtSet; - -template <> inline void SPIRVMap::init() { - add(SPV_INTEL_blocking_pipes, "SPV_INTEL_blocking_pipes"); - add(SPV_INTEL_device_side_avc_motion_estimation, - "SPV_INTEL_device_side_avc_motion_estimation"); - add(SPV_INTEL_unstructured_loop_controls, - "SPV_INTEL_unstructured_loop_controls"); - add(SPV_KHR_no_integer_wrap_decoration, "SPV_KHR_no_integer_wrap_decoration"); - add(SPV_INTEL_fpga_reg, "SPV_INTEL_fpga_reg"); - add(SPV_INTEL_fpga_memory_attributes, "SPV_INTEL_fpga_memory_attributes"); - add(SPV_INTEL_function_pointers, "SPV_INTEL_function_pointers"); +template <> inline void SPIRVMap::init() { +#define _STRINGIFY(X) #X +#define STRINGIFY(X) _STRINGIFY(X) +#define EXT(X) add(ExtensionID::X, STRINGIFY(X)); +#include "LLVMSPIRVExtensions.inc" +#undef EXT +#undef STRINGIFY +#undef _STRINGIFY } template <> inline void SPIRVMap::init() { @@ -378,7 +362,8 @@ template <> inline void SPIRVMap::init() { ADD_VEC_INIT(DecorationSimpleDualPortINTEL, {CapabilityFPGAMemoryAttributesINTEL}); ADD_VEC_INIT(DecorationMergeINTEL, {CapabilityFPGAMemoryAttributesINTEL}); - ADD_VEC_INIT(DecorationReferencedIndirectlyINTEL, {CapabilityIndirectReferencesINTEL}); + ADD_VEC_INIT(DecorationReferencedIndirectlyINTEL, + {CapabilityIndirectReferencesINTEL}); } template <> inline void SPIRVMap::init() { diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVErrorEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVErrorEnum.h index 1867c15332b80..d469d7615402d 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVErrorEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVErrorEnum.h @@ -10,4 +10,4 @@ _SPIRV_OP(InvalidFunctionCall, "Unexpected llvm intrinsic:") _SPIRV_OP(InvalidArraySize, "Array size must be at least 1:") _SPIRV_OP(InvalidModule, "Invalid SPIR-V module:") _SPIRV_OP(UnimplementedOpCode, "Unimplemented opcode") -_SPIRV_OP(FunctionPointersDisallowed, "Can't translate the function pointer:\n") +_SPIRV_OP(FunctionPointers, "Can't translate function pointer:\n") diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h index 37b885bd7881a..f8e428844b2e0 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVInstruction.h @@ -880,7 +880,7 @@ class SPIRVFPGARegINTELInstBase : public SPIRVInstTemplateBase { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_fpga_reg); + return getSet(ExtensionID::SPV_INTEL_fpga_reg); } protected: @@ -1372,7 +1372,7 @@ class SPIRVLoopControlINTEL : public SPIRVInstruction { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_unstructured_loop_controls); + return getSet(ExtensionID::SPV_INTEL_unstructured_loop_controls); } void setWordCount(SPIRVWord TheWordCount) override { @@ -1455,16 +1455,16 @@ class SPIRVFunctionPointerCallINTEL : public SPIRVFunctionCallGeneric { public: SPIRVFunctionPointerCallINTEL(SPIRVId TheId, SPIRVValue *TheCalledValue, - SPIRVType *TheReturnType, - const std::vector &TheArgs, - SPIRVBasicBlock *BB); + SPIRVType *TheReturnType, + const std::vector &TheArgs, + SPIRVBasicBlock *BB); SPIRVFunctionPointerCallINTEL() : CalledValueId(SPIRVID_INVALID) {} SPIRVValue *getCalledValue() const { return get(CalledValueId); } _SPIRV_DEF_ENCDEC4(Type, Id, CalledValueId, Args) void validate() const override; bool isOperandLiteral(unsigned Index) const override { return false; } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_function_pointers); + return getSet(ExtensionID::SPV_INTEL_function_pointers); } SPIRVCapVec getRequiredCapability() const override { return getVec(CapabilityFunctionPointersINTEL); @@ -1477,20 +1477,23 @@ class SPIRVFunctionPointerCallINTEL class SPIRVFunctionPointerINTEL : public SPIRVInstruction { const static Op OC = OpFunctionPointerINTEL; const static SPIRVWord FixedWordCount = 4; + public: SPIRVFunctionPointerINTEL(SPIRVId TheId, SPIRVType *TheType, SPIRVFunction *TheFunction, SPIRVBasicBlock *BB); - SPIRVFunctionPointerINTEL() : SPIRVInstruction(OC), TheFunction(SPIRVID_INVALID) {} + SPIRVFunctionPointerINTEL() + : SPIRVInstruction(OC), TheFunction(SPIRVID_INVALID) {} SPIRVFunction *getFunction() const { return get(TheFunction); } _SPIRV_DEF_ENCDEC3(Type, Id, TheFunction) void validate() const override; bool isOperandLiteral(unsigned Index) const override { return false; } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_function_pointers); + return getSet(ExtensionID::SPV_INTEL_function_pointers); } SPIRVCapVec getRequiredCapability() const override { return getVec(CapabilityFunctionPointersINTEL); } + protected: SPIRVId TheFunction; }; @@ -2215,7 +2218,7 @@ class SPIRVBlockingPipesIntelInst : public SPIRVInstTemplateBase { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_blocking_pipes); + return getSet(ExtensionID::SPV_INTEL_blocking_pipes); } }; @@ -2385,7 +2388,7 @@ class SPIRVSubgroupAVCIntelInstBase : public SPIRVInstTemplateBase { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_device_side_avc_motion_estimation); + return getSet(ExtensionID::SPV_INTEL_device_side_avc_motion_estimation); } }; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp index 4753e575c5b3c..aa5b48c66a8c3 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.cpp @@ -61,7 +61,8 @@ SPIRVModule::~SPIRVModule() {} class SPIRVModuleImpl : public SPIRVModule { public: SPIRVModuleImpl() - : SPIRVModule(), NextId(1), SPIRVVersion(SPIRV_1_0), + : SPIRVModule(), NextId(1), + SPIRVVersion(static_cast(VersionNumber::SPIRV_1_0)), GeneratorId(SPIRVGEN_KhronosLLVMSPIRVTranslator), GeneratorVer(0), InstSchema(SPIRVISCH_Default), SrcLang(SourceLanguageOpenCL_C), SrcLangVer(102000) { @@ -70,6 +71,11 @@ class SPIRVModuleImpl : public SPIRVModule { // OpenCL memory model requires Kernel capability setMemoryModel(MemoryModelOpenCL); } + + SPIRVModuleImpl(const SPIRV::TranslatorOpts &Opts) : SPIRVModuleImpl() { + TranslationOpts = Opts; + } + ~SPIRVModuleImpl() override; // Object query functions @@ -87,6 +93,13 @@ class SPIRVModuleImpl : public SPIRVModule { SPIRVErrorCode getError(std::string &ErrMsg) override { return ErrLog.getError(ErrMsg); } + bool checkExtension(ExtensionID Ext, SPIRVErrorCode ErrCode, + const std::string &Msg) override { + if (ErrLog.checkError(isAllowedToUseExtension(Ext), ErrCode, Msg)) + return true; + setInvalid(); + return false; + } // Module query functions SPIRVAddressingModelKind getAddressingModel() override { return AddrModel; } @@ -164,7 +177,10 @@ class SPIRVModuleImpl : public SPIRVModule { void setGeneratorVer(unsigned short Ver) override { GeneratorVer = Ver; } void resolveUnknownStructFields() override; - void setSPIRVVersion(SPIRVWord Ver) override { SPIRVVersion = Ver; } + void setSPIRVVersion(SPIRVWord Ver) override { + assert(this->isAllowedToUseVersion(static_cast(Ver))); + SPIRVVersion = Ver; + } // Object creation functions template void addTo(std::vector &V, SPIRVEntry *E); @@ -181,7 +197,7 @@ class SPIRVModuleImpl : public SPIRVModule { void setCurrentLine(const std::shared_ptr &Line) override; void addCapability(SPIRVCapabilityKind) override; void addCapabilityInternal(SPIRVCapabilityKind) override; - void addExtension(SPIRVExtensionKind) override; + void addExtension(ExtensionID) override; const SPIRVDecorateGeneric *addDecorate(SPIRVDecorateGeneric *) override; SPIRVDecorationGroup *addDecorationGroup() override; SPIRVDecorationGroup * @@ -537,9 +553,10 @@ SPIRVValue *SPIRVModuleImpl::addPipeStorageConstant(SPIRVType *TheType, this, TheType, getId(), PacketSize, PacketAlign, Capacity)); } -void SPIRVModuleImpl::addExtension(SPIRVExtensionKind Ext) { +void SPIRVModuleImpl::addExtension(ExtensionID Ext) { std::string ExtName; - SPIRVMap::find(Ext, &ExtName); + SPIRVMap::find(Ext, &ExtName); + assert(isAllowedToUseExtension(Ext)); SPIRVExt.insert(ExtName); } @@ -1260,7 +1277,7 @@ SPIRVInstruction *SPIRVModuleImpl::addLoopControlINTELInst( SPIRVWord LoopControl, std::vector LoopControlParameters, SPIRVBasicBlock *BB) { addCapability(CapabilityUnstructuredLoopControlsINTEL); - addExtension(SPV_INTEL_unstructured_loop_controls); + addExtension(ExtensionID::SPV_INTEL_unstructured_loop_controls); return addInstruction( new SPIRVLoopControlINTEL(LoopControl, LoopControlParameters, BB), BB, const_cast(BB->getTerminateInstr())); @@ -1593,6 +1610,27 @@ void SPIRVModuleImpl::addUnknownStructField(SPIRVTypeStruct *Struct, unsigned I, UnknownStructFieldMap[Struct].push_back(std::make_pair(I, ID)); } +static std::string to_string(uint32_t Version) { + std::string Res; + switch (Version) { + case static_cast(VersionNumber::SPIRV_1_0): + Res = "1.0"; + break; + case static_cast(VersionNumber::SPIRV_1_1): + Res = "1.1"; + break; + default: + Res = "unknown"; + } + + Res += " (" + std::to_string(Version) + ")"; + return Res; +} + +static std::string to_string(VersionNumber Version) { + return to_string(static_cast(Version)); +} + std::istream &operator>>(std::istream &I, SPIRVModule &M) { SPIRVDecoder Decoder(I, M); SPIRVModuleImpl &MI = *static_cast(&M); @@ -1609,9 +1647,26 @@ std::istream &operator>>(std::istream &I, SPIRVModule &M) { } Decoder >> MI.SPIRVVersion; - if (!M.getErrorLog().checkError(MI.SPIRVVersion <= SPV_VERSION, - SPIRVEC_InvalidModule, - "unsupported SPIR-V version number")) { + bool SPIRVVersionIsKnown = + static_cast(VersionNumber::MinimumVersion) <= MI.SPIRVVersion && + MI.SPIRVVersion <= static_cast(VersionNumber::MaximumVersion); + if (!M.getErrorLog().checkError( + SPIRVVersionIsKnown, SPIRVEC_InvalidModule, + "unsupported SPIR-V version number '" + to_string(MI.SPIRVVersion) + + "'. Range of supported/known SPIR-V " + "versions is " + + to_string(VersionNumber::MinimumVersion) + " - " + + to_string(VersionNumber::MaximumVersion))) { + M.setInvalid(); + return I; + } + + bool SPIRVVersionIsAllowed = M.isAllowedToUseVersion(MI.SPIRVVersion); + if (!M.getErrorLog().checkError( + SPIRVVersionIsAllowed, SPIRVEC_InvalidModule, + "incorrect SPIR-V version number " + to_string(MI.SPIRVVersion) + + " - it conflicts with --spirv-max-version which is set to " + + to_string(M.getMaximumAllowedSPIRVVersion()))) { M.setInvalid(); return I; } @@ -1644,7 +1699,11 @@ std::istream &operator>>(std::istream &I, SPIRVModule &M) { return I; } -SPIRVModule *SPIRVModule::createSPIRVModule() { return new SPIRVModuleImpl; } +SPIRVModule *SPIRVModule::createSPIRVModule() { return new SPIRVModuleImpl(); } + +SPIRVModule *SPIRVModule::createSPIRVModule(const SPIRV::TranslatorOpts &Opts) { + return new SPIRVModuleImpl(Opts); +} SPIRVValue *SPIRVModuleImpl::getValue(SPIRVId TheId) const { return get(TheId); @@ -1725,7 +1784,14 @@ bool convertSpirv(std::istream &IS, std::ostream &OS, std::string &ErrMsg, bool FromText, bool ToText) { auto SaveOpt = SPIRVUseTextFormat; SPIRVUseTextFormat = FromText; - SPIRVModuleImpl M; + // Conversion from/to SPIR-V text representation is a side feature of the + // translator which is mostly intended for debug usage. So, this step cannot + // be customized to enable/disable particular extensions or restrict/allow + // particular SPIR-V versions: all known SPIR-V versions are allowed, all + // known SPIR-V extensions are enabled during this conversion + SPIRV::TranslatorOpts DefaultOpts; + DefaultOpts.enableAllExtensions(); + SPIRVModuleImpl M(DefaultOpts); IS >> M; if (M.getError(ErrMsg) != SPIRVEC_Success) { SPIRVUseTextFormat = SaveOpt; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h index 565dc622bd489..d72676379c223 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVModule.h @@ -40,6 +40,7 @@ #ifndef SPIRV_LIBSPIRV_SPIRVMODULE_H #define SPIRV_LIBSPIRV_SPIRVMODULE_H +#include "LLVMSPIRVOpts.h" #include "SPIRVEntry.h" #include @@ -92,6 +93,7 @@ class SPIRVModule { typedef std::map SPIRVCapMap; static SPIRVModule *createSPIRVModule(); + static SPIRVModule *createSPIRVModule(const SPIRV::TranslatorOpts &); SPIRVModule(); virtual ~SPIRVModule(); @@ -107,6 +109,10 @@ class SPIRVModule { // Error handling functions virtual SPIRVErrorLog &getErrorLog() = 0; virtual SPIRVErrorCode getError(std::string &) = 0; + // Check if extension is allowed, and set ErrCode and DetailedMsg if not. + // Returns true if no error. + virtual bool checkExtension(ExtensionID, SPIRVErrorCode, + const std::string &) = 0; void setInvalid() { IsValid = false; } bool isModuleValid() { return IsValid; } @@ -281,7 +287,7 @@ class SPIRVModule { for (auto I : Caps) addCapability(I); } - virtual void addExtension(SPIRVExtensionKind) = 0; + virtual void addExtension(ExtensionID) = 0; /// Used by SPIRV entries to add required capability internally. /// Should not be used by users directly. virtual void addCapabilityInternal(SPIRVCapabilityKind) = 0; @@ -392,6 +398,35 @@ class SPIRVModule { SPIRVBasicBlock *) = 0; virtual SPIRVId getExtInstSetId(SPIRVExtInstSetKind Kind) const = 0; + virtual bool + isAllowedToUseVersion(SPIRV::VersionNumber RequestedVersion) const final { + return TranslationOpts.isAllowedToUseVersion(RequestedVersion); + } + + virtual bool isAllowedToUseVersion(SPIRVWord RequestedVersion) const final { + return TranslationOpts.isAllowedToUseVersion( + static_cast(RequestedVersion)); + } + + virtual SPIRV::VersionNumber getMaximumAllowedSPIRVVersion() const final { + return TranslationOpts.getMaxVersion(); + } + + virtual bool + isAllowedToUseExtension(ExtensionID RequestedExtension) const final { + return TranslationOpts.isAllowedToUseExtension(RequestedExtension); + } + + virtual bool + isAllowedToUseExtensions(const SPIRVExtSet &RequestedExtensions) const final { + for (const auto &Ext : RequestedExtensions) { + if (!TranslationOpts.isAllowedToUseExtension(Ext)) + return false; + } + + return true; + } + // I/O functions friend spv_ostream &operator<<(spv_ostream &O, SPIRVModule &M); friend std::istream &operator>>(std::istream &I, SPIRVModule &M); @@ -400,6 +435,7 @@ class SPIRVModule { bool AutoAddCapability; bool ValidateCapability; bool AutoAddExtensions = true; + SPIRV::TranslatorOpts TranslationOpts; private: bool IsValid; diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h index f0a78e723604d..127960329750c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVOpCodeEnum.h @@ -305,6 +305,8 @@ _SPIRV_OP(SubgroupImageBlockReadINTEL, 5577) _SPIRV_OP(SubgroupImageBlockWriteINTEL, 5578) _SPIRV_OP(SubgroupImageMediaBlockReadINTEL, 5580) _SPIRV_OP(SubgroupImageMediaBlockWriteINTEL, 5581) +_SPIRV_OP(FunctionPointerINTEL, 5600) +_SPIRV_OP(FunctionPointerCallINTEL, 5601) _SPIRV_OP(VmeImageINTEL, 5699) _SPIRV_OP(TypeVmeImageINTEL, 5700) _SPIRV_OP(TypeAvcImePayloadINTEL, 5701) @@ -433,5 +435,3 @@ _SPIRV_OP(LoopControlINTEL, 5887) _SPIRV_OP(ReadPipeBlockingINTEL, 5946) _SPIRV_OP(WritePipeBlockingINTEL, 5947) _SPIRV_OP(FPGARegINTEL, 5949) -_SPIRV_OP(FunctionPointerINTEL, 5600) -_SPIRV_OP(FunctionPointerCallINTEL, 5601) diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVStream.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVStream.cpp index 2d85d889a5bf8..2b921f3117d6c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVStream.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVStream.cpp @@ -235,6 +235,27 @@ SPIRVEntry *SPIRVDecoder::getEntry() { IS >> *Entry; if (Entry->isEndOfBlock() || OpCode == OpNoLine) M.setCurrentLine(nullptr); + + if (OpExtension == OpCode) { + auto *OpExt = static_cast(Entry); + ExtensionID ExtID; + bool ExtIsKnown = SPIRVMap::rfind( + OpExt->getExtensionName(), &ExtID); + if (!M.getErrorLog().checkError( + ExtIsKnown, SPIRVEC_InvalidModule, + "input SPIR-V module uses unknown extension '" + + OpExt->getExtensionName() + "'")) { + M.setInvalid(); + } + + if (!M.getErrorLog().checkError( + M.isAllowedToUseExtension(ExtID), SPIRVEC_InvalidModule, + "input SPIR-V module uses extension '" + OpExt->getExtensionName() + + "' which were disabled by --spirv-ext option")) { + M.setInvalid(); + } + } + assert(!IS.bad() && !IS.fail() && "SPIRV stream fails"); return Entry; } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h index e198210b908cd..a3ce1d0ab8af4 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVType.h @@ -780,7 +780,7 @@ class SPIRVTypeVmeImageINTEL : public SPIRVType { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_device_side_avc_motion_estimation); + return getSet(ExtensionID::SPV_INTEL_device_side_avc_motion_estimation); } protected: @@ -835,7 +835,7 @@ class SPIRVTypeSubgroupAvcINTEL : public SPIRVType { } SPIRVExtSet getRequiredExtensions() const override { - return getSet(SPV_INTEL_device_side_avc_motion_estimation); + return getSet(ExtensionID::SPV_INTEL_device_side_avc_motion_estimation); } SPIRVValue *getOperand() { return getValue(Opn); } diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVUtil.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVUtil.h index 794b76cf2f314..ac3b6032db45c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVUtil.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVUtil.h @@ -343,6 +343,18 @@ inline std::string getString(const std::vector &V) { return getString(V.cbegin(), V.cend()); } +// if vector of Literals is expected to contain more than one Literal String +inline std::vector getVecString(const std::vector &V) { + std::vector Result; + std::string Str; + for (auto It = V.cbegin(); It < V.cend(); It += getSizeInWords(Str)) { + Str.clear(); + Str = getString(It, V.cend()); + Result.push_back(Str); + } + return Result; +} + inline std::vector getVec(const std::string &Str) { std::vector V; auto StrSize = Str.size(); diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.cpp b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.cpp index d5591caaa7afa..2b52c309a0c0c 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.cpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.cpp @@ -75,11 +75,18 @@ bool SPIRVValue::hasNoSignedWrap() const { void SPIRVValue::setNoSignedWrap(bool HasNoSignedWrap) { if (!HasNoSignedWrap) { eraseDecorate(DecorationNoSignedWrap); - return; } - addDecorate(new SPIRVDecorate(DecorationNoSignedWrap, this)); - SPIRVDBG(spvdbgs() << "Set nsw " - << " for obj " << Id << "\n") + if (Module->isAllowedToUseExtension( + ExtensionID::SPV_KHR_no_integer_wrap_decoration)) { + // NoSignedWrap decoration is available only if it is allowed to use SPIR-V + // 1.4 or if SPV_KHR_no_integer_wrap_decoration extension is allowed + // FIXME: update this 'if' to include check for SPIR-V 1.4 once translator + // support this version + addDecorate(new SPIRVDecorate(DecorationNoSignedWrap, this)); + SPIRVDBG(spvdbgs() << "Set nsw for obj " << Id << "\n") + } else { + SPIRVDBG(spvdbgs() << "Skip setting nsw for obj " << Id << "\n") + } } bool SPIRVValue::hasNoUnsignedWrap() const { @@ -91,9 +98,17 @@ void SPIRVValue::setNoUnsignedWrap(bool HasNoUnsignedWrap) { eraseDecorate(DecorationNoUnsignedWrap); return; } - addDecorate(new SPIRVDecorate(DecorationNoUnsignedWrap, this)); - SPIRVDBG(spvdbgs() << "Set nuw " - << " for obj " << Id << "\n") + if (Module->isAllowedToUseExtension( + ExtensionID::SPV_KHR_no_integer_wrap_decoration)) { + // NoUnsignedWrap decoration is available only if it is allowed to use + // SPIR-V 1.4 or if SPV_KHR_no_integer_wrap_decoration extension is allowed + // FIXME: update this 'if' to include check for SPIR-V 1.4 once translator + // support this version + addDecorate(new SPIRVDecorate(DecorationNoUnsignedWrap, this)); + SPIRVDBG(spvdbgs() << "Set nuw for obj " << Id << "\n") + } else { + SPIRVDBG(spvdbgs() << "Skip setting nuw for obj " << Id << "\n") + } } } // namespace SPIRV diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.h b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.h index 7b1ee3e17880e..a4d6d52768a04 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.h +++ b/llvm-spirv/lib/SPIRV/libSPIRV/SPIRVValue.h @@ -124,7 +124,9 @@ class SPIRVValue : public SPIRVEntry { SPIRVExtSet EV; if (!hasType()) return EV; - return Type->getRequiredExtensions(); + EV = Type->getRequiredExtensions(); + assert(!Module || Module->isAllowedToUseExtensions(EV)); + return EV; } protected: diff --git a/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp b/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp index ea4ef7a028ce9..28a7c71eccb26 100644 --- a/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp +++ b/llvm-spirv/lib/SPIRV/libSPIRV/spirv.hpp @@ -388,6 +388,7 @@ enum Decoration { DecorationPassthroughNV = 5250, DecorationViewportRelativeNV = 5252, DecorationSecondaryViewportRelativeNV = 5256, + DecorationReferencedIndirectlyINTEL = 5602, DecorationUserSemantic = 5635, DecorationRegisterINTEL = 5825, DecorationMemoryINTEL = 5826, @@ -399,7 +400,6 @@ enum Decoration { DecorationMaxReplicatesINTEL = 5832, DecorationSimpleDualPortINTEL = 5833, DecorationMergeINTEL = 5834, - DecorationReferencedIndirectlyINTEL = 5602, DecorationMax = 0x7fffffff, }; @@ -676,6 +676,8 @@ enum Capability { CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityFunctionPointersINTEL = 5603, + CapabilityIndirectReferencesINTEL = 5604, CapabilitySubgroupAvcMotionEstimationINTEL = 5696, CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, @@ -684,8 +686,6 @@ enum Capability { CapabilityFPGALoopControlsINTEL = 5888, CapabilityBlockingPipesINTEL = 5945, CapabilityFPGARegINTEL = 5948, - CapabilityFunctionPointersINTEL = 5603, - CapabilityIndirectReferencesINTEL = 5604, CapabilityMax = 0x7fffffff, }; @@ -1011,6 +1011,8 @@ enum Op { OpSubgroupImageBlockWriteINTEL = 5578, OpSubgroupImageMediaBlockReadINTEL = 5580, OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpFunctionPointerINTEL = 5600, + OpFunctionPointerCallINTEL = 5601, OpVmeImageINTEL = 5699, OpTypeVmeImageINTEL = 5700, OpTypeAvcImePayloadINTEL = 5701, @@ -1134,8 +1136,6 @@ enum Op { OpReadPipeBlockingINTEL = 5946, OpWritePipeBlockingINTEL = 5947, OpFPGARegINTEL = 5949, - OpFunctionPointerINTEL = 5600, - OpFunctionPointerCallINTEL = 5601, OpMax = 0x7fffffff, }; diff --git a/llvm-spirv/test/CMakeLists.txt b/llvm-spirv/test/CMakeLists.txt index 436922ac859a8..211f804c9d536 100644 --- a/llvm-spirv/test/CMakeLists.txt +++ b/llvm-spirv/test/CMakeLists.txt @@ -10,11 +10,22 @@ set(LLVM_SPIRV_TEST_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # find spirv-val pkg_search_module(SPIRV_TOOLS SPIRV-Tools) if(SPIRV_TOOLS_FOUND) + find_program(SPIRV_TOOLS_SPIRV_AS NAMES spirv-as PATHS ${SPIRV_TOOLS_PREFIX}/bin) + if(SPIRV_TOOLS_SPIRV_AS) + set(SPIRV_TOOLS_SPIRV_AS_FOUND True) + endif() + find_program(SPIRV_TOOLS_SPIRV_VAL NAMES spirv-val PATHS ${SPIRV_TOOLS_PREFIX}/bin) if(SPIRV_TOOLS_SPIRV_VAL) - get_filename_component(SPIRV_TOOLS_BINDIR "${SPIRV_TOOLS_SPIRV_VAL}" DIRECTORY) set(SPIRV_TOOLS_SPIRV_VAL_FOUND True) endif() + + set(SPIRV_TOOLS_BINDIR "${SPIRV_TOOLS_PREFIX}/bin") +endif() + +if(NOT SPIRV_TOOLS_SPIRV_AS) + message(WARNING "spirv-as not found! SPIR-V assembly tests will not be run.") + set(SPIRV_TOOLS_SPIRV_AS_FOUND False) endif() if(NOT SPIRV_TOOLS_SPIRV_VAL) diff --git a/llvm-spirv/test/IntelFPGAMemoryAttributes.ll b/llvm-spirv/test/IntelFPGAMemoryAttributes.ll index 0ac3a05d38d43..67112e79f6423 100644 --- a/llvm-spirv/test/IntelFPGAMemoryAttributes.ll +++ b/llvm-spirv/test/IntelFPGAMemoryAttributes.ll @@ -1,10 +1,16 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_memory_attributes -o %t.spv +; RUN: llvm-spirv %t.spv --spirv-ext=+SPV_INTEL_fpga_memory_attributes -to-text -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv -r %t.spt -spirv-text -o %t.rev.bc +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; RUN: llvm-spirv -spirv-text -r %t.spt -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; +; TODO: add a bunch of different tests for --spirv-ext option + ; CHECK-SPIRV: Capability FPGAMemoryAttributesINTEL ; CHECK-SPIRV: Extension "SPV_INTEL_fpga_memory_attributes" ; CHECK-SPIRV: Decorate {{[0-9]+}} MemoryINTEL "DEFAULT" diff --git a/llvm-spirv/test/IntelFPGAMemoryAttributesForStruct.ll b/llvm-spirv/test/IntelFPGAMemoryAttributesForStruct.ll index ae4d3d021ea6e..1bf3b89723c8b 100644 --- a/llvm-spirv/test/IntelFPGAMemoryAttributesForStruct.ll +++ b/llvm-spirv/test/IntelFPGAMemoryAttributesForStruct.ll @@ -1,10 +1,16 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_memory_attributes -o %t.spv +; RUN: llvm-spirv %t.spv --spirv-ext=+SPV_INTEL_fpga_memory_attributes -to-text -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv -r %t.spt -spirv-text -o %t.rev.bc +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; RUN: llvm-spirv -spirv-text -r %t.spt -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; +; TODO: add a bunch of different tests for --spirv-ext option + ; CHECK-SPIRV: Capability FPGAMemoryAttributesINTEL ; CHECK-SPIRV: Extension "SPV_INTEL_fpga_memory_attributes" ; CHECK-SPIRV: MemberDecorate {{[0-9]+}} 1 RegisterINTEL diff --git a/llvm-spirv/test/IntelFPGAReg.ll b/llvm-spirv/test/IntelFPGAReg.ll index 075ffa5b727b2..70d26df1f52f5 100644 --- a/llvm-spirv/test/IntelFPGAReg.ll +++ b/llvm-spirv/test/IntelFPGAReg.ll @@ -55,7 +55,8 @@ ; A cb = __builtin_intel_fpga_reg(ca); ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -o %t.spv +; FIXME: add more negative test cases +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_reg -o %t.spv ; RUN: llvm-spirv %t.spv -to-text -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV diff --git a/llvm-spirv/test/NoSignedUnsignedWrap.ll b/llvm-spirv/test/NoSignedUnsignedWrap.ll index 6af4d8ac7c2a1..788878d33ecc0 100644 --- a/llvm-spirv/test/NoSignedUnsignedWrap.ll +++ b/llvm-spirv/test/NoSignedUnsignedWrap.ll @@ -4,19 +4,48 @@ ; } ; Command ; clang -cc1 -triple spir -emit-llvm -O2 -o NoSignedUnsignedWrap.ll test.cl - +; +; Positive tests: +; ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV - -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_no_integer_wrap_decoration -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_KHR_no_integer_wrap_decoration -o %t.spv ; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv --spirv-ext=+SPV_KHR_no_integer_wrap_decoration -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; +; During consumption, any SPIR-V extension must be accepted by default +; ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM +; +; Negative tests: +; +; Check that translator is able to reject SPIR-V if extension is disallowed +; +; RUN: not --crash llvm-spirv -r %t.spv --spirv-ext=-SPV_KHR_no_integer_wrap_decoration -o - 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-SPIRV +; +; Check that translator is able to skip nsw/nuw attributes if extension is disabled implicitly or explicitly +; +; RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV-NOEXT +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-NOEXT +; +; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_KHR_no_integer_wrap_decoration -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV-NOEXT +; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_KHR_no_integer_wrap_decoration -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-NOEXT ; CHECK-SPIRV: Extension "SPV_KHR_no_integer_wrap_decoration" - ; CHECK-SPIRV: Decorate {{[0-9]+}} NoSignedWrap ; CHECK-SPIRV: Decorate {{[0-9]+}} NoUnsignedWrap +; +; CHECK-SPIRV-NOEXT-NOT: Extension "SPV_KHR_no_integer_wrap_decoration" +; CHECK-SPIRV-NOEXT-NOT: Decorate {{[0-9]+}} NoSignedWrap +; CHECK-SPIRV-NOEXT-NOT: Decorate {{[0-9]+}} NoUnsignedWrap +; +; CHECK-INVALID-SPIRV: input SPIR-V module uses extension 'SPV_KHR_no_integer_wrap_decoration' which were disabled target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir" @@ -26,6 +55,7 @@ define spir_func i32 @square(i16 zeroext %a) local_unnamed_addr #0 { entry: %conv = zext i16 %a to i32 ; CHECK-LLVM: mul nuw nsw + ; CHECK-LLVM-NOEXT: mul i32 %mul = mul nuw nsw i32 %conv, %conv ret i32 %mul } diff --git a/llvm-spirv/test/OpFNegate.spvasm b/llvm-spirv/test/OpFNegate.spvasm new file mode 100644 index 0000000000000..559a4d292f9e8 --- /dev/null +++ b/llvm-spirv/test/OpFNegate.spvasm @@ -0,0 +1,19 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testFNegate" + OpName %a "a" + %void = OpTypeVoid + %float = OpTypeFloat 32 + %5 = OpTypeFunction %void %float + %1 = OpFunction %void None %5 + %a = OpFunctionParameter %float + %6 = OpLabel + %7 = OpFNegate %float %a + OpReturn + OpFunctionEnd + +; CHECK: fsub float -0.000000e+00, %a diff --git a/llvm-spirv/test/OpFRem.spvasm b/llvm-spirv/test/OpFRem.spvasm new file mode 100644 index 0000000000000..ab4fe46afd12a --- /dev/null +++ b/llvm-spirv/test/OpFRem.spvasm @@ -0,0 +1,21 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testFRem" + OpName %a "a" + OpName %b "b" + %void = OpTypeVoid + %float = OpTypeFloat 32 + %5 = OpTypeFunction %void %float %float + %1 = OpFunction %void None %5 + %a = OpFunctionParameter %float + %b = OpFunctionParameter %float + %6 = OpLabel + %7 = OpFRem %float %a %b + OpReturn + OpFunctionEnd + +; CHECK: frem float %a, %b diff --git a/llvm-spirv/test/OpGroupIAdd.spt b/llvm-spirv/test/OpGroupIAdd.spt new file mode 100644 index 0000000000000..cb1deb1260fc1 --- /dev/null +++ b/llvm-spirv/test/OpGroupIAdd.spt @@ -0,0 +1,38 @@ +119734787 65536 393230 13 0 +2 Capability Addresses +2 Capability Kernel +2 Capability Groups +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 1 2 +10 EntryPoint 6 6 "testWorkGroupIAddUnsigned" +3 Source 3 200000 +3 Name 7 "a" +4 Decorate 8 FuncParamAttr 5 +4 TypeInt 3 32 0 +4 Constant 3 11 2 +2 TypeVoid 2 +4 TypePointer 4 5 3 +5 TypeFunction 5 2 3 4 + + +5 Function 2 6 0 5 +3 FunctionParameter 3 7 +3 FunctionParameter 4 8 + +2 Label 9 +6 GroupIAdd 3 10 11 0 7 +5 Store 8 10 2 4 +1 Return + +1 FunctionEnd + +; TODO: This currently maps to _Z21work_group_reduce_addi, but should map +; to _Z21work_group_reduce_addj, instead. Remove this test and update +; test/transcoding/group_ops.cl when fixing this. +; XFAIL: * +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc +; RUN: llvm-dis < %t.bc | FileCheck %s + +; CHECK: call spir_func i32 @_Z21work_group_reduce_addj(i32 %a) diff --git a/llvm-spirv/test/OpLogicalAnd.spvasm b/llvm-spirv/test/OpLogicalAnd.spvasm new file mode 100644 index 0000000000000..3af764e6926cd --- /dev/null +++ b/llvm-spirv/test/OpLogicalAnd.spvasm @@ -0,0 +1,24 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testLogicalAnd" + OpName %a "a" + OpName %b "b" + %void = OpTypeVoid + %bool = OpTypeBool +%_ptr_CrossWorkgroup_bool = OpTypePointer CrossWorkgroup %bool + %7 = OpTypeFunction %void %_ptr_CrossWorkgroup_bool %_ptr_CrossWorkgroup_bool + %1 = OpFunction %void None %7 + %8 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %9 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %10 = OpLabel + %a = OpLoad %bool %8 Aligned 8 + %b = OpLoad %bool %9 Aligned 8 + %11 = OpLogicalAnd %bool %a %b + OpReturn + OpFunctionEnd + +; CHECK: and i1 {{%a, %b|%b, %a}} diff --git a/llvm-spirv/test/OpLogicalEqual.spvasm b/llvm-spirv/test/OpLogicalEqual.spvasm new file mode 100644 index 0000000000000..8ed6995a9d093 --- /dev/null +++ b/llvm-spirv/test/OpLogicalEqual.spvasm @@ -0,0 +1,24 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testLogicalEqual" + OpName %a "a" + OpName %b "b" + %void = OpTypeVoid + %bool = OpTypeBool +%_ptr_CrossWorkgroup_bool = OpTypePointer CrossWorkgroup %bool + %7 = OpTypeFunction %void %_ptr_CrossWorkgroup_bool %_ptr_CrossWorkgroup_bool + %1 = OpFunction %void None %7 + %8 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %9 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %10 = OpLabel + %a = OpLoad %bool %8 Aligned 8 + %b = OpLoad %bool %9 Aligned 8 + %11 = OpLogicalEqual %bool %a %b + OpReturn + OpFunctionEnd + +; CHECK: icmp eq i1 {{%a, %b|%b, %a}} diff --git a/llvm-spirv/test/OpLogicalNot.spvasm b/llvm-spirv/test/OpLogicalNot.spvasm new file mode 100644 index 0000000000000..41238a583c4bd --- /dev/null +++ b/llvm-spirv/test/OpLogicalNot.spvasm @@ -0,0 +1,21 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testLogicalNot" + OpName %a "a" + %void = OpTypeVoid + %bool = OpTypeBool +%_ptr_CrossWorkgroup_bool = OpTypePointer CrossWorkgroup %bool + %7 = OpTypeFunction %void %_ptr_CrossWorkgroup_bool + %1 = OpFunction %void None %7 + %8 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %9 = OpLabel + %a = OpLoad %bool %8 Aligned 8 + %10 = OpLogicalNot %bool %a + OpReturn + OpFunctionEnd + +; CHECK: xor i1 {{%a, true|true, %a}} diff --git a/llvm-spirv/test/OpLogicalNotEqual.spvasm b/llvm-spirv/test/OpLogicalNotEqual.spvasm new file mode 100644 index 0000000000000..3529f2d5bde05 --- /dev/null +++ b/llvm-spirv/test/OpLogicalNotEqual.spvasm @@ -0,0 +1,24 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testLogicalNotEqual" + OpName %a "a" + OpName %b "b" + %void = OpTypeVoid + %bool = OpTypeBool +%_ptr_CrossWorkgroup_bool = OpTypePointer CrossWorkgroup %bool + %7 = OpTypeFunction %void %_ptr_CrossWorkgroup_bool %_ptr_CrossWorkgroup_bool + %1 = OpFunction %void None %7 + %8 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %9 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %10 = OpLabel + %a = OpLoad %bool %8 Aligned 8 + %b = OpLoad %bool %9 Aligned 8 + %11 = OpLogicalNotEqual %bool %a %b + OpReturn + OpFunctionEnd + +; CHECK: icmp ne i1 {{%a, %b|%b, %a}} diff --git a/llvm-spirv/test/OpLogicalOr.spvasm b/llvm-spirv/test/OpLogicalOr.spvasm new file mode 100644 index 0000000000000..13e6f77bc024a --- /dev/null +++ b/llvm-spirv/test/OpLogicalOr.spvasm @@ -0,0 +1,24 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testLogicalOr" + OpName %a "a" + OpName %b "b" + %void = OpTypeVoid + %bool = OpTypeBool +%_ptr_CrossWorkgroup_bool = OpTypePointer CrossWorkgroup %bool + %7 = OpTypeFunction %void %_ptr_CrossWorkgroup_bool %_ptr_CrossWorkgroup_bool + %1 = OpFunction %void None %7 + %8 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %9 = OpFunctionParameter %_ptr_CrossWorkgroup_bool + %10 = OpLabel + %a = OpLoad %bool %8 Aligned 8 + %b = OpLoad %bool %9 Aligned 8 + %11 = OpLogicalOr %bool %a %b + OpReturn + OpFunctionEnd + +; CHECK: or i1 {{%a, %b|%b, %a}} diff --git a/llvm-spirv/test/OpNop.spvasm b/llvm-spirv/test/OpNop.spvasm new file mode 100644 index 0000000000000..7135074d104a4 --- /dev/null +++ b/llvm-spirv/test/OpNop.spvasm @@ -0,0 +1,20 @@ +; REQUIRES: spirv-as +; TODO: OpNop cannot currently be decoded +; XFAIL: * +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testNop" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %5 = OpTypeFunction %void + %1 = OpFunction %void None %5 + %6 = OpLabel + OpNop + OpReturn + OpFunctionEnd + +; CHECK-LABEL: @testNop +; CHECK-NEXT: ret diff --git a/llvm-spirv/test/OpNot.spvasm b/llvm-spirv/test/OpNot.spvasm new file mode 100644 index 0000000000000..bc12d384badcf --- /dev/null +++ b/llvm-spirv/test/OpNot.spvasm @@ -0,0 +1,19 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testNot" + OpName %a "a" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %5 = OpTypeFunction %void %uint + %1 = OpFunction %void None %5 + %a = OpFunctionParameter %uint + %6 = OpLabel + %7 = OpNot %uint %a + OpReturn + OpFunctionEnd + +; CHECK: xor i32 {{%a, -1|-1, %a}} diff --git a/llvm-spirv/test/OpSNegate.spvasm b/llvm-spirv/test/OpSNegate.spvasm new file mode 100644 index 0000000000000..53ad49f1eebdb --- /dev/null +++ b/llvm-spirv/test/OpSNegate.spvasm @@ -0,0 +1,19 @@ +; REQUIRES: spirv-as +; RUN: spirv-as --target-env spv1.0 -o %t.spv %s +; RUN: llvm-spirv -r -o - %t.spv | llvm-dis | FileCheck %s + OpCapability Addresses + OpCapability Kernel + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %1 "testSNegate" + OpName %a "a" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %5 = OpTypeFunction %void %uint + %1 = OpFunction %void None %5 + %a = OpFunctionParameter %uint + %6 = OpLabel + %7 = OpSNegate %uint %a + OpReturn + OpFunctionEnd + +; CHECK: sub nsw i32 0, %a diff --git a/llvm-spirv/test/PipeBlocking.ll b/llvm-spirv/test/PipeBlocking.ll index fbc46e65308dd..4caf15daa8019 100644 --- a/llvm-spirv/test/PipeBlocking.ll +++ b/llvm-spirv/test/PipeBlocking.ll @@ -1,7 +1,8 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_blocking_pipes -spirv-text -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; FIXME: add more negative test cases +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_blocking_pipes -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.bc ; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM @@ -19,17 +20,39 @@ target triple = "spir64-unknown-unknown" ; CHECK-SPIRV: 3 TypePipe [[PipeWTy:[0-9]+]] 1 ; CHECK-SPIRV: 6 Load [[PipeRTy]] [[PipeR:[0-9]+]] {{[0-9]+}} {{[0-9]+}} ; CHECK-SPIRV: 5 ReadPipeBlockingINTEL [[PipeR]] {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} +; CHECK-SPIRV: 6 Load [[PipeRTy]] [[PipeR:[0-9]+]] {{[0-9]+}} {{[0-9]+}} +; CHECK-SPIRV: 5 ReadPipeBlockingINTEL [[PipeR]] {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} +; CHECK-SPIRV: 6 Load [[PipeWTy]] [[PipeW:[0-9]+]] {{[0-9]+}} {{[0-9]+}} +; CHECK-SPIRV: 5 WritePipeBlockingINTEL [[PipeW]] {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} ; CHECK-SPIRV: 6 Load [[PipeWTy]] [[PipeW:[0-9]+]] {{[0-9]+}} {{[0-9]+}} ; CHECK-SPIRV: 5 WritePipeBlockingINTEL [[PipeW]] {{[0-9]+}} {{[0-9]+}} {{[0-9]+}} ; CHECK-LLVM: %opencl.pipe_ro_t = type opaque ; CHECK-LLVM: %opencl.pipe_wo_t = type opaque +; CHECK-LLVM: call spir_func void @__read_pipe_2_bl(%opencl.pipe_ro_t addrspace(1)* %0, i8 addrspace(4)* %{{[0-9]+}}, i32 4, i32 4) ; CHECK-LLVM: call spir_func void @__read_pipe_2_bl(%opencl.pipe_ro_t addrspace(1)* %0, i8 addrspace(4)* %{{[0-9]+}}, i32 4, i32 4) ; CHECK-LLVM: call spir_func void @__write_pipe_2_bl(%opencl.pipe_wo_t addrspace(1)* %0, i8 addrspace(4)* %{{[0-9]+}}, i32 4, i32 4) +; CHECK-LLVM: call spir_func void @__write_pipe_2_bl(%opencl.pipe_wo_t addrspace(1)* %0, i8 addrspace(4)* %{{[0-9]+}}, i32 4, i32 4) ; Function Attrs: convergent noinline nounwind optnone define spir_func void @foo(%opencl.pipe_ro_t addrspace(1)* %p, i32 addrspace(1)* %ptr) #0 { +entry: + %p.addr = alloca %opencl.pipe_ro_t addrspace(1)*, align 8 + %ptr.addr = alloca i32 addrspace(1)*, align 8 + store %opencl.pipe_ro_t addrspace(1)* %p, %opencl.pipe_ro_t addrspace(1)** %p.addr, align 8 + store i32 addrspace(1)* %ptr, i32 addrspace(1)** %ptr.addr, align 8 + %0 = load %opencl.pipe_ro_t addrspace(1)*, %opencl.pipe_ro_t addrspace(1)** %p.addr, align 8 + %1 = load i32 addrspace(1)*, i32 addrspace(1)** %ptr.addr, align 8 + %2 = addrspacecast i32 addrspace(1)* %1 to i32 addrspace(4)* + call spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePiii(%opencl.pipe_ro_t addrspace(1)* %0, i32 addrspace(4)* %2, i32 4, i32 4) + ret void +} + +declare dso_local spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePiii(%opencl.pipe_ro_t addrspace(1)*, i32 addrspace(4)*, i32, i32) + +; Function Attrs: convergent noinline nounwind optnone +define spir_func void @bar(%opencl.pipe_ro_t addrspace(1)* %p, i32 addrspace(1)* %ptr) #0 { entry: %p.addr = alloca %opencl.pipe_ro_t addrspace(1)*, align 8 %ptr.addr = alloca i32 addrspace(1)*, align 8 @@ -38,15 +61,30 @@ entry: %0 = load %opencl.pipe_ro_t addrspace(1)*, %opencl.pipe_ro_t addrspace(1)** %p.addr, align 8 %1 = load i32 addrspace(1)*, i32 addrspace(1)** %ptr.addr, align 8 %2 = addrspacecast i32 addrspace(1)* %1 to i8 addrspace(4)* - call spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePT_ii(%opencl.pipe_ro_t addrspace(1)* %0, i8 addrspace(4)* %2, i32 4, i32 4) + call spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePvii(%opencl.pipe_ro_t addrspace(1)* %0, i8 addrspace(4)* %2, i32 4, i32 4) ret void } -declare dso_local spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePT_ii(%opencl.pipe_ro_t addrspace(1)*, i8 addrspace(4)*, i32, i32) -; CHECK-LLVM: declare spir_func void @__read_pipe_2_bl(%opencl.pipe_ro_t addrspace(1)*, i8 addrspace(4)*, i32, i32) +declare dso_local spir_func void @_Z29__spirv_ReadPipeBlockingINTELIiEv8ocl_pipePvii(%opencl.pipe_ro_t addrspace(1)*, i8 addrspace(4)*, i32, i32) ; Function Attrs: convergent noinline nounwind optnone define spir_func void @boo(%opencl.pipe_wo_t addrspace(1)* %p, i32 addrspace(1)* %ptr) #0 { +entry: + %p.addr = alloca %opencl.pipe_wo_t addrspace(1)*, align 8 + %ptr.addr = alloca i32 addrspace(1)*, align 8 + store %opencl.pipe_wo_t addrspace(1)* %p, %opencl.pipe_wo_t addrspace(1)** %p.addr, align 8 + store i32 addrspace(1)* %ptr, i32 addrspace(1)** %ptr.addr, align 8 + %0 = load %opencl.pipe_wo_t addrspace(1)*, %opencl.pipe_wo_t addrspace(1)** %p.addr, align 8 + %1 = load i32 addrspace(1)*, i32 addrspace(1)** %ptr.addr, align 8 + %2 = addrspacecast i32 addrspace(1)* %1 to i32 addrspace(4)* + call spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePiii(%opencl.pipe_wo_t addrspace(1)* %0, i32 addrspace(4)* %2, i32 4, i32 4) + ret void +} + +declare dso_local spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePiii(%opencl.pipe_wo_t addrspace(1)*, i32 addrspace(4)*, i32, i32) + +; Function Attrs: convergent noinline nounwind optnone +define spir_func void @baz(%opencl.pipe_wo_t addrspace(1)* %p, i32 addrspace(1)* %ptr) #0 { entry: %p.addr = alloca %opencl.pipe_wo_t addrspace(1)*, align 8 %ptr.addr = alloca i32 addrspace(1)*, align 8 @@ -55,10 +93,13 @@ entry: %0 = load %opencl.pipe_wo_t addrspace(1)*, %opencl.pipe_wo_t addrspace(1)** %p.addr, align 8 %1 = load i32 addrspace(1)*, i32 addrspace(1)** %ptr.addr, align 8 %2 = addrspacecast i32 addrspace(1)* %1 to i8 addrspace(4)* - call spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePT_ii(%opencl.pipe_wo_t addrspace(1)* %0, i8 addrspace(4)* %2, i32 4, i32 4) + call spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePvii(%opencl.pipe_wo_t addrspace(1)* %0, i8 addrspace(4)* %2, i32 4, i32 4) ret void } -declare dso_local spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePT_ii(%opencl.pipe_wo_t addrspace(1)*, i8 addrspace(4)*, i32, i32) + +declare dso_local spir_func void @_Z30__spirv_WritePipeBlockingINTELIKiEv8ocl_pipePvii(%opencl.pipe_wo_t addrspace(1)*, i8 addrspace(4)*, i32, i32) + +; CHECK-LLVM: declare spir_func void @__read_pipe_2_bl(%opencl.pipe_ro_t addrspace(1)*, i8 addrspace(4)*, i32, i32) ; CHECK-LLVM: declare spir_func void @__write_pipe_2_bl(%opencl.pipe_wo_t addrspace(1)*, i8 addrspace(4)*, i32, i32) attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "denorms-are-zero"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } diff --git a/llvm-spirv/test/debug-label-skip.ll b/llvm-spirv/test/debug-label-skip.ll new file mode 100644 index 0000000000000..fe926838a0f66 --- /dev/null +++ b/llvm-spirv/test/debug-label-skip.ll @@ -0,0 +1,51 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -o %t.spv + +source_filename = "debug-label-bitcode.c" + +target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir64-unknown-linux" + +; Function Attrs: noinline nounwind optnone +define i32 @foo(i32 signext %a, i32 signext %b) !dbg !4 { +entry: + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + %sum = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + br label %top + +top: ; preds = %entry + call void @llvm.dbg.label(metadata !9), !dbg !10 + %0 = load i32, i32* %a.addr, align 4 + %1 = load i32, i32* %b.addr, align 4 + %add = add nsw i32 %0, %1 + store i32 %add, i32* %sum, align 4 + br label %done + +done: ; preds = %top + call void @llvm.dbg.label(metadata !11), !dbg !12 + %2 = load i32, i32* %sum, align 4 + ret i32 %2 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.label(metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang 6.0.0", isOptimized: false, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "debug-label-bitcode.c", directory: "./") +!2 = !{} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !6, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !5) +!5 = !{!9} +!6 = !DISubroutineType(types: !7) +!7 = !{!8, !8, !8} +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !DILabel(scope: !4, name: "top", file: !1, line: 4) +!10 = !DILocation(line: 4, column: 1, scope: !4) +!11 = !DILabel(scope: !4, name: "done", file: !1, line: 7) +!12 = !DILocation(line: 7, column: 1, scope: !4) diff --git a/llvm-spirv/test/float_atomic_spv_to_ocl12.spt b/llvm-spirv/test/float_atomic_spv_to_ocl12.spt new file mode 100644 index 0000000000000..cc8d489684b85 --- /dev/null +++ b/llvm-spirv/test/float_atomic_spv_to_ocl12.spt @@ -0,0 +1,82 @@ +119734787 65536 393230 38 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 2 2 +3 Source 4 100000 +7 Name 4 "test_atomicStore" +4 Name 5 "entry" +7 Name 20 "test_atomicExchange" +4 Name 21 "entry" +6 Name 29 "test_atomicLoad" +4 Name 30 "entry" +4 Decorate 36 Alignment 4 +2 DecorationGroup 36 +4 Decorate 37 Alignment 8 +2 DecorationGroup 37 +8 Decorate 29 LinkageAttributes "test_atomicLoad" Export +9 Decorate 20 LinkageAttributes "test_atomicExchange" Export +9 Decorate 4 LinkageAttributes "test_atomicStore" Export +7 GroupDecorate 36 12 14 23 24 32 +5 GroupDecorate 37 9 22 31 +4 TypeInt 10 32 0 +4 Constant 10 18 2 +2 TypeVoid 2 +3 TypeFunction 3 2 +3 TypeFloat 6 32 +4 TypePointer 7 4 6 +4 TypePointer 8 7 7 +4 TypePointer 11 7 10 +4 TypePointer 13 7 6 +3 TypeFunction 19 6 + + +5 Function 2 4 0 3 + +2 Label 5 +4 Variable 8 9 7 +4 Variable 11 12 7 +4 Variable 13 14 7 +6 Load 7 15 9 2 8 +6 Load 10 16 12 2 4 +6 Load 6 17 14 2 4 +5 AtomicStore 15 18 16 17 +1 Return + +1 FunctionEnd + +5 Function 6 20 0 19 + +2 Label 21 +4 Variable 8 22 7 +4 Variable 11 23 7 +4 Variable 13 24 7 +6 Load 7 25 22 2 8 +6 Load 10 26 23 2 4 +6 Load 6 27 24 2 4 +7 AtomicExchange 6 28 25 18 26 27 +2 ReturnValue 28 + +1 FunctionEnd + +5 Function 6 29 0 19 + +2 Label 30 +4 Variable 8 31 7 +4 Variable 11 32 7 +6 Load 7 33 31 2 8 +6 Load 10 34 32 2 4 +6 AtomicLoad 6 35 33 18 34 +2 ReturnValue 35 + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.bc -spirv-ocl-builtins-version="CL1.2" +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-LLVM-12 + +; CHECK-LLVM-12: %{{[0-9]+}} = call spir_func float @{{[_A-Z0-9]+}}atomic_xchg{{[_A-Za-z0-9]+}}ff(float addrspace({{[0-9]+}})* %{{[0-9]+}}, float %{{[0-9]+}}) +; CHECK-LLVM-12: %{{[0-9]+}} = call spir_func float @{{[_A-Z0-9]+}}atomic_add{{[_A-Za-z0-9]+}}ff(float addrspace({{[0-9]+}})* %{{[0-9]+}}, float 0.000000e+00) + diff --git a/llvm-spirv/test/lit.cfg.py b/llvm-spirv/test/lit.cfg.py index 30db195bf8076..12fc1c2ae45ac 100644 --- a/llvm-spirv/test/lit.cfg.py +++ b/llvm-spirv/test/lit.cfg.py @@ -16,7 +16,7 @@ config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) # suffixes: A list of file extensions to treat as test files. -config.suffixes = ['.cl', '.ll', '.spt'] +config.suffixes = ['.cl', '.ll', '.spt', '.spvasm'] # excludes: A list of directories and fles to exclude from the testsuite. config.excludes = ['CMakeLists.txt'] @@ -53,9 +53,19 @@ llvm_config.add_tool_substitutions(tools, tool_dirs) +using_spirv_tools = False + +if config.spirv_tools_have_spirv_as: + llvm_config.add_tool_substitutions(['spirv-as'], [config.spirv_tools_bin_dir]) + config.available_features.add('spirv-as') + using_spirv_tools = True + if config.spirv_tools_have_spirv_val: - new_ld_library_path = os.path.pathsep.join((config.spirv_tools_lib_dir, config.environment['LD_LIBRARY_PATH'])) - config.environment['LD_LIBRARY_PATH'] = new_ld_library_path llvm_config.add_tool_substitutions(['spirv-val'], [config.spirv_tools_bin_dir]) + using_spirv_tools = True else: config.substitutions.append(('spirv-val', 'echo')) + +if using_spirv_tools: + new_ld_library_path = os.path.pathsep.join((config.spirv_tools_lib_dir, config.environment['LD_LIBRARY_PATH'])) + config.environment['LD_LIBRARY_PATH'] = new_ld_library_path diff --git a/llvm-spirv/test/lit.site.cfg.py.in b/llvm-spirv/test/lit.site.cfg.py.in index d68fbaec3f734..86b5400c6022a 100644 --- a/llvm-spirv/test/lit.site.cfg.py.in +++ b/llvm-spirv/test/lit.site.cfg.py.in @@ -15,6 +15,7 @@ config.target_triple = "@TARGET_TRIPLE@" config.host_arch = "@HOST_ARCH@" config.python_executable = "@PYTHON_EXECUTABLE@" config.test_run_dir = "@CMAKE_CURRENT_BINARY_DIR@" +config.spirv_tools_have_spirv_as = @SPIRV_TOOLS_SPIRV_AS_FOUND@ config.spirv_tools_have_spirv_val = @SPIRV_TOOLS_SPIRV_VAL_FOUND@ config.spirv_tools_bin_dir = "@SPIRV_TOOLS_BINDIR@" config.spirv_tools_lib_dir = "@SPIRV_TOOLS_LIBDIR@" diff --git a/llvm-spirv/test/negative/unsupported-triple.ll b/llvm-spirv/test/negative/unsupported-triple.ll new file mode 100644 index 0000000000000..c5172c4928248 --- /dev/null +++ b/llvm-spirv/test/negative/unsupported-triple.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: not --crash llvm-spirv %t.bc -o %t.spv 2>&1 | FileCheck %s + +; CHECK: InvalidTargetTriple: Expects spir-unknown-unknown or spir64-unknown-unknown. Actual target triple is aarch64 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "aarch64" + +; Function Attrs: convergent noinline nounwind optnone +define spir_func void @_Z3foov() { +entry: + ret void +} + +!llvm.module.flags = !{!0} +!opencl.spir.version = !{!1} +!opencl.ocl.version = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 2, i32 0} diff --git a/llvm-spirv/test/regularize-invalid-llvm.ll b/llvm-spirv/test/regularize-invalid-llvm.ll new file mode 100644 index 0000000000000..689ab05e662c5 --- /dev/null +++ b/llvm-spirv/test/regularize-invalid-llvm.ll @@ -0,0 +1,2 @@ +; RUN: not llvm-spirv -s %s 2>&1 | FileCheck %s +; CHECK: Invalid bitcode signature diff --git a/llvm-spirv/test/spirv-extensions-control.ll b/llvm-spirv/test/spirv-extensions-control.ll new file mode 100644 index 0000000000000..a8d15531e72fd --- /dev/null +++ b/llvm-spirv/test/spirv-extensions-control.ll @@ -0,0 +1,53 @@ +; Bunch of negative tests: +; +; RUN: not llvm-spirv --spirv-ext=EXT 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-FORMAT +; RUN: not llvm-spirv --spirv-ext=+EXT 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-EXT +; RUN: not llvm-spirv --spirv-ext=-EXT 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-EXT +; RUN: not llvm-spirv --spirv-ext=- 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-FORMAT +; RUN: not llvm-spirv --spirv-ext=+ 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-FORMAT +; RUN: not llvm-spirv --spirv-ext=, 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-FORMAT +; RUN: not llvm-spirv --spirv-ext= 2>&1 | FileCheck %s --check-prefix=CHECK-INVALID-FORMAT +; +; Bunch of positive tests: +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc --spirv-ext=+all -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=-all -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=+all,-SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=-all,+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; RUN: llvm-spirv %t.bc --spirv-ext=-SPV_INTEL_subgroups,+SPV_INTEL_subgroups -o - 2>&1 | FileCheck %s --check-prefix=CHECK-VALID +; +; CHECK-INVALID-FORMAT: Invalid value of --spirv-ext +; CHECK-INVALID-EXT: Unknown extension 'EXT' was specified +; +; CHECK-VALID-NOT: Unknown extension '{{.*}}' was specified + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @foo(i32 addrspace(1)* %a) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 { +entry: + %a.addr = alloca i32 addrspace(1)*, align 4 + store i32 addrspace(1)* %a, i32 addrspace(1)** %a.addr, align 4 + ret void +} + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!6} +!opencl.ocl.version = !{!6} +!opencl.used.extensions = !{!7} +!opencl.used.optional.core.features = !{!7} +!opencl.compiler.options = !{!7} + +!1 = !{i32 1} +!2 = !{!"none"} +!3 = !{!"int*"} +!4 = !{!"int*"} +!5 = !{!""} +!6 = !{i32 1, i32 2} +!7 = !{} + diff --git a/llvm-spirv/test/spirv-extensions-control.spt b/llvm-spirv/test/spirv-extensions-control.spt new file mode 100644 index 0000000000000..caee5106d18a1 --- /dev/null +++ b/llvm-spirv/test/spirv-extensions-control.spt @@ -0,0 +1,46 @@ +119734787 65536 393230 16 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Extension "SPV_KHR_no_integer_wrap_decoration" +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 2 2 +3 Source 3 200000 +3 Name 4 "foo" +4 Name 5 "entry" +4 Name 11 "agg1" +3 Name 12 "bar" +4 Name 13 "entry" +4 Name 14 "agg2" +5 Decorate 4 LinkageAttributes "foo" Export +5 Decorate 12 LinkageAttributes "bar" Export +4 TypeInt 7 32 0 +4 Constant 7 10 1 +2 TypeVoid 2 +3 TypeFunction 3 2 +3 TypeFloat 8 32 +4 TypeStruct 6 7 8 + +5 Function 2 4 0 3 + +2 Label 5 +3 Undef 6 9 +6 CompositeInsert 6 11 10 9 0 +1 Return + +1 FunctionEnd + +5 Function 2 12 0 3 + +2 Label 13 +3 Undef 6 15 +6 CompositeInsert 6 14 10 15 0 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: spirv-val %t.spv +; The purpose of this test is to check that SPIR-V file that uses extensions is +; not rejected by the translator by default +; RUN: llvm-spirv -r %t.spv -o %t.bc diff --git a/llvm-spirv/test/spirv-ocl-builtins-version.spt b/llvm-spirv/test/spirv-ocl-builtins-version.spt index a51284b83ec09..d3ea86d73ad01 100644 --- a/llvm-spirv/test/spirv-ocl-builtins-version.spt +++ b/llvm-spirv/test/spirv-ocl-builtins-version.spt @@ -41,7 +41,7 @@ ; CHECK-LLVM-12: call spir_func void @_Z7barrierj(i32 3) [[attr]] ; CHECK-LLVM-12: call spir_func void @_Z7barrierj(i32 5) [[attr]] ; CHECK-LLVM-12: call spir_func void @_Z7barrierj(i32 7) [[attr]] -; CHECK-LLVM-12: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM-12: attributes [[attr]] = { convergent nounwind } ; RUN: llvm-spirv %s -to-binary -o %t2.spv ; RUN: spirv-val %t2.spv @@ -54,4 +54,4 @@ ; CHECK-LLVM-20: call spir_func void @_Z18work_group_barrierj12memory_scope(i32 3, i32 1) [[attr]] ; CHECK-LLVM-20: call spir_func void @_Z18work_group_barrierj12memory_scope(i32 5, i32 1) [[attr]] ; CHECK-LLVM-20: call spir_func void @_Z18work_group_barrierj12memory_scope(i32 7, i32 1) [[attr]] -; CHECK-LLVM-20: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM-20: attributes [[attr]] = { convergent nounwind } diff --git a/llvm-spirv/test/spirv-unknown-extensions.spt b/llvm-spirv/test/spirv-unknown-extensions.spt new file mode 100644 index 0000000000000..008ee10f734c2 --- /dev/null +++ b/llvm-spirv/test/spirv-unknown-extensions.spt @@ -0,0 +1,44 @@ +119734787 65536 393230 16 0 +2 Capability Addresses +2 Capability Linkage +2 Capability Kernel +2 Extension "unknown_spirv_extension" +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 2 2 +3 Source 3 200000 +3 Name 4 "foo" +4 Name 5 "entry" +4 Name 11 "agg1" +3 Name 12 "bar" +4 Name 13 "entry" +4 Name 14 "agg2" +5 Decorate 4 LinkageAttributes "foo" Export +5 Decorate 12 LinkageAttributes "bar" Export +4 TypeInt 7 32 0 +4 Constant 7 10 1 +2 TypeVoid 2 +3 TypeFunction 3 2 +3 TypeFloat 8 32 +4 TypeStruct 6 7 8 + +5 Function 2 4 0 3 + +2 Label 5 +3 Undef 6 9 +6 CompositeInsert 6 11 10 9 0 +1 Return + +1 FunctionEnd + +5 Function 2 12 0 3 + +2 Label 13 +3 Undef 6 15 +6 CompositeInsert 6 14 10 15 0 +1 Return + +1 FunctionEnd + +; RUN: not --crash llvm-spirv %s -to-binary -o - 2>&1 | FileCheck %s +; CHECK: input SPIR-V module uses unknown extension 'unknown_spirv_extension' + diff --git a/llvm-spirv/test/spirv-version-controls-negative-1.spt b/llvm-spirv/test/spirv-version-controls-negative-1.spt new file mode 100644 index 0000000000000..f47dac3000f2f --- /dev/null +++ b/llvm-spirv/test/spirv-version-controls-negative-1.spt @@ -0,0 +1,33 @@ +119734787 66560 393230 12 0 +2 Capability Addresses +2 Capability Kernel +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 1 2 +4 EntryPoint 6 6 "foo" +9 String 11 "kernel_arg_type.foo.int*," +3 Source 3 102000 +3 Name 7 "a" +4 Name 8 "entry" +4 Name 10 "a.addr" +4 Decorate 10 Alignment 4 +4 TypeInt 3 32 0 +2 TypeVoid 2 +4 TypePointer 4 5 3 +4 TypeFunction 5 2 4 +4 TypePointer 9 7 4 + + +5 Function 2 6 0 5 +3 FunctionParameter 4 7 + +2 Label 8 +4 Variable 9 10 7 +5 Store 10 7 2 4 +1 Return + +1 FunctionEnd + +; RUN: not --crash llvm-spirv %s -to-binary -o - 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +; +; CHECK-ERROR: Invalid SPIR-V module: unsupported SPIR-V version number 'unknown (66560)'. Range of supported/known SPIR-V versions is 1.0 (65536) - 1.1 (65792) + diff --git a/llvm-spirv/test/spirv-version-controls-negative-2.spt b/llvm-spirv/test/spirv-version-controls-negative-2.spt new file mode 100644 index 0000000000000..ce0d9deb7a8d6 --- /dev/null +++ b/llvm-spirv/test/spirv-version-controls-negative-2.spt @@ -0,0 +1,34 @@ +119734787 1024 393230 12 0 +2 Capability Addresses +2 Capability Kernel +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 1 2 +4 EntryPoint 6 6 "foo" +9 String 11 "kernel_arg_type.foo.int*," +3 Source 3 102000 +3 Name 7 "a" +4 Name 8 "entry" +4 Name 10 "a.addr" +4 Decorate 10 Alignment 4 +4 TypeInt 3 32 0 +2 TypeVoid 2 +4 TypePointer 4 5 3 +4 TypeFunction 5 2 4 +4 TypePointer 9 7 4 + + +5 Function 2 6 0 5 +3 FunctionParameter 4 7 + +2 Label 8 +4 Variable 9 10 7 +5 Store 10 7 2 4 +1 Return + +1 FunctionEnd + +; RUN: not --crash llvm-spirv %s -to-binary -o - 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +; +; CHECK-ERROR: Invalid SPIR-V module: unsupported SPIR-V version number 'unknown (1024)'. Range of supported/known SPIR-V versions is 1.0 (65536) - 1.1 (65792) + + diff --git a/llvm-spirv/test/spirv-version-controls.spt b/llvm-spirv/test/spirv-version-controls.spt new file mode 100644 index 0000000000000..ccf98d8cab7cd --- /dev/null +++ b/llvm-spirv/test/spirv-version-controls.spt @@ -0,0 +1,35 @@ +119734787 65792 393230 12 0 +2 Capability Addresses +2 Capability Kernel +5 ExtInstImport 1 "OpenCL.std" +3 MemoryModel 1 2 +4 EntryPoint 6 6 "foo" +9 String 11 "kernel_arg_type.foo.int*," +3 Source 3 102000 +3 Name 7 "a" +4 Name 8 "entry" +4 Name 10 "a.addr" +4 Decorate 10 Alignment 4 +4 TypeInt 3 32 0 +2 TypeVoid 2 +4 TypePointer 4 5 3 +4 TypeFunction 5 2 4 +4 TypePointer 9 7 4 + + +5 Function 2 6 0 5 +3 FunctionParameter 4 7 + +2 Label 8 +4 Variable 9 10 7 +5 Store 10 7 2 4 +1 Return + +1 FunctionEnd + +; RUN: llvm-spirv %s -to-binary -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv --spirv-max-version=1.1 -o %t +; RUN: not --crash llvm-spirv -r %t.spv --spirv-max-version=1.0 -o - 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +; +; CHECK-ERROR: Invalid SPIR-V module: incorrect SPIR-V version number 1.1 (65792) - it conflicts with --spirv-max-version which is set to 1.0 (65536) diff --git a/llvm-spirv/test/transcoding/DecorationMaxByteOffset.ll b/llvm-spirv/test/transcoding/DecorationMaxByteOffset.ll index 27fb92ed3fa8f..bb5bbc0c433d4 100644 --- a/llvm-spirv/test/transcoding/DecorationMaxByteOffset.ll +++ b/llvm-spirv/test/transcoding/DecorationMaxByteOffset.ll @@ -4,8 +4,7 @@ ; RUN: llvm-spirv %t.bc -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM -; RUN: llvm-spirv %t.bc -spirv-text --spirv-no-deref-attr -o %t.txt -; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-NO-DEREF-ATTR +; RUN: llvm-spirv %t.bc -spirv-text --spirv-max-version=1.0 -o - | FileCheck %s --check-prefix=CHECK-SPIRV_1_0 ; CHECK-LLVM: define spir_kernel void @worker(i8 addrspace(3)* dereferenceable(12) %ptr) ; CHECK-LLVM: define spir_func void @not_a_kernel(i8 addrspace(3)* dereferenceable(123) %ptr2) @@ -19,7 +18,7 @@ ; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR_ID]] ; CHECK-SPIRV: 3 FunctionParameter [[CHAR_PTR_T]] [[PTR2_ID]] -; CHECK-NO-DEREF-ATTR-NOT: Decorate {{[0-9]+}} MaxByteOffset +; CHECK-SPIRV_1_0-NOT: Decorate {{[0-9]+}} MaxByteOffset target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir-unknown-unknown" diff --git a/llvm-spirv/test/transcoding/DivRem.cl b/llvm-spirv/test/transcoding/DivRem.cl new file mode 100644 index 0000000000000..dfb67f7c2c9b7 --- /dev/null +++ b/llvm-spirv/test/transcoding/DivRem.cl @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -triple spir-unknown-unknown -O1 -cl-std=CL2.0 -finclude-default-header -emit-llvm-bc %s -o %t.bc +// RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: llvm-spirv %t.bc -o %t.spv +// RUN: spirv-val %t.spv +// RUN: llvm-spirv -r %t.spv -o %t.rev.bc +// RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +// CHECK-SPIRV-DAG: TypeInt [[int:[0-9]+]] 32 0 +// CHECK-SPIRV-DAG: TypeVector [[int2:[0-9]+]] [[int]] 2 +// CHECK-SPIRV-DAG: TypeFloat [[float:[0-9]+]] 32 +// CHECK-SPIRV-DAG: TypeVector [[float2:[0-9]+]] [[float]] 2 + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SDiv [[int2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSDiv +// CHECK-LLVM: sdiv <2 x i32> %a, %b + +kernel void testSDiv(int2 a, int2 b, global int2 *res) { + res[0] = a / b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: UDiv [[int2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testUDiv +// CHECK-LLVM: udiv <2 x i32> %a, %b + +kernel void testUDiv(uint2 a, uint2 b, global uint2 *res) { + res[0] = a / b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FDiv [[float2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFDiv +// CHECK-LLVM: fdiv <2 x float> %a, %b + +kernel void testFDiv(float2 a, float2 b, global float2 *res) { + res[0] = a / b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SRem [[int2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSRem +// CHECK-LLVM: srem <2 x i32> %a, %b + +kernel void testSRem(int2 a, int2 b, global int2 *res) { + res[0] = a % b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: UMod [[int2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testUMod +// CHECK-LLVM: urem <2 x i32> %a, %b + +kernel void testUMod(uint2 a, uint2 b, global uint2 *res) { + res[0] = a % b; +} diff --git a/llvm-spirv/test/transcoding/FPGAUnstructuredLoopAttr.ll b/llvm-spirv/test/transcoding/FPGAUnstructuredLoopAttr.ll index 4c9b21a78b595..afc5fb8939a09 100644 --- a/llvm-spirv/test/transcoding/FPGAUnstructuredLoopAttr.ll +++ b/llvm-spirv/test/transcoding/FPGAUnstructuredLoopAttr.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as < %s > %t.bc -; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_unstructured_loop_controls -o - -spirv-text | FileCheck %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_unstructured_loop_controls -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.rev.bc ; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/OpControlBarrier_cl12.ll b/llvm-spirv/test/transcoding/OpControlBarrier_cl12.ll index 9f2f7ef02374f..c4ae02e2235ca 100644 --- a/llvm-spirv/test/transcoding/OpControlBarrier_cl12.ll +++ b/llvm-spirv/test/transcoding/OpControlBarrier_cl12.ll @@ -11,7 +11,7 @@ ; CHECK-LLVM-NEXT: call spir_func void @_Z7barrierj(i32 3) [[attr]] ; CHECK-LLVM-NEXT: call spir_func void @_Z7barrierj(i32 5) [[attr]] ; CHECK-LLVM-NEXT: call spir_func void @_Z7barrierj(i32 7) [[attr]] -; CHECK-LLVM: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM: attributes [[attr]] = { convergent nounwind } ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema1:[0-9]+]] 528 ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema2:[0-9]+]] 272 diff --git a/llvm-spirv/test/transcoding/OpControlBarrier_cl20.ll b/llvm-spirv/test/transcoding/OpControlBarrier_cl20.ll index 02e8905ade6c9..b88ce970d2e02 100644 --- a/llvm-spirv/test/transcoding/OpControlBarrier_cl20.ll +++ b/llvm-spirv/test/transcoding/OpControlBarrier_cl20.ll @@ -28,7 +28,7 @@ ; CHECK-LLVM-NEXT: call spir_func void @_Z18work_group_barrierj12memory_scope(i32 4, i32 2) [[attr]] ; CHECK-LLVM-NEXT: call spir_func void @_Z18work_group_barrierj12memory_scope(i32 4, i32 3) [[attr]] -; CHECK-LLVM: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM: attributes [[attr]] = { convergent nounwind } ; Both 'CrossDevice' memory scope and 'None' memory order enums have value equal to 0. ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[Null:[0-9]+]] 0 diff --git a/llvm-spirv/test/transcoding/OpControlBarrier_cl20_subgroup.ll b/llvm-spirv/test/transcoding/OpControlBarrier_cl20_subgroup.ll index ee02f26f73651..b43cb9b5f9d84 100644 --- a/llvm-spirv/test/transcoding/OpControlBarrier_cl20_subgroup.ll +++ b/llvm-spirv/test/transcoding/OpControlBarrier_cl20_subgroup.ll @@ -27,7 +27,7 @@ ; CHECK-LLVM-NEXT: call spir_func void @_Z17sub_group_barrierj12memory_scope(i32 4, i32 2) [[attr]] ; CHECK-LLVM-NEXT: call spir_func void @_Z17sub_group_barrierj12memory_scope(i32 4, i32 3) [[attr]] -; CHECK-LLVM: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM: attributes [[attr]] = { convergent nounwind } ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema1:[0-9]+]] 528 ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema2:[0-9]+]] 272 diff --git a/llvm-spirv/test/transcoding/OpControlBarrier_cl21.ll b/llvm-spirv/test/transcoding/OpControlBarrier_cl21.ll index 10de5082d0aa2..d062a7c764d03 100644 --- a/llvm-spirv/test/transcoding/OpControlBarrier_cl21.ll +++ b/llvm-spirv/test/transcoding/OpControlBarrier_cl21.ll @@ -27,7 +27,7 @@ ; CHECK-LLVM-NEXT: call spir_func void @_Z17sub_group_barrierj12memory_scope(i32 4, i32 2) [[attr]] ; CHECK-LLVM-NEXT: call spir_func void @_Z17sub_group_barrierj12memory_scope(i32 4, i32 3) [[attr]] -; CHECK-LLVM: attributes [[attr]] = { noduplicate nounwind } +; CHECK-LLVM: attributes [[attr]] = { convergent nounwind } ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema1:[0-9]+]] 528 ; CHECK-SPIRV-DAG: 4 Constant {{[0-9]+}} [[MemSema2:[0-9]+]] 272 diff --git a/llvm-spirv/test/transcoding/RelationalOperators.cl b/llvm-spirv/test/transcoding/RelationalOperators.cl new file mode 100644 index 0000000000000..7823b2e478aeb --- /dev/null +++ b/llvm-spirv/test/transcoding/RelationalOperators.cl @@ -0,0 +1,191 @@ +// RUN: %clang_cc1 -triple spir-unknown-unknown -O1 -cl-std=CL2.0 -finclude-default-header -emit-llvm-bc %s -o %t.bc +// RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: llvm-spirv %t.bc -o %t.spv +// RUN: spirv-val %t.spv +// RUN: llvm-spirv -r %t.spv -o %t.rev.bc +// RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +// CHECK-SPIRV: TypeBool [[bool:[0-9]+]] +// CHECK-SPIRV: TypeVector [[bool2:[0-9]+]] [[bool]] 2 + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: UGreaterThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testUGreaterThan +// CHECK-LLVM: icmp ugt <2 x i32> %a, %b + +kernel void testUGreaterThan(uint2 a, uint2 b, global int2 *res) { + res[0] = a > b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SGreaterThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSGreaterThan +// CHECK-LLVM: icmp sgt <2 x i32> %a, %b + +kernel void testSGreaterThan(int2 a, int2 b, global int2 *res) { + res[0] = a > b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: UGreaterThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testUGreaterThanEqual +// CHECK-LLVM: icmp uge <2 x i32> %a, %b + +kernel void testUGreaterThanEqual(uint2 a, uint2 b, global int2 *res) { + res[0] = a >= b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SGreaterThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSGreaterThanEqual +// CHECK-LLVM: icmp sge <2 x i32> %a, %b + +kernel void testSGreaterThanEqual(int2 a, int2 b, global int2 *res) { + res[0] = a >= b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: ULessThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testULessThan +// CHECK-LLVM: icmp ult <2 x i32> %a, %b + +kernel void testULessThan(uint2 a, uint2 b, global int2 *res) { + res[0] = a < b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SLessThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSLessThan +// CHECK-LLVM: icmp slt <2 x i32> %a, %b + +kernel void testSLessThan(int2 a, int2 b, global int2 *res) { + res[0] = a < b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: ULessThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testULessThanEqual +// CHECK-LLVM: icmp ule <2 x i32> %a, %b + +kernel void testULessThanEqual(uint2 a, uint2 b, global int2 *res) { + res[0] = a <= b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: SLessThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSLessThanEqual +// CHECK-LLVM: icmp sle <2 x i32> %a, %b + +kernel void testSLessThanEqual(int2 a, int2 b, global int2 *res) { + res[0] = a <= b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FOrdEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFOrdEqual +// CHECK-LLVM: fcmp oeq <2 x float> %a, %b + +kernel void testFOrdEqual(float2 a, float2 b, global int2 *res) { + res[0] = a == b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FUnordNotEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFUnordNotEqual +// CHECK-LLVM: fcmp une <2 x float> %a, %b + +kernel void testFUnordNotEqual(float2 a, float2 b, global int2 *res) { + res[0] = a != b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FOrdGreaterThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFOrdGreaterThan +// CHECK-LLVM: fcmp ogt <2 x float> %a, %b + +kernel void testFOrdGreaterThan(float2 a, float2 b, global int2 *res) { + res[0] = a > b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FOrdGreaterThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFOrdGreaterThanEqual +// CHECK-LLVM: fcmp oge <2 x float> %a, %b + +kernel void testFOrdGreaterThanEqual(float2 a, float2 b, global int2 *res) { + res[0] = a >= b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FOrdLessThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFOrdLessThan +// CHECK-LLVM: fcmp olt <2 x float> %a, %b + +kernel void testFOrdLessThan(float2 a, float2 b, global int2 *res) { + res[0] = a < b; +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +// CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +// CHECK-SPIRV: FOrdLessThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testFOrdLessThanEqual +// CHECK-LLVM: fcmp ole <2 x float> %a, %b + +kernel void testFOrdLessThanEqual(float2 a, float2 b, global int2 *res) { + res[0] = a <= b; +} diff --git a/llvm-spirv/test/transcoding/RelationalOperatorsFOrd.ll b/llvm-spirv/test/transcoding/RelationalOperatorsFOrd.ll new file mode 100644 index 0000000000000..cced9fd01f3bd --- /dev/null +++ b/llvm-spirv/test/transcoding/RelationalOperatorsFOrd.ll @@ -0,0 +1,43 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: TypeBool [[bool:[0-9]+]] +; CHECK-SPIRV: TypeVector [[bool2:[0-9]+]] [[bool]] 2 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FOrdNotEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFOrdNotEqual +; CHECK-LLVM: fcmp one <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFOrdNotEqual(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp one <2 x float> %a, %b + ret void +} + +attributes #0 = { nounwind } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!0} +!opencl.used.extensions = !{!1} +!opencl.used.optional.core.features = !{!1} + +!0 = !{i32 2, i32 0} +!1 = !{} +!2 = !{i32 0, i32 0} +!3 = !{!"none", !"none"} +!4 = !{!"float2", !"float2"} +!5 = !{!"", !""} diff --git a/llvm-spirv/test/transcoding/RelationalOperatorsFUnord.ll b/llvm-spirv/test/transcoding/RelationalOperatorsFUnord.ll new file mode 100644 index 0000000000000..8dd1801bf5db4 --- /dev/null +++ b/llvm-spirv/test/transcoding/RelationalOperatorsFUnord.ll @@ -0,0 +1,107 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-SPIRV: TypeBool [[bool:[0-9]+]] +; CHECK-SPIRV: TypeVector [[bool2:[0-9]+]] [[bool]] 2 + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FUnordEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFUnordEqual +; CHECK-LLVM: fcmp ueq <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFUnordEqual(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp ueq <2 x float> %a, %b + ret void +} + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FUnordGreaterThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFUnordGreaterThan +; CHECK-LLVM: fcmp ugt <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFUnordGreaterThan(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp ugt <2 x float> %a, %b + ret void +} + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FUnordGreaterThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFUnordGreaterThanEqual +; CHECK-LLVM: fcmp uge <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFUnordGreaterThanEqual(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp uge <2 x float> %a, %b + ret void +} + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FUnordLessThan [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFUnordLessThan +; CHECK-LLVM: fcmp ult <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFUnordLessThan(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp ult <2 x float> %a, %b + ret void +} + +; CHECK-SPIRV-LABEL: 5 Function +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[A:[0-9]+]] +; CHECK-SPIRV-NEXT: FunctionParameter {{[0-9]+}} [[B:[0-9]+]] +; CHECK-SPIRV: 5 FUnordLessThanEqual [[bool2]] {{[0-9]+}} [[A]] [[B]] +; CHECK-SPIRV: FunctionEnd + +; CHECK-LLVM-LABEL: @testFUnordLessThanEqual +; CHECK-LLVM: fcmp ule <2 x float> %a, %b + +; Function Attrs: nounwind +define spir_kernel void @testFUnordLessThanEqual(<2 x float> %a, <2 x float> %b) #0 !kernel_arg_addr_space !2 !kernel_arg_access_qual !3 !kernel_arg_type !4 !kernel_arg_type_qual !5 !kernel_arg_base_type !4 { +entry: + %0 = fcmp ule <2 x float> %a, %b + ret void +} + +attributes #0 = { nounwind } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!0} +!opencl.ocl.version = !{!0} +!opencl.used.extensions = !{!1} +!opencl.used.optional.core.features = !{!1} + +!0 = !{i32 2, i32 0} +!1 = !{} +!2 = !{i32 0, i32 0} +!3 = !{!"none", !"none"} +!4 = !{!"float2", !"float2"} +!5 = !{!"", !""} diff --git a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/fp-from-host.ll b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/fp-from-host.ll index b85161ec6d88e..9d1dba82ca83e 100644 --- a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/fp-from-host.ll +++ b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/fp-from-host.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc -spirv-text --spirv-ext=+SPV_INTEL_function_pointers -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_function_pointers -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.r.bc ; RUN: llvm-dis %t.r.bc -o %t.r.ll ; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer-as-function-arg.ll b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer-as-function-arg.ll index 144c6e9ad650f..962895bd71aaf 100644 --- a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer-as-function-arg.ll +++ b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer-as-function-arg.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc -spirv-text --spirv-ext=+SPV_INTEL_function_pointers -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_function_pointers -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.r.bc ; RUN: llvm-dis %t.r.bc -o %t.r.ll ; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer.ll b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer.ll index 9f84646522030..c9f1139e827e2 100644 --- a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer.ll +++ b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/function-pointer.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc -spirv-text --spirv-ext=+SPV_INTEL_function_pointers -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_function_pointers -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.r.bc ; RUN: llvm-dis %t.r.bc -o %t.r.ll ; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/non-uniform-function-pointer.ll b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/non-uniform-function-pointer.ll index 323ee4ef412f1..b6151aa19634f 100644 --- a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/non-uniform-function-pointer.ll +++ b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/non-uniform-function-pointer.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc -spirv-text --spirv-ext=+SPV_INTEL_function_pointers -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_function_pointers -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.r.bc ; RUN: llvm-dis %t.r.bc -o %t.r.ll ; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/referenced-indirectly.ll b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/referenced-indirectly.ll index 734720d962790..5a22b9ed0a75b 100644 --- a/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/referenced-indirectly.ll +++ b/llvm-spirv/test/transcoding/SPV_INTEL_function_pointers/referenced-indirectly.ll @@ -1,7 +1,7 @@ ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -spirv-text -o %t.spt +; RUN: llvm-spirv %t.bc -spirv-text --spirv-ext=+SPV_INTEL_function_pointers -o %t.spt ; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV -; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_function_pointers -o %t.spv ; RUN: llvm-spirv -r %t.spv -o %t.r.bc ; RUN: llvm-dis %t.r.bc -o %t.r.ll ; RUN: FileCheck < %t.r.ll %s --check-prefix=CHECK-LLVM diff --git a/llvm-spirv/test/transcoding/enqueue_kernel.cl b/llvm-spirv/test/transcoding/enqueue_kernel.cl index a07b2f7eb9d5c..aaa539e5f1089 100644 --- a/llvm-spirv/test/transcoding/enqueue_kernel.cl +++ b/llvm-spirv/test/transcoding/enqueue_kernel.cl @@ -134,7 +134,7 @@ kernel void device_side_enqueue(global int *a, global int *b, int i, char c0) { // CHECK-SPIRV-DAG: Function [[VoidTy]] [[BlockKer3]] 0 [[BlockTy2]] // CHECK-SPIRV-DAG: Function [[VoidTy]] [[BlockKer4]] 0 [[BlockTy3]] -// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_kernel(i8 addrspace(4)*) -// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_2_kernel(i8 addrspace(4)*) -// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_3_kernel(i8 addrspace(4)*, i8 addrspace(3)*) -// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_4_kernel(i8 addrspace(4)*, i8 addrspace(3)*, i8 addrspace(3)*, i8 addrspace(3)*) +// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_kernel(i8 addrspace(4)*{{.*}}) +// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_2_kernel(i8 addrspace(4)*{{.*}}) +// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_3_kernel(i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}}) +// CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_4_kernel(i8 addrspace(4)*{{.*}}, i8 addrspace(3)*{{.*}}, i8 addrspace(3)*{{.*}}, i8 addrspace(3)*{{.*}}) diff --git a/llvm-spirv/test/transcoding/group_ops.cl b/llvm-spirv/test/transcoding/group_ops.cl new file mode 100644 index 0000000000000..b90aba7eaefd1 --- /dev/null +++ b/llvm-spirv/test/transcoding/group_ops.cl @@ -0,0 +1,182 @@ +// RUN: %clang_cc1 -triple spir-unknown-unknown -O1 -cl-std=CL2.0 -finclude-default-header -emit-llvm-bc %s -o %t.bc +// RUN: llvm-spirv %t.bc -spirv-text -o - | FileCheck %s --check-prefix=CHECK-SPIRV +// RUN: llvm-spirv %t.bc -o %t.spv +// RUN: spirv-val %t.spv +// RUN: llvm-spirv -r %t.spv -o %t.rev.bc +// RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +// CHECK-SPIRV-DAG: TypeInt [[int:[0-9]+]] 32 0 +// CHECK-SPIRV-DAG: TypeFloat [[float:[0-9]+]] 32 +// CHECK-SPIRV-DAG: Constant [[int]] [[ScopeWorkgroup:[0-9]+]] 2 +// CHECK-SPIRV-DAG: Constant [[int]] [[ScopeSubgroup:[0-9]+]] 3 + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupFMax [[float]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupFMax +// CHECK-LLVM: call spir_func float @_Z21work_group_reduce_maxf(float %a) + +kernel void testWorkGroupFMax(float a, global float *res) { + res[0] = work_group_reduce_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupFMin [[float]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupFMin +// CHECK-LLVM: call spir_func float @_Z21work_group_reduce_minf(float %a) + +kernel void testWorkGroupFMin(float a, global float *res) { + res[0] = work_group_reduce_min(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupFAdd [[float]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupFAdd +// CHECK-LLVM: call spir_func float @_Z21work_group_reduce_addf(float %a) + +kernel void testWorkGroupFAdd(float a, global float *res) { + res[0] = work_group_reduce_add(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupFMax [[float]] {{[0-9]+}} [[ScopeWorkgroup]] 1 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupScanInclusiveFMax +// CHECK-LLVM: call spir_func float @_Z29work_group_scan_inclusive_maxf(float %a) + +kernel void testWorkGroupScanInclusiveFMax(float a, global float *res) { + res[0] = work_group_scan_inclusive_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupFMax [[float]] {{[0-9]+}} [[ScopeWorkgroup]] 2 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupScanExclusiveFMax +// CHECK-LLVM: call spir_func float @_Z29work_group_scan_exclusive_maxf(float %a) + +kernel void testWorkGroupScanExclusiveFMax(float a, global float *res) { + res[0] = work_group_scan_exclusive_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupSMax [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupSMax +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_maxi(i32 %a) + +kernel void testWorkGroupSMax(int a, global int *res) { + res[0] = work_group_reduce_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupSMin [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupSMin +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_mini(i32 %a) + +kernel void testWorkGroupSMin(int a, global int *res) { + res[0] = work_group_reduce_min(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupIAdd [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupIAddSigned +// TODO: This should map to _Z21work_group_reduce_addj, instead. +// Update this test and remove OpGroupIAdd.spt when fixing this. +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_addi(i32 %a) + +kernel void testWorkGroupIAddSigned(int a, global int *res) { + res[0] = work_group_reduce_add(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupIAdd [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupIAddUnsigned +// TODO: This should map to _Z21work_group_reduce_addj, instead. +// Update this test and remove OpGroupIAdd.spt when fixing this. +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_addi(i32 %a) + +kernel void testWorkGroupIAddUnsigned(uint a, global uint *res) { + res[0] = work_group_reduce_add(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupUMax [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupUMax +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_maxj(i32 %a) + +kernel void testWorkGroupUMax(uint a, global uint *res) { + res[0] = work_group_reduce_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupUMax [[int]] {{[0-9]+}} [[ScopeSubgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testSubGroupUMax +// CHECK-LLVM: call spir_func i32 @_Z20sub_group_reduce_maxj(i32 %a) + +#pragma OPENCL EXTENSION cl_khr_subgroups: enable +kernel void testSubGroupUMax(uint a, global uint *res) { + res[0] = sub_group_reduce_max(a); +} +#pragma OPENCL EXTENSION cl_khr_subgroups: disable + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupUMax [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 1 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupScanInclusiveUMax +// CHECK-LLVM: call spir_func i32 @_Z29work_group_scan_inclusive_maxj(i32 %a) + +kernel void testWorkGroupScanInclusiveUMax(uint a, global uint *res) { + res[0] = work_group_scan_inclusive_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupUMax [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 2 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupScanExclusiveUMax +// CHECK-LLVM: call spir_func i32 @_Z29work_group_scan_exclusive_maxj(i32 %a) + +kernel void testWorkGroupScanExclusiveUMax(uint a, global uint *res) { + res[0] = work_group_scan_exclusive_max(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupUMin [[int]] {{[0-9]+}} [[ScopeWorkgroup]] 0 +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupUMin +// CHECK-LLVM: call spir_func i32 @_Z21work_group_reduce_minj(i32 %a) + +kernel void testWorkGroupUMin(uint a, global uint *res) { + res[0] = work_group_reduce_min(a); +} + +// CHECK-SPIRV-LABEL: 5 Function +// CHECK-SPIRV: GroupBroadcast [[int]] {{[0-9]+}} [[ScopeWorkgroup]] +// CHECK-SPIRV: FunctionEnd + +// CHECK-LLVM-LABEL: @testWorkGroupBroadcast +// CHECK-LLVM: call spir_func i32 @_Z20work_group_broadcast{{[ji]}}{{[jm]}}(i32 %a, i32 %0) + +kernel void testWorkGroupBroadcast(uint a, global size_t *id, global int *res) { + res[0] = work_group_broadcast(a, *id); +} diff --git a/llvm-spirv/test/transcoding/kernel_arg_name.ll b/llvm-spirv/test/transcoding/kernel_arg_name.ll index ae771ae205e72..1cda3220fcb7f 100644 --- a/llvm-spirv/test/transcoding/kernel_arg_name.ll +++ b/llvm-spirv/test/transcoding/kernel_arg_name.ll @@ -2,8 +2,8 @@ ; RUN: llvm-spirv %t.spv -spirv-gen-kernel-arg-name-md -r -o - | llvm-dis -o - | FileCheck %s ; CHECK: spir_kernel void @named_arg(float %f) {{.*}} !kernel_arg_name ![[MD_named:[0-9]+]] -; CHECK: spir_kernel void @unnamed_arg(float) {{.*}} !kernel_arg_name ![[MD_unnamed:[0-9]+]] -; CHECK: spir_kernel void @one_unnamed_arg(i8 %a, i8 %b, i8) {{.*}} !kernel_arg_name ![[MD_one_unnamed:[0-9]+]] +; CHECK: spir_kernel void @unnamed_arg(float{{.*}}) {{.*}} !kernel_arg_name ![[MD_unnamed:[0-9]+]] +; CHECK: spir_kernel void @one_unnamed_arg(i8 %a, i8 %b, i8{{.*}}) {{.*}} !kernel_arg_name ![[MD_one_unnamed:[0-9]+]] ; CHECK: ![[MD_unnamed]] = !{!""} ; CHECK: ![[MD_named]] = !{!"f"} diff --git a/llvm-spirv/test/transcoding/kernel_query.ll b/llvm-spirv/test/transcoding/kernel_query.ll index 356d1f8e4f103..d78a99a1ad408 100644 --- a/llvm-spirv/test/transcoding/kernel_query.ll +++ b/llvm-spirv/test/transcoding/kernel_query.ll @@ -187,10 +187,10 @@ declare i32 @__get_kernel_sub_group_count_for_ndrange_impl(%struct.ndrange_t*, i ; CHECK-SPIRV-DAG: Function [[VoidTy]] [[BlockKer3]] 0 [[BlockKerTy]] ; CHECK-SPIRV-DAG: Function [[VoidTy]] [[BlockKer4]] 0 [[BlockKerTy]] -; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_kernel(i8 addrspace(4)*) -; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_2_kernel(i8 addrspace(4)*) -; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_3_kernel(i8 addrspace(4)*) -; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_4_kernel(i8 addrspace(4)*) +; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_kernel(i8 addrspace(4)*{{.*}}) +; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_2_kernel(i8 addrspace(4)*{{.*}}) +; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_3_kernel(i8 addrspace(4)*{{.*}}) +; CHECK-LLVM-DAG: define spir_kernel void @__device_side_enqueue_block_invoke_4_kernel(i8 addrspace(4)*{{.*}}) attributes #0 = { convergent noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "uniform-work-group-size"="false" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { convergent noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } diff --git a/llvm-spirv/test/transcoding/relationals_float.ll b/llvm-spirv/test/transcoding/relationals_float.ll new file mode 100644 index 0000000000000..7dc43c7d3655f --- /dev/null +++ b/llvm-spirv/test/transcoding/relationals_float.ll @@ -0,0 +1,140 @@ +; RUN: llvm-as %s -o %t.bc +; RUN: llvm-spirv %t.bc -spirv-text -o %t.txt +; RUN: FileCheck < %t.txt %s --check-prefix=CHECK-SPIRV +; RUN: llvm-spirv %t.bc -o %t.spv +; RUN: llvm-spirv -r %t.spv -o %t.rev.bc +; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM + +; CHECK-LLVM: call spir_func i32 @_Z8isfinitef( +; CHECK-LLVM: call spir_func i32 @_Z5isnanf( +; CHECK-LLVM: call spir_func i32 @_Z5isinff( +; CHECK-LLVM: call spir_func i32 @_Z8isnormalf( +; CHECK-LLVM: call spir_func i32 @_Z7signbitf( +; CHECK-LLVM: call spir_func i32 @_Z13islessgreaterff( +; CHECK-LLVM: call spir_func i32 @_Z9isorderedff( +; CHECK-LLVM: call spir_func i32 @_Z11isunorderedff( + +; CHECK-LLVM: call spir_func <2 x i32> @_Z8isfiniteDv2_f( +; CHECK-LLVM: call spir_func <2 x i32> @_Z5isnanDv2_f( +; CHECK-LLVM: call spir_func <2 x i32> @_Z5isinfDv2_f( +; CHECK-LLVM: call spir_func <2 x i32> @_Z8isnormalDv2_f( +; CHECK-LLVM: call spir_func <2 x i32> @_Z13islessgreaterDv2_fS_( +; CHECK-LLVM: call spir_func <2 x i32> @_Z9isorderedDv2_fS_( +; CHECK-LLVM: call spir_func <2 x i32> @_Z11isunorderedDv2_fS_( + +; CHECK-SPIRV: 2 TypeBool [[BoolTypeID:[0-9]+]] +; CHECK-SPIRV: 4 TypeVector [[BoolVectorTypeID:[0-9]+]] [[BoolTypeID]] 2 + +; CHECK-SPIRV: 4 IsFinite [[BoolTypeID]] +; CHECK-SPIRV: 4 IsNan [[BoolTypeID]] +; CHECK-SPIRV: 4 IsInf [[BoolTypeID]] +; CHECK-SPIRV: 4 IsNormal [[BoolTypeID]] +; CHECK-SPIRV: 4 SignBitSet [[BoolTypeID]] +; CHECK-SPIRV: 5 LessOrGreater [[BoolTypeID]] +; CHECK-SPIRV: 5 Ordered [[BoolTypeID]] +; CHECK-SPIRV: 5 Unordered [[BoolTypeID]] + +; CHECK-SPIRV: 4 IsFinite [[BoolVectorTypeID]] +; CHECK-SPIRV: 4 IsNan [[BoolVectorTypeID]] +; CHECK-SPIRV: 4 IsInf [[BoolVectorTypeID]] +; CHECK-SPIRV: 4 IsNormal [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 LessOrGreater [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 Ordered [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 Unordered [[BoolVectorTypeID]] + +target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" +target triple = "spir-unknown-unknown" + +; Function Attrs: nounwind +define spir_kernel void @test_scalar(i32 addrspace(1)* nocapture %out, float %f) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !3 !kernel_arg_base_type !4 !kernel_arg_type_qual !5 { +entry: + %call = tail call spir_func i32 @_Z8isfinitef(float %f) #2 + %call1 = tail call spir_func i32 @_Z5isnanf(float %f) #2 + %add = add nsw i32 %call1, %call + %call2 = tail call spir_func i32 @_Z5isinff(float %f) #2 + %add3 = add nsw i32 %add, %call2 + %call4 = tail call spir_func i32 @_Z8isnormalf(float %f) #2 + %add5 = add nsw i32 %add3, %call4 + %call6 = tail call spir_func i32 @_Z7signbitf(float %f) #2 + %add7 = add nsw i32 %add5, %call6 + %call8 = tail call spir_func i32 @_Z13islessgreaterff(float %f, float %f) #2 + %add9 = add nsw i32 %add7, %call8 + %call10 = tail call spir_func i32 @_Z9isorderedff(float %f, float %f) #2 + %add11 = add nsw i32 %add9, %call10 + %call12 = tail call spir_func i32 @_Z11isunorderedff(float %f, float %f) #2 + %add13 = add nsw i32 %add11, %call12 + store i32 %add13, i32 addrspace(1)* %out, align 4 + ret void +} + +declare spir_func i32 @_Z8isfinitef(float) #1 + +declare spir_func i32 @_Z5isnanf(float) #1 + +declare spir_func i32 @_Z5isinff(float) #1 + +declare spir_func i32 @_Z8isnormalf(float) #1 + +declare spir_func i32 @_Z7signbitf(float) #1 + +declare spir_func i32 @_Z13islessgreaterff(float, float) #1 + +declare spir_func i32 @_Z9isorderedff(float, float) #1 + +declare spir_func i32 @_Z11isunorderedff(float, float) #1 + +; Function Attrs: nounwind +define spir_kernel void @test_vector(<2 x i32> addrspace(1)* nocapture %out, <2 x float> %f) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !7 !kernel_arg_base_type !8 !kernel_arg_type_qual !5 { +entry: + %call = tail call spir_func <2 x i32> @_Z8isfiniteDv2_f(<2 x float> %f) #2 + %call1 = tail call spir_func <2 x i32> @_Z5isnanDv2_f(<2 x float> %f) #2 + %add = add <2 x i32> %call, %call1 + %call2 = tail call spir_func <2 x i32> @_Z5isinfDv2_f(<2 x float> %f) #2 + %add3 = add <2 x i32> %add, %call2 + %call4 = tail call spir_func <2 x i32> @_Z8isnormalDv2_f(<2 x float> %f) #2 + %add5 = add <2 x i32> %add3, %call4 + %call6 = tail call spir_func <2 x i32> @_Z13islessgreaterDv2_fS_(<2 x float> %f, <2 x float> %f) #2 + %add7 = add <2 x i32> %add5, %call6 + %call8 = tail call spir_func <2 x i32> @_Z9isorderedDv2_fS_(<2 x float> %f, <2 x float> %f) #2 + %add9 = add <2 x i32> %add7, %call8 + %call10 = tail call spir_func <2 x i32> @_Z11isunorderedDv2_fS_(<2 x float> %f, <2 x float> %f) #2 + %add11 = add <2 x i32> %add9, %call10 + store <2 x i32> %add11, <2 x i32> addrspace(1)* %out, align 8 + ret void +} + +declare spir_func <2 x i32> @_Z8isfiniteDv2_f(<2 x float>) #1 + +declare spir_func <2 x i32> @_Z5isnanDv2_f(<2 x float>) #1 + +declare spir_func <2 x i32> @_Z5isinfDv2_f(<2 x float>) #1 + +declare spir_func <2 x i32> @_Z8isnormalDv2_f(<2 x float>) #1 + +declare spir_func <2 x i32> @_Z13islessgreaterDv2_fS_(<2 x float>, <2 x float>) #1 + +declare spir_func <2 x i32> @_Z9isorderedDv2_fS_(<2 x float>, <2 x float>) #1 + +declare spir_func <2 x i32> @_Z11isunorderedDv2_fS_(<2 x float>, <2 x float>) #1 + +attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { nounwind } + +!opencl.enable.FP_CONTRACT = !{} +!opencl.spir.version = !{!9} +!opencl.ocl.version = !{!10} +!opencl.used.extensions = !{!11} +!opencl.used.optional.core.features = !{!11} +!opencl.compiler.options = !{!11} + +!1 = !{i32 1, i32 0} +!2 = !{!"none", !"none"} +!3 = !{!"int*", !"float"} +!4 = !{!"int*", !"float"} +!5 = !{!"", !""} +!7 = !{!"int2*", !"float2"} +!8 = !{!"int2*", !"float2"} +!9 = !{i32 1, i32 2} +!10 = !{i32 2, i32 0} +!11 = !{} diff --git a/llvm-spirv/test/transcoding/relationals_half.ll b/llvm-spirv/test/transcoding/relationals_half.ll index 5bc2022554002..b5843a8c34ad9 100644 --- a/llvm-spirv/test/transcoding/relationals_half.ll +++ b/llvm-spirv/test/transcoding/relationals_half.ll @@ -10,11 +10,17 @@ ; CHECK-LLVM: call spir_func i32 @_Z5isinfDh( ; CHECK-LLVM: call spir_func i32 @_Z8isnormalDh( ; CHECK-LLVM: call spir_func i32 @_Z7signbitDh( +; CHECK-LLVM: call spir_func i32 @_Z13islessgreaterDhDh( +; CHECK-LLVM: call spir_func i32 @_Z9isorderedDhDh( +; CHECK-LLVM: call spir_func i32 @_Z11isunorderedDhDh( ; CHECK-LLVM: call spir_func <2 x i16> @_Z8isfiniteDv2_Dh( ; CHECK-LLVM: call spir_func <2 x i16> @_Z5isnanDv2_Dh( ; CHECK-LLVM: call spir_func <2 x i16> @_Z5isinfDv2_Dh( ; CHECK-LLVM: call spir_func <2 x i16> @_Z8isnormalDv2_Dh( +; CHECK-LLVM: call spir_func <2 x i16> @_Z13islessgreaterDv2_DhS_( +; CHECK-LLVM: call spir_func <2 x i16> @_Z9isorderedDv2_DhS_( +; CHECK-LLVM: call spir_func <2 x i16> @_Z11isunorderedDv2_DhS_( ; CHECK-SPIRV: 2 TypeBool [[BoolTypeID:[0-9]+]] ; CHECK-SPIRV: 4 TypeVector [[BoolVectorTypeID:[0-9]+]] [[BoolTypeID]] 2 @@ -24,11 +30,17 @@ ; CHECK-SPIRV: 4 IsInf [[BoolTypeID]] ; CHECK-SPIRV: 4 IsNormal [[BoolTypeID]] ; CHECK-SPIRV: 4 SignBitSet [[BoolTypeID]] +; CHECK-SPIRV: 5 LessOrGreater [[BoolTypeID]] +; CHECK-SPIRV: 5 Ordered [[BoolTypeID]] +; CHECK-SPIRV: 5 Unordered [[BoolTypeID]] ; CHECK-SPIRV: 4 IsFinite [[BoolVectorTypeID]] ; CHECK-SPIRV: 4 IsNan [[BoolVectorTypeID]] ; CHECK-SPIRV: 4 IsInf [[BoolVectorTypeID]] ; CHECK-SPIRV: 4 IsNormal [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 LessOrGreater [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 Ordered [[BoolVectorTypeID]] +; CHECK-SPIRV: 5 Unordered [[BoolVectorTypeID]] target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024" target triple = "spir-unknown-unknown" @@ -45,7 +57,13 @@ entry: %add5 = add nsw i32 %add3, %call4 %call6 = tail call spir_func i32 @_Z7signbitDh(half %f) #2 %add7 = add nsw i32 %add5, %call6 - store i32 %add7, i32 addrspace(1)* %out, align 4 + %call8 = tail call spir_func i32 @_Z13islessgreaterDhDh(half %f, half %f) #2 + %add9 = add nsw i32 %add7, %call8 + %call10 = tail call spir_func i32 @_Z9isorderedDhDh(half %f, half %f) #2 + %add11 = add nsw i32 %add9, %call10 + %call12 = tail call spir_func i32 @_Z11isunorderedDhDh(half %f, half %f) #2 + %add13 = add nsw i32 %add11, %call12 + store i32 %add13, i32 addrspace(1)* %out, align 4 ret void } @@ -59,6 +77,12 @@ declare spir_func i32 @_Z8isnormalDh(half) #1 declare spir_func i32 @_Z7signbitDh(half) #1 +declare spir_func i32 @_Z13islessgreaterDhDh(half, half) #1 + +declare spir_func i32 @_Z9isorderedDhDh(half, half) #1 + +declare spir_func i32 @_Z11isunorderedDhDh(half, half) #1 + ; Function Attrs: nounwind define spir_kernel void @test_vector(<2 x i16> addrspace(1)* nocapture %out, <2 x half> %f) #0 !kernel_arg_addr_space !1 !kernel_arg_access_qual !2 !kernel_arg_type !7 !kernel_arg_base_type !8 !kernel_arg_type_qual !5 { entry: @@ -69,7 +93,13 @@ entry: %add3 = add <2 x i16> %add, %call2 %call4 = tail call spir_func <2 x i16> @_Z8isnormalDv2_Dh(<2 x half> %f) #2 %add5 = add <2 x i16> %add3, %call4 - store <2 x i16> %add5, <2 x i16> addrspace(1)* %out, align 8 + %call6 = tail call spir_func <2 x i16> @_Z13islessgreaterDv2_DhS_(<2 x half> %f, <2 x half> %f) #2 + %add7 = add <2 x i16> %add5, %call6 + %call8 = tail call spir_func <2 x i16> @_Z9isorderedDv2_DhS_(<2 x half> %f, <2 x half> %f) #2 + %add9 = add <2 x i16> %add7, %call8 + %call10 = tail call spir_func <2 x i16> @_Z11isunorderedDv2_DhS_(<2 x half> %f, <2 x half> %f) #2 + %add11 = add <2 x i16> %add9, %call10 + store <2 x i16> %add11, <2 x i16> addrspace(1)* %out, align 8 ret void } @@ -81,6 +111,12 @@ declare spir_func <2 x i16> @_Z5isinfDv2_Dh(<2 x half>) #1 declare spir_func <2 x i16> @_Z8isnormalDv2_Dh(<2 x half>) #1 +declare spir_func <2 x i16> @_Z13islessgreaterDv2_DhS_(<2 x half>, <2 x half>) #1 + +declare spir_func <2 x i16> @_Z9isorderedDv2_DhS_(<2 x half>, <2 x half>) #1 + +declare spir_func <2 x i16> @_Z11isunorderedDv2_DhS_(<2 x half>, <2 x half>) #1 + attributes #0 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind } diff --git a/llvm-spirv/test/transcoding/subgroup_avc_intel_generic.ll b/llvm-spirv/test/transcoding/subgroup_avc_intel_generic.ll index e11747f18a715..ea85926bb2dca 100644 --- a/llvm-spirv/test/transcoding/subgroup_avc_intel_generic.ll +++ b/llvm-spirv/test/transcoding/subgroup_avc_intel_generic.ll @@ -39,7 +39,7 @@ ; } ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_device_side_avc_motion_estimation -o - -spirv-text | FileCheck %s ; The test checks several (not all) 'cl_intel_device_side_avc_motion_estimation' ; extension built-ins. diff --git a/llvm-spirv/test/transcoding/subgroup_avc_intel_types.ll b/llvm-spirv/test/transcoding/subgroup_avc_intel_types.ll index 7ee83ac14017c..72e8dffbd8d5c 100644 --- a/llvm-spirv/test/transcoding/subgroup_avc_intel_types.ll +++ b/llvm-spirv/test/transcoding/subgroup_avc_intel_types.ll @@ -20,7 +20,7 @@ ; } ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_device_side_avc_motion_estimation -o - -spirv-text | FileCheck %s ; CHECK: Capability Groups ; CHECK: Capability SubgroupAvcMotionEstimationINTEL diff --git a/llvm-spirv/test/transcoding/subgroup_avc_intel_types.spt b/llvm-spirv/test/transcoding/subgroup_avc_intel_types.spt index 74f874b19d72c..65660f485944d 100644 --- a/llvm-spirv/test/transcoding/subgroup_avc_intel_types.spt +++ b/llvm-spirv/test/transcoding/subgroup_avc_intel_types.spt @@ -108,4 +108,4 @@ ; CHECK-LLVM: %opencl.intel_sub_group_avc_ime_result_dual_reference_streamout_t = type opaque ; CHECK-LLVM: %opencl.intel_sub_group_avc_ime_single_reference_streamin_t = type opaque ; CHECK-LLVM: %opencl.intel_sub_group_avc_ime_dual_reference_streamin_t = type opaque -; CHECK-LLVM: define spir_func void @foo() \ No newline at end of file +; CHECK-LLVM: define spir_func void @foo() diff --git a/llvm-spirv/test/transcoding/subgroup_avc_intel_vme_image.ll b/llvm-spirv/test/transcoding/subgroup_avc_intel_vme_image.ll index 4da31b482c3a8..4787eaadcc063 100644 --- a/llvm-spirv/test/transcoding/subgroup_avc_intel_vme_image.ll +++ b/llvm-spirv/test/transcoding/subgroup_avc_intel_vme_image.ll @@ -44,7 +44,7 @@ ; } ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_device_side_avc_motion_estimation -o - -spirv-text | FileCheck %s ; CHECK: Capability Groups ; CHECK: Capability SubgroupAvcMotionEstimationINTEL diff --git a/llvm-spirv/test/transcoding/subgroup_avc_intel_wrappers.ll b/llvm-spirv/test/transcoding/subgroup_avc_intel_wrappers.ll index b6c1e58b36405..2d2c5c5afd465 100644 --- a/llvm-spirv/test/transcoding/subgroup_avc_intel_wrappers.ll +++ b/llvm-spirv/test/transcoding/subgroup_avc_intel_wrappers.ll @@ -27,7 +27,7 @@ ; } ; RUN: llvm-as %s -o %t.bc -; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s +; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_device_side_avc_motion_estimation -o - -spirv-text | FileCheck %s ; The test checks that 'cl_intel_device_side_avc_motion_estimation' wrapper built-ins correctly ; translated to 'SPV_INTEL_device_side_avc_motion_estimation' extension instructions. diff --git a/llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp b/llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp index 165d036bedb30..335255b9977e6 100644 --- a/llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp +++ b/llvm-spirv/tools/llvm-spirv/llvm-spirv.cpp @@ -67,7 +67,10 @@ #include #include +#include #include +#include +#include #define DEBUG_TYPE "spirv" @@ -93,6 +96,23 @@ static cl::opt IsRegularization("s", cl::desc("Regularize LLVM to be representable by SPIR-V")); +using SPIRV::VersionNumber; + +static cl::opt MaxSPIRVVersion( + "spirv-max-version", + cl::desc("Choose maximum SPIR-V version which can be emitted"), + cl::values(clEnumValN(VersionNumber::SPIRV_1_0, "1.0", "SPIR-V 1.0"), + clEnumValN(VersionNumber::SPIRV_1_1, "1.1", "SPIR-V 1.1")), + cl::init(VersionNumber::MaximumVersion)); + +static cl::list + SPVExt("spirv-ext", cl::CommaSeparated, + cl::desc("Specify list of allowed/disallowed extensions"), + cl::value_desc("+SPV_extenstion1_name,-SPV_extension2_name"), + cl::ValueRequired); + +using SPIRV::ExtensionID; + #ifdef _SPIRV_SUPPORT_TEXT_FMT namespace SPIRV { // Use textual format for SPIRV. @@ -117,7 +137,7 @@ static std::string removeExt(const std::string &FileName) { static ExitOnError ExitOnErr; -static int convertLLVMToSPIRV() { +static int convertLLVMToSPIRV(const SPIRV::TranslatorOpts &Opts) { LLVMContext Context; std::unique_ptr MB = @@ -140,9 +160,9 @@ static int convertLLVMToSPIRV() { bool Success = false; if (OutputFile != "-") { std::ofstream OutFile(OutputFile, std::ios::binary); - Success = writeSpirv(M.get(), OutFile, Err); + Success = writeSpirv(M.get(), Opts, OutFile, Err); } else { - Success = writeSpirv(M.get(), std::cout, Err); + Success = writeSpirv(M.get(), Opts, std::cout, Err); } if (!Success) { @@ -152,13 +172,13 @@ static int convertLLVMToSPIRV() { return 0; } -static int convertSPIRVToLLVM() { +static int convertSPIRVToLLVM(const SPIRV::TranslatorOpts &Opts) { LLVMContext Context; std::ifstream IFS(InputFile, std::ios::binary); Module *M; std::string Err; - if (!readSpirv(Context, IFS, M, Err)) { + if (!readSpirv(Context, Opts, IFS, M, Err)) { errs() << "Fails to load SPIR-V as LLVM Module: " << Err << '\n'; return -1; } @@ -266,6 +286,66 @@ static int regularizeLLVM() { return 0; } +static int parseSPVExtOption( + SPIRV::TranslatorOpts::ExtensionsStatusMap &ExtensionsStatus) { + // Map name -> id for known extensions + std::map ExtensionNamesMap; +#define _STRINGIFY(X) #X +#define STRINGIFY(X) _STRINGIFY(X) +#define EXT(X) ExtensionNamesMap[STRINGIFY(X)] = ExtensionID::X; +#include "LLVMSPIRVExtensions.inc" +#undef EXT +#undef STRINGIFY +#undef _STRINGIFY + + // Set the initial state: + // - during SPIR-V consumption, assume that any known extension is allowed. + // - during SPIR-V generation, assume that any known extension is disallowed. + // - during conversion to/from SPIR-V text representation, assume that any + // known extension is allowed. + for (const auto &It : ExtensionNamesMap) + ExtensionsStatus[It.second] = IsReverse; + + if (SPVExt.empty()) + return 0; // Nothing to do + + for (unsigned i = 0; i < SPVExt.size(); ++i) { + const std::string &ExtString = SPVExt[i]; + if ('+' != ExtString.front() && '-' != ExtString.front()) { + errs() << "Invalid value of --spirv-ext, expected format is:\n" + << "\t--spirv-ext=+EXT_NAME,-EXT_NAME\n"; + return -1; + } + + auto ExtName = ExtString.substr(1); + + if (ExtName.empty()) { + errs() << "Invalid value of --spirv-ext, expected format is:\n" + << "\t--spirv-ext=+EXT_NAME,-EXT_NAME\n"; + return -1; + } + + bool ExtStatus = ('+' == ExtString.front()); + if ("all" == ExtName) { + // Update status for all known extensions + for (const auto &It : ExtensionNamesMap) + ExtensionsStatus[It.second] = ExtStatus; + } else { + // Reject unknown extensions + const auto &It = ExtensionNamesMap.find(ExtName); + if (ExtensionNamesMap.end() == It) { + errs() << "Unknown extension '" << ExtName << "' was specified via " + << "--spirv-ext option\n"; + return -1; + } + + ExtensionsStatus[It->second] = ExtStatus; + } + } + + return 0; +} + int main(int Ac, char **Av) { EnablePrettyStackTrace(); sys::PrintStackTraceOnErrorSignal(Av[0]); @@ -273,6 +353,15 @@ int main(int Ac, char **Av) { cl::ParseCommandLineOptions(Ac, Av, "LLVM/SPIR-V translator"); + SPIRV::TranslatorOpts::ExtensionsStatusMap ExtensionsStatus; + // ExtensionsStatus will be properly initialized and update according to + // values passed via --spirv-ext option in parseSPVExtOption function. + int Ret = parseSPVExtOption(ExtensionsStatus); + if (0 != Ret) + return Ret; + + SPIRV::TranslatorOpts Opts(MaxSPIRVVersion, ExtensionsStatus); + #ifdef _SPIRV_SUPPORT_TEXT_FMT if (ToText && (ToBinary || IsReverse || IsRegularization)) { errs() << "Cannot use -to-text with -to-binary, -r, -s\n"; @@ -289,14 +378,14 @@ int main(int Ac, char **Av) { #endif if (!IsReverse && !IsRegularization) - return convertLLVMToSPIRV(); + return convertLLVMToSPIRV(Opts); if (IsReverse && IsRegularization) { errs() << "Cannot have both -r and -s options\n"; return -1; } if (IsReverse) - return convertSPIRVToLLVM(); + return convertSPIRVToLLVM(Opts); if (IsRegularization) return regularizeLLVM();