shaderc: Add WGSL support. (#3542)

This commit is contained in:
Branimir Karadžić
2026-01-09 18:41:05 -08:00
committed by GitHub
parent fbff26d5e5
commit 1c08bab55a
1199 changed files with 357030 additions and 36 deletions

26
3rdparty/dawn/LICENSE vendored Normal file
View File

@@ -0,0 +1,26 @@
// Copyright 2017-2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

85
3rdparty/dawn/include/tint/tint.h vendored Normal file
View File

@@ -0,0 +1,85 @@
// Copyright 2020 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef INCLUDE_TINT_TINT_H_
#define INCLUDE_TINT_TINT_H_
// Guard for accidental includes to private headers
#define CURRENTLY_IN_TINT_PUBLIC_HEADER
// TODO(tint:88): When implementing support for an install target, all of these
// headers will need to be moved to include/tint/.
#include "src/tint/api/common/subgroup_matrix.h"
#include "src/tint/api/common/substitute_overrides_config.h"
#include "src/tint/api/common/vertex_pulling_config.h"
#include "src/tint/api/tint.h"
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/lang/wgsl/inspector/inspector.h"
#include "src/tint/utils/diagnostic/formatter.h"
#include "src/tint/utils/text/styled_text.h"
///////////////
// NOTE if adding a new guard include here, it must also appear in src/tint/api/tint.cc for the
// build to work correctly.
///////////////
#if TINT_BUILD_SPV_READER
#include "src/tint/lang/spirv/reader/reader.h"
#endif // TINT_BUILD_SPV_READER
#if TINT_BUILD_WGSL_READER
#include "src/tint/lang/wgsl/reader/reader.h"
#endif // TINT_BUILD_WGSL_READER
#if TINT_BUILD_SPV_WRITER
#include "src/tint/lang/spirv/writer/writer.h"
#endif // TINT_BUILD_SPV_WRITER
#if TINT_BUILD_WGSL_WRITER
#include "src/tint/lang/wgsl/writer/writer.h"
#endif // TINT_BUILD_WGSL_WRITER
#if TINT_BUILD_MSL_WRITER
#include "src/tint/lang/msl/writer/writer.h"
#endif // TINT_BUILD_MSL_WRITER
#if TINT_BUILD_HLSL_WRITER
#include "src/tint/lang/hlsl/writer/writer.h"
#endif // TINT_BUILD_HLSL_WRITER
#if TINT_BUILD_GLSL_WRITER
#include "src/tint/lang/glsl/writer/writer.h"
#endif // TINT_BUILD_GLSL_WRITER
#if TINT_BUILD_NULL_WRITER
#include "src/tint/lang/null/writer/writer.h"
#endif // TINT_BUILD_NULL_WRITER
#undef CURRENTLY_IN_TINT_PUBLIC_HEADER
#endif // INCLUDE_TINT_TINT_H_

4887
3rdparty/dawn/include/webgpu/webgpu.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_BINDING_POINT_H_
#define SRC_TINT_API_COMMON_BINDING_POINT_H_
#include <stdint.h>
#include <functional>
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/reflection.h"
#include "src/tint/utils/rtti/traits.h"
namespace tint {
/// BindingPoint holds a group and binding index.
struct BindingPoint {
/// The `@group` part of the binding point
uint32_t group = 0;
/// The `@binding` part of the binding point
uint32_t binding = 0;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(BindingPoint, group, binding);
/// @returns the hash code of the BindingPoint
tint::HashCode HashCode() const { return tint::Hash(group, binding); }
/// Equality operator
/// @param rhs the BindingPoint to compare against
/// @returns true if this BindingPoint is equal to `rhs`
bool operator==(const BindingPoint& rhs) const {
return group == rhs.group && binding == rhs.binding;
}
/// Inequality operator
/// @param rhs the BindingPoint to compare against
/// @returns true if this BindingPoint is not equal to `rhs`
bool operator!=(const BindingPoint& rhs) const { return !(*this == rhs); }
/// Less-than operator
/// @param rhs the BindingPoint to compare against
/// @returns true if this BindingPoint comes before @p rhs
bool operator<(const BindingPoint& rhs) const {
if (group < rhs.group) {
return true;
}
if (group > rhs.group) {
return false;
}
return binding < rhs.binding;
}
};
/// Prints the BindingPoint @p bp to @p o
/// @param o the stream to write to
/// @param bp the BindingPoint
/// @return the stream so calls can be chained
template <typename STREAM>
requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, const BindingPoint& bp) {
return o << "[group: " << bp.group << ", binding: " << bp.binding << "]";
}
} // namespace tint
namespace std {
/// Custom std::hash specialization for tint::BindingPoint so BindingPoints can be used as keys for
/// std::unordered_map and std::unordered_set.
template <>
class hash<tint::BindingPoint> {
public:
/// @param binding_point the binding point to create a hash for
/// @return the hash value
size_t operator()(const tint::BindingPoint& binding_point) const {
return (static_cast<size_t>(binding_point.group) << 16) |
static_cast<size_t>(binding_point.binding);
}
};
} // namespace std
#endif // SRC_TINT_API_COMMON_BINDING_POINT_H_

View File

@@ -0,0 +1,90 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_BINDINGS_H_
#define SRC_TINT_API_COMMON_BINDINGS_H_
#include <unordered_map>
#include "src/tint/api/common/binding_point.h"
#include "src/tint/utils/reflection.h"
namespace tint {
/// An external texture
struct ExternalTexture {
/// Metadata
BindingPoint metadata{};
/// Plane0 binding data
BindingPoint plane0{};
/// Plane1 binding data
BindingPoint plane1{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
TINT_REFLECT_EQUALS(ExternalTexture);
TINT_REFLECT_HASH_CODE(ExternalTexture);
};
using BindingMap = std::unordered_map<BindingPoint, BindingPoint>;
using ExternalTextureBindings = std::unordered_map<BindingPoint, ExternalTexture>;
/// Binding information
struct Bindings {
/// Uniform bindings
BindingMap uniform{};
/// Storage bindings
BindingMap storage{};
/// Texture bindings
BindingMap texture{};
/// Storage texture bindings
BindingMap storage_texture{};
/// Sampler bindings
BindingMap sampler{};
/// External bindings
ExternalTextureBindings external_texture{};
/// Input attachment bindings
BindingMap input_attachment{};
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(Bindings,
uniform,
storage,
texture,
storage_texture,
sampler,
external_texture,
input_attachment);
TINT_REFLECT_EQUALS(Bindings);
TINT_REFLECT_HASH_CODE(Bindings);
};
} // namespace tint
#endif // SRC_TINT_API_COMMON_BINDINGS_H_

View File

@@ -0,0 +1,84 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_OVERRIDE_ID_H_
#define SRC_TINT_API_COMMON_OVERRIDE_ID_H_
#include <stdint.h>
#include <functional>
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/reflection.h"
namespace tint {
/// OverrideId is a numerical identifier for an override variable, unique per program.
struct OverrideId {
/// The identifier value
uint16_t value = 0;
/// Reflect the fields of this struct so that it can be used by tint::ForeachField()
TINT_REFLECT(OverrideId, value);
/// @returns the hash code of the OverrideId
tint::HashCode HashCode() const { return Hash(value); }
};
/// Equality operator for OverrideId
/// @param lhs the OverrideId on the left of the '=' operator
/// @param rhs the OverrideId on the right of the '=' operator
/// @returns true if `lhs` is equal to `rhs`
inline bool operator==(OverrideId lhs, OverrideId rhs) {
return lhs.value == rhs.value;
}
/// Less-than operator for OverrideId
/// @param lhs the OverrideId on the left of the '<' operator
/// @param rhs the OverrideId on the right of the '<' operator
/// @returns true if `lhs` comes before `rhs`
inline bool operator<(OverrideId lhs, OverrideId rhs) {
return lhs.value < rhs.value;
}
} // namespace tint
namespace std {
/// Custom std::hash specialization for tint::OverrideId.
template <>
class hash<tint::OverrideId> {
public:
/// @param id the override identifier
/// @return the hash of the override identifier
inline size_t operator()(tint::OverrideId id) const {
return std::hash<decltype(tint::OverrideId::value)>()(id.value);
}
};
} // namespace std
#endif // SRC_TINT_API_COMMON_OVERRIDE_ID_H_

View File

@@ -0,0 +1,98 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_RESOURCE_TABLE_CONFIG_H_
#define SRC_TINT_API_COMMON_RESOURCE_TABLE_CONFIG_H_
#include <unordered_map>
#include <vector>
#include "src/tint/api/common/binding_point.h"
#include "src/tint/api/common/resource_type.h"
#include "src/tint/utils/reflection.h"
namespace tint {
// Configuration for the resource table transform.
//
// The resource table transform assumes that for each resource table entry there will be an
// entry in the `bindings` hash map. That binding will provide information on the storage buffer
// attached for the resource table. Specifically, the storage buffer should have a format of:
//
// ```
// struct SB {
// array_length: u32,
// bindings: array<u32>, // Has `array_length` entries (doesn't include the default bindings).
// }
// ```
//
// The values used in the `bindings` are from the `u32` conversion of the `ResourceType` enum
// entries.
//
struct ResourceTableConfig {
// The binding point for the resource_table. This is a post-remapping binding point.
BindingPoint resource_table_binding;
// The binding point for the supporting storage buffer. This is a post-remapping binding point.
BindingPoint storage_buffer_binding;
// The ordering of default bindings which are placed after the user bindings. These will be used
// as the index to lookup the given `ResourceType` if the user accesses with an incorrect
// texture type (or out of bounds).
//
// These `default_binding_type_order` entries will be used when we need to substitute in a
// default binding. So, we assume that Dawn is providing the resource table memory as:
//
// `[user 1 (2d_i32), user 2 (3d_f32), user 3 (1d_u32), 1d_u32_default, 2d_f32_default,
// 3d_f32_default]`
//
// We would then have `default_binding_type_order` entries of:
//
// `[1d_u32, 2d_f32, 3d_f32]`
//
// Then when we compile a `getResource<T>(i)` call, we will have created the storage buffer,
// call it `metadata` in this case:
//
// ```
// const len = metadata.array_length;
// if (i < len && type_to_u32(T) == metadata.bindings[i]) {
// return bindings[i];
// }
// return bindings[len + index_in_binding_order(T)];
// ```
//
std::vector<ResourceType> default_binding_type_order;
TINT_REFLECT(ResourceTableConfig,
resource_table_binding,
storage_buffer_binding,
default_binding_type_order);
};
} // namespace tint
#endif // SRC_TINT_API_COMMON_RESOURCE_TABLE_CONFIG_H_

View File

@@ -0,0 +1,71 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_RESOURCE_TYPE_H_
#define SRC_TINT_API_COMMON_RESOURCE_TYPE_H_
#include "src/tint/utils/reflection.h"
namespace tint {
enum class ResourceType : uint32_t {
kEmpty,
kTexture1d_f32,
kTexture1d_i32,
kTexture1d_u32,
kTexture2d_f32,
kTexture2d_i32,
kTexture2d_u32,
kTexture2dArray_f32,
kTexture2dArray_i32,
kTexture2dArray_u32,
kTexture3d_f32,
kTexture3d_i32,
kTexture3d_u32,
kTextureCube_f32,
kTextureCube_i32,
kTextureCube_u32,
kTextureCubeArray_f32,
kTextureCubeArray_i32,
kTextureCubeArray_u32,
kTextureMultisampled2d_f32,
kTextureMultisampled2d_i32,
kTextureMultisampled2d_u32,
kTextureDepth2d,
kTextureDepth2dArray,
kTextureDepthCube,
kTextureDepthCubeArray,
kTextureDepthMultisampled2d,
};
TINT_REFLECT_ENUM_RANGE(tint::ResourceType, kEmpty, kTextureDepthMultisampled2d);
} // namespace tint
#endif // SRC_TINT_API_COMMON_RESOURCE_TYPE_H_

View File

@@ -0,0 +1,113 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_SUBGROUP_MATRIX_H_
#define SRC_TINT_API_COMMON_SUBGROUP_MATRIX_H_
#include <unordered_set>
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/reflection.h"
namespace tint {
enum class SubgroupMatrixType : uint8_t {
kF16 = 0,
kF32,
kU8,
kI8,
kU32,
kI32,
};
TINT_REFLECT_ENUM_RANGE(tint::SubgroupMatrixType, kF16, kI32);
struct SubgroupMatrixMultiply {
uint32_t M;
uint32_t N;
uint32_t K;
SubgroupMatrixType input_type;
SubgroupMatrixType output_type;
TINT_REFLECT(SubgroupMatrixMultiply, M, N, K, input_type, output_type);
TINT_REFLECT_EQUALS(SubgroupMatrixMultiply);
TINT_REFLECT_HASH_CODE(SubgroupMatrixMultiply);
};
enum class SubgroupMatrixDirection : uint8_t {
kLeft,
kRight,
kResult,
};
TINT_REFLECT_ENUM_RANGE(tint::SubgroupMatrixDirection, kLeft, kResult);
struct SubgroupMatrixConfig {
uint32_t M;
uint32_t N;
uint32_t K;
SubgroupMatrixType type;
SubgroupMatrixDirection direction;
TINT_REFLECT(SubgroupMatrixConfig, M, N, K, type, direction);
TINT_REFLECT_EQUALS(SubgroupMatrixConfig);
TINT_REFLECT_HASH_CODE(SubgroupMatrixConfig);
};
} // namespace tint
template <>
class std::hash<tint::SubgroupMatrixMultiply> {
public:
inline std::size_t operator()(const tint::SubgroupMatrixMultiply& sm) const {
return tint::Hash(sm.M, sm.N, sm.K, sm.input_type, sm.output_type);
}
};
template <>
class std::hash<tint::SubgroupMatrixConfig> {
public:
inline std::size_t operator()(const tint::SubgroupMatrixConfig sm) const {
return tint::Hash(sm.M, sm.N, sm.K, sm.type, sm.direction);
}
};
namespace tint {
struct SubgroupMatrixInfo {
std::unordered_set<SubgroupMatrixMultiply> multiplies;
std::unordered_set<SubgroupMatrixConfig> configs;
TINT_REFLECT(SubgroupMatrixInfo, multiplies, configs);
TINT_REFLECT_EQUALS(SubgroupMatrixInfo);
TINT_REFLECT_HASH_CODE(SubgroupMatrixInfo);
};
} // namespace tint
#endif // SRC_TINT_API_COMMON_SUBGROUP_MATRIX_H_

View File

@@ -0,0 +1,53 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_SUBSTITUTE_OVERRIDES_CONFIG_H_
#define SRC_TINT_API_COMMON_SUBSTITUTE_OVERRIDES_CONFIG_H_
#include <unordered_map>
#include "src/tint/api/common/override_id.h"
#include "src/tint/utils/reflection.h"
namespace tint {
/// Configuration options for the transform
struct SubstituteOverridesConfig {
/// The map of override identifier to the override value.
/// The value is always a double coming into the transform and will be
/// converted to the correct type through and initializer.
std::unordered_map<OverrideId, double> map;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(SubstituteOverridesConfig, map);
TINT_REFLECT_EQUALS(SubstituteOverridesConfig);
TINT_REFLECT_HASH_CODE(SubstituteOverridesConfig);
};
} // namespace tint
#endif // SRC_TINT_API_COMMON_SUBSTITUTE_OVERRIDES_CONFIG_H_

View File

@@ -0,0 +1,44 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/api/common/vertex_pulling_config.h"
#include <utility>
namespace tint {
VertexBufferLayoutDescriptor::VertexBufferLayoutDescriptor() = default;
VertexBufferLayoutDescriptor::VertexBufferLayoutDescriptor(
uint32_t in_array_stride,
VertexStepMode in_step_mode,
std::vector<VertexAttributeDescriptor> in_attributes)
: array_stride(in_array_stride),
step_mode(in_step_mode),
attributes(std::move(in_attributes)) {}
} // namespace tint

View File

@@ -0,0 +1,148 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_COMMON_VERTEX_PULLING_CONFIG_H_
#define SRC_TINT_API_COMMON_VERTEX_PULLING_CONFIG_H_
#include <cstdint>
#include <vector>
#include "src/tint/utils/reflection.h"
namespace tint {
/// Describes the format of data in a vertex buffer.
enum class VertexFormat : uint8_t {
kUint8, // uint8
kUint8x2, // uint8x2
kUint8x4, // uint8x4
kSint8, // sint8
kSint8x2, // sint8x2
kSint8x4, // sint8x4
kUnorm8, // unorm8
kUnorm8x2, // unorm8x2
kUnorm8x4, // unorm8x4
kSnorm8, // snorm8
kSnorm8x2, // snorm8x2
kSnorm8x4, // snorm8x4
kUint16, // uint16
kUint16x2, // uint16x2
kUint16x4, // uint16x4
kSint16, // sint16
kSint16x2, // sint16x2
kSint16x4, // sint16x4
kUnorm16, // unorm16
kUnorm16x2, // unorm16x2
kUnorm16x4, // unorm16x4
kSnorm16, // snorm16
kSnorm16x2, // snorm16x2
kSnorm16x4, // snorm16x4
kFloat16, // float16
kFloat16x2, // float16x2
kFloat16x4, // float16x4
kFloat32, // float32
kFloat32x2, // float32x2
kFloat32x3, // float32x3
kFloat32x4, // float32x4
kUint32, // uint32
kUint32x2, // uint32x2
kUint32x3, // uint32x3
kUint32x4, // uint32x4
kSint32, // sint32
kSint32x2, // sint32x2
kSint32x3, // sint32x3
kSint32x4, // sint32x4
kUnorm10_10_10_2, // unorm10-10-10-2
kUnorm8x4BGRA, // unorm8x4-bgra
};
/// Describes if a vertex attribute increments with vertex index or instance index.
enum class VertexStepMode : uint8_t { kVertex, kInstance };
/// Describes a vertex attribute within a buffer
struct VertexAttributeDescriptor {
/// The format of the attribute.
VertexFormat format;
/// The byte offset of the attribute in the buffer.
uint32_t offset;
/// The shader location used for the attribute.
uint32_t shader_location;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(VertexAttributeDescriptor, format, offset, shader_location);
TINT_REFLECT_EQUALS(VertexAttributeDescriptor);
TINT_REFLECT_HASH_CODE(VertexAttributeDescriptor);
};
/// Describes a buffer containing multiple vertex attributes
struct VertexBufferLayoutDescriptor {
/// Constructor
VertexBufferLayoutDescriptor();
/// Constructor
/// @param in_array_stride the array stride in bytes of the in buffer
/// @param in_step_mode the step mode of the in buffer
/// @param in_attributes the in attributes
VertexBufferLayoutDescriptor(uint32_t in_array_stride,
VertexStepMode in_step_mode,
std::vector<VertexAttributeDescriptor> in_attributes);
/// The array stride in bytes used in the in buffer.
uint32_t array_stride = 0u;
/// The input step mode used.
VertexStepMode step_mode = VertexStepMode::kVertex;
/// The vertex attributes.
std::vector<VertexAttributeDescriptor> attributes;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(VertexBufferLayoutDescriptor, array_stride, step_mode, attributes);
TINT_REFLECT_EQUALS(VertexBufferLayoutDescriptor);
TINT_REFLECT_HASH_CODE(VertexBufferLayoutDescriptor);
};
/// Configuration options that control the vertex pulling transform.
struct VertexPullingConfig {
/// The vertex state descriptor, containing info about attributes.
std::vector<VertexBufferLayoutDescriptor> vertex_state;
/// The "group" we will put all our vertex buffers into (as storage buffers).
/// Default to 4 as it is past the limits of user-accessible groups.
uint32_t pulling_group = 4u;
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(VertexPullingConfig, vertex_state, pulling_group);
TINT_REFLECT_EQUALS(VertexPullingConfig);
TINT_REFLECT_HASH_CODE(VertexPullingConfig);
};
/// Reflection for VertexFormat.
TINT_REFLECT_ENUM_RANGE(tint::VertexFormat, kUint8x2, kUnorm8x4BGRA);
/// Reflection for VertexStepMode.
TINT_REFLECT_ENUM_RANGE(tint::VertexStepMode, kVertex, kInstance);
} // namespace tint
#endif // SRC_TINT_API_COMMON_VERTEX_PULLING_CONFIG_H_

View File

@@ -0,0 +1,174 @@
/// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/api/helpers/generate_bindings.h"
#include <algorithm>
#include <iostream>
#include "src/tint/api/common/binding_point.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/referenced_module_vars.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/external_texture.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/storage_texture.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint {
Bindings GenerateBindings(const core::ir::Module& module,
const std::string& ep,
bool set_group_to_zero,
bool flatten_bindings) {
Bindings bindings{};
uint32_t next_buffer_idx = 0;
uint32_t next_sampler_idx = 0;
uint32_t next_texture_idx = 0;
// Collect next valid binding number per group
Hashmap<uint32_t, uint32_t, 4> group_to_next_binding_number;
Vector<tint::BindingPoint, 4> ext_tex_bps;
core::ir::Function* ep_func = nullptr;
for (auto* f : module.functions) {
if (!f->IsEntryPoint()) {
continue;
}
if (module.NameOf(f).NameView() == ep) {
ep_func = f;
break;
}
}
// No entrypoint, so no bindings needed
if (!ep_func) {
return bindings;
}
core::ir::ReferencedModuleVars<const core::ir::Module> referenced_module_vars{module};
auto& refs = referenced_module_vars.TransitiveReferences(ep_func);
for (auto* var : refs) {
auto bp = var->BindingPoint();
if (!bp.has_value()) {
continue;
}
if (auto val = group_to_next_binding_number.Get(bp->group)) {
*val = std::max(*val, bp->binding + 1);
} else {
group_to_next_binding_number.Add(bp->group, bp->binding + 1);
}
auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
// Store up the external textures, we'll add them in the next step
if (ptr->StoreType()->Is<core::type::ExternalTexture>()) {
ext_tex_bps.Push(*bp);
continue;
}
switch (ptr->AddressSpace()) {
case core::AddressSpace::kHandle:
Switch(
ptr->StoreType(), //
[&](const core::type::Sampler*) {
tint::BindingPoint info{
.group = set_group_to_zero ? 0 : bp->group,
.binding = flatten_bindings ? next_sampler_idx++ : bp->binding,
};
bindings.sampler.emplace(*bp, info);
},
[&](const core::type::StorageTexture*) {
tint::BindingPoint info{
.group = set_group_to_zero ? 0 : bp->group,
.binding = flatten_bindings ? next_texture_idx++ : bp->binding,
};
bindings.storage_texture.emplace(*bp, info);
},
[&](const core::type::Texture*) {
tint::BindingPoint info{
.group = set_group_to_zero ? 0 : bp->group,
.binding = flatten_bindings ? next_texture_idx++ : bp->binding,
};
bindings.texture.emplace(*bp, info);
});
break;
case core::AddressSpace::kStorage: {
tint::BindingPoint info{
.group = set_group_to_zero ? 0 : bp->group,
.binding = flatten_bindings ? next_buffer_idx++ : bp->binding,
};
bindings.storage.emplace(*bp, info);
break;
}
case core::AddressSpace::kUniform: {
tint::BindingPoint info{
.group = set_group_to_zero ? 0 : bp->group,
.binding = flatten_bindings ? next_buffer_idx++ : bp->binding,
};
bindings.uniform.emplace(*bp, info);
break;
}
case core::AddressSpace::kUndefined:
case core::AddressSpace::kPixelLocal:
case core::AddressSpace::kPrivate:
case core::AddressSpace::kImmediate:
case core::AddressSpace::kIn:
case core::AddressSpace::kOut:
case core::AddressSpace::kFunction:
case core::AddressSpace::kWorkgroup:
break;
}
}
if (flatten_bindings) {
for (auto bp : ext_tex_bps) {
uint32_t g = set_group_to_zero ? 0 : bp.group;
tint::BindingPoint plane0{.group = g, .binding = next_texture_idx++};
tint::BindingPoint plane1{.group = g, .binding = next_texture_idx++};
tint::BindingPoint metadata{.group = g, .binding = next_buffer_idx++};
bindings.external_texture.emplace(bp, ExternalTexture{metadata, plane0, plane1});
}
} else {
for (auto bp : ext_tex_bps) {
uint32_t& next_num = group_to_next_binding_number.GetOrAddZero(bp.group);
uint32_t g = set_group_to_zero ? 0 : bp.group;
tint::BindingPoint plane0{.group = g, .binding = bp.binding};
tint::BindingPoint plane1{.group = g, .binding = next_num++};
tint::BindingPoint metadata{.group = g, .binding = next_num++};
bindings.external_texture.emplace(bp, ExternalTexture{metadata, plane0, plane1});
}
}
return bindings;
}
} // namespace tint

View File

@@ -0,0 +1,54 @@
/// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_HELPERS_GENERATE_BINDINGS_H_
#define SRC_TINT_API_HELPERS_GENERATE_BINDINGS_H_
#include <string>
#include "src/tint/api/common/bindings.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint {
/// Generate the resource bindings
/// @param module the module to generate from
/// @param set_group_to_zero if true, the group used for bindings will always be zero
/// @param flatten_bindings if true, the bindings will remap to count from 0
/// @returns the bindings
Bindings GenerateBindings(const core::ir::Module& module,
const std::string& ep,
bool set_group_to_zero,
bool flatten_bindings);
} // namespace tint
#endif // SRC_TINT_API_HELPERS_GENERATE_BINDINGS_H_

116
3rdparty/dawn/src/tint/api/tint.cc vendored Normal file
View File

@@ -0,0 +1,116 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/api/tint.h"
////////////////////////////////////////////////////////////////////////////////
// The following includes are used by './tools/run gen' to add an implicit
// dependency from 'tint/api' to the libraries used to make up the Tint API.
////////////////////////////////////////////////////////////////////////////////
// IWYU pragma: begin_keep
#include "src/tint/api/common/override_id.h"
#if TINT_BUILD_GLSL_WRITER
#include "src/tint/lang/glsl/writer/writer.h" // nogncheck
#endif
#if TINT_BUILD_HLSL_WRITER
#include "src/tint/lang/hlsl/writer/writer.h" // nogncheck
#endif
#if TINT_BUILD_MSL_WRITER
#include "src/tint/lang/msl/writer/writer.h" // nogncheck
#endif
#if TINT_BUILD_SPV_READER
#include "src/tint/lang/spirv/reader/reader.h" // nogncheck
#endif
#if TINT_BUILD_SPV_WRITER
#include "src/tint/lang/spirv/writer/writer.h" // nogncheck
#endif
#if TINT_BUILD_WGSL_READER
#include "src/tint/lang/wgsl/inspector/inspector.h" // nogncheck
#include "src/tint/lang/wgsl/reader/reader.h" // nogncheck
#endif
#if TINT_BUILD_WGSL_WRITER
#include "src/tint/lang/wgsl/program/program.h"
#include "src/tint/lang/wgsl/writer/writer.h" // nogncheck
#endif
#if TINT_BUILD_NULL_WRITER
#include "src/tint/lang/null/writer/writer.h" // nogncheck
#endif
// IWYU pragma: end_keep
#if TINT_BUILD_SPV_READER && TINT_BUILD_WGSL_WRITER
#include "src/tint/lang/core/ir/module.h"
#endif
namespace tint {
/// Initialize initializes the Tint library. Call before using the Tint API.
void Initialize() {
#if TINT_BUILD_WGSL_WRITER
// Register the Program printer. This is used for debugging purposes.
tint::Program::printer = [](const tint::Program& program) {
auto result = wgsl::writer::Generate(program);
if (result != Success) {
return result.Failure().reason;
}
return result->wgsl;
};
#endif
}
/// Shutdown uninitializes the Tint library. Call after using the Tint API.
void Shutdown() {
// Currently no-op, but may release tint resources in the future.
}
Result<std::string> SpirvToWgsl([[maybe_unused]] const std::vector<uint32_t>& spirv,
[[maybe_unused]] const wgsl::writer::Options& wgsl_options) {
#if !TINT_BUILD_SPV_READER
return Failure{"Tint SPIR-V reader is not enabled"};
#elif !TINT_BUILD_WGSL_WRITER
return Failure{"Tint WGSL writer is not enabled"};
#else
// Convert the SPIR-V program to an IR module.
TINT_CHECK_RESULT_UNWRAP(ir_from_spirv, tint::spirv::reader::ReadIR(spirv));
// Convert the IR module to WGSL.
TINT_CHECK_RESULT_UNWRAP(wgsl_from_ir,
tint::wgsl::writer::WgslFromIR(ir_from_spirv, wgsl_options));
return wgsl_from_ir.wgsl;
#endif // TINT_BUILD_SPV_READER && TINT_BUILD_WGSL_WRITER
}
} // namespace tint

55
3rdparty/dawn/src/tint/api/tint.h vendored Normal file
View File

@@ -0,0 +1,55 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_API_TINT_H_
#define SRC_TINT_API_TINT_H_
#include <cstdint>
#include <string>
#include <vector>
#include "src/tint/lang/wgsl/writer/common/options.h"
#include "src/tint/utils/result.h"
namespace tint {
/// Initialize initializes the Tint library. Call before using the Tint API.
void Initialize();
/// Shutdown uninitializes the Tint library. Call after using the Tint API.
void Shutdown();
/// Convert a SPIR-V binary to a WGSL shader module string.
/// @param spirv the SPIR-V binary
/// @param wgsl_options the options to use for generating WGSL
/// @returns the WGSL module, or a failure
tint::Result<std::string> SpirvToWgsl(const std::vector<uint32_t>& spirv,
const wgsl::writer::Options& wgsl_options = {});
} // namespace tint
#endif // SRC_TINT_API_TINT_H_

View File

@@ -0,0 +1,74 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/binary_op.h"
namespace tint::core {
std::string_view ToString(BinaryOp value) {
switch (value) {
case BinaryOp::kAnd:
return "&";
case BinaryOp::kOr:
return "|";
case BinaryOp::kXor:
return "^";
case BinaryOp::kLogicalAnd:
return "&&";
case BinaryOp::kLogicalOr:
return "||";
case BinaryOp::kEqual:
return "==";
case BinaryOp::kNotEqual:
return "!=";
case BinaryOp::kLessThan:
return "<";
case BinaryOp::kGreaterThan:
return ">";
case BinaryOp::kLessThanEqual:
return "<=";
case BinaryOp::kGreaterThanEqual:
return ">=";
case BinaryOp::kShiftLeft:
return "<<";
case BinaryOp::kShiftRight:
return ">>";
case BinaryOp::kAdd:
return "+";
case BinaryOp::kSubtract:
return "-";
case BinaryOp::kMultiply:
return "*";
case BinaryOp::kDivide:
return "/";
case BinaryOp::kModulo:
return "%";
}
return "<unknown>";
}
} // namespace tint::core

View File

@@ -0,0 +1,72 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_BINARY_OP_H_
#define SRC_TINT_LANG_CORE_BINARY_OP_H_
#include "src/tint/utils/rtti/traits.h"
namespace tint::core {
/// An enumerator of binary operators.
enum class BinaryOp {
kAnd, // &
kOr, // |
kXor,
kLogicalAnd, // &&
kLogicalOr, // ||
kEqual,
kNotEqual,
kLessThan,
kGreaterThan,
kLessThanEqual,
kGreaterThanEqual,
kShiftLeft,
kShiftRight,
kAdd,
kSubtract,
kMultiply,
kDivide,
kModulo,
};
/// @param value the enum value
/// @returns the string for the given enum value
std::string_view ToString(BinaryOp value);
/// @param out the stream to write to
/// @param value the BinaryOp
/// @returns @p out so calls can be chained
template <typename STREAM>
requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& out, BinaryOp value) {
return out << ToString(value);
}
} // namespace tint::core
#endif // SRC_TINT_LANG_CORE_BINARY_OP_H_

View File

@@ -0,0 +1,51 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_CLONE_CONTEXT_H_
#define SRC_TINT_LANG_CORE_CONSTANT_CLONE_CONTEXT_H_
#include "src/tint/lang/core/type/clone_context.h"
// Forward declarations
namespace tint::core::constant {
class Manager;
} // namespace tint::core::constant
namespace tint::core::constant {
/// Context information for cloning of constants
struct CloneContext {
/// The context for cloning type information
core::type::CloneContext type_ctx;
/// Destination information
constant::Manager& dst;
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_CLONE_CONTEXT_H_

View File

@@ -0,0 +1,58 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/composite.h"
#include <utility>
#include "src/tint/lang/core/constant/manager.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Composite);
namespace tint::core::constant {
Composite::Composite(const core::type::Type* t, VectorRef<const Value*> els, bool all_0, bool any_0)
: type(t), elements(std::move(els)), all_zero(all_0), any_zero(any_0), hash(CalcHash()) {
const size_t n = elements.Length();
TINT_ASSERT(n == t->Elements().count);
for (size_t i = 0; i < n; i++) {
TINT_ASSERT(t->Element(static_cast<uint32_t>(i)) == elements[i]->Type());
}
}
Composite::~Composite() = default;
const Composite* Composite::Clone(CloneContext& ctx) const {
auto* ty = type->Clone(ctx.type_ctx);
Vector<const Value*, 4> els;
for (const auto* el : elements) {
els.Push(el->Clone(ctx));
}
return ctx.dst.Get<Composite>(ty, std::move(els), all_zero, any_zero);
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,106 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_COMPOSITE_H_
#define SRC_TINT_LANG_CORE_CONSTANT_COMPOSITE_H_
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// Composite holds a number of mixed child values.
/// Composite may be of a vector, matrix, array or structure type.
/// If each element is the same type and value, then a Splat would be a more efficient constant
/// implementation. Use CreateComposite() to create the appropriate type.
class Composite : public Castable<Composite, Value> {
public:
/// Constructor
/// @param t the compsite type
/// @param els the composite elements
/// @param all_0 true if all elements are 0
/// @param any_0 true if any element is 0
Composite(const core::type::Type* t, VectorRef<const Value*> els, bool all_0, bool any_0);
~Composite() override;
/// @copydoc Value::Type()
const core::type::Type* Type() const override { return type; }
/// @copydoc Value::Index()
const Value* Index(size_t i) const override {
return i < elements.Length() ? elements[i] : nullptr;
}
/// @copydoc Value::NumElements()
size_t NumElements() const override { return elements.Length(); }
/// @copydoc Value::AllZero()
bool AllZero() const override { return all_zero; }
/// @copydoc Value::AnyZero()
bool AnyZero() const override { return any_zero; }
/// @copydoc Value::Hash()
HashCode Hash() const override { return hash; }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
const Composite* Clone(CloneContext& ctx) const override;
/// The composite type
core::type::Type const* const type;
/// The composite elements
const Vector<const Value*, 4> elements;
/// True if all elements are zero
const bool all_zero;
/// True if any element is zero
const bool any_zero;
/// The hash of the composite
const HashCode hash;
protected:
/// @copydoc Value::InternalValue()
std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }
private:
HashCode CalcHash() {
auto h = tint::Hash(type, all_zero, any_zero);
for (auto* el : elements) {
h = HashCombine(h, el->Hash());
}
return h;
}
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_COMPOSITE_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,45 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/invalid.h"
#include "src/tint/lang/core/constant/manager.h"
#include "src/tint/lang/core/type/invalid.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Invalid);
namespace tint::core::constant {
Invalid::Invalid(const core::type::Invalid* ty) : type(ty) {}
Invalid::~Invalid() = default;
const Invalid* Invalid::Clone(CloneContext& ctx) const {
return ctx.dst.Invalid();
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,81 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_INVALID_H_
#define SRC_TINT_LANG_CORE_CONSTANT_INVALID_H_
#include <variant>
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/invalid.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// Invalid represents an invalid constant, used as a placeholder in a failed parse / resolve.
class Invalid : public Castable<Invalid, Value> {
public:
/// Constructor
/// @param ty the Invalid type
explicit Invalid(const core::type::Invalid* ty);
~Invalid() override;
/// @returns the type of the Invalid
const core::type::Type* Type() const override { return type; }
/// Retrieve item at index @p i
/// @param i the index to retrieve
/// @returns the element, or nullptr if out of bounds
const Value* Index([[maybe_unused]] size_t i) const override { return nullptr; }
/// @copydoc Value::NumElements()
size_t NumElements() const override { return 0; }
/// @returns true if the element is zero
bool AllZero() const override { return false; }
/// @returns true if the element is zero
bool AnyZero() const override { return false; }
/// @returns the hash for the Invalid
HashCode Hash() const override { return tint::Hash(type); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
const Invalid* Clone(CloneContext& ctx) const override;
/// The Invalid type
core::type::Invalid const* const type;
protected:
/// @returns a monostate variant.
std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_INVALID_H_

View File

@@ -0,0 +1,197 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/manager.h"
#include "src/tint/lang/core/constant/composite.h"
#include "src/tint/lang/core/constant/invalid.h"
#include "src/tint/lang/core/constant/scalar.h"
#include "src/tint/lang/core/constant/splat.h"
#include "src/tint/lang/core/constant/string.h"
#include "src/tint/lang/core/type/abstract_float.h"
#include "src/tint/lang/core/type/abstract_int.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/bool.h"
#include "src/tint/lang/core/type/f16.h"
#include "src/tint/lang/core/type/f32.h"
#include "src/tint/lang/core/type/i32.h"
#include "src/tint/lang/core/type/i8.h"
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/lang/core/type/matrix.h"
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/lang/core/type/u64.h"
#include "src/tint/lang/core/type/u8.h"
#include "src/tint/lang/core/type/vector.h"
#include "src/tint/utils/containers/predicates.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::core::constant {
Manager::Manager() = default;
Manager::Manager(Manager&&) = default;
Manager& Manager::operator=(Manager&& rhs) = default;
Manager::~Manager() = default;
const constant::Value* Manager::Composite(const core::type::Type* type,
VectorRef<const constant::Value*> elements) {
if (elements.IsEmpty()) {
return nullptr;
}
bool any_zero = false;
bool all_zero = true;
bool all_equal = true;
auto* first = elements.Front();
for (auto* el : elements) {
if (DAWN_UNLIKELY(!el)) {
return nullptr;
}
if (!any_zero && el->AnyZero()) {
any_zero = true;
}
if (all_zero && !el->AllZero()) {
all_zero = false;
}
if (all_equal && el != first) {
all_equal = false;
}
}
if (all_equal) {
return Splat(type, elements.Front());
}
return Get<constant::Composite>(type, std::move(elements), all_zero, any_zero);
}
const constant::Splat* Manager::Splat(const core::type::Type* type,
const constant::Value* element) {
return Get<constant::Splat>(type, element);
}
const Scalar<i32>* Manager::Get(i32 value) {
return Get<Scalar<i32>>(types.i32(), value);
}
const Scalar<u32>* Manager::Get(u32 value) {
return Get<Scalar<u32>>(types.u32(), value);
}
const Scalar<u64>* Manager::Get(u64 value) {
return Get<Scalar<u64>>(types.u64(), value);
}
const Scalar<i8>* Manager::Get(i8 value) {
return Get<Scalar<i8>>(types.i8(), value);
}
const Scalar<u8>* Manager::Get(u8 value) {
return Get<Scalar<u8>>(types.u8(), value);
}
const Scalar<f32>* Manager::Get(f32 value) {
return Get<Scalar<f32>>(types.f32(), value);
}
const Scalar<f16>* Manager::Get(f16 value) {
return Get<Scalar<f16>>(types.f16(), value);
}
const Scalar<bool>* Manager::Get(bool value) {
return Get<Scalar<bool>>(types.bool_(), value);
}
const Scalar<AFloat>* Manager::Get(AFloat value) {
return Get<Scalar<AFloat>>(types.AFloat(), value);
}
const Scalar<AInt>* Manager::Get(AInt value) {
return Get<Scalar<AInt>>(types.AInt(), value);
}
const constant::String* Manager::Get(std::string_view value) {
return Get<String>(types.String(), value);
}
const Value* Manager::Zero(const core::type::Type* type) {
return Switch(
type, //
[&](const core::type::Vector* v) -> const Value* {
auto* zero_el = Zero(v->Type());
return Splat(type, zero_el);
},
[&](const core::type::Matrix* m) -> const Value* {
auto* zero_el = Zero(m->ColumnType());
return Splat(type, zero_el);
},
[&](const core::type::Array* a) -> const Value* {
if (a->ConstantCount()) {
if (auto* zero_el = Zero(a->ElemType())) {
return Splat(type, zero_el);
}
}
return nullptr;
},
[&](const core::type::Struct* s) -> const Value* {
Hashmap<const core::type::Type*, const Value*, 8> zero_by_type;
Vector<const Value*, 4> zeros;
zeros.Reserve(s->Members().Length());
for (auto* member : s->Members()) {
auto* zero =
zero_by_type.GetOrAdd(member->Type(), [&] { return Zero(member->Type()); });
if (!zero) {
return nullptr;
}
zeros.Push(zero);
}
if (zero_by_type.Count() == 1) {
// All members were of the same type, so the zero value is the same for all members.
return Splat(type, zeros[0]);
}
return Composite(s, std::move(zeros));
},
[&](const core::type::AbstractInt*) { return Get(AInt(0)); }, //
[&](const core::type::AbstractFloat*) { return Get(AFloat(0)); }, //
[&](const core::type::I32*) { return Get(i32(0)); }, //
[&](const core::type::U32*) { return Get(u32(0)); }, //
[&](const core::type::I8*) { return Get(i8(0)); }, //
[&](const core::type::U8*) { return Get(u8(0)); }, //
[&](const core::type::U64*) { return Get(u64(0)); }, //
[&](const core::type::F32*) { return Get(f32(0)); }, //
[&](const core::type::F16*) { return Get(f16(0)); }, //
[&](const core::type::Bool*) { return Get(false); }, //
[&](const core::type::Invalid*) { return Invalid(); }, //
TINT_ICE_ON_NO_MATCH);
}
const constant::Invalid* Manager::Invalid() {
return values_.Get<constant::Invalid>(types.invalid());
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,181 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_MANAGER_H_
#define SRC_TINT_LANG_CORE_CONSTANT_MANAGER_H_
#include <utility>
#include "src/tint/lang/core/constant/invalid.h"
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/utils/containers/unique_allocator.h"
#include "src/tint/utils/math/hash.h"
namespace tint::core::constant {
class Splat;
class String;
template <typename T>
class Scalar;
} // namespace tint::core::constant
namespace tint::core::constant {
/// The constant manager holds a type manager and all the pointers to the known constant values.
class Manager final {
public:
/// Iterator is the type returned by begin() and end()
using TypeIterator = BlockAllocator<Value>::ConstIterator;
/// Constructor
Manager();
/// Move constructor
Manager(Manager&&);
/// Move assignment operator
/// @param rhs the Manager to move
/// @return this Manager
Manager& operator=(Manager&& rhs);
/// Destructor
~Manager();
/// @param args the arguments used to construct the type, unique node or node.
/// @return a pointer to an instance of `T` with the provided arguments.
/// If NODE derives from UniqueNode and an existing instance of `T` has been
/// constructed, then the same pointer is returned.
template <typename NODE, typename... ARGS>
NODE* Get(ARGS&&... args) {
return values_.Get<NODE>(std::forward<ARGS>(args)...);
}
/// @returns an iterator to the beginning of the types
TypeIterator begin() const { return values_.begin(); }
/// @returns an iterator to the end of the types
TypeIterator end() const { return values_.end(); }
/// Constructs a constant of a vector, matrix or array type.
///
/// Examines the element values and will return either a constant::Composite or a
/// constant::Splat, depending on the element types and values.
///
/// @param type the composite type
/// @param elements the composite elements
/// @returns the value pointer
const constant::Value* Composite(const core::type::Type* type,
VectorRef<const constant::Value*> elements);
/// Constructs a splat constant.
/// @param type the splat type
/// @param element the splat element
/// @returns the value pointer
const constant::Splat* Splat(const core::type::Type* type, const constant::Value* element);
/// @param value the constant value
/// @return a Scalar holding the i32 value @p value
const Scalar<i32>* Get(i32 value);
/// @param value the constant value
/// @return a Scalar holding the u32 value @p value
const Scalar<u32>* Get(u32 value);
/// @param value the constant value
/// @return a Scalar holding the u64 value @p value
const Scalar<u64>* Get(u64 value);
/// @param value the constant value
/// @return a Scalar holding the i8 value @p value
const Scalar<i8>* Get(i8 value);
/// @param value the constant value
/// @return a Scalar holding the u8 value @p value
const Scalar<u8>* Get(u8 value);
/// @param value the constant value
/// @return a Scalar holding the f32 value @p value
const Scalar<f32>* Get(f32 value);
/// @param value the constant value
/// @return a Scalar holding the f16 value @p value
const Scalar<f16>* Get(f16 value);
/// @param value the constant value
/// @return a Scalar holding the bool value @p value
const Scalar<bool>* Get(bool value);
/// @param value the constant value
/// @return a Scalar holding the AFloat value @p value
const Scalar<AFloat>* Get(AFloat value);
/// @param value the constant value
/// @return a Scalar holding the AInt value @p value
const Scalar<AInt>* Get(AInt value);
/// @param value the string value
/// @return a String holding the value @p value
const String* Get(std::string_view value);
/// Constructs a constant zero-value of the type @p type.
/// @param type the constant type
/// @returns a constant zero-value for the type
const Value* Zero(const core::type::Type* type);
/// Constructs an invalid constant
/// @returns an invalid constant
const constant::Invalid* Invalid();
/// The type manager
core::type::Manager types;
private:
/// A specialization of Hasher for constant::Value
struct Hasher {
/// @param value the value to hash
/// @returns a hash of the value
HashCode operator()(const constant::Value& value) const { return value.Hash(); }
};
/// An equality helper for constant::Value
struct Equal {
/// @param a the LHS value
/// @param b the RHS value
/// @returns true if the two constants are equal
bool operator()(const constant::Value& a, const constant::Value& b) const {
return a.Equal(&b);
}
};
/// Unique types owned by the manager
UniqueAllocator<Value, Hasher, Equal> values_;
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_MANAGER_H_

View File

@@ -0,0 +1,40 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/node.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Node);
namespace tint::core::constant {
Node::Node() = default;
Node::Node(const Node&) = default;
Node::~Node() = default;
} // namespace tint::core::constant

View File

@@ -0,0 +1,50 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_NODE_H_
#define SRC_TINT_LANG_CORE_CONSTANT_NODE_H_
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// Node is the base class for all constant nodes
class Node : public Castable<Node> {
public:
/// Constructor
Node();
/// Copy constructor
Node(const Node&);
/// Destructor
~Node() override;
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_NODE_H_

View File

@@ -0,0 +1,46 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/scalar.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::ScalarBase);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::AInt>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::AFloat>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::i32>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::i8>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::u32>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::u64>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::u8>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::f16>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<tint::core::f32>);
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Scalar<bool>);
namespace tint::core::constant {
ScalarBase::~ScalarBase() = default;
}

View File

@@ -0,0 +1,125 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_SCALAR_H_
#define SRC_TINT_LANG_CORE_CONSTANT_SCALAR_H_
#include "src/tint/lang/core/constant/manager.h"
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// ScalarBase is the base class of all Scalar<T> specializations.
/// Used for querying whether a value is a scalar type.
class ScalarBase : public Castable<ScalarBase, Value> {
public:
~ScalarBase() override;
};
/// Scalar holds a single scalar or abstract-numeric value.
template <typename T>
class Scalar : public Castable<Scalar<T>, ScalarBase> {
public:
static_assert(!std::is_same_v<UnwrapNumber<T>, T> || std::is_same_v<T, bool>,
"T must be a Number or bool");
/// Constructor
/// @param t the scalar type
/// @param v the scalar value
Scalar(const core::type::Type* t, T v) : type(t), value(v) {
if constexpr (IsFloatingPoint<T>) {
TINT_ASSERT(std::isfinite(v.value));
}
}
~Scalar() override = default;
/// @copydoc Value::Type()
const core::type::Type* Type() const override { return type; }
/// @return nullptr, as Scalar does not hold any elements.
const Value* Index(size_t) const override { return nullptr; }
/// @copydoc Value::NumElements()
size_t NumElements() const override { return 1; }
/// @copydoc Value::AllZero()
bool AllZero() const override { return IsZero(); }
/// @copydoc Value::AnyZero()
bool AnyZero() const override { return IsZero(); }
/// @copydoc Value::Hash()
HashCode Hash() const override { return tint::Hash(type, ValueOf()); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
const Scalar* Clone(CloneContext& ctx) const override {
auto* ty = type->Clone(ctx.type_ctx);
return ctx.dst.Get<Scalar<T>>(ty, value);
}
/// @returns `value` if `T` is not a Number, otherwise ValueOf returns the inner value of the
/// Number.
inline auto ValueOf() const {
if constexpr (std::is_same_v<UnwrapNumber<T>, T>) {
return value;
} else {
return value.value;
}
}
/// @returns true if `value` is zero.
/// For floating point -0.0 equals 0.0, according to IEEE 754.
inline bool IsZero() const {
using N = UnwrapNumber<T>;
return Number<N>(value) == Number<N>(0);
}
/// The scalar type
core::type::Type const* const type;
/// The scalar value
const T value;
protected:
/// @copydoc Value::InternalValue()
std::variant<std::monostate, AInt, AFloat> InternalValue() const override {
if constexpr (IsFloatingPoint<UnwrapNumber<T>>) {
return static_cast<AFloat>(value);
} else {
return static_cast<AInt>(value);
}
}
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_SCALAR_H_

View File

@@ -0,0 +1,61 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/splat.h"
#include "src/tint/lang/core/constant/manager.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Splat);
namespace tint::core::constant {
namespace {
/// Asserts that the element type of @p in_type matches the type of @p value, and that the type has
/// at least one element.
/// @returns the number of elements in @p in_type
inline size_t GetCountAndAssertType(const core::type::Type* in_type, const constant::Value* value) {
auto elements = in_type->Elements();
TINT_ASSERT(!elements.type || elements.type == value->Type());
TINT_ASSERT(elements.count > 0);
return elements.count;
}
} // namespace
Splat::Splat(const core::type::Type* t, const constant::Value* e)
: type(t), el(e), count(GetCountAndAssertType(t, e)) {}
Splat::~Splat() = default;
const Splat* Splat::Clone(CloneContext& ctx) const {
auto* ty = type->Clone(ctx.type_ctx);
auto* element = el->Clone(ctx);
return ctx.dst.Splat(ty, element);
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,88 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_SPLAT_H_
#define SRC_TINT_LANG_CORE_CONSTANT_SPLAT_H_
#include "src/tint/lang/core/constant/composite.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// Splat holds a single value, duplicated as all children.
///
/// Splat is used for zero-initializers, 'splat' initializers, or initializers where each element is
/// identical. Splat may be of a vector, matrix, array or structure type.
class Splat : public Castable<Splat, Value> {
public:
/// Constructor
/// @param t the splat type
/// @param e the splat element
Splat(const core::type::Type* t, const Value* e);
~Splat() override;
/// @returns the type of the splat
const core::type::Type* Type() const override { return type; }
/// Retrieve item at index @p i
/// @param i the index to retrieve
/// @returns the element, or nullptr if out of bounds
const Value* Index(size_t i) const override { return i < count ? el : nullptr; }
/// @copydoc Value::NumElements()
size_t NumElements() const override { return count; }
/// @returns true if the element is zero
bool AllZero() const override { return el->AllZero(); }
/// @returns true if the element is zero
bool AnyZero() const override { return el->AnyZero(); }
/// @returns the hash for the splat
HashCode Hash() const override { return tint::Hash(type, el->Hash(), count); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
const Splat* Clone(CloneContext& ctx) const override;
/// The type of the splat element
core::type::Type const* const type;
/// The element stored in the splat
const Value* el;
/// The number of items in the splat
const size_t count;
protected:
/// @returns a monostate variant.
std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_SPLAT_H_

View File

@@ -0,0 +1,39 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/string.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::String);
namespace tint::core::constant {
const String* String::Clone(CloneContext& ctx) const {
auto* ty = type->Clone(ctx.type_ctx);
return ctx.dst.Get<String>(ty, value);
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,89 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_STRING_H_
#define SRC_TINT_LANG_CORE_CONSTANT_STRING_H_
#include <string>
#include "src/tint/lang/core/constant/manager.h"
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/type/string.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// String holds a constant string value.
class String : public Castable<constant::String, Value> {
public:
/// Constructor
/// @param t the scalar type
/// @param v the scalar value
String(const core::type::Type* t, std::string_view v) : type(t), value(v) {}
~String() override = default;
/// @copydoc Value::Type()
const core::type::Type* Type() const override { return type; }
/// @return nullptr, as String does not allow individual character access
const Value* Index(size_t) const override { return nullptr; }
/// @copydoc Value::NumElements()
size_t NumElements() const override { return 1; }
/// @copydoc Value::AllZero()
bool AllZero() const override { return false; }
/// @copydoc Value::AnyZero()
bool AnyZero() const override { return false; }
/// @copydoc Value::Hash()
HashCode Hash() const override { return tint::Hash(type, Value()); }
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
const String* Clone(CloneContext& ctx) const override;
/// @returns the string value
inline std::string_view Value() const { return value; }
/// The string type
core::type::Type const* const type;
/// The string value
const std::string value;
protected:
/// @copydoc Value::InternalValue()
std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_STRING_H_

View File

@@ -0,0 +1,114 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/constant/splat.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/invalid.h"
#include "src/tint/lang/core/type/matrix.h"
#include "src/tint/lang/core/type/struct.h"
#include "src/tint/lang/core/type/vector.h"
#include "src/tint/utils/rtti/switch.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::constant::Value);
namespace tint::core::constant {
Value::Value() = default;
Value::~Value() = default;
/// Equal returns true if the constants `a` and `b` are of the same type and value.
bool Value::Equal(const constant::Value* b) const {
if (this == b) {
return true;
}
if (Hash() != b->Hash()) {
return false;
}
if (Type() != b->Type()) {
return false;
}
auto elements_equal = [&](size_t count) {
if (count == 0) {
return true;
}
// Avoid per-element comparisons if the constants are splats
bool a_is_splat = Is<Splat>();
bool b_is_splat = b->Is<Splat>();
if (a_is_splat && b_is_splat) {
return Index(0)->Equal(b->Index(0));
}
if (a_is_splat) {
auto* el_a = Index(0);
for (size_t i = 0; i < count; i++) {
if (!el_a->Equal(b->Index(i))) {
return false;
}
}
return true;
}
if (b_is_splat) {
auto* el_b = b->Index(0);
for (size_t i = 0; i < count; i++) {
if (!Index(i)->Equal(el_b)) {
return false;
}
}
return true;
}
// Per-element comparison
for (size_t i = 0; i < count; i++) {
if (!Index(i)->Equal(b->Index(i))) {
return false;
}
}
return true;
};
return Switch(
Type(), //
[&](const core::type::Vector* vec) { return elements_equal(vec->Width()); },
[&](const core::type::Matrix* mat) { return elements_equal(mat->Columns()); },
[&](const core::type::Struct* str) { return elements_equal(str->Members().Length()); },
[&](const core::type::Array* arr) {
if (auto n = arr->ConstantCount()) {
return elements_equal(*n);
}
return false;
},
[&](const core::type::Invalid*) { return true; },
[&](Default) { return InternalValue() == b->InternalValue(); });
}
} // namespace tint::core::constant

View File

@@ -0,0 +1,106 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_CONSTANT_VALUE_H_
#define SRC_TINT_LANG_CORE_CONSTANT_VALUE_H_
#include <variant>
#include "src/tint/lang/core/constant/clone_context.h"
#include "src/tint/lang/core/constant/node.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::constant {
/// Value is the interface to a compile-time evaluated expression value.
class Value : public Castable<Value, Node> {
public:
/// Constructor
Value();
/// Destructor
~Value() override;
/// @returns the type of the value
virtual const core::type::Type* Type() const = 0;
/// @param i the index of the element
/// @returns the child element with the given index, or nullptr if there are no children, or
/// the index is out of bounds.
///
/// For arrays, this returns the i'th element of the array.
/// For vectors, this returns the i'th element of the vector.
/// For matrices, this returns the i'th column vector of the matrix.
/// For structures, this returns the i'th member field of the structure.
virtual const Value* Index(size_t i) const = 0;
/// @return the number of elements held by this Value
virtual size_t NumElements() const = 0;
/// @returns true if child elements are positive-zero valued.
virtual bool AllZero() const = 0;
/// @returns true if any child elements are positive-zero valued.
virtual bool AnyZero() const = 0;
/// @returns a hash of the value.
virtual HashCode Hash() const = 0;
/// @returns the value as the given scalar or abstract value.
template <typename T>
T ValueAs() const {
return std::visit(
[](auto v) {
if constexpr (std::is_same_v<decltype(v), std::monostate>) {
return T(0);
} else {
return static_cast<T>(v);
}
},
InternalValue());
}
/// @param b the value to compare too
/// @returns true if this value is equal to @p b
bool Equal(const Value* b) const;
/// Clones the constant into the provided context
/// @param ctx the clone context
/// @returns the cloned node
virtual const Value* Clone(CloneContext& ctx) const = 0;
protected:
/// @returns the value, if this is of a scalar value or abstract numeric, otherwise
/// std::monostate.
virtual std::variant<std::monostate, AInt, AFloat> InternalValue() const = 0;
};
} // namespace tint::core::constant
#endif // SRC_TINT_LANG_CORE_CONSTANT_VALUE_H_

2229
3rdparty/dawn/src/tint/lang/core/enums.cc vendored Normal file

File diff suppressed because it is too large Load Diff

1389
3rdparty/dawn/src/tint/lang/core/enums.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_EVALUATION_STAGE_H_
#define SRC_TINT_LANG_CORE_EVALUATION_STAGE_H_
#include <algorithm>
#include <initializer_list>
namespace tint::core {
/// The earliest point in time that an expression can be evaluated
enum class EvaluationStage {
/// Expression will not be evaluated
kNotEvaluated,
/// Expression can be evaluated at shader creation time
kConstant,
/// Expression can be evaluated at pipeline creation time
kOverride,
/// Expression can be evaluated at runtime
kRuntime,
};
/// @returns true if stage `a` comes earlier than stage `b`
inline bool operator<(EvaluationStage a, EvaluationStage b) {
return static_cast<int>(a) < static_cast<int>(b);
}
/// @returns true if stage `a` comes later than stage `b`
inline bool operator>(EvaluationStage a, EvaluationStage b) {
return static_cast<int>(a) > static_cast<int>(b);
}
/// @param stages a list of EvaluationStage.
/// @returns the earliest stage supported by all the provided stages
inline EvaluationStage EarliestStage(std::initializer_list<EvaluationStage> stages) {
auto earliest = EvaluationStage::kNotEvaluated;
for (auto stage : stages) {
earliest = std::max(stage, earliest);
}
return static_cast<EvaluationStage>(earliest);
}
template <typename... ARGS>
inline EvaluationStage EarliestStage(ARGS... args) {
return EarliestStage({args...});
}
} // namespace tint::core
#endif // SRC_TINT_LANG_CORE_EVALUATION_STAGE_H_

View File

@@ -0,0 +1,294 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_FLUENT_TYPES_H_
#define SRC_TINT_LANG_CORE_FLUENT_TYPES_H_
#include <stdint.h>
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/number.h"
namespace tint::core::fluent_types {
using f16 = tint::core::f16;
using f32 = tint::core::f32;
using i32 = tint::core::i32;
using i8 = tint::core::i8;
using u32 = tint::core::u32;
using u64 = tint::core::u64;
using u8 = tint::core::u8;
using AFloat = tint::core::AFloat;
using AInt = tint::core::AInt;
// A sentinel type used by some template arguments to signal that the a type should be inferred.
struct Infer {};
/// A 'fluent' type helper used to construct an ast::Array or type::Array.
/// @tparam T the array element type
/// @tparam N the array length. 0 represents a runtime-sized array.
/// @see https://www.w3.org/TR/WGSL/#array-types
template <typename T, uint32_t N = 0>
struct array {
/// the array element type
using type = T;
/// the array length. 0 represents a runtime-sized array.
static constexpr uint32_t length = N;
};
/// A 'fluent' type helper used to construct an ast::Atomic or type::Atomic.
/// @tparam T the atomic element type
/// @see https://www.w3.org/TR/WGSL/#atomic-types
template <typename T>
struct atomic {
/// the atomic element type
using type = T;
};
/// A 'fluent' type helper used to construct an ast::Vector or type::Vector.
/// @tparam N the vector width
/// @tparam T the vector element type
template <uint32_t N, typename T>
struct vec {
/// the vector width
static constexpr uint32_t width = N;
/// the vector element type
using type = T;
};
/// A 'fluent' type helper used to construct an ast::Matrix or type::Matrix.
/// @tparam C the number of columns of the matrix
/// @tparam R the number of rows of the matrix
/// @tparam T the matrix element type
/// @see https://www.w3.org/TR/WGSL/#matrix-types
template <uint32_t C, uint32_t R, typename T>
struct mat {
/// the number of columns of the matrix
static constexpr uint32_t columns = C;
/// the number of rows of the matrix
static constexpr uint32_t rows = R;
/// the matrix element type
using type = T;
/// the column vector type
using column = vec<R, T>;
};
/// A 'fluent' type helper used to construct an ast::Pointer or type::Pointer.
/// @tparam ADDRESS the pointer address space
/// @tparam T the pointer storage type
/// @tparam ACCESS the pointer access control
template <core::AddressSpace ADDRESS, typename T, core::Access ACCESS = core::Access::kUndefined>
struct ptr {
/// the pointer address space
static constexpr core::AddressSpace address = ADDRESS;
/// the pointer storage type
using type = T;
/// the pointer access control
static constexpr core::Access access = ACCESS;
};
////////////////////////////////////////////////////////////////////////////////
// Aliases
//
// Shorthand aliases for the types declared above
////////////////////////////////////////////////////////////////////////////////
//! @cond Doxygen_Suppress
template <typename T>
using mat2x2 = mat<2, 2, T>;
template <typename T>
using mat2x3 = mat<2, 3, T>;
template <typename T>
using mat2x4 = mat<2, 4, T>;
template <typename T>
using mat3x2 = mat<3, 2, T>;
template <typename T>
using mat3x3 = mat<3, 3, T>;
template <typename T>
using mat3x4 = mat<3, 4, T>;
template <typename T>
using mat4x2 = mat<4, 2, T>;
template <typename T>
using mat4x3 = mat<4, 3, T>;
template <typename T>
using mat4x4 = mat<4, 4, T>;
template <typename T>
using vec2 = vec<2, T>;
template <typename T>
using vec3 = vec<3, T>;
template <typename T>
using vec4 = vec<4, T>;
using mat2x2f = mat<2, 2, f32>;
using mat2x3f = mat<2, 3, f32>;
using mat2x4f = mat<2, 4, f32>;
using mat3x2f = mat<3, 2, f32>;
using mat3x3f = mat<3, 3, f32>;
using mat3x4f = mat<3, 4, f32>;
using mat4x2f = mat<4, 2, f32>;
using mat4x3f = mat<4, 3, f32>;
using mat4x4f = mat<4, 4, f32>;
using mat2x2h = mat<2, 2, f16>;
using mat2x3h = mat<2, 3, f16>;
using mat2x4h = mat<2, 4, f16>;
using mat3x2h = mat<3, 2, f16>;
using mat3x3h = mat<3, 3, f16>;
using mat3x4h = mat<3, 4, f16>;
using mat4x2h = mat<4, 2, f16>;
using mat4x3h = mat<4, 3, f16>;
using mat4x4h = mat<4, 4, f16>;
using vec2f = vec<2, f32>;
using vec3f = vec<3, f32>;
using vec4f = vec<4, f32>;
using vec2h = vec<2, f16>;
using vec3h = vec<3, f16>;
using vec4h = vec<4, f16>;
using vec2i = vec<2, i32>;
using vec3i = vec<3, i32>;
using vec4i = vec<4, i32>;
using vec2u = vec<2, u32>;
using vec3u = vec<3, u32>;
using vec4u = vec<4, u32>;
//! @endcond
////////////////////////////////////////////////////////////////////////////////
// Address space aliases
////////////////////////////////////////////////////////////////////////////////
static constexpr core::AddressSpace function = core::AddressSpace::kFunction;
static constexpr core::AddressSpace handle = core::AddressSpace::kHandle;
static constexpr core::AddressSpace private_ = core::AddressSpace::kPrivate;
static constexpr core::AddressSpace immediate = core::AddressSpace::kImmediate;
static constexpr core::AddressSpace storage = core::AddressSpace::kStorage;
static constexpr core::AddressSpace uniform = core::AddressSpace::kUniform;
static constexpr core::AddressSpace workgroup = core::AddressSpace::kWorkgroup;
////////////////////////////////////////////////////////////////////////////////
// Access control aliases
////////////////////////////////////////////////////////////////////////////////
static constexpr core::Access read = core::Access::kRead;
static constexpr core::Access read_write = core::Access::kReadWrite;
static constexpr core::Access write = core::Access::kWrite;
////////////////////////////////////////////////////////////////////////////////
// Traits
////////////////////////////////////////////////////////////////////////////////
namespace detail {
//! @cond Doxygen_Suppress
template <typename T>
struct IsArray {
static constexpr bool value = false;
};
template <typename T, uint32_t N>
struct IsArray<array<T, N>> {
static constexpr bool value = true;
};
template <typename T>
struct IsAtomic {
static constexpr bool value = false;
};
template <typename T>
struct IsAtomic<atomic<T>> {
static constexpr bool value = true;
};
template <typename T>
struct IsMatrix {
static constexpr bool value = false;
};
template <uint32_t C, uint32_t R, typename T>
struct IsMatrix<mat<C, R, T>> {
static constexpr bool value = true;
};
template <typename T>
struct IsVector {
static constexpr bool value = false;
};
template <uint32_t N, typename T>
struct IsVector<vec<N, T>> {
static constexpr bool value = true;
};
template <typename T>
struct IsPointer {
static constexpr bool value = false;
};
template <core::AddressSpace ADDRESS, typename T, core::Access ACCESS>
struct IsPointer<ptr<ADDRESS, T, ACCESS>> {
static constexpr bool value = true;
};
//! @endcond
} // namespace detail
/// Evaluates to true if `T` is a array
template <typename T>
static constexpr bool IsArray = fluent_types::detail::IsArray<T>::value;
/// Evaluates to true if `T` is a atomic
template <typename T>
static constexpr bool IsAtomic = fluent_types::detail::IsAtomic<T>::value;
/// Evaluates to true if `T` is a mat
template <typename T>
static constexpr bool IsMatrix = fluent_types::detail::IsMatrix<T>::value;
/// Evaluates to true if `T` is a vec
template <typename T>
static constexpr bool IsVector = fluent_types::detail::IsVector<T>::value;
/// Evaluates to true if `T` is a ptr
template <typename T>
static constexpr bool IsPointer = fluent_types::detail::IsPointer<T>::value;
} // namespace tint::core::fluent_types
#endif // SRC_TINT_LANG_CORE_FLUENT_TYPES_H_

View File

@@ -0,0 +1,45 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_INTERPOLATION_H_
#define SRC_TINT_LANG_CORE_INTERPOLATION_H_
#include "src/tint/lang/core/enums.h"
namespace tint::core {
/// The values of an `@interpolate` attribute
struct Interpolation {
/// The first argument of a `@interpolate` attribute
core::InterpolationType type = core::InterpolationType::kUndefined;
/// The second argument of a `@interpolate` attribute
core::InterpolationSampling sampling = core::InterpolationSampling::kUndefined;
};
} // namespace tint::core
#endif // SRC_TINT_LANG_CORE_INTERPOLATION_H_

View File

@@ -0,0 +1,93 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////
// File generated by 'tools/src/cmd/gen' using the template:
// src/tint/lang/core/intrinsic/ctor_conv.cc.tmpl
//
// To regenerate run: './tools/run gen'
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
// clang-format off
#include "src/tint/lang/core/intrinsic/ctor_conv.h"
namespace tint::core::intrinsic {
const char* str(CtorConv i) {
switch (i) {
case CtorConv::kNone:
return "<none>";
case CtorConv::kI32:
return "i32";
case CtorConv::kU32:
return "u32";
case CtorConv::kF32:
return "f32";
case CtorConv::kF16:
return "f16";
case CtorConv::kBool:
return "bool";
case CtorConv::kVec2:
return "vec2";
case CtorConv::kVec3:
return "vec3";
case CtorConv::kVec4:
return "vec4";
case CtorConv::kMat2x2:
return "mat2x2";
case CtorConv::kMat2x3:
return "mat2x3";
case CtorConv::kMat2x4:
return "mat2x4";
case CtorConv::kMat3x2:
return "mat3x2";
case CtorConv::kMat3x3:
return "mat3x3";
case CtorConv::kMat3x4:
return "mat3x4";
case CtorConv::kMat4x2:
return "mat4x2";
case CtorConv::kMat4x3:
return "mat4x3";
case CtorConv::kMat4x4:
return "mat4x4";
case CtorConv::kSubgroup_matrix_left:
return "subgroup_matrix_left";
case CtorConv::kSubgroup_matrix_right:
return "subgroup_matrix_right";
case CtorConv::kSubgroup_matrix_result:
return "subgroup_matrix_result";
}
return "<unknown>";
}
} // namespace tint::core::intrinsic
// clang-format on

View File

@@ -0,0 +1,133 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////
// File generated by 'tools/src/cmd/gen' using the template:
// src/tint/lang/core/intrinsic/ctor_conv.h.tmpl
//
// To regenerate run: './tools/run gen'
//
// Do not modify this file directly
////////////////////////////////////////////////////////////////////////////////
#ifndef SRC_TINT_LANG_CORE_INTRINSIC_CTOR_CONV_H_
#define SRC_TINT_LANG_CORE_INTRINSIC_CTOR_CONV_H_
// clang-format off
#include <cstdint>
#include "src/tint/utils/rtti/traits.h"
namespace tint::core::intrinsic {
/// CtorConv is an enumerator of types that have a constructor or converter overload
/// declared in the intrinsic table.
enum class CtorConv : uint8_t {
kI32,
kU32,
kF32,
kF16,
kBool,
kVec2,
kVec3,
kVec4,
kMat2x2,
kMat2x3,
kMat2x4,
kMat3x2,
kMat3x3,
kMat3x4,
kMat4x2,
kMat4x3,
kMat4x4,
kSubgroup_matrix_left,
kSubgroup_matrix_right,
kSubgroup_matrix_result,
kNone,
};
/// @returns the name of the enumerator
/// @param i the CtorConv enumerator
const char* str(CtorConv i);
/// Prints the CtorConv @p c to @p o
/// @param o the stream to write to
/// @param c the CtorConv
/// @return the stream so calls can be chained
template <typename STREAM>
requires(traits::IsOStream<STREAM>)
auto& operator<<(STREAM& o, CtorConv c) {
return o << str(c);
}
/// @param n the width of the vector
/// @return the CtorConv for a vector of width `n`
inline CtorConv VectorCtorConv(uint32_t n) {
switch (n) {
case 2:
return CtorConv::kVec2;
case 3:
return CtorConv::kVec3;
case 4:
return CtorConv::kVec4;
}
return CtorConv::kNone;
}
/// @param c the number of columns in the matrix
/// @param r the number of rows in the matrix
/// @return the CtorConv for a matrix with `c` columns and `r` rows
inline CtorConv MatrixCtorConv(uint32_t c, uint32_t r) {
switch ((c - 2) * 3 + (r - 2)) {
case 0:
return CtorConv::kMat2x2;
case 1:
return CtorConv::kMat2x3;
case 2:
return CtorConv::kMat2x4;
case 3:
return CtorConv::kMat3x2;
case 4:
return CtorConv::kMat3x3;
case 5:
return CtorConv::kMat3x4;
case 6:
return CtorConv::kMat4x2;
case 7:
return CtorConv::kMat4x3;
case 8:
return CtorConv::kMat4x4;
}
return CtorConv::kNone;
}
} // namespace tint::core::intrinsic
// clang-format on
#endif // SRC_TINT_LANG_CORE_INTRINSIC_CTOR_CONV_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_INTRINSIC_DIALECT_H_
#define SRC_TINT_LANG_CORE_INTRINSIC_DIALECT_H_
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/intrinsic/ctor_conv.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
namespace tint::core::intrinsic {
/// Dialect holds the intrinsic table data and types for the core dialect
struct Dialect {
/// The dialect's intrinsic table data
static const TableData kData;
/// The dialect's builtin function enumerator
using BuiltinFn = core::BuiltinFn;
/// The dialect's type constructor / convertor enumerator
using CtorConv = core::intrinsic::CtorConv;
/// @returns the name of the builtin function @p fn
/// @param fn the builtin function
static std::string_view ToString(BuiltinFn fn) { return str(fn); }
/// @returns the name of the type constructor / convertor @p ty
/// @param ty the type constructor / convertor
static std::string_view ToString(CtorConv ty) { return str(ty); }
};
} // namespace tint::core::intrinsic
#endif // SRC_TINT_LANG_CORE_INTRINSIC_DIALECT_H_

View File

@@ -0,0 +1,895 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/intrinsic/table.h"
#include <algorithm>
#include <limits>
#include <ostream>
#include <utility>
#include "src/tint/lang/core/evaluation_stage.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
#include "src/tint/lang/core/type/invalid.h"
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/lang/core/type/void.h"
#include "src/tint/utils/containers/slice.h"
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/defer.h"
#include "src/tint/utils/text/string_stream.h"
#include "src/tint/utils/text/styled_text.h"
#include "src/tint/utils/text/text_style.h"
namespace tint::core::intrinsic {
const Number Number::any{Number::kAny};
const Number Number::invalid{Number::kInvalid};
Any::Any() : Base(0u, core::type::Flags{}) {}
Any::~Any() = default;
bool Any::Equals(const core::type::UniqueNode&) const {
return false;
}
std::string Any::FriendlyName() const {
return "<any>";
}
core::type::Type* Any::Clone(core::type::CloneContext&) const {
return nullptr;
}
namespace {
/// The Vector `N` template argument value for arrays of parameters.
constexpr const size_t kNumFixedParameters = Overload::kNumFixedParameters;
/// The Vector `N` template argument value for arrays of overload candidates.
constexpr const size_t kNumFixedCandidates = 8;
/// A list of candidates
using Candidates = Vector<Candidate, kNumFixedCandidates>;
/// Callback function when no overloads match.
using OnNoMatch = std::function<StyledText(VectorRef<Candidate>)>;
/// Sorts the candidates based on their score, with the lowest (best-ranking) scores first.
static inline void SortCandidates(Candidates& candidates) {
std::stable_sort(candidates.begin(), candidates.end(),
[&](const Candidate& a, const Candidate& b) { return a.score < b.score; });
}
/// Prints a list of types.
static void PrintTypeList(StyledText& ss, VectorRef<const core::type::Type*> types) {
bool first = true;
for (auto* arg : types) {
if (!first) {
ss << ", ";
}
first = false;
ss << style::Type((arg != nullptr) ? arg->FriendlyName() : "undef");
}
}
/// Attempts to find a single intrinsic overload that matches the provided argument types.
/// @param context the intrinsic context
/// @param intrinsic the intrinsic being called
/// @param intrinsic_name the name of the intrinsic
/// @param template_args the template argument types
/// @param args the argument types
/// @param earliest_eval_stage the earliest evaluation stage that the call can be made
/// @param member_function `true` if the builtin should be a member function
/// @param on_no_match an error callback when no intrinsic overloads matched the provided
/// arguments.
/// @returns the matched intrinsic
Result<Overload, StyledText> MatchIntrinsic(Context& context,
const IntrinsicInfo& intrinsic,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage,
bool member_function,
const OnNoMatch& on_no_match);
/// The scoring mode for ScoreOverload()
enum class ScoreMode {
/// If the overload doesn't match, then the returned Candidate will simply have a score of 1.
/// No other fields will be populated.
kEarlyReject,
/// A more expensive score calculations will be made for the overload, which can be used
/// to rank potential overloads
kFull
};
/// Evaluates the single overload for the provided argument types.
/// @param context the intrinsic context
/// @param overload the overload being considered
/// @param template_args the template argument types
/// @param args the argument types
/// @tparam MODE the scoring mode to use. Passed as a template argument to ensure that the
/// extremely-hot function is specialized without scoring logic for the common code path.
/// @returns the evaluated Candidate information.
template <ScoreMode MODE>
Candidate ScoreOverload(Context& context,
const OverloadInfo& overload,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage);
/// Performs overload resolution given the list of candidates, by ranking the conversions of
/// arguments to the each of the candidate's parameter types.
/// @param context the intrinsic context
/// @param candidates the list of candidate overloads
/// @param intrinsic_name the name of the intrinsic
/// @param template_args the template argument types
/// @param args the argument types
/// @see https://www.w3.org/TR/WGSL/#overload-resolution-section
/// @returns the resolved Candidate.
Result<Candidate, StyledText> ResolveCandidate(Context& context,
Candidates&& candidates,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args);
// Prints the list of candidates for emitting diagnostics
void PrintCandidates(StyledText& err,
Context& context,
VectorRef<Candidate> candidates,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args);
/// Raises an ICE when no overload is a clear winner of overload resolution
StyledText ErrAmbiguousOverload(Context& context,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
VectorRef<Candidate> candidates);
/// @return a string representing a call to a builtin with the given argument types.
StyledText CallSignature(std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args) {
StyledText out;
out << style::Code << style::Function(intrinsic_name);
if (!template_args.IsEmpty()) {
out << "<";
PrintTypeList(out, template_args);
out << ">";
}
out << "(";
PrintTypeList(out, args);
out << ")";
return out;
}
Result<Overload, StyledText> MatchIntrinsic(Context& context,
const IntrinsicInfo& intrinsic,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage,
bool member_function,
const OnNoMatch& on_no_match) {
const size_t num_overloads = static_cast<size_t>(intrinsic.num_overloads);
size_t num_matched = 0;
size_t match_idx = 0;
Vector<Candidate, kNumFixedCandidates> candidates;
candidates.Reserve(intrinsic.num_overloads);
for (size_t overload_idx = 0; overload_idx < num_overloads; overload_idx++) {
auto& overload = context.data[intrinsic.overloads + overload_idx];
// Check that the overload is a member function iff we expect one.
if (overload.flags.Contains(OverloadFlag::kMemberFunction) != member_function) {
continue;
}
auto candidate = ScoreOverload<ScoreMode::kEarlyReject>(context, overload, template_args,
args, earliest_eval_stage);
if (candidate.score == 0) {
match_idx = candidates.Length();
num_matched++;
}
candidates.Push(std::move(candidate));
}
// How many candidates matched?
if (DAWN_UNLIKELY(num_matched == 0)) {
// Perform the full scoring of each overload
for (size_t overload_idx = 0; overload_idx < num_overloads; overload_idx++) {
auto& overload = context.data[intrinsic.overloads + overload_idx];
// Check that the overload is a member function iff we expect one.
if (overload.flags.Contains(OverloadFlag::kMemberFunction) != member_function) {
continue;
}
candidates[overload_idx] = ScoreOverload<ScoreMode::kFull>(
context, overload, template_args, args, earliest_eval_stage);
}
// Sort the candidates with the most promising first
SortCandidates(candidates);
return on_no_match(std::move(candidates));
}
Candidate match;
if (num_matched == 1) {
match = std::move(candidates[match_idx]);
} else {
TINT_CHECK_RESULT_UNWRAP(result, ResolveCandidate(context, std::move(candidates),
intrinsic_name, template_args, args));
match = result;
}
// Build the return type
const core::type::Type* return_type = nullptr;
if (auto* matcher_indices = context.data[match.overload->return_matcher_indices]) {
Any any;
return_type =
context.Match(match.templates, *match.overload, matcher_indices, earliest_eval_stage)
.Type(&any);
if (DAWN_UNLIKELY(!return_type)) {
StyledText err;
err << "MatchState.MatchState() returned null";
TINT_ICE() << err.Plain();
}
} else {
return_type = context.types.void_();
}
return Overload{match.overload, return_type, std::move(match.parameters),
context.data[match.overload->const_eval_fn]};
}
template <ScoreMode MODE>
Candidate ScoreOverload(Context& context,
const OverloadInfo& overload,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
#define MATCH_FAILURE(PENALTY) \
do { \
if constexpr (MODE == ScoreMode::kEarlyReject) { \
return Candidate{1}; \
} else { \
score += PENALTY; \
} \
} while (false)
// Penalty weights for overload mismatching.
// This scoring is used to order the suggested overloads in diagnostic on overload mismatch, and
// has no impact for a correct program.
// The overloads with the lowest score will be displayed first (top-most).
constexpr int kMismatchedExplicitTemplateCountPenalty = 10;
constexpr int kMismatchedParamCountPenalty = 3;
constexpr int kMismatchedParamTypePenalty = 2;
constexpr int kMismatchedExplicitTemplateTypePenalty = 1;
constexpr int kMismatchedImplicitTemplateTypePenalty = 1;
constexpr int kMismatchedImplicitTemplateNumberPenalty = 1;
const size_t num_parameters = static_cast<size_t>(overload.num_parameters);
const size_t num_arguments = static_cast<size_t>(args.Length());
size_t score = 0;
if (num_parameters != num_arguments) {
MATCH_FAILURE(kMismatchedParamCountPenalty * (std::max(num_parameters, num_arguments) -
std::min(num_parameters, num_arguments)));
}
// Check that all of the template arguments provided are actually expected by the overload.
const size_t expected_templates = overload.num_explicit_templates;
const size_t provided_templates = template_args.Length();
if (provided_templates != expected_templates) {
MATCH_FAILURE(kMismatchedExplicitTemplateCountPenalty *
(std::max(expected_templates, provided_templates) -
std::min(expected_templates, provided_templates)));
}
TemplateState templates;
// Check that the explicit template arguments match the constraint if specified, otherwise
// just set the template type.
auto num_tmpl_args = std::min<size_t>(overload.num_explicit_templates, template_args.Length());
for (size_t i = 0; i < num_tmpl_args; ++i) {
auto& tmpl = context.data[overload.templates + i];
auto* type = template_args[i];
if (auto* matcher_indices = context.data[tmpl.matcher_indices]) {
// Ensure type matches the template's matcher.
type =
context.Match(templates, overload, matcher_indices, earliest_eval_stage).Type(type);
if (!type) {
MATCH_FAILURE(kMismatchedExplicitTemplateTypePenalty);
continue;
}
}
templates.SetType(i, type);
}
// Invoke the matchers for each parameter <-> argument pair.
// If any arguments cannot be matched, then `score` will be increased.
// If the overload has any template types or numbers then these will be set based on the
// argument types. Template types may be refined by constraining with later argument types. For
// example calling `F<T>(T, T)` with the argument types (abstract-int, i32) will first set T to
// abstract-int when matching the first argument, and then constrained down to i32 when matching
// the second argument.
// Note that inferred template types are not tested against their matchers at this point.
auto num_params = std::min(num_parameters, num_arguments);
for (size_t p = 0; p < num_params; p++) {
auto& parameter = context.data[overload.parameters + p];
auto* matcher_indices = context.data[parameter.matcher_indices];
if (!context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(args[p])) {
MATCH_FAILURE(kMismatchedParamTypePenalty);
}
}
// Check each of the inferred types and numbers for the implicit templates match their
// respective matcher.
for (size_t i = overload.num_explicit_templates; i < overload.num_templates; i++) {
auto& tmpl = context.data[overload.templates + i];
auto* matcher_indices = context.data[tmpl.matcher_indices];
if (!matcher_indices) {
continue;
}
auto matcher = context.Match(templates, overload, matcher_indices, earliest_eval_stage);
switch (tmpl.kind) {
case TemplateInfo::Kind::kType: {
// Check all constrained template types matched their constraint matchers.
// If the template type *does not* match any of the types in the constraint
// matcher, then `score` is incremented and the template is assigned an invalid
// type. If the template type *does* match a type, then the template type is
// replaced with the first matching type. The order of types in the template matcher
// is important here, which can be controlled with the [[precedence(N)]] decorations
// on the types in the def file.
if (auto* type = templates.Type(i)) {
if (auto* ty = matcher.Type(type)) {
// Template type matched one of the types in the template type's
// matcher. Replace the template type with this type.
templates.SetType(i, ty);
continue;
}
}
templates.SetType(i, context.types.invalid());
MATCH_FAILURE(kMismatchedImplicitTemplateTypePenalty);
break;
}
case TemplateInfo::Kind::kNumber: {
// Checking that the inferred number matches the constraints on the
// template. Increments `score` and assigns the template an invalid number if the
// template numbers do not match their constraint matchers.
auto number = templates.Num(i);
if (!number.IsValid() || !matcher.Num(number).IsValid()) {
templates.SetNum(i, Number::invalid);
MATCH_FAILURE(kMismatchedImplicitTemplateNumberPenalty);
}
}
}
}
// Now that all the template types have been finalized, we can construct the parameters.
Vector<Overload::Parameter, kNumFixedParameters> parameters;
parameters.Reserve(num_params);
for (size_t p = 0; p < num_params; p++) {
auto& parameter = context.data[overload.parameters + p];
auto* matcher_indices = context.data[parameter.matcher_indices];
auto* ty =
context.Match(templates, overload, matcher_indices, earliest_eval_stage).Type(args[p]);
parameters.Emplace(ty, parameter.usage);
}
return Candidate{score, &overload, templates, parameters};
#undef MATCH_FAILURE
}
Result<Candidate, StyledText> ResolveCandidate(Context& context,
Candidates&& candidates,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args) {
Vector<uint32_t, kNumFixedParameters> best_ranks;
best_ranks.Resize(args.Length(), 0xffffffff);
size_t num_matched = 0;
Candidate* best = nullptr;
for (auto& candidate : candidates) {
if (candidate.score > 0) {
continue; // Candidate has already been ruled out.
}
bool some_won = false; // An argument ranked less than the 'best' overload's argument
bool some_lost = false; // An argument ranked more than the 'best' overload's argument
for (size_t i = 0; i < args.Length(); i++) {
auto rank = core::type::Type::ConversionRank(args[i], candidate.parameters[i].type);
if (best_ranks[i] > rank) {
best_ranks[i] = rank;
some_won = true;
} else if (best_ranks[i] < rank) {
some_lost = true;
}
}
// If no arguments of this candidate ranked worse than the previous best candidate, then
// this candidate becomes the new best candidate.
// If no arguments of this candidate ranked better than the previous best candidate, then
// this candidate is removed from the list of matches.
// If neither of the above apply, then we have two candidates with no clear winner, which
// results in an ambiguous overload error. In this situation the loop ends with
// `num_matched > 1`.
if (some_won) {
// One or more arguments of this candidate ranked better than the previous best
// candidate's argument(s).
num_matched++;
if (!some_lost) {
// All arguments were at as-good or better than the previous best.
if (best) {
// Mark the previous best candidate as no longer being in the running, by
// setting its score to a non-zero value. We pick 1 as this is the closest to 0
// (match) as we can get.
best->score = 1;
num_matched--;
}
// This candidate is the new best.
best = &candidate;
}
} else {
// No arguments ranked better than the current best.
// Change the score of this candidate to a non-zero value, so that it's not considered a
// match.
candidate.score = 1;
}
}
if (num_matched > 1) {
// Re-sort the candidates with the most promising first
SortCandidates(candidates);
// Raise an error
return ErrAmbiguousOverload(context, intrinsic_name, template_args, args, candidates);
}
return std::move(*best);
}
void PrintCandidates(StyledText& ss,
Context& context,
VectorRef<Candidate> candidates,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args) {
for (auto& candidate : candidates) {
ss << "";
PrintCandidate(ss, context, candidate, intrinsic_name, template_args, args);
ss << "\n";
}
}
StyledText ErrAmbiguousOverload(Context& context,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
VectorRef<Candidate> candidates) {
StyledText err;
err << "ambiguous overload while attempting to match "
<< CallSignature(intrinsic_name, template_args, args) << "\n";
for (auto& candidate : candidates) {
if (candidate.score == 0) {
err << " ";
PrintCandidate(err, context, candidate, intrinsic_name, template_args, args);
err << "\n";
}
}
TINT_ICE() << err.Plain();
}
} // namespace
void PrintCandidate(StyledText& ss,
Context& context,
const Candidate& candidate,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args) {
// Restore old style before returning.
auto prev_style = ss.Style();
TINT_DEFER(ss << prev_style);
auto& overload = *candidate.overload;
TemplateState templates = candidate.templates;
// TODO(crbug.com/tint/1730): Use input evaluation stage to output only relevant overloads.
auto earliest_eval_stage = EvaluationStage::kConstant;
ss << style::Code << style::Function(intrinsic_name);
if (overload.num_explicit_templates > 0) {
ss << "<";
for (size_t i = 0; i < overload.num_explicit_templates; i++) {
const auto& tmpl = context.data[overload.templates + i];
bool matched = false;
if (i < template_args.Length()) {
auto* matcher_indices = context.data[tmpl.matcher_indices];
matched = (matcher_indices == nullptr) ||
(context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(template_args[i]) != nullptr);
}
if (i > 0) {
ss << ", ";
}
ss << style::Type(tmpl.name) << " ";
if (matched) {
ss << (style::Code + style::Match)("");
} else {
ss << (style::Code + style::Mismatch)("");
}
}
ss << ">";
}
bool all_params_match = true;
ss << "(";
for (size_t i = 0; i < overload.num_parameters; i++) {
const auto& parameter = context.data[overload.parameters + i];
auto* matcher_indices = context.data[parameter.matcher_indices];
bool matched = false;
if (i < args.Length()) {
matched = (context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(args[i]) != nullptr);
}
all_params_match = all_params_match && matched;
if (i > 0) {
ss << ", ";
}
if (parameter.usage != ParameterUsage::kNone) {
ss << style::Variable(parameter.usage, ": ");
}
context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
ss << style::Code << " ";
if (matched) {
ss << (style::Code + style::Match)("");
} else {
ss << (style::Code + style::Mismatch)("");
}
}
ss << ")";
if (overload.return_matcher_indices.IsValid()) {
ss << " -> ";
auto* matcher_indices = context.data[overload.return_matcher_indices];
context.Match(templates, overload, matcher_indices, earliest_eval_stage).PrintType(ss);
}
bool first = true;
auto separator = [&] {
ss << style::Plain(first ? " where:\n " : "\n ");
first = false;
};
if (all_params_match && args.Length() > overload.num_parameters) {
separator();
ss << style::Mismatch("")
<< style::Plain(" overload expects ", static_cast<int>(overload.num_parameters),
" argument", overload.num_parameters != 1 ? "s" : "", ", call passed ",
args.Length(), " argument", args.Length() != 1 ? "s" : "");
}
if (all_params_match && template_args.Length() > overload.num_explicit_templates) {
separator();
ss << style::Mismatch("")
<< style::Plain(" overload expects ", static_cast<int>(overload.num_explicit_templates),
" template argument", overload.num_explicit_templates != 1 ? "s" : "",
", call passed ", template_args.Length(), " argument",
template_args.Length() != 1 ? "s" : "");
}
for (size_t i = 0; i < overload.num_templates; i++) {
auto& tmpl = context.data[overload.templates + i];
if (auto* matcher_indices = context.data[tmpl.matcher_indices]) {
separator();
bool matched = false;
if (tmpl.kind == TemplateInfo::Kind::kType) {
if (auto* ty = templates.Type(i)) {
matched =
(context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Type(ty) != nullptr);
}
} else {
matched = context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.Num(templates.Num(i))
.IsValid();
}
if (matched) {
ss << style::Match("") << style::Plain(" ");
} else {
ss << style::Mismatch("") << style::Plain(" ");
}
ss << style::Type(tmpl.name) << style::Plain(" is ");
if (tmpl.kind == TemplateInfo::Kind::kType) {
context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.PrintType(ss);
} else {
context.Match(templates, overload, matcher_indices, earliest_eval_stage)
.PrintNum(ss);
}
}
}
}
Result<Overload, StyledText> LookupFn(Context& context,
std::string_view intrinsic_name,
size_t function_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](VectorRef<Candidate> candidates) {
StyledText err;
err << "no matching call to " << CallSignature(intrinsic_name, template_args, args) << "\n";
if (!candidates.IsEmpty()) {
err << "\n"
<< candidates.Length() << " candidate function"
<< (candidates.Length() > 1 ? "s:" : ":") << "\n";
PrintCandidates(err, context, candidates, intrinsic_name, template_args, args);
}
return err;
};
// Resolve the intrinsic overload
return MatchIntrinsic(context, context.data.builtins[function_id], intrinsic_name,
template_args, args, earliest_eval_stage, /* member_function */ false,
on_no_match);
}
Result<Overload, StyledText> LookupMemberFn(Context& context,
std::string_view intrinsic_name,
size_t function_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](VectorRef<Candidate> candidates) {
StyledText err;
err << "no matching call to " << CallSignature(intrinsic_name, template_args, args) << "\n";
if (!candidates.IsEmpty()) {
err << "\n"
<< candidates.Length() << " candidate function"
<< (candidates.Length() > 1 ? "s:" : ":") << "\n";
PrintCandidates(err, context, candidates, intrinsic_name, template_args, args);
}
return err;
};
// Resolve the intrinsic overload
return MatchIntrinsic(context, context.data.builtins[function_id], intrinsic_name,
template_args, args, earliest_eval_stage, /* member_function */ true,
on_no_match);
}
Result<Overload, StyledText> LookupUnary(Context& context,
core::UnaryOp op,
const core::type::Type* arg,
EvaluationStage earliest_eval_stage) {
const IntrinsicInfo* intrinsic_info = nullptr;
std::string_view intrinsic_name;
switch (op) {
case core::UnaryOp::kComplement:
intrinsic_info = &context.data.unary_complement;
intrinsic_name = "operator ~ ";
break;
case core::UnaryOp::kNegation:
intrinsic_info = &context.data.unary_minus;
intrinsic_name = "operator - ";
break;
case core::UnaryOp::kAddressOf:
intrinsic_info = &context.data.unary_and;
intrinsic_name = "operator & ";
break;
case core::UnaryOp::kIndirection:
intrinsic_info = &context.data.unary_star;
intrinsic_name = "operator * ";
break;
case core::UnaryOp::kNot:
intrinsic_info = &context.data.unary_not;
intrinsic_name = "operator ! ";
break;
}
Vector args{arg};
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](VectorRef<Candidate> candidates) {
StyledText err;
err << "no matching overload for " << CallSignature(name, Empty, args) << "\n";
if (!candidates.IsEmpty()) {
err << "\n"
<< candidates.Length() << " candidate operator"
<< (candidates.Length() > 1 ? "s:" : ":") << "\n";
PrintCandidates(err, context, candidates, name, Empty, Vector{arg});
}
return err;
};
// Resolve the intrinsic overload
return MatchIntrinsic(context, *intrinsic_info, intrinsic_name, Empty, args,
earliest_eval_stage, /* member_function */ false, on_no_match);
}
Result<Overload, StyledText> LookupBinary(Context& context,
core::BinaryOp op,
const core::type::Type* lhs,
const core::type::Type* rhs,
EvaluationStage earliest_eval_stage,
bool is_compound) {
const IntrinsicInfo* intrinsic_info = nullptr;
std::string_view intrinsic_name;
switch (op) {
case core::BinaryOp::kAnd:
intrinsic_info = &context.data.binary_and;
intrinsic_name = is_compound ? "operator &= " : "operator & ";
break;
case core::BinaryOp::kOr:
intrinsic_info = &context.data.binary_or;
intrinsic_name = is_compound ? "operator |= " : "operator | ";
break;
case core::BinaryOp::kXor:
intrinsic_info = &context.data.binary_xor;
intrinsic_name = is_compound ? "operator ^= " : "operator ^ ";
break;
case core::BinaryOp::kLogicalAnd:
intrinsic_info = &context.data.binary_logical_and;
intrinsic_name = "operator && ";
break;
case core::BinaryOp::kLogicalOr:
intrinsic_info = &context.data.binary_logical_or;
intrinsic_name = "operator || ";
break;
case core::BinaryOp::kEqual:
intrinsic_info = &context.data.binary_equal;
intrinsic_name = "operator == ";
break;
case core::BinaryOp::kNotEqual:
intrinsic_info = &context.data.binary_not_equal;
intrinsic_name = "operator != ";
break;
case core::BinaryOp::kLessThan:
intrinsic_info = &context.data.binary_less_than;
intrinsic_name = "operator < ";
break;
case core::BinaryOp::kGreaterThan:
intrinsic_info = &context.data.binary_greater_than;
intrinsic_name = "operator > ";
break;
case core::BinaryOp::kLessThanEqual:
intrinsic_info = &context.data.binary_less_than_equal;
intrinsic_name = "operator <= ";
break;
case core::BinaryOp::kGreaterThanEqual:
intrinsic_info = &context.data.binary_greater_than_equal;
intrinsic_name = "operator >= ";
break;
case core::BinaryOp::kShiftLeft:
intrinsic_info = &context.data.binary_shift_left;
intrinsic_name = is_compound ? "operator <<= " : "operator << ";
break;
case core::BinaryOp::kShiftRight:
intrinsic_info = &context.data.binary_shift_right;
intrinsic_name = is_compound ? "operator >>= " : "operator >> ";
break;
case core::BinaryOp::kAdd:
intrinsic_info = &context.data.binary_plus;
intrinsic_name = is_compound ? "operator += " : "operator + ";
break;
case core::BinaryOp::kSubtract:
intrinsic_info = &context.data.binary_minus;
intrinsic_name = is_compound ? "operator -= " : "operator - ";
break;
case core::BinaryOp::kMultiply:
intrinsic_info = &context.data.binary_star;
intrinsic_name = is_compound ? "operator *= " : "operator * ";
break;
case core::BinaryOp::kDivide:
intrinsic_info = &context.data.binary_divide;
intrinsic_name = is_compound ? "operator /= " : "operator / ";
break;
case core::BinaryOp::kModulo:
intrinsic_info = &context.data.binary_modulo;
intrinsic_name = is_compound ? "operator %= " : "operator % ";
break;
}
Vector args{lhs, rhs};
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&, name = intrinsic_name](VectorRef<Candidate> candidates) {
StyledText err;
err << "no matching overload for " << CallSignature(name, Empty, args) << "\n";
if (!candidates.IsEmpty()) {
err << "\n"
<< candidates.Length() << " candidate operator"
<< (candidates.Length() > 1 ? "s:" : ":") << "\n";
PrintCandidates(err, context, candidates, name, Empty, args);
}
return err;
};
// Resolve the intrinsic overload
return MatchIntrinsic(context, *intrinsic_info, intrinsic_name, Empty, args,
earliest_eval_stage, /* member_function */ false, on_no_match);
}
Result<Overload, StyledText> LookupCtorConv(Context& context,
std::string_view type_name,
size_t type_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
// Generates an error when no overloads match the provided arguments
auto on_no_match = [&](VectorRef<Candidate> candidates) {
StyledText err;
err << "no matching constructor for " << CallSignature(type_name, template_args, args)
<< "\n";
Candidates ctor, conv;
for (auto candidate : candidates) {
if (candidate.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
ctor.Push(candidate);
} else {
conv.Push(candidate);
}
}
if (!ctor.IsEmpty()) {
err << "\n"
<< ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
<< "\n";
PrintCandidates(err, context, ctor, type_name, template_args, args);
}
if (!conv.IsEmpty()) {
err << "\n"
<< conv.Length() << " candidate conversion" << (conv.Length() > 1 ? "s:" : ":")
<< "\n";
PrintCandidates(err, context, conv, type_name, template_args, args);
}
return err;
};
// Resolve the intrinsic overload
return MatchIntrinsic(context, context.data.ctor_conv[type_id], type_name, template_args, args,
earliest_eval_stage, /* member_function */ false, on_no_match);
}
} // namespace tint::core::intrinsic
/// TypeInfo for the Any type declared in the anonymous namespace above
TINT_INSTANTIATE_TYPEINFO(tint::core::intrinsic::Any);

View File

@@ -0,0 +1,401 @@
// Copyright 2021 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_
#define SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_
#include <memory>
#include <string>
#include <utility>
#include "src/tint/lang/core/binary_op.h"
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/evaluation_stage.h"
#include "src/tint/lang/core/intrinsic/ctor_conv.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
#include "src/tint/lang/core/unary_op.h"
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/text/string.h"
#include "src/tint/utils/text/string_stream.h"
#include "src/tint/utils/text/styled_text.h"
// Forward declarations
namespace tint::diag {
class List;
} // namespace tint::diag
namespace tint::core::intrinsic {
/// Overload describes a fully matched builtin function overload
struct Overload {
static constexpr size_t kNumFixedParameters = 8;
/// Parameter describes a single parameter
struct Parameter {
/// Parameter type
const core::type::Type* const type;
/// Parameter usage
core::ParameterUsage const usage = core::ParameterUsage::kNone;
/// Equality operator
/// @param other the parameter to compare against
/// @returns true if this parameter and @p other are the same
bool operator==(const Parameter& other) const {
return type == other.type && usage == other.usage;
}
/// Inequality operator
/// @param other the parameter to compare against
/// @returns false if this parameter and @p other are the same
bool operator!=(const Parameter& other) const { return !(*this == other); }
};
/// The overload information
const OverloadInfo* info = nullptr;
/// The resolved overload return type
core::type::Type const* return_type = nullptr;
/// The resolved overload parameters
Vector<Parameter, kNumFixedParameters> parameters;
/// The constant evaluation function
constant::Eval::Function const_eval_fn = nullptr;
/// Equality operator
/// @param other the overload to compare against
/// @returns true if this overload and @p other are the same
bool operator==(const Overload& other) const {
return info == other.info && return_type == other.return_type &&
parameters == other.parameters;
}
/// Inequality operator
/// @param other the overload to compare against
/// @returns false if this overload and @p other are the same
bool operator!=(const Overload& other) const { return !(*this == other); }
};
/// The context data used to lookup intrinsic information
struct Context {
/// The table table
const TableData& data;
/// The type manager
core::type::Manager& types;
/// The symbol table
SymbolTable& symbols;
/// @returns a MatchState from the context and arguments.
/// @param templates the template state used for matcher evaluation
/// @param overload the overload being evaluated
/// @param matcher_indices pointer to a list of matcher indices
MatchState Match(TemplateState& templates,
const OverloadInfo& overload,
const MatcherIndex* matcher_indices,
EvaluationStage earliest_eval_stage) {
return MatchState(types, symbols, templates, data, overload, matcher_indices,
earliest_eval_stage);
}
};
/// Candidate holds information about an overload evaluated for resolution.
struct Candidate {
/// The match-score of the candidate overload.
/// A score of zero indicates an exact match.
/// Non-zero scores are used for diagnostics when no overload matches.
/// Lower scores are displayed first (top-most).
size_t score = 0;
/// The candidate overload
const OverloadInfo* overload = nullptr;
/// The template types and numbers
TemplateState templates{};
/// The parameter types for the candidate overload
Vector<Overload::Parameter, Overload::kNumFixedParameters> parameters{};
};
// Prints the candidate overload for emitting diagnostics
void PrintCandidate(StyledText& ss,
Context& context,
const Candidate& candidate,
std::string_view intrinsic_name,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args);
/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
/// if the builtin was not found.
/// @param context the intrinsic context
/// @param function_name the name of the function
/// @param function_id the function identifier
/// @param template_args the optional template arguments
/// @param args the argument types passed to the builtin function
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the builtin can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
/// only overloads with concrete argument types will be considered, as all
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @return the resolved builtin function overload
Result<Overload, StyledText> LookupFn(Context& context,
std::string_view function_name,
size_t function_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage);
/// Lookup looks for the member builtin overload with the given signature, raising an error
/// diagnostic if the builtin was not found.
/// @param context the intrinsic context
/// @param function_name the name of the function
/// @param function_id the function identifier
/// @param template_args the optional template arguments
/// @param args the argument types passed to the builtin function
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the builtin can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
/// only overloads with concrete argument types will be considered, as all
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @return the resolved builtin function overload
Result<Overload, StyledText> LookupMemberFn(Context& context,
std::string_view function_name,
size_t function_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage);
/// Lookup looks for the unary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
/// @param context the intrinsic context
/// @param op the unary operator
/// @param arg the type of the expression passed to the operator
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the unary operator can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved unary operator overload
Result<Overload, StyledText> LookupUnary(Context& context,
core::UnaryOp op,
const core::type::Type* arg,
EvaluationStage earliest_eval_stage);
/// Lookup looks for the binary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
/// @param context the intrinsic context
/// @param op the binary operator
/// @param lhs the LHS value type passed to the operator
/// @param rhs the RHS value type passed to the operator
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the binary operator can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @param is_compound true if the binary operator is being used as a compound assignment
/// @return the resolved binary operator overload
Result<Overload, StyledText> LookupBinary(Context& context,
core::BinaryOp op,
const core::type::Type* lhs,
const core::type::Type* rhs,
EvaluationStage earliest_eval_stage,
bool is_compound);
/// Lookup looks for the value constructor or conversion overload for the given CtorConv.
/// @param context the intrinsic context
/// @param type_name the name of the type being constructed or converted
/// @param type_id the type identifier
/// @param template_args the optional template arguments
/// @param args the argument types passed to the constructor / conversion call
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the constructor or conversion can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved type constructor or conversion function overload
Result<Overload, StyledText> LookupCtorConv(Context& context,
std::string_view type_name,
size_t type_id,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage);
/// Table is a wrapper around a dialect to provide type-safe interface to the intrinsic table.
template <typename DIALECT>
struct Table {
/// Alias to DIALECT::BuiltinFn
using BuiltinFn = typename DIALECT::BuiltinFn;
/// Alias to DIALECT::CtorConv
using CtorConv = typename DIALECT::CtorConv;
static_assert(std::is_enum_v<BuiltinFn>);
static_assert(std::is_enum_v<CtorConv>);
/// @param types The type manager
/// @param symbols The symbol table
Table(core::type::Manager& types, SymbolTable& symbols)
: context{DIALECT::kData, types, symbols} {}
/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
/// if the builtin was not found.
/// @param builtin_fn the builtin function
/// @param template_args the optional template arguments
/// @param args the argument types passed to the builtin function
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the builtin can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
/// only overloads with concrete argument types will be considered, as all
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @return the resolved builtin function overload
Result<Overload, StyledText> Lookup(BuiltinFn builtin_fn,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
std::string_view name = DIALECT::ToString(builtin_fn);
size_t id = static_cast<size_t>(builtin_fn);
return LookupFn(context, name, id, std::move(template_args), std::move(args),
earliest_eval_stage);
}
/// Lookup looks for the member builtin overload with the given signature, raising an error
/// diagnostic if the builtin was not found.
/// @param builtin_fn the builtin function
/// @param object the object type
/// @param template_args the optional template arguments
/// @param args the argument types passed to the builtin function
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the builtin can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
/// only overloads with concrete argument types will be considered, as all
/// abstract-numerics will have been materialized after shader creation time
/// (EvaluationStage::kConstant).
/// @return the resolved builtin function overload
Result<Overload, StyledText> Lookup(BuiltinFn builtin_fn,
const core::type::Type* object,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
// Push the object type into the argument list.
auto full_args = Vector<const core::type::Type*, 8>({object});
for (auto* arg : args) {
full_args.Push(arg);
}
std::string_view name = DIALECT::ToString(builtin_fn);
size_t id = static_cast<size_t>(builtin_fn);
return LookupMemberFn(context, name, id, std::move(template_args), std::move(full_args),
earliest_eval_stage);
}
/// Lookup looks for the unary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
/// @param op the unary operator
/// @param arg the type of the expression passed to the operator
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the unary operator can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved unary operator overload
Result<Overload, StyledText> Lookup(core::UnaryOp op,
const core::type::Type* arg,
EvaluationStage earliest_eval_stage) {
return LookupUnary(context, op, arg, earliest_eval_stage);
}
/// Lookup looks for the binary op overload with the given signature, raising an error
/// diagnostic if the operator was not found.
/// @param op the binary operator
/// @param lhs the LHS value type passed to the operator
/// @param rhs the RHS value type passed to the operator
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the binary operator can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @param is_compound true if the binary operator is being used as a compound assignment
/// @return the resolved binary operator overload
Result<Overload, StyledText> Lookup(core::BinaryOp op,
const core::type::Type* lhs,
const core::type::Type* rhs,
EvaluationStage earliest_eval_stage,
bool is_compound) {
return LookupBinary(context, op, lhs, rhs, earliest_eval_stage, is_compound);
}
/// Lookup looks for the value constructor or conversion overload for the given CtorConv.
/// @param type the type being constructed or converted
/// @param template_args the optional template arguments
/// @param args the argument types passed to the constructor / conversion call
/// @param earliest_eval_stage the earliest evaluation stage that a call to
/// the constructor or conversion can be made. This can alter the overloads considered.
/// For example, if the earliest evaluation stage is
/// `EvaluationStage::kRuntime`, then only overloads with concrete argument types
/// will be considered, as all abstract-numerics will have been materialized
/// after shader creation time (EvaluationStage::kConstant).
/// @return the resolved type constructor or conversion function overload
Result<Overload, StyledText> Lookup(CtorConv type,
VectorRef<const core::type::Type*> template_args,
VectorRef<const core::type::Type*> args,
EvaluationStage earliest_eval_stage) {
std::string_view name = DIALECT::ToString(type);
size_t id = static_cast<size_t>(type);
return LookupCtorConv(context, name, id, std::move(template_args), std::move(args),
earliest_eval_stage);
}
/// The intrinsic context
Context context;
};
} // namespace tint::core::intrinsic
namespace tint {
/// Hasher specialization for core::intrinsic::Overload
template <>
struct Hasher<core::intrinsic::Overload> {
/// @param i the core::intrinsic::Overload to create a hash for
/// @return the hash value
inline HashCode operator()(const core::intrinsic::Overload& i) const {
HashCode hash = Hash(i.parameters.Length());
for (auto& p : i.parameters) {
hash = HashCombine(hash, p.type, p.usage);
}
return Hash(hash, i.info, i.return_type);
}
};
} // namespace tint
#endif // SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_

View File

@@ -0,0 +1,678 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_INTRINSIC_TABLE_DATA_H_
#define SRC_TINT_LANG_CORE_INTRINSIC_TABLE_DATA_H_
#include <stdint.h>
#include <limits>
#include <string>
#include "src/tint/lang/core/constant/eval.h"
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/evaluation_stage.h"
#include "src/tint/utils/containers/enum_set.h"
#include "src/tint/utils/containers/slice.h"
#include "src/tint/utils/text/styled_text.h"
#include "src/tint/utils/text/text_style.h"
/// Forward declaration
namespace tint::core::intrinsic {
struct TableData;
} // namespace tint::core::intrinsic
namespace tint::core::intrinsic {
/// An enumerator of index namespaces.
enum class TableIndexNamespace : uint8_t {
kTemplate,
kMatcher,
kMatcherIndices,
kTypeMatcher,
kNumberMatcher,
kParameter,
kOverload,
kConstEvalFunction,
};
/// A wrapper around an integer type, used to index intrinsic table data
/// @tparam T the index data type
/// @tparam N the index namespace
template <TableIndexNamespace N, typename T>
struct TableIndex {
static_assert(std::is_integral_v<T> && std::is_unsigned_v<T>,
"T must be an unsigned integer type");
/// The value used to represent an invalid index
static constexpr T kInvalid = std::numeric_limits<T>::max();
/// Constructor for invalid index
constexpr TableIndex() : value(kInvalid) {}
/// Constructor
/// @param index the index value
constexpr explicit TableIndex(T index) : value(index) {}
/// @returns true if this index is not invalid
bool IsValid() const { return value != kInvalid; }
/// Equality operator
/// @param other the index to compare against
/// @returns true if this index is equal to @p other
bool operator==(const TableIndex& other) { return value == other.value; }
/// Inequality operator
/// @param other the index to compare against
/// @returns true if this index is equal to @p other
bool operator!=(const TableIndex& other) { return value != other.value; }
/// @param offset the offset to apply to this index
/// @returns a new index offset by @p offset
template <typename U>
auto operator+(U offset) const {
static_assert(std::is_integral_v<U> && std::is_unsigned_v<U>,
"T must be an unsigned integer type");
using C = std::conditional_t<(sizeof(U) > sizeof(T)), U, T>;
C new_value = static_cast<C>(value) + static_cast<C>(offset);
return TableIndex<N, decltype(new_value)>(new_value);
}
/// @param arr a C-style array
/// @returns true if the integer type `T` has enough bits to index all the
/// elements in the array @p arr.
template <typename U, size_t COUNT>
static constexpr bool CanIndex(U (&arr)[COUNT]) {
(void)arr; // The array isn't actually used
/// kInvalid is the largest value representable by `T`. It is not a valid index.
return COUNT < kInvalid;
}
/// The index value
const T value = kInvalid;
};
/// Index type used to index TableData::template_types
using TemplateIndex = TableIndex<TableIndexNamespace::kTemplate, uint8_t>;
/// Index type used to index TableData::type_matchers or TableData::number_matchers
using MatcherIndex = TableIndex<TableIndexNamespace::kMatcher, uint8_t>;
/// Index type used to index TableData::matcher_indices
using MatcherIndicesIndex = TableIndex<TableIndexNamespace::kMatcherIndices, uint16_t>;
/// Index type used to index TableData::type_matchers
using TypeMatcherIndex = TableIndex<TableIndexNamespace::kTypeMatcher, uint8_t>;
/// Index type used to index TableData::number_matchers
using NumberMatcherIndex = TableIndex<TableIndexNamespace::kNumberMatcher, uint8_t>;
/// Index type used to index TableData::parameters
using ParameterIndex = TableIndex<TableIndexNamespace::kParameter, uint16_t>;
/// Index type used to index TableData::overloads
using OverloadIndex = TableIndex<TableIndexNamespace::kOverload, uint16_t>;
/// Index type used to index TableData::const_eval_functions
using ConstEvalFunctionIndex = TableIndex<TableIndexNamespace::kConstEvalFunction, uint8_t>;
/// Unique flag bits for overloads
enum class OverloadFlag : uint8_t {
kIsBuiltin, // The overload is a builtin ('fn')
kIsOperator, // The overload is an operator ('op')
kIsConstructor, // The overload is a value constructor ('ctor')
kIsConverter, // The overload is a value converter ('conv')
kSupportsVertexPipeline, // The overload can be used in vertex shaders
kSupportsFragmentPipeline, // The overload can be used in fragment shaders
kSupportsComputePipeline, // The overload can be used in compute shaders
kMustUse, // The overload cannot be called as a statement
kMemberFunction, // The overload is a member function
kIsDeprecated, // The overload is deprecated
};
/// An enum set of OverloadFlag, used by OperatorInfo
using OverloadFlags = tint::EnumSet<OverloadFlag>;
/// ParameterInfo describes a parameter
struct ParameterInfo {
/// The parameter usage (parameter name in definition file)
const ParameterUsage usage;
/// Index of the matcher indices that are used to match the parameter types.
/// These indices are consumed by the matchers themselves.
const MatcherIndicesIndex matcher_indices;
};
/// TemplateInfo describes an template
struct TemplateInfo {
/// An enumerator of template kind
enum class Kind : uint8_t { kType, kNumber };
/// Name of the template type (e.g. 'T')
const char* name;
/// Index of the type matcher indices that are used to match the template types.
/// These indices are consumed by the matchers themselves.
const MatcherIndicesIndex matcher_indices;
/// The template kind
const Kind kind;
};
/// OverloadInfo describes a single function overload
struct OverloadInfo {
/// The flags for the overload
const OverloadFlags flags;
/// Total number of parameters for the overload
const uint8_t num_parameters;
/// Total number of explicit templates for the overload
const uint8_t num_explicit_templates;
/// Total number of implicit and explicit templates for the overload
const uint8_t num_templates;
/// Index of the first template in TableData::templates
/// This is a list of explicit template types followed by the implicit template types.
const TemplateIndex templates;
/// Index of the first parameter in TableData::parameters
const ParameterIndex parameters;
/// Index of a list of type matcher indices that are used to build the return type.
const MatcherIndicesIndex return_matcher_indices;
/// The function used to evaluate the overload at shader-creation time.
const ConstEvalFunctionIndex const_eval_fn;
};
/// IntrinsicInfo describes a builtin function or operator overload
struct IntrinsicInfo {
/// Number of overloads of the intrinsic
const uint8_t num_overloads;
/// Index of the first overload for the function
const OverloadIndex overloads;
};
/// A IntrinsicInfo with no overloads
static constexpr IntrinsicInfo kNoOverloads{0, OverloadIndex(OverloadIndex::kInvalid)};
/// Number is an 32 bit unsigned integer, which can be in one of three states:
/// * Invalid - Number has not been assigned a value
/// * Valid - a fixed integer value
/// * Any - matches any other non-invalid number
class Number {
enum State : uint8_t {
kInvalid,
kValid,
kAny,
};
constexpr explicit Number(State state) : state_(state) {}
public:
/// A special number representing any number
static const Number any;
/// An invalid number
static const Number invalid;
/// Constructed as a valid number with the value v
/// @param v the value for the number
explicit constexpr Number(uint32_t v) : value_(v), state_(kValid) {}
/// @returns the value of the number
inline uint32_t Value() const { return value_; }
/// @returns the true if the number is valid
inline bool IsValid() const { return state_ == kValid; }
/// @returns the true if the number is any
inline bool IsAny() const { return state_ == kAny; }
/// Assignment operator.
/// The number becomes valid, with the value n
/// @param n the new value for the number
/// @returns this so calls can be chained
inline Number& operator=(uint32_t n) {
value_ = n;
state_ = kValid;
return *this;
}
private:
uint32_t value_ = 0;
State state_ = kInvalid;
};
/// A special type that matches all TypeMatchers
class Any final : public Castable<Any, core::type::Type> {
public:
Any();
~Any() override;
/// @copydoc core::type::UniqueNode::Equals
bool Equals(const core::type::UniqueNode& other) const override;
/// @copydoc core::type::Type::FriendlyName
std::string FriendlyName() const override;
/// @copydoc core::type::Type::Clone
core::type::Type* Clone(core::type::CloneContext& ctx) const override;
};
/// TemplateState holds the state of the template numbers and types.
/// Used by the MatchState.
class TemplateState {
public:
/// If the template type with index @p idx is undefined, then it is defined with the @p ty
/// and Type() returns @p ty. If the template type is defined, and @p ty can be converted to
/// the template type then the template type is returned. If the template type is defined,
/// and the template type can be converted to @p ty, then the template type is replaced with
/// @p ty, and @p ty is returned. If none of the above applies, then @p ty is a type
/// mismatch for the template type, and nullptr is returned.
/// @param idx the index of the template type
/// @param ty the type
/// @returns true on match or newly defined
const core::type::Type* Type(size_t idx, const core::type::Type* ty) {
if (idx >= types_.Length()) {
types_.Resize(idx + 1);
}
auto& t = types_[idx];
if (t == nullptr) {
t = ty;
return ty;
}
ty = core::type::Type::Common(Vector{t, ty});
if (ty) {
t = ty;
}
return ty;
}
/// If the number with index @p idx is undefined, then it is defined with the number
/// `number` and Num() returns true. If the number is defined, then `Num()` returns true iff
/// it is equal to @p ty.
/// @param idx the index of the template number
/// @param number the number
/// @returns true on match or newly defined
bool Num(size_t idx, Number number) {
if (idx >= numbers_.Length()) {
numbers_.Resize(idx + 1, Number::any);
}
auto& n = numbers_[idx];
if (n.IsAny()) {
n = number.Value();
return true;
}
return n.Value() == number.Value();
}
/// @param idx the index of the template type
/// @returns the template type with index @p idx, or nullptr if the type was not
/// defined.
const core::type::Type* Type(size_t idx) const {
if (idx >= types_.Length()) {
return nullptr;
}
return types_[idx];
}
/// SetType replaces the template type with index @p idx with type @p ty.
/// @param idx the index of the template type
/// @param ty the new type for the template
void SetType(size_t idx, const core::type::Type* ty) {
if (idx >= types_.Length()) {
types_.Resize(idx + 1);
}
types_[idx] = ty;
}
/// @returns the number type with index @p idx.
/// @param idx the index of the template number
Number Num(size_t idx) const {
if (idx >= numbers_.Length()) {
return Number::invalid;
}
return numbers_[idx];
}
/// SetNum replaces the template number with index @p idx with number @p num.
/// @param idx the index of the template number
/// @param num the new number for the template
void SetNum(size_t idx, Number num) {
if (idx >= numbers_.Length()) {
numbers_.Resize(idx + 1, Number::any);
}
numbers_[idx] = num;
}
/// @return the total number of type and number templates
size_t Count() const { return types_.Length() + numbers_.Length(); }
private:
Vector<const core::type::Type*, 4> types_;
Vector<Number, 2> numbers_;
};
/// The current overload match state
/// MatchState holds the state used to match an overload.
class MatchState {
public:
/// Constructor
/// @param ty_mgr the type manager
/// @param syms the symbol table
/// @param t the template state
/// @param d the table data
/// @param o the current overload
/// @param matcher_indices the remaining matcher indices
/// @param s the required evaluation stage of the overload
MatchState(core::type::Manager& ty_mgr,
SymbolTable& syms,
TemplateState& t,
const TableData& d,
const OverloadInfo& o,
const MatcherIndex* matcher_indices,
EvaluationStage s)
: types(ty_mgr),
symbols(syms),
templates(t),
data(d),
overload(o),
earliest_eval_stage(s),
matcher_indices_(matcher_indices) {}
/// The type manager
core::type::Manager& types;
/// The symbol manager
SymbolTable& symbols;
/// The template types and numbers
TemplateState& templates;
/// The table data
const TableData& data;
/// The current overload being evaluated
const OverloadInfo& overload;
/// The earliest evaluation stage of the builtin call
EvaluationStage earliest_eval_stage;
/// Type uses the next TypeMatcher from the matcher indices to match the type @p ty.
/// @param ty the type to try matching
/// @returns the canonical expected type if the type matches, otherwise nullptr.
/// @note: The matcher indices are progressed on calling.
inline const core::type::Type* Type(const core::type::Type* ty);
/// Num uses the next NumMatcher from the matcher indices to match @p number.
/// @param number the number to try matching
/// @returns the canonical expected number if the number matches, otherwise an invalid
/// number.
/// @note: The matcher indices are progressed on calling.
inline Number Num(Number number);
/// Prints the type matcher representation to @p out
/// @note: The matcher indices are progressed on calling.
inline void PrintType(StyledText& out);
/// Prints the number matcher representation to @p out
/// @note: The matcher indices are progressed on calling.
inline void PrintNum(StyledText& out);
private:
const MatcherIndex* matcher_indices_ = nullptr;
};
/// A TypeMatcher is the interface used to match an type used as part of an
/// overload's parameter or return type.
struct TypeMatcher {
/// Checks whether the given type matches the matcher rules, and returns the
/// expected, canonicalized type on success.
/// Match may define and refine the template types and numbers in state.
/// The parameter `type` is the type to match
/// Returns the canonicalized type on match, otherwise nullptr
using MatchFn = const core::type::Type*(MatchState& state, const core::type::Type* type);
/// @see #MatchFn
MatchFn* const match;
/// Prints the representation of the matcher.
/// Used for printing error messages when no overload is found.
using PrintFn = void(MatchState* state, StyledText& out);
/// @see #PrintFn
PrintFn* const print;
};
/// A NumberMatcher is the interface used to match a number or enumerator used
/// as part of an overload's parameter or return type.
struct NumberMatcher {
/// Checks whether the given number matches the matcher rules.
/// Match may define template numbers in state.
/// The parameter `number` is the number to match
/// Returns true if the argument type is as expected.
using MatchFn = Number(MatchState& state, Number number);
/// @see #MatchFn
MatchFn* const match;
/// Prints the representation of the matcher.
/// Used for printing error messages when no overload is found.
using PrintFn = void(MatchState* state, StyledText& out);
/// @see #PrintFn
PrintFn* const print;
};
/// TableData holds the immutable data that holds the intrinsic data for a language.
struct TableData {
/// @param idx the index of the TemplateInfo in the table data
/// @returns the TemplateInfo with the given index
template <typename T>
const TemplateInfo& operator[](TableIndex<TableIndexNamespace::kTemplate, T> idx) const {
return templates[idx.value];
}
/// @param idx the index of the MatcherIndices in the table data
/// @returns the MatcherIndices with the given index
template <typename T>
const MatcherIndex* operator[](TableIndex<TableIndexNamespace::kMatcherIndices, T> idx) const {
if (idx.IsValid()) {
return &matcher_indices[idx.value];
}
return nullptr;
}
/// @param idx the index of the TypeMatcher in the table data
/// @returns the TypeMatcher with the given index
template <typename T>
const TypeMatcher& operator[](TableIndex<TableIndexNamespace::kTypeMatcher, T> idx) const {
return type_matchers[idx.value];
}
/// @param idx the index of the NumberMatcher in the table data
/// @returns the NumberMatcher with the given index
template <typename T>
const NumberMatcher& operator[](TableIndex<TableIndexNamespace::kNumberMatcher, T> idx) const {
return number_matchers[idx.value];
}
/// @param idx the index of the ParameterInfo in the table data
/// @returns the ParameterInfo with the given index
template <typename T>
const ParameterInfo& operator[](TableIndex<TableIndexNamespace::kParameter, T> idx) const {
return parameters[idx.value];
}
/// @param idx the index of the OverloadInfo in the table data
/// @returns the OverloadInfo with the given index
template <typename T>
const OverloadInfo& operator[](TableIndex<TableIndexNamespace::kOverload, T> idx) const {
return overloads[idx.value];
}
/// @param idx the index of the constant::Eval::Function in the table data
/// @returns the constant::Eval::Function with the given index
template <typename T>
constant::Eval::Function operator[](
TableIndex<TableIndexNamespace::kConstEvalFunction, T> idx) const {
return idx.IsValid() ? const_eval_functions[idx.value] : nullptr;
}
/// The list of templates used by the intrinsic overloads
const Slice<const TemplateInfo> templates;
/// The list of type matcher indices
const Slice<const MatcherIndex> matcher_indices;
/// The list of type matchers used by the intrinsic overloads
const Slice<const TypeMatcher> type_matchers;
/// The list of number matchers used by the intrinsic overloads
const Slice<const NumberMatcher> number_matchers;
/// The list of parameters used by the intrinsic overloads
const Slice<const ParameterInfo> parameters;
/// The list of overloads used by the intrinsics
const Slice<const OverloadInfo> overloads;
/// The list of constant evaluation functions used by the intrinsics
const Slice<const constant::Eval::Function> const_eval_functions;
/// The type constructor and convertor intrinsics
const Slice<const IntrinsicInfo> ctor_conv;
/// The builtin function intrinsic
const Slice<const IntrinsicInfo> builtins;
/// The IntrinsicInfo for the binary operator 'plus'
const IntrinsicInfo& binary_plus;
/// The IntrinsicInfo for the binary operator 'minus'
const IntrinsicInfo& binary_minus;
/// The IntrinsicInfo for the binary operator 'star'
const IntrinsicInfo& binary_star;
/// The IntrinsicInfo for the binary operator 'divide'
const IntrinsicInfo& binary_divide;
/// The IntrinsicInfo for the binary operator 'modulo'
const IntrinsicInfo& binary_modulo;
/// The IntrinsicInfo for the binary operator 'xor'
const IntrinsicInfo& binary_xor;
/// The IntrinsicInfo for the binary operator 'and'
const IntrinsicInfo& binary_and;
/// The IntrinsicInfo for the binary operator 'or'
const IntrinsicInfo& binary_or;
/// The IntrinsicInfo for the binary operator 'logical_and'
const IntrinsicInfo& binary_logical_and;
/// The IntrinsicInfo for the binary operator 'logical_or'
const IntrinsicInfo& binary_logical_or;
/// The IntrinsicInfo for the binary operator 'equal'
const IntrinsicInfo& binary_equal;
/// The IntrinsicInfo for the binary operator 'not_equal'
const IntrinsicInfo& binary_not_equal;
/// The IntrinsicInfo for the binary operator 'less_than'
const IntrinsicInfo& binary_less_than;
/// The IntrinsicInfo for the binary operator 'greater_than'
const IntrinsicInfo& binary_greater_than;
/// The IntrinsicInfo for the binary operator 'less_than_equal'
const IntrinsicInfo& binary_less_than_equal;
/// The IntrinsicInfo for the binary operator 'greater_than_equal'
const IntrinsicInfo& binary_greater_than_equal;
/// The IntrinsicInfo for the binary operator 'shift_left'
const IntrinsicInfo& binary_shift_left;
/// The IntrinsicInfo for the binary operator 'shift_right'
const IntrinsicInfo& binary_shift_right;
/// The IntrinsicInfo for the unary operator 'not'
const IntrinsicInfo& unary_not;
/// The IntrinsicInfo for the unary operator 'complement'
const IntrinsicInfo& unary_complement;
/// The IntrinsicInfo for the unary operator 'minus'
const IntrinsicInfo& unary_minus;
/// The IntrinsicInfo for the unary operator 'star'
const IntrinsicInfo& unary_star;
/// The IntrinsicInfo for the unary operator 'and'
const IntrinsicInfo& unary_and;
};
TINT_BEGIN_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
const core::type::Type* MatchState::Type(const core::type::Type* ty) {
TypeMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
return matcher.match(*this, ty);
}
Number MatchState::Num(Number number) {
NumberMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
return matcher.match(*this, number);
}
void MatchState::PrintType(StyledText& out) {
TypeMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
matcher.print(this, out);
}
void MatchState::PrintNum(StyledText& out) {
NumberMatcherIndex matcher_index{(*matcher_indices_++).value};
auto& matcher = data[matcher_index];
matcher.print(this, out);
}
TINT_END_DISABLE_WARNING(UNSAFE_BUFFER_USAGE);
/// TemplateTypeMatcher is a Matcher for a template type.
/// The TemplateTypeMatcher will initially match against any type, and then will only be further
/// constrained based on the conversion rules defined at
/// https://www.w3.org/TR/WGSL/#conversion-rank
template <size_t INDEX>
struct TemplateTypeMatcher {
/// The TypeMatcher for the template type with the index `INDEX`
static constexpr TypeMatcher matcher{
/* match */
[](MatchState& state, const core::type::Type* type) -> const core::type::Type* {
if (type->Is<Any>()) {
return state.templates.Type(INDEX);
}
if (auto* templates = state.templates.Type(INDEX, type)) {
return templates;
}
return nullptr;
},
/* print */
[](MatchState* state, StyledText& out) {
out << style::Type(state->data[state->overload.templates + INDEX].name);
},
};
};
/// TemplateNumberMatcher is a Matcher for a template number.
/// The TemplateNumberMatcher will match against any number (so long as it is
/// consistent for all uses in the overload)
template <size_t INDEX>
struct TemplateNumberMatcher {
/// The NumberMatcher for the template number with the index `INDEX`
static constexpr NumberMatcher matcher{
/* match */
[](MatchState& state, Number number) -> Number {
if (number.IsAny()) {
return state.templates.Num(INDEX);
}
return state.templates.Num(INDEX, number) ? number : Number::invalid;
},
/* print */
[](MatchState* state, StyledText& out) {
out << style::Variable(state->data[state->overload.templates + INDEX].name);
},
};
};
} // namespace tint::core::intrinsic
#endif // SRC_TINT_LANG_CORE_INTRINSIC_TABLE_DATA_H_

View File

@@ -0,0 +1,824 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_
#define SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_
#include "src/tint/lang/core/evaluation_stage.h"
#include "src/tint/lang/core/intrinsic/table_data.h"
#include "src/tint/lang/core/type/abstract_float.h"
#include "src/tint/lang/core/type/abstract_int.h"
#include "src/tint/lang/core/type/abstract_numeric.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/atomic.h"
#include "src/tint/lang/core/type/binding_array.h"
#include "src/tint/lang/core/type/bool.h"
#include "src/tint/lang/core/type/builtin_structs.h"
#include "src/tint/lang/core/type/depth_multisampled_texture.h"
#include "src/tint/lang/core/type/depth_texture.h"
#include "src/tint/lang/core/type/external_texture.h"
#include "src/tint/lang/core/type/f16.h"
#include "src/tint/lang/core/type/f32.h"
#include "src/tint/lang/core/type/i32.h"
#include "src/tint/lang/core/type/i8.h"
#include "src/tint/lang/core/type/input_attachment.h"
#include "src/tint/lang/core/type/manager.h"
#include "src/tint/lang/core/type/matrix.h"
#include "src/tint/lang/core/type/multisampled_texture.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/reference.h"
#include "src/tint/lang/core/type/sampled_texture.h"
#include "src/tint/lang/core/type/storage_texture.h"
#include "src/tint/lang/core/type/string.h"
#include "src/tint/lang/core/type/texture_dimension.h"
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/lang/core/type/u64.h"
#include "src/tint/lang/core/type/u8.h"
#include "src/tint/lang/core/type/vector.h"
//! @cond Doxygen_Suppress
namespace tint::core::intrinsic {
inline bool MatchBool(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::Bool>();
}
inline const type::Bool* BuildBool(intrinsic::MatchState& state, const type::Type*) {
return state.types.bool_();
}
inline const type::F16* BuildF16(intrinsic::MatchState& state, const type::Type*) {
return state.types.f16();
}
inline bool MatchF16(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::F16, type::AbstractNumeric>();
}
inline const type::F32* BuildF32(intrinsic::MatchState& state, const type::Type*) {
return state.types.f32();
}
inline bool MatchF32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::F32, type::AbstractNumeric>();
}
inline const type::I32* BuildI32(intrinsic::MatchState& state, const type::Type*) {
return state.types.i32();
}
inline bool MatchI32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::I32, type::AbstractInt>();
}
inline const type::I8* BuildI8(intrinsic::MatchState& state, const type::Type*) {
return state.types.i8();
}
inline bool MatchI8(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::I8, type::AbstractInt>();
}
inline const type::U32* BuildU32(intrinsic::MatchState& state, const type::Type*) {
return state.types.u32();
}
inline bool MatchU32(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::U32, type::AbstractInt>();
}
inline const type::U64* BuildU64(intrinsic::MatchState& state, const type::Type*) {
return state.types.u64();
}
inline bool MatchU64(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::U64, type::AbstractInt>();
}
inline const type::U8* BuildU8(intrinsic::MatchState& state, const type::Type*) {
return state.types.u8();
}
inline bool MatchU8(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::U8, type::AbstractInt>();
}
inline bool MatchVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
N = intrinsic::Number::any;
T = ty;
return true;
}
if (auto* v = ty->As<type::Vector>()) {
N = v->Width();
T = v->Type();
return true;
}
return false;
}
template <uint32_t N>
inline bool MatchVec(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* v = ty->As<type::Vector>()) {
if (v->Width() == N) {
T = v->Type();
return true;
}
}
return false;
}
inline const type::Vector* BuildVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number N,
const type::Type* el) {
return state.types.vec(el, N.Value());
}
template <uint32_t N>
inline const type::Vector* BuildVec(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return state.types.vec(el, N);
}
constexpr auto MatchVec2 = MatchVec<2>;
constexpr auto MatchVec3 = MatchVec<3>;
constexpr auto MatchVec4 = MatchVec<4>;
constexpr auto BuildVec2 = BuildVec<2>;
constexpr auto BuildVec3 = BuildVec<3>;
constexpr auto BuildVec4 = BuildVec<4>;
inline bool MatchPackedVec3(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* v = ty->As<type::Vector>()) {
if (v->Packed()) {
T = v->Type();
return true;
}
}
return false;
}
inline const type::Vector* BuildPackedVec3(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return state.types.packed_vec(el, 3u);
}
inline bool MatchMat(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& M,
intrinsic::Number& N,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
M = intrinsic::Number::any;
N = intrinsic::Number::any;
T = ty;
return true;
}
if (auto* m = ty->As<type::Matrix>()) {
M = m->Columns();
N = m->ColumnType()->Width();
T = m->Type();
return true;
}
return false;
}
template <uint32_t C, uint32_t R>
inline bool MatchMat(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* m = ty->As<type::Matrix>()) {
if (m->Columns() == C && m->Rows() == R) {
T = m->Type();
return true;
}
}
return false;
}
inline const type::Matrix* BuildMat(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number C,
intrinsic::Number R,
const type::Type* T) {
auto* column_type = state.types.vec(T, R.Value());
return state.types.mat(column_type, C.Value());
}
template <uint32_t C, uint32_t R>
inline const type::Matrix* BuildMat(intrinsic::MatchState& state,
const type::Type*,
const type::Type* T) {
auto* column_type = state.types.vec(T, R);
return state.types.mat(column_type, C);
}
constexpr auto BuildMat2X2 = BuildMat<2, 2>;
constexpr auto BuildMat2X3 = BuildMat<2, 3>;
constexpr auto BuildMat2X4 = BuildMat<2, 4>;
constexpr auto BuildMat3X2 = BuildMat<3, 2>;
constexpr auto BuildMat3X3 = BuildMat<3, 3>;
constexpr auto BuildMat3X4 = BuildMat<3, 4>;
constexpr auto BuildMat4X2 = BuildMat<4, 2>;
constexpr auto BuildMat4X3 = BuildMat<4, 3>;
constexpr auto BuildMat4X4 = BuildMat<4, 4>;
constexpr auto MatchMat2X2 = MatchMat<2, 2>;
constexpr auto MatchMat2X3 = MatchMat<2, 3>;
constexpr auto MatchMat2X4 = MatchMat<2, 4>;
constexpr auto MatchMat3X2 = MatchMat<3, 2>;
constexpr auto MatchMat3X3 = MatchMat<3, 3>;
constexpr auto MatchMat3X4 = MatchMat<3, 4>;
constexpr auto MatchMat4X2 = MatchMat<4, 2>;
constexpr auto MatchMat4X3 = MatchMat<4, 3>;
constexpr auto MatchMat4X4 = MatchMat<4, 4>;
inline bool MatchSubgroupMatrix(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& S,
const type::Type*& T,
intrinsic::Number& A,
intrinsic::Number& B) {
if (ty->Is<intrinsic::Any>()) {
A = intrinsic::Number::any;
B = intrinsic::Number::any;
S = intrinsic::Number::any;
T = ty;
return true;
}
if (auto* sm = ty->As<type::SubgroupMatrix>()) {
A = sm->Columns();
B = sm->Rows();
S = intrinsic::Number(static_cast<uint32_t>(sm->Kind()));
T = sm->Type();
return true;
}
return false;
}
inline const type::SubgroupMatrix* BuildSubgroupMatrix(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number S,
const type::Type* T,
intrinsic::Number A,
intrinsic::Number B) {
return state.types.subgroup_matrix(static_cast<core::SubgroupMatrixKind>(S.Value()), T,
A.Value(), B.Value());
}
inline bool MatchUnsizedBuffer(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
if (auto* b = ty->As<type::Buffer>()) {
return b->Size() == 0;
}
return false;
}
inline const type::Buffer* BuildUnsizedBuffer(intrinsic::MatchState& state, const type::Type*) {
return state.types.unsized_buffer();
}
inline bool MatchBuffer(intrinsic::MatchState&, const type::Type* ty, intrinsic::Number& N) {
if (ty->Is<intrinsic::Any>()) {
N = intrinsic::Number::any;
return true;
}
if (auto* b = ty->As<type::Buffer>()) {
if (b->Size() != 0) {
N = b->Size();
return true;
}
}
return false;
}
inline const type::Buffer* BuildBuffer(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number N) {
return state.types.buffer(N.Value());
}
inline bool MatchArray(intrinsic::MatchState&,
const type::Type* ty,
const type::Type*& T,
intrinsic::Number& C) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
C = intrinsic::Number::any;
return true;
}
if (auto* a = ty->As<type::Array>()) {
if (auto count = a->Count()->As<type::ConstantArrayCount>()) {
T = a->ElemType();
C = intrinsic::Number(count->value);
return true;
}
}
return false;
}
inline const type::Array* BuildArray(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el,
intrinsic::Number C) {
return state.types.array(el, C.Value());
}
inline bool MatchRuntimeArray(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* a = ty->As<type::Array>()) {
if (a->Count()->Is<type::RuntimeArrayCount>()) {
T = a->ElemType();
return true;
}
}
return false;
}
inline const type::Array* BuildRuntimeArray(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return state.types.runtime_array(el);
}
inline const type::BindingArray* BuildBindingArray(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el,
intrinsic::Number N) {
return state.types.binding_array(el, N.Value());
}
inline bool MatchBindingArray(intrinsic::MatchState&,
const type::Type* ty,
const type::Type*& T,
intrinsic::Number& N) {
if (ty->Is<intrinsic::Any>()) {
N = intrinsic::Number::any;
T = ty;
return true;
}
if (auto* a = ty->As<type::BindingArray>()) {
if (auto count = a->Count()->As<type::ConstantArrayCount>()) {
N = intrinsic::Number(count->value);
T = a->ElemType();
return true;
}
}
return false;
}
inline bool MatchPtr(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& S,
const type::Type*& T,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
S = intrinsic::Number::any;
T = ty;
A = intrinsic::Number::any;
return true;
}
if (auto* p = ty->As<type::Pointer>()) {
S = intrinsic::Number(static_cast<uint32_t>(p->AddressSpace()));
T = p->StoreType();
A = intrinsic::Number(static_cast<uint32_t>(p->Access()));
return true;
}
return false;
}
inline const type::Pointer* BuildPtr(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number S,
const type::Type* T,
intrinsic::Number& A) {
return state.types.ptr(static_cast<core::AddressSpace>(S.Value()), T,
static_cast<core::Access>(A.Value()));
}
inline bool MatchRef(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& S,
const type::Type*& T,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
S = intrinsic::Number::any;
T = ty;
A = intrinsic::Number::any;
return true;
}
if (auto* p = ty->As<type::Reference>()) {
S = intrinsic::Number(static_cast<uint32_t>(p->AddressSpace()));
T = p->StoreType();
A = intrinsic::Number(static_cast<uint32_t>(p->Access()));
return true;
}
return false;
}
inline const type::Reference* BuildRef(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number S,
const type::Type* T,
intrinsic::Number& A) {
return state.types.ref(static_cast<core::AddressSpace>(S.Value()), T,
static_cast<core::Access>(A.Value()));
}
inline bool MatchAtomic(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* a = ty->As<type::Atomic>()) {
T = a->Type();
return true;
}
return false;
}
inline const type::Atomic* BuildAtomic(intrinsic::MatchState& state,
const type::Type*,
const type::Type* T) {
return state.types.atomic(T);
}
inline bool MatchSampler(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([](const type::Sampler* s) { return s->Kind() == type::SamplerKind::kSampler; });
}
inline const type::Sampler* BuildSampler(intrinsic::MatchState& state, const type::Type*) {
return state.types.sampler();
}
inline bool MatchSamplerComparison(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is(
[](const type::Sampler* s) { return s->Kind() == type::SamplerKind::kComparisonSampler; });
}
inline const type::Sampler* BuildSamplerComparison(intrinsic::MatchState& state,
const type::Type*) {
return state.types.comparison_sampler();
}
inline bool MatchTexture(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* v = ty->As<type::SampledTexture>()) {
if (v->Dim() == dim) {
T = v->Type();
return true;
}
}
return false;
}
#define JOIN(a, b) a##b
#define DECLARE_SAMPLED_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTexture, suffix)(intrinsic::MatchState & state, const type::Type* ty, \
const type::Type*& T) { \
return MatchTexture(state, ty, dim, T); \
} \
inline const type::SampledTexture* JOIN(BuildTexture, suffix)( \
intrinsic::MatchState & state, const type::Type*, const type::Type* T) { \
return state.types.sampled_texture(dim, T); \
}
DECLARE_SAMPLED_TEXTURE(1D, type::TextureDimension::k1d)
DECLARE_SAMPLED_TEXTURE(2D, type::TextureDimension::k2d)
DECLARE_SAMPLED_TEXTURE(2DArray, type::TextureDimension::k2dArray)
DECLARE_SAMPLED_TEXTURE(3D, type::TextureDimension::k3d)
DECLARE_SAMPLED_TEXTURE(Cube, type::TextureDimension::kCube)
DECLARE_SAMPLED_TEXTURE(CubeArray, type::TextureDimension::kCubeArray)
#undef DECLARE_SAMPLED_TEXTURE
inline bool MatchTextureMultisampled(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* v = ty->As<type::MultisampledTexture>()) {
if (v->Dim() == dim) {
T = v->Type();
return true;
}
}
return false;
}
#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTextureMultisampled, suffix)( \
intrinsic::MatchState & state, const type::Type* ty, const type::Type*& T) { \
return MatchTextureMultisampled(state, ty, dim, T); \
} \
inline const type::MultisampledTexture* JOIN(BuildTextureMultisampled, suffix)( \
intrinsic::MatchState & state, const type::Type*, const type::Type* T) { \
return state.types.multisampled_texture(dim, T); \
}
DECLARE_MULTISAMPLED_TEXTURE(2D, type::TextureDimension::k2d)
#undef DECLARE_MULTISAMPLED_TEXTURE
inline bool MatchTextureDepth(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([&](const type::DepthTexture* t) { return t->Dim() == dim; });
}
#define DECLARE_DEPTH_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTextureDepth, suffix)(intrinsic::MatchState & state, \
const type::Type* ty) { \
return MatchTextureDepth(state, ty, dim); \
} \
inline const type::DepthTexture* JOIN(BuildTextureDepth, suffix)( \
intrinsic::MatchState & state, const type::Type*) { \
return state.types.depth_texture(dim); \
}
DECLARE_DEPTH_TEXTURE(2D, type::TextureDimension::k2d)
DECLARE_DEPTH_TEXTURE(2DArray, type::TextureDimension::k2dArray)
DECLARE_DEPTH_TEXTURE(Cube, type::TextureDimension::kCube)
DECLARE_DEPTH_TEXTURE(CubeArray, type::TextureDimension::kCubeArray)
#undef DECLARE_DEPTH_TEXTURE
inline bool MatchTextureDepthMultisampled2D(intrinsic::MatchState&, const type::Type* ty) {
if (ty->Is<intrinsic::Any>()) {
return true;
}
return ty->Is([&](const type::DepthMultisampledTexture* t) {
return t->Dim() == type::TextureDimension::k2d;
});
}
inline const type::DepthMultisampledTexture* BuildTextureDepthMultisampled2D(
intrinsic::MatchState& state,
const type::Type*) {
return state.types.depth_multisampled_texture(type::TextureDimension::k2d);
}
inline bool MatchTextureStorage(intrinsic::MatchState&,
const type::Type* ty,
type::TextureDimension dim,
intrinsic::Number& F,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
F = intrinsic::Number::any;
A = intrinsic::Number::any;
return true;
}
if (auto* v = ty->As<type::StorageTexture>()) {
if (v->Dim() == dim) {
F = intrinsic::Number(static_cast<uint32_t>(v->TexelFormat()));
A = intrinsic::Number(static_cast<uint32_t>(v->Access()));
return true;
}
}
return false;
}
#define DECLARE_STORAGE_TEXTURE(suffix, dim) \
inline bool JOIN(MatchTextureStorage, suffix)(intrinsic::MatchState & state, \
const type::Type* ty, intrinsic::Number& F, \
intrinsic::Number& A) { \
return MatchTextureStorage(state, ty, dim, F, A); \
} \
inline const type::StorageTexture* JOIN(BuildTextureStorage, suffix)( \
intrinsic::MatchState & state, const type::Type*, intrinsic::Number F, \
intrinsic::Number A) { \
auto format = static_cast<TexelFormat>(F.Value()); \
auto access = static_cast<Access>(A.Value()); \
return state.types.storage_texture(dim, format, access); \
}
DECLARE_STORAGE_TEXTURE(1D, type::TextureDimension::k1d)
DECLARE_STORAGE_TEXTURE(2D, type::TextureDimension::k2d)
DECLARE_STORAGE_TEXTURE(2DArray, type::TextureDimension::k2dArray)
DECLARE_STORAGE_TEXTURE(3D, type::TextureDimension::k3d)
#undef DECLARE_STORAGE_TEXTURE
inline bool MatchTextureExternal(intrinsic::MatchState&, const type::Type* ty) {
return ty->IsAnyOf<intrinsic::Any, type::ExternalTexture>();
}
inline const type::ExternalTexture* BuildTextureExternal(intrinsic::MatchState& state,
const type::Type*) {
return state.types.external_texture();
}
inline bool MatchTexelBuffer(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& F,
intrinsic::Number& A) {
if (ty->Is<intrinsic::Any>()) {
F = intrinsic::Number::any;
A = intrinsic::Number::any;
return true;
}
if (auto* v = ty->As<type::TexelBuffer>()) {
F = intrinsic::Number(static_cast<uint32_t>(v->TexelFormat()));
A = intrinsic::Number(static_cast<uint32_t>(v->Access()));
return true;
}
return false;
}
inline const type::TexelBuffer* BuildTexelBuffer(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number F,
intrinsic::Number A) {
auto format = static_cast<TexelFormat>(F.Value());
auto access = static_cast<Access>(A.Value());
return state.types.texel_buffer(format, access);
}
inline bool MatchInputAttachment(intrinsic::MatchState&,
const type::Type* ty,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
if (auto* v = ty->As<type::InputAttachment>()) {
T = v->Type();
return true;
}
return false;
}
inline const type::InputAttachment* BuildInputAttachment(intrinsic::MatchState& state,
const type::Type*,
const type::Type* T) {
return state.types.input_attachment(T);
}
// Builtin types starting with a _ prefix cannot be declared in WGSL, so they
// can only be used as return types. Because of this, they must only match Any,
// which is used as the return type matcher.
inline bool MatchModfResult(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
T = ty;
return true;
}
inline bool MatchModfResultVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
N = intrinsic::Number::any;
T = ty;
return true;
}
inline bool MatchFrexpResult(intrinsic::MatchState&, const type::Type* ty, const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
T = ty;
return true;
}
inline bool MatchFrexpResultVec(intrinsic::MatchState&,
const type::Type* ty,
intrinsic::Number& N,
const type::Type*& T) {
if (!ty->Is<intrinsic::Any>()) {
return false;
}
N = intrinsic::Number::any;
T = ty;
return true;
}
inline bool MatchAtomicCompareExchangeResult(intrinsic::MatchState&,
const type::Type* ty,
const type::Type*& T) {
if (ty->Is<intrinsic::Any>()) {
T = ty;
return true;
}
return false;
}
inline const type::Struct* BuildModfResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return type::CreateModfResult(state.types, state.symbols, el);
}
inline const type::Struct* BuildModfResultVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number& n,
const type::Type* el) {
auto* vec = state.types.vec(el, n.Value());
return type::CreateModfResult(state.types, state.symbols, vec);
}
inline const type::Struct* BuildFrexpResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* el) {
return type::CreateFrexpResult(state.types, state.symbols, el);
}
inline const type::Struct* BuildFrexpResultVec(intrinsic::MatchState& state,
const type::Type*,
intrinsic::Number& n,
const type::Type* el) {
auto* vec = state.types.vec(el, n.Value());
return type::CreateFrexpResult(state.types, state.symbols, vec);
}
inline const type::Struct* BuildAtomicCompareExchangeResult(intrinsic::MatchState& state,
const type::Type*,
const type::Type* ty) {
return type::CreateAtomicCompareExchangeResult(state.types, state.symbols, ty);
}
inline bool MatchString(core::intrinsic::MatchState&, const core::type::Type* ty) {
return ty->Is<type::String>();
}
inline const core::type::Type* BuildString(core::intrinsic::MatchState& state,
const core::type::Type*) {
return state.types.String();
}
} // namespace tint::core::intrinsic
//! @endcond
#endif // SRC_TINT_LANG_CORE_INTRINSIC_TYPE_MATCHERS_H_

View File

@@ -0,0 +1,104 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IO_ATTRIBUTES_H_
#define SRC_TINT_LANG_CORE_IO_ATTRIBUTES_H_
#include <cstdint>
#include <optional>
#include "src/tint/api/common/binding_point.h"
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/interpolation.h"
namespace tint::core {
/// Attributes that can be applied to an object that will be used for shader IO.
struct IOAttributes {
/// The value of a `@location` attribute.
std::optional<uint32_t> location = std::nullopt;
/// The value of a `@blend_src` attribute.
std::optional<uint32_t> blend_src = std::nullopt;
/// The value of a `@color` attribute.
std::optional<uint32_t> color = std::nullopt;
/// The value of a `@builtin` attribute.
std::optional<core::BuiltinValue> builtin = std::nullopt;
/// The depth mode of a `@builtin` attribute.
std::optional<core::BuiltinDepthMode> depth_mode = std::nullopt;
/// The values of a `@interpolate` attribute.
std::optional<core::Interpolation> interpolation = std::nullopt;
/// The value of an `@input_attachment_index` attribute
std::optional<uint32_t> input_attachment_index = std::nullopt;
/// The value of the `@binding` and `@group` attributes
std::optional<BindingPoint> binding_point = std::nullopt;
/// True if the object is annotated with `@invariant`.
bool invariant = false;
};
/// Used for referencing/tagging a specific IOAttribute.
/// IOAttributes above is intentionally not a key-value map (e.g. HashSet) using this enum, since it
/// has heterogeneous value types and would also cease to be a POD.
enum class IOAttributeKind : uint8_t {
kLocation,
kBlendSrc,
kColor,
kBuiltin,
kDepthMode,
kInterpolation,
kInputAttachmentIndex,
kBindingPoint,
kInvariant,
};
/// @returns a human-readable string representation of @p kind
inline std::string_view ToString(const IOAttributeKind kind) {
switch (kind) {
case IOAttributeKind::kLocation:
return "location";
case IOAttributeKind::kBlendSrc:
return "blend src";
case IOAttributeKind::kColor:
return "color";
case IOAttributeKind::kBuiltin:
return "builtin";
case IOAttributeKind::kDepthMode:
return "depth mode";
case IOAttributeKind::kInterpolation:
return "interpolation";
case IOAttributeKind::kInputAttachmentIndex:
return "input attachment index";
case IOAttributeKind::kBindingPoint:
return "binding point";
case IOAttributeKind::kInvariant:
return "invariant";
}
TINT_ICE() << "Unknown kind passed to ToString(IOAttributeKind)";
}
} // namespace tint::core
#endif // SRC_TINT_LANG_CORE_IO_ATTRIBUTES_H_

View File

@@ -0,0 +1,59 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/access.h"
#include <utility>
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Access);
namespace tint::core::ir {
//! @cond Doxygen_Suppress
Access::Access(Id id) : Base(id) {}
Access::Access(Id id, InstructionResult* result, Value* object, VectorRef<Value*> indices)
: Base(id) {
AddOperand(Access::kObjectOperandOffset, object);
AddOperands(Access::kIndicesOperandOffset, std::move(indices));
AddResult(result);
}
Access::~Access() = default;
Access* Access::Clone(CloneContext& ctx) {
auto new_result = ctx.Clone(Result());
auto obj = ctx.Remap(Object());
auto indices = ctx.Remap<Access::kDefaultNumOperands>(Indices());
return ctx.ir.CreateInstruction<Access>(new_result, obj, indices);
}
//! @endcond
} // namespace tint::core::ir

View File

@@ -0,0 +1,97 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_ACCESS_H_
#define SRC_TINT_LANG_CORE_IR_ACCESS_H_
#include <string>
#include "src/tint/lang/core/ir/operand_instruction.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// An access instruction in the IR.
class Access final : public Castable<Access, OperandInstruction<3, 1>> {
public:
/// The offset in Operands() for the object being accessed
static constexpr size_t kObjectOperandOffset = 0;
/// The base offset in Operands() for the access indices
static constexpr size_t kIndicesOperandOffset = 1;
/// The fixed number of results returned by this instruction
static constexpr size_t kNumResults = 1;
/// The minimum number of operands used by this instruction
static constexpr size_t kMinNumOperands = 2;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit Access(Instruction::Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param object the accessor object
/// @param indices the indices to access
Access(Instruction::Id id, InstructionResult* result, Value* object, VectorRef<Value*> indices);
~Access() override;
/// @copydoc Instruction::Clone()
Access* Clone(CloneContext& ctx) override;
/// @returns the object used for the access
Value* Object() { return Operand(kObjectOperandOffset); }
/// @returns the object used for the access
const Value* Object() const { return Operand(kObjectOperandOffset); }
/// Adds the given index to the end of the access chain
/// @param idx the index to add
void AddIndex(Value* idx) { AddOperand(operands_.Length(), idx); }
/// @returns the accessor indices
tint::Slice<Value* const> Indices() { return operands_.Slice().Offset(kIndicesOperandOffset); }
/// @returns the accessor indices
tint::Slice<const Value* const> Indices() const {
return operands_.Slice().Offset(kIndicesOperandOffset);
}
/// Removes the last index from the access indices
/// @returns the last index value
Value* PopLastIndex() { return PopOperand(); }
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "access"; }
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_ACCESS_H_

View File

@@ -0,0 +1,124 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/analysis/for_loop_analysis.h"
#include <utility>
#include "src/tint/lang/core/ir/access.h"
#include "src/tint/lang/core/ir/binary.h"
#include "src/tint/lang/core/ir/bitcast.h"
#include "src/tint/lang/core/ir/builtin_call.h"
#include "src/tint/lang/core/ir/exit_if.h"
#include "src/tint/lang/core/ir/exit_loop.h"
#include "src/tint/lang/core/ir/function.h"
#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/let.h"
#include "src/tint/lang/core/ir/load.h"
#include "src/tint/lang/core/ir/load_vector_element.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
#include "src/tint/lang/core/ir/store.h"
#include "src/tint/lang/core/ir/swizzle.h"
#include "src/tint/lang/core/ir/traverse.h"
#include "src/tint/lang/core/ir/unary.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/i32.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/utils/containers/hashset.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::core::ir::analysis {
void ForLoopAnalysis::AttemptForLoopDeduction(const Loop* loop) {
// Find the first 'if' which should be the condition for the for-loop.
// Order here is critical since instructions in blocks are forward dependencies.
const core::ir::If* if_to_remove = nullptr;
for (auto* inst : *loop->Body()) {
if (auto* if_ = inst->As<const core::ir::If>()) {
if (if_->Results().IsEmpty() && if_->True()->Length() == 1 &&
if_->False()->Length() == 1 && tint::Is<core::ir::ExitIf>(if_->True()->Front()) &&
tint::Is<core::ir::ExitLoop>(if_->False()->Front())) {
// Matched the loop condition as it was converted from the 'for' originally.
if_to_remove = if_;
break;
} else {
// Conservatively fail to avoid the possibility of reordering instructions (when
// moving into conditional).
return;
}
} else if (inst->Is<const Binary>() || inst->Is<const BuiltinCall>() ||
inst->Is<const Access>() || inst->Is<const Load>() ||
inst->Is<const Swizzle>() || inst->Is<const Unary>() ||
inst->Is<const LoadVectorElement>()) {
// Allowed instructions since either load or operate on values (side effect free).
continue;
} else {
// Conservatively fail for all other functions that could potentially store/mutate
// memory.
return;
}
}
if (!if_to_remove) {
return;
}
Hashset<const core::ir::Instruction*, 32> sink_chain;
// Add the 'if' instruction to set to avoid adding it to the body.
sink_chain.Add(if_to_remove);
const Instruction* inst = if_to_remove->prev;
while (inst) {
const auto& results = inst->Results();
if (results.Length() != 1u) {
// We do not support more than one result for simplicity.
return;
}
for (const auto& each_usage : inst->Result()->UsagesUnsorted()) {
// All usages must sink into the condition of the if
if (!each_usage->instruction || !sink_chain.Contains(each_usage->instruction)) {
return;
}
}
sink_chain.Add(inst);
inst = inst->prev;
}
body_removed_instructions = std::move(sink_chain);
// Valid condition found. Success criteria for condition hoisting.
for_condition = if_to_remove->Condition();
}
ForLoopAnalysis::ForLoopAnalysis(const Loop& loop) {
AttemptForLoopDeduction(&loop);
}
ForLoopAnalysis::~ForLoopAnalysis() = default;
} // namespace tint::core::ir::analysis

View File

@@ -0,0 +1,73 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_ANALYSIS_FOR_LOOP_ANALYSIS_H_
#define SRC_TINT_LANG_CORE_IR_ANALYSIS_FOR_LOOP_ANALYSIS_H_
#include <memory>
#include <set>
#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/utils/ice/ice.h"
namespace tint::core::ir::analysis {
/// ForLoopAnalysis is a helper used to find and hoist the condition into the for loop directly.
/// See crbug.com/429187478 for the rationale behind this analysis.
class ForLoopAnalysis {
public:
/// Constructor
/// @param loop the Loop to cache analyses for
explicit ForLoopAnalysis(const Loop& loop);
~ForLoopAnalysis();
/// Returns the condition for the loop.
/// Otherwise if no condition can be hoisted it returns nullptr.
/// @returns the loop condition instruction result
const core::ir::Value* GetIfCondition() { return for_condition; }
/// Returns true if the instruction should be removed from the body to support condition
/// hoisting.
/// @param inst from the body of the loop
/// @returns a boolean
bool IsBodyRemovedInstruction(const core::ir::Instruction* inst) {
TINT_ASSERT(GetIfCondition());
return body_removed_instructions.Contains(inst);
}
private:
void AttemptForLoopDeduction(const Loop* loop);
Hashset<const core::ir::Instruction*, 32> body_removed_instructions;
const core::ir::Value* for_condition = nullptr;
};
} // namespace tint::core::ir::analysis
#endif // SRC_TINT_LANG_CORE_IR_ANALYSIS_FOR_LOOP_ANALYSIS_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,196 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_ANALYSIS_INTEGER_RANGE_ANALYSIS_H_
#define SRC_TINT_LANG_CORE_IR_ANALYSIS_INTEGER_RANGE_ANALYSIS_H_
#include <cstdint>
#include <memory>
#include <variant>
namespace tint::core::ir {
class Access;
class Binary;
class Constant;
class Convert;
class CoreBuiltinCall;
class Function;
class FunctionParam;
class Let;
class Load;
class Loop;
class Module;
class Value;
class Var;
} // namespace tint::core::ir
namespace tint::core::ir::analysis {
/// The result of a integer range analysis: the upper and lower bound of a given integer variable.
/// The bound is inclusive, which means the value x being bound satisfies:
/// min_bound <= x <= max_bound.
struct IntegerRangeInfo {
IntegerRangeInfo() = default;
IntegerRangeInfo(int64_t min_bound, int64_t max_bound);
IntegerRangeInfo(uint64_t min_bound, uint64_t max_bound);
bool IsValid() const;
struct SignedIntegerRange {
int64_t min_bound;
int64_t max_bound;
};
struct UnsignedIntegerRange {
uint64_t min_bound;
uint64_t max_bound;
};
std::variant<std::monostate, SignedIntegerRange, UnsignedIntegerRange> range;
};
struct IntegerRangeAnalysisImpl;
/// IntegerRangeAnalysis is a helper used to analyze integer ranges.
class IntegerRangeAnalysis {
public:
/// Constructor
/// @module ir_module the ir module to cache analyses for
explicit IntegerRangeAnalysis(Module* ir_module);
~IntegerRangeAnalysis();
/// Returns the integer range info of a given parameter with given index, if it is an integer
/// or an integer vector parameter. The index must not be over the maximum size of the vector
/// and must be 0 if the parameter is an integer.
/// Otherwise is not analyzable and returns an invalid `IntegerRangeInfo` object. If it is the
/// first time to query the info, the result will also be stored into a cache for future
/// queries.
/// @param param the variable to get information about
/// @param index the vector component index when the parameter is a vector type. if the
/// parameter is a scalar, then `index` must be zero.
/// @returns the integer range info
IntegerRangeInfo GetInfo(const FunctionParam* param, uint32_t index = 0);
/// Returns the integer range info of a given variable if it is an integer variable and it has a
/// meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
/// @param var the variable to get information about
/// @returns the integer range info
IntegerRangeInfo GetInfo(const Var* var);
/// Returns the integer range info of a given `Load` variable if it is an integer variable and
/// it has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Load* load_var);
/// Returns the integer range info of a given `Access` variable if it is an integer variable and
/// it has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Access* access);
/// Returns the integer range info of a given `Let` variable if it is an integer variable and it
/// has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Let* let);
/// Returns the integer range info of a given `Constant` if it is an integer.
/// Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Constant* constant);
/// Returns the integer range info of a given `Value` variable if it is an integer variable and
/// it has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Value* value);
/// Returns the integer range info of a given `Binary` variable if it is an integer variable and
/// it has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Binary* binary);
/// Returns the integer range info of a given `Convert` variable if it is an integer variable
/// and it has a meaningful range. Returns an invalid `IntegerRangeInfo` object otherwise.
IntegerRangeInfo GetInfo(const Convert* convert);
/// Returns the integer range info of a given `CoreBuiltinCall` variable if it is an integer
/// variable and it has a meaningful range. Returns an invalid `IntegerRangeInfo` object
/// otherwise.
IntegerRangeInfo GetInfo(const CoreBuiltinCall* call);
/// Note: This function is only for tests.
/// Returns the pointer of the loop control variable in the given loop when its initializer
/// meets the below requirements.
/// - There are only two instructions in the loop initializer block.
/// - The first instruction is to initialize the loop control variable
/// with a constant integer (signed or unsigned) value.
/// - The second instruction is `next_iteration`.
/// @param loop the Loop variable to investigate
/// @returns the pointer of the loop control variable when its loop initializer meets the
/// requirements, return nullptr otherwise.
const Var* GetLoopControlVariableFromConstantInitializerForTest(const Loop* loop);
/// Note: This function is only for tests.
/// Returns the pointer of the binary operation that updates the loop control variable in the
/// continuing block of the given loop if the loop meets the below requirements.
/// - There are only 4 instructions in the loop initializer block.
/// - The first instruction is to load the loop control variable into a temporary variable.
/// - The second instruction is to add one or minus one to the temporary variable.
/// - The third instruction is to store the value of the temporary variable into the loop
/// control variable.
/// - The fourth instruction is `next_iteration`.
/// @param loop the Loop variable to investigate.
/// @param loop_control_variable the loop control variable to investigate.
/// @returns the pointer of the binary operation that updates the loop control variable in the
/// continuing block of the given loop if the loop meets all the requirements, return nullptr
/// otherwise.
const Binary* GetBinaryToUpdateLoopControlVariableInContinuingBlockForTest(
const Loop* loop,
const Var* loop_control_variable);
/// Note: This function is only for tests
/// Returns the pointer of the binary operation that compares the loop control variable with its
/// limitations in the body block of the loop if the loop meets the below requirements:
/// - The loop control variable is only used as the parameter of the load instruction.
/// - The first instruction is to load the loop control variable into a temporary variable.
/// - The second instruction is to compare the temporary variable with a constant value and save
/// the result to a boolean variable.
/// - The second instruction cannot be a comparison that will never return true.
/// - The third instruction is an `ifelse` expression that uses the boolean variable got in the
/// second instruction as the condition.
// - The true block of the above `ifelse` expression doesn't contain `exit_loop`.
// - The false block of the above `ifelse` expression only contains `exit_loop`.
/// @param loop the Loop variable to investigate.
/// @param loop_control_variable the loop control variable to investigate.
/// @returns the pointer of the binary operation that compares the loop control variable with
/// its limitations in the body block of the loop if the loop meets the below requirements,
/// return nullptr otherwise.
const Binary* GetBinaryToCompareLoopControlVariableInLoopBodyForTest(
const Loop* loop,
const Var* loop_control_variable);
private:
IntegerRangeAnalysis(const IntegerRangeAnalysis&) = delete;
IntegerRangeAnalysis(IntegerRangeAnalysis&&) = delete;
std::unique_ptr<IntegerRangeAnalysisImpl> impl_;
};
} // namespace tint::core::ir::analysis
#endif // SRC_TINT_LANG_CORE_IR_ANALYSIS_INTEGER_RANGE_ANALYSIS_H_

View File

@@ -0,0 +1,321 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/analysis/loop_analysis.h"
#include "src/tint/lang/core/ir/binary.h"
#include "src/tint/lang/core/ir/bitcast.h"
#include "src/tint/lang/core/ir/exit_loop.h"
#include "src/tint/lang/core/ir/function.h"
#include "src/tint/lang/core/ir/if.h"
#include "src/tint/lang/core/ir/let.h"
#include "src/tint/lang/core/ir/load.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
#include "src/tint/lang/core/ir/store.h"
#include "src/tint/lang/core/ir/traverse.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/ir/var.h"
#include "src/tint/lang/core/type/i32.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::core::ir::analysis {
namespace {
/// Returns an instruction of the given kind if @p val is the result of such an instruction.
/// Otherwise returns nullptr.
template <typename InstClass>
InstClass* As(Value* val) {
if (auto* instres = val->As<InstructionResult>()) {
return instres->Instruction()->As<InstClass>();
}
return nullptr;
}
/// Returns the value, after unwrapping all bitcasts.
Value* UnwrapBitcast(Value* val) {
while (auto* bitcast = As<Bitcast>(val)) {
val = bitcast->Val();
}
return val;
}
/// Returns true if v is the integer constant 1.
bool IsOne(Value* v) {
if (auto* cv = v->As<Constant>()) {
return Switch(
cv->Type(),
[&](const core::type::I32*) { return cv->Value()->ValueAs<int32_t>() == 1; },
[&](const core::type::U32*) { return cv->Value()->ValueAs<uint32_t>() == 1; },
[&](const Default) -> bool { return false; });
}
return false;
}
/// Returns `true` if `val` is definitely `var +/- 1`.
bool IsIncrementOrDecrementOfVar(const Var& var, Value* val) {
auto is_var_op_one = [&](Value* a, Value* b) {
if (auto* a_load = As<Load>(a)) {
return (a_load->From() == var.Result()) && IsOne(b);
}
return false;
};
if (auto* binary = As<Binary>(UnwrapBitcast(val))) {
auto* lhs = UnwrapBitcast(binary->LHS());
auto* rhs = UnwrapBitcast(binary->RHS());
if (binary->Op() == BinaryOp::kAdd) {
// Allow `var + 1` or `1 + var`.
return is_var_op_one(lhs, rhs) || is_var_op_one(rhs, lhs);
} else if (binary->Op() == BinaryOp::kSubtract) {
// Only allow `var - 1`.
return is_var_op_one(lhs, rhs);
}
}
return false;
}
} // anonymous namespace
/// PIMPL class that performs the analysis and holds the analysis cache.
struct LoopAnalysisImpl {
explicit LoopAnalysisImpl(Function& func) {
// Analyze all of the loops in the function.
Traverse(func.Block(), [&](Loop* l) { AnalyzeLoop(*l); });
}
/// @returns the info for a loop
const LoopInfo* GetInfo(const Loop& loop) const { return loop_info_map_.Get(&loop).value; }
private:
Hashmap<const Loop*, LoopInfo, 8> loop_info_map_;
/// Analyze a loop.
void AnalyzeLoop(Loop& loop) {
if (auto* init_block = loop.Initializer()) {
// Look for variables that could be used as iteration indices.
for (auto* inst : *init_block) {
auto* var = inst->As<Var>();
if (!var) {
continue;
}
const auto* pty = var->Result()->Type()->As<core::type::Pointer>();
if (!pty->StoreType()->IsIntegerScalar()) {
break;
}
// Check if the variable is an index that gives this loop a finite range.
if (IsFiniteLoopIndex(loop, *var)) {
loop_info_map_.Add(&loop, LoopInfo{var});
return;
}
}
}
// We could not determine that this was a finite loop.
loop_info_map_.Add(&loop, LoopInfo{});
}
/// Analyzes @p var as a candidate loop index variable for the given @p loop to see if it is
/// used in a way that guarantees the loop will be iterating over a finite range.
/// @returns true if @p var is an index variable for a finite ranged loop
bool IsFiniteLoopIndex(Loop& loop, Var& index) {
// Look for a store to the index in the continuing block.
// Make sure there is only one, and make sure that the only other uses are loads.
Store* single_store_in_continue_block = nullptr;
const auto& uses = index.Result()->UsagesUnsorted();
for (auto& use : uses) {
if (auto* store = use->instruction->As<Store>()) {
if (store->Block() != loop.Continuing()) {
// Not in the continuing block, so we cannot easily prove that it will be
// executed.
return false;
}
if (single_store_in_continue_block) {
// Found more than one store, so we cannot easily analyze this candidate.
return false;
}
single_store_in_continue_block = store;
} else if (!use->instruction->Is<Load>()) {
// Not a store or a load, so reject this candidate.
return false;
}
}
if (!single_store_in_continue_block) {
return false;
}
// Check that the store we found is either incrementing or decrementing the index by `1`.
if (!IsIncrementOrDecrementOfVar(index, single_store_in_continue_block->From())) {
return false;
}
// We have proven that the variable increments exactly once per iteration.
// Now check that the loop body begins with a break-if construct that will is guaranteed to
// exit the loop if the index reaches the loop bound.
bool has_break_if = false;
for (auto* inst : *loop.Body()) {
// The Switch returns `true` if more instructions should be checked, otherwise `false`.
bool keep_going = Switch(
inst, //
[&](Load*) { return true; }, //
[&](Bitcast*) { return true; }, //
[&](Binary*) { return true; }, //
[&](If* i) {
if (IsBreakIfOnIndex(loop, i, index)) {
// The loop is finite.
has_break_if = true;
}
// Only look at the first 'if' we find.
return false;
},
[&](Default) { return false; });
if (!keep_going) {
break;
}
}
return has_break_if;
}
/// @returns `true` if @p is a break-if construct that exits the loop based on @p index.
bool IsBreakIfOnIndex(const Loop& loop, If* i, Var& index) {
// Returns `true` if the given value is a load of the index variable.
auto is_index = [&index](Value* v) {
if (auto* load = As<Load>(UnwrapBitcast(v))) {
return load->From() == index.Result();
}
return false;
};
// Returns `true` if the given value an immutable value declared before the loop body.
auto is_immutable_before_body = [&loop](Value* v) {
return tint::Switch(
UnwrapBitcast(v), //
[](ir::Constant*) { return true; }, //
[](ir::FunctionParam*) { return true; }, //
[&](ir::InstructionResult* r) {
auto* let = r->Instruction()->As<Let>();
return let && let->Block() != loop.Body();
} //
);
};
auto is_constant_i32_or_u32 = [](Value* v) {
auto* constant_value = v->As<Constant>();
if (!constant_value) {
return false;
}
return constant_value->Type()->IsAnyOf<type::I32, type::U32>();
};
auto is_capable_binary_for_loop_exit = [&](Binary* binary) {
switch (binary->Op()) {
case BinaryOp::kLessThan:
case BinaryOp::kGreaterThan: {
return (is_index(binary->LHS()) && is_immutable_before_body(binary->RHS())) ||
(is_index(binary->RHS()) && is_immutable_before_body(binary->LHS()));
}
case BinaryOp::kLessThanEqual: {
if (is_index(binary->LHS()) && is_constant_i32_or_u32(binary->RHS())) {
// index <= kConstantValue
// `kConstantValue` being the highest value will cause an infinite loop.
auto* constant_value = binary->RHS()->As<Constant>()->Value();
if (constant_value->Type()->Is<type::I32>()) {
return constant_value->ValueAs<int32_t>() < i32::kHighestValue;
} else {
TINT_ASSERT(constant_value->Type()->Is<type::U32>());
return constant_value->ValueAs<uint32_t>() < u32::kHighestValue;
}
} else if (is_index(binary->RHS()) && is_constant_i32_or_u32(binary->LHS())) {
// kConstantValue <= index
// `kConstantValue` being the lowest value will cause an infinite loop.
auto* constant_value = binary->LHS()->As<Constant>()->Value();
if (constant_value->Type()->Is<type::I32>()) {
return constant_value->ValueAs<int32_t>() > i32::kLowestValue;
} else {
TINT_ASSERT(constant_value->Type()->Is<type::U32>());
return constant_value->ValueAs<uint32_t>() > u32::kLowestValue;
}
}
return false;
}
case BinaryOp::kGreaterThanEqual: {
if (is_index(binary->LHS()) && is_constant_i32_or_u32(binary->RHS())) {
// index >= kConstantValue
// `kConstantValue` being the lowest value will cause an infinite loop.
auto* constant_value = binary->RHS()->As<Constant>()->Value();
if (constant_value->Type()->Is<type::I32>()) {
return constant_value->ValueAs<int32_t>() > i32::kLowestValue;
} else {
TINT_ASSERT(constant_value->Type()->Is<type::U32>());
return constant_value->ValueAs<uint32_t>() > u32::kLowestValue;
}
} else if (is_index(binary->RHS()) && is_constant_i32_or_u32(binary->LHS())) {
// kConstantValue >= index
// `kConstantValue` being the highest value will cause an infinite loop.
auto* constant_value = binary->LHS()->As<Constant>()->Value();
if (constant_value->Type()->Is<type::I32>()) {
return constant_value->ValueAs<int32_t>() < i32::kHighestValue;
} else {
TINT_ASSERT(constant_value->Type()->Is<type::U32>());
return constant_value->ValueAs<uint32_t>() < u32::kHighestValue;
}
}
return false;
}
default:
return false;
}
};
// Check if the condition matches (%idx < %bound) or (%idx > %bound).
// The value %bound can be any immutable value that was declared before the body.
auto* binary = As<Binary>(i->Condition());
if (!binary) {
return false;
}
if (is_capable_binary_for_loop_exit(binary)) {
// The condition matches, so now make sure that one of the branches will exit from the
// loop and do nothing else.
auto is_simple_loop_exit = [](Block* b) {
return b && !b->IsEmpty() && (b->Front()->Is<ExitLoop>());
};
return is_simple_loop_exit(i->True()) || is_simple_loop_exit(i->False());
}
return false;
}
};
LoopAnalysis::LoopAnalysis(Function& func) : impl_(new LoopAnalysisImpl(func)) {}
LoopAnalysis::~LoopAnalysis() = default;
const LoopInfo* LoopAnalysis::GetInfo(const Loop& loop) const {
return impl_->GetInfo(loop);
}
} // namespace tint::core::ir::analysis

View File

@@ -0,0 +1,73 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_ANALYSIS_LOOP_ANALYSIS_H_
#define SRC_TINT_LANG_CORE_IR_ANALYSIS_LOOP_ANALYSIS_H_
#include <memory>
#include "src/tint/lang/core/ir/function.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/var.h"
namespace tint::core::ir::analysis {
/// The result of a loop analysis.
struct LoopInfo {
Var* const index_var = nullptr;
/// @returns `true` if the loop is definitely finite, otherwise `false`.
bool IsFinite() const { return index_var != nullptr; }
};
struct LoopAnalysisImpl;
/// LoopAnalysis is a helper used to analyze loops.
/// It caches loop analyses for a function.
class LoopAnalysis {
public:
/// Constructor
/// @param func the function to cache analyses for
explicit LoopAnalysis(ir::Function& func);
~LoopAnalysis();
/// Returns the info for a given loop, if it is a loop.
/// Otherwise is not analyzable, and returns nullptr.
/// @param loop the loop to get information about
/// @returns the loop info
const LoopInfo* GetInfo(const Loop& loop) const;
private:
LoopAnalysis(const LoopAnalysis&) = delete;
LoopAnalysis(LoopAnalysis&&) = delete;
std::unique_ptr<LoopAnalysisImpl> impl_;
};
} // namespace tint::core::ir::analysis
#endif // SRC_TINT_LANG_CORE_IR_ANALYSIS_LOOP_ANALYSIS_H_

View File

@@ -0,0 +1,169 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/analysis/subgroup_matrix.h"
#include <unordered_set>
#include <utility>
#include "src/tint/lang/core/ir/core_builtin_call.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/type/array.h"
#include "src/tint/lang/core/type/f16.h"
#include "src/tint/lang/core/type/f32.h"
#include "src/tint/lang/core/type/i32.h"
#include "src/tint/lang/core/type/i8.h"
#include "src/tint/lang/core/type/struct.h"
#include "src/tint/lang/core/type/subgroup_matrix.h"
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/lang/core/type/u8.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::core::ir::analysis {
namespace {
struct State {
/// The IR module.
core::ir::Module& ir;
SubgroupMatrixInfo info{};
/// Process the module.
SubgroupMatrixInfo Process() {
for (const auto* inst : ir.Instructions()) {
if (auto* call = inst->As<core::ir::CoreBuiltinCall>()) {
GatherCall(call);
}
for (auto* res : inst->Results()) {
GatherType(res->Type()->UnwrapPtr());
}
}
return std::move(info);
}
SubgroupMatrixType TypeToSMType(const core::type::Type* ty) {
return tint::Switch(
ty, //
[&](const core::type::F16*) { return SubgroupMatrixType::kF16; },
[&](const core::type::F32*) { return SubgroupMatrixType::kF32; },
[&](const core::type::U8*) { return SubgroupMatrixType::kU8; },
[&](const core::type::I8*) { return SubgroupMatrixType::kI8; },
[&](const core::type::U32*) { return SubgroupMatrixType::kU32; },
[&](const core::type::I32*) { return SubgroupMatrixType::kI32; }, //
TINT_ICE_ON_NO_MATCH);
}
void GatherCall(const core::ir::CoreBuiltinCall* call) {
if (call->Func() != BuiltinFn::kSubgroupMatrixMultiply &&
call->Func() != BuiltinFn::kSubgroupMatrixMultiplyAccumulate) {
return;
}
auto* result_ty = call->Result()->Type()->As<core::type::SubgroupMatrix>();
TINT_ASSERT(result_ty);
auto* left_ty = call->Args()[0]->Type()->As<core::type::SubgroupMatrix>();
TINT_ASSERT(left_ty);
auto* right_ty = call->Args()[1]->Type()->As<core::type::SubgroupMatrix>();
TINT_ASSERT(right_ty);
SubgroupMatrixMultiply cfg{
.M = left_ty->Rows(),
.N = right_ty->Columns(),
.K = right_ty->Rows(),
.input_type = TypeToSMType(left_ty->Type()),
.output_type = TypeToSMType(result_ty->Type()),
};
info.multiplies.insert(cfg);
}
void GatherType(const core::type::Type* ty) {
if (auto* str = ty->As<core::type::Struct>()) {
for (auto* mem : str->Members()) {
GatherType(mem->Type());
}
return;
}
if (auto* arr = ty->As<core::type::Array>()) {
GatherType(arr->ElemType());
return;
}
auto* sm = ty->As<core::type::SubgroupMatrix>();
if (!sm) {
return;
}
SubgroupMatrixDirection dir = SubgroupMatrixDirection::kResult;
uint32_t M = 0;
uint32_t N = 0;
uint32_t K = 0;
switch (sm->Kind()) {
case SubgroupMatrixKind::kResult:
dir = SubgroupMatrixDirection::kResult;
M = sm->Rows();
N = sm->Columns();
break;
case SubgroupMatrixKind::kLeft:
dir = SubgroupMatrixDirection::kLeft;
M = sm->Rows();
K = sm->Columns();
break;
case SubgroupMatrixKind::kRight:
dir = SubgroupMatrixDirection::kRight;
K = sm->Rows();
N = sm->Columns();
break;
case SubgroupMatrixKind::kUndefined:
TINT_UNREACHABLE();
}
SubgroupMatrixConfig cfg{
.M = M,
.N = N,
.K = K,
.type = TypeToSMType(sm->Type()),
.direction = dir,
};
info.configs.insert(cfg);
}
};
} // namespace
SubgroupMatrixInfo GatherSubgroupMatrixInfo(core::ir::Module& ir) {
return State{ir}.Process();
}
} // namespace tint::core::ir::analysis

View File

@@ -0,0 +1,60 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_ANALYSIS_SUBGROUP_MATRIX_H_
#define SRC_TINT_LANG_CORE_IR_ANALYSIS_SUBGROUP_MATRIX_H_
#include "src/tint/api/common/subgroup_matrix.h"
// Forward declarations.
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::analysis {
/// Gathers information about the subgroup matrix configurations used in the module.
///
/// This returns two fundamental types of information on the subgroup matrix uses.
///
/// 1. The Matrix multiply configurations
/// * This provides the `M`, `N`, `K`, input and output types for the
/// `subgroupMatrixMultiply` and `subgroupMatrtixMultiplyAccumulate` calls in the
/// module. (The configs are de-duplicated so each combination is only returned once.)
///
/// 2. The used matrix configurations
/// * This provides the `C`, `R`, type and if it's left/right (input) or result usage for
/// every subgroup matrix seen in the file. (The configs are de-duplicated so each
/// combination is only returned once.)
///
/// @param module the module to transform
/// @returns the subgroup matrix information
SubgroupMatrixInfo GatherSubgroupMatrixInfo(core::ir::Module& module);
} // namespace tint::core::ir::analysis
#endif // SRC_TINT_LANG_CORE_IR_ANALYSIS_SUBGROUP_MATRIX_H_

View File

@@ -0,0 +1,48 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/binary.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Binary);
namespace tint::core::ir {
Binary::Binary(Id id) : Base(id) {}
Binary::Binary(Id id, InstructionResult* result, BinaryOp op, Value* lhs, Value* rhs)
: Base(id), op_(op) {
AddOperand(Binary::kLhsOperandOffset, lhs);
AddOperand(Binary::kRhsOperandOffset, rhs);
AddResult(result);
}
Binary::~Binary() = default;
} // namespace tint::core::ir

View File

@@ -0,0 +1,101 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_H_
#include <string>
#include "src/tint/lang/core/binary_op.h"
#include "src/tint/lang/core/ir/operand_instruction.h"
// Forward declarations
namespace tint::core::intrinsic {
struct TableData;
}
namespace tint::core::ir {
/// The abstract base class for dialect-specific binary-op instructions in the IR.
class Binary : public Castable<Binary, OperandInstruction<2, 1>> {
public:
/// The offset in Operands() for the LHS
static constexpr size_t kLhsOperandOffset = 0;
/// The offset in Operands() for the RHS
static constexpr size_t kRhsOperandOffset = 1;
/// The fixed number of results returned by binary instructions
static constexpr size_t kNumResults = 1;
/// The fixed number of operands expected for binary instructions
static constexpr size_t kNumOperands = 2;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit Binary(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param op the binary operator
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
Binary(Id id, InstructionResult* result, BinaryOp op, Value* lhs, Value* rhs);
~Binary() override;
/// @returns the binary operator
BinaryOp Op() const { return op_; }
/// @param op the new binary operator
void SetOp(BinaryOp op) { op_ = op; }
/// @returns the left-hand-side value for the instruction
Value* LHS() { return Operand(kLhsOperandOffset); }
/// @returns the left-hand-side value for the instruction
const Value* LHS() const { return Operand(kLhsOperandOffset); }
/// @returns the right-hand-side value for the instruction
Value* RHS() { return Operand(kRhsOperandOffset); }
/// @returns the right-hand-side value for the instruction
const Value* RHS() const { return Operand(kRhsOperandOffset); }
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "binary"; }
/// @returns the table data to validate this builtin
virtual const core::intrinsic::TableData& TableData() const = 0;
private:
BinaryOp op_ = BinaryOp::kAdd;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BINARY_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_
#include <span>
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::binary::pb {
class Module;
} // namespace tint::core::ir::binary::pb
namespace tint::core::ir::binary {
/// @returns the decoded Module from the serialized protobuf.
Result<Module> Decode(std::span<const std::byte> encoded);
/// @returns the decoded Module from the protobuf.
Result<Module> Decode(const pb::Module& module);
} // namespace tint::core::ir::binary
#endif // SRC_TINT_LANG_CORE_IR_BINARY_DECODE_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
#define SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_
#include <memory>
#include "src/tint/utils/containers/vector.h"
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir::binary::pb {
class Module;
}
namespace tint::core::ir::binary {
// Encode the module into a proto representation.
Result<std::unique_ptr<pb::Module>> EncodeToProto(const Module& module);
// Encode the module into a binary representation.
Result<Vector<std::byte, 0>> EncodeToBinary(const Module& module);
} // namespace tint::core::ir::binary
#endif // SRC_TINT_LANG_CORE_IR_BINARY_ENCODE_H_

View File

@@ -0,0 +1,52 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/bitcast.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Bitcast);
namespace tint::core::ir {
Bitcast::Bitcast(Id id) : Base(id) {}
Bitcast::Bitcast(Id id, InstructionResult* result, Value* val) : Base(id) {
AddOperand(Bitcast::kValueOperandOffset, val);
AddResult(result);
}
Bitcast::~Bitcast() = default;
Bitcast* Bitcast::Clone(CloneContext& ctx) {
auto* new_result = ctx.Clone(Result());
auto* val = ctx.Remap(Val());
return ctx.ir.CreateInstruction<Bitcast>(new_result, val);
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,80 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BITCAST_H_
#define SRC_TINT_LANG_CORE_IR_BITCAST_H_
#include <string>
#include "src/tint/lang/core/ir/call.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// A bitcast instruction in the IR.
class Bitcast final : public Castable<Bitcast, Call> {
public:
/// The offset in Operands() for the value
static constexpr size_t kValueOperandOffset = 0;
/// The fixed number of results returned by this instruction
static constexpr size_t kNumResults = 1;
/// The fixed number of operands expected for this instruction
static constexpr size_t kNumOperands = 1;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit Bitcast(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param val the value being bitcast
Bitcast(Id id, InstructionResult* result, Value* val);
~Bitcast() override;
/// @copydoc Instruction::Clone()
Bitcast* Clone(CloneContext& ctx) override;
/// @returns the operand value
Value* Val() { return Operand(kValueOperandOffset); }
/// @returns the operand value
const Value* Val() const { return Operand(kValueOperandOffset); }
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "bitcast"; }
/// @returns an empty access as the bitcast neither loads nor stores.
Accesses GetSideEffects() const override { return Accesses{}; }
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BITCAST_H_

View File

@@ -0,0 +1,207 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/block.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/control_instruction.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Block);
namespace tint::core::ir {
Block::Block() : Base() {}
Block::~Block() = default;
Block* Block::Clone(CloneContext&) {
TINT_UNREACHABLE() << "blocks must be cloned with CloneInto";
}
void Block::CloneInto(CloneContext& ctx, Block* out) {
// Note, the `parent_` is not cloned here. Doing so can end up in infinite loops as we try to
// clone a control instruction and the blocks inside of it. The `parent_` pointer should be set
// by the control instructions constructor.
for (auto* inst_in : *this) {
auto* inst_out = inst_in->Clone(ctx);
auto results_out = inst_out->Results();
auto results_in = inst_in->Results();
TINT_ASSERT(results_out.Length() == results_in.Length());
size_t len = results_out.Length();
for (size_t i = 0; i < len; ++i) {
ctx.Replace(results_in[i], results_out[i]);
}
out->Append(inst_out);
}
}
Instruction* Block::Prepend(Instruction* inst) {
TINT_ASSERT(inst);
TINT_ASSERT(inst->Block() == nullptr);
inst->SetBlock(this);
instructions_.count += 1;
if (instructions_.first == nullptr) {
instructions_.first = inst;
instructions_.last = inst;
} else {
inst->next = instructions_.first;
instructions_.first->prev = inst;
instructions_.first = inst;
}
return inst;
}
Instruction* Block::Append(Instruction* inst) {
TINT_ASSERT(inst);
TINT_ASSERT(inst->Block() == nullptr);
inst->SetBlock(this);
instructions_.count += 1;
if (instructions_.first == nullptr) {
instructions_.first = inst;
instructions_.last = inst;
} else {
inst->prev = instructions_.last;
instructions_.last->next = inst;
instructions_.last = inst;
}
return inst;
}
void Block::InsertBefore(Instruction* before, Instruction* inst) {
TINT_ASSERT(before);
TINT_ASSERT(inst);
TINT_ASSERT(before->Block() == this);
TINT_ASSERT(inst->Block() == nullptr);
inst->SetBlock(this);
instructions_.count += 1;
inst->next = before;
inst->prev = before->prev;
before->prev = inst;
if (inst->prev) {
inst->prev->next = inst;
}
if (before == instructions_.first) {
instructions_.first = inst;
}
}
void Block::InsertAfter(Instruction* after, Instruction* inst) {
TINT_ASSERT(after);
TINT_ASSERT(inst);
TINT_ASSERT(after->Block() == this);
TINT_ASSERT(inst->Block() == nullptr);
inst->SetBlock(this);
instructions_.count += 1;
inst->prev = after;
inst->next = after->next;
after->next = inst;
if (inst->next) {
inst->next->prev = inst;
}
if (after == instructions_.last) {
instructions_.last = inst;
}
}
void Block::Replace(Instruction* target, Instruction* inst) {
TINT_ASSERT(target);
TINT_ASSERT(inst);
TINT_ASSERT(target->Block() == this);
TINT_ASSERT(inst->Block() == nullptr);
inst->SetBlock(this);
target->SetBlock(nullptr);
inst->next = target->next;
inst->prev = target->prev;
target->next = nullptr;
target->prev = nullptr;
if (inst->next) {
inst->next->prev = inst;
}
if (inst->prev) {
inst->prev->next = inst;
}
if (target == instructions_.first) {
instructions_.first = inst;
}
if (target == instructions_.last) {
instructions_.last = inst;
}
}
void Block::Remove(Instruction* inst) {
TINT_ASSERT(inst);
TINT_ASSERT(inst->Block() == this);
inst->SetBlock(nullptr);
instructions_.count -= 1;
if (inst->prev) {
inst->prev->next = inst->next;
}
if (inst->next) {
inst->next->prev = inst->prev;
}
if (inst == instructions_.first) {
instructions_.first = inst->next;
}
if (inst == instructions_.last) {
instructions_.last = inst->prev;
}
inst->prev = nullptr;
inst->next = nullptr;
}
void Block::Destroy() {
while (instructions_.first) {
instructions_.first->Destroy();
}
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,194 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BLOCK_H_
#define SRC_TINT_LANG_CORE_IR_BLOCK_H_
#include <utility>
#include "src/tint/lang/core/ir/instruction.h"
#include "src/tint/lang/core/ir/terminator.h"
#include "src/tint/utils/containers/vector.h"
// Forward declarations
namespace tint::core::ir {
class ControlInstruction;
} // namespace tint::core::ir
namespace tint::core::ir {
/// A block of statements. The instructions in the block are a linear list of instructions to
/// execute. The block will terminate with a Terminator instruction at the end.
/// The instructions are held in a doubly-linked list with explicit first and last pointer,
/// and with an explicit count.
class Block : public Castable<Block> {
public:
/// Constructor
Block();
~Block() override;
/// @param ctx the CloneContext used to clone this block
/// @returns a clone of this block
virtual Block* Clone(CloneContext& ctx);
/// Clones the block contents into the given block
/// @param ctx the CloneContext used to clone
/// @param out the block to clone into
virtual void CloneInto(CloneContext& ctx, Block* out);
/// @return the terminator instruction for this block, or nullptr if this block does not end in
/// a terminator.
ir::Terminator* Terminator() { return tint::As<ir::Terminator>(instructions_.last); }
/// @return the terminator instruction for this block, or nullptr if this block does not end in
/// a terminator.
const ir::Terminator* Terminator() const {
return tint::As<ir::Terminator>(instructions_.last);
}
/// @returns the instructions in the block
Instruction* Instructions() { return instructions_.first; }
/// @returns the instructions in the block
const Instruction* Instructions() const { return instructions_.first; }
/// Iterator for the instructions inside a block
template <typename T>
class Iterator {
public:
/// Constructor
/// @param inst the instruction to start iterating from
explicit Iterator(T* inst) : inst_(inst) {}
~Iterator() = default;
/// Dereference operator
/// @returns the instruction for this iterator
T* operator*() const { return inst_; }
/// Comparison operator
/// @param itr to compare against
/// @returns true if this iterator and @p itr point to the same instruction
bool operator==(const Iterator& itr) const { return itr.inst_ == inst_; }
/// Not equal operator
/// @param itr to compare against
/// @returns true if this iterator and @p itr point to different instructions
bool operator!=(const Iterator& itr) const { return !(*this == itr); }
/// Increment operator
/// @returns this iterator advanced to the next element
Iterator& operator++() {
inst_ = inst_->next;
return *this;
}
private:
T* inst_ = nullptr;
};
/// @returns the iterator pointing to the start of the instruction list
Iterator<Instruction> begin() { return Iterator<Instruction>{instructions_.first}; }
/// @returns the ending iterator
Iterator<Instruction> end() { return Iterator<Instruction>{nullptr}; }
/// @returns the iterator pointing to the start of the instruction list
Iterator<const Instruction> begin() const {
return Iterator<const Instruction>{instructions_.first};
}
/// @returns the ending iterator
Iterator<const Instruction> end() const { return Iterator<const Instruction>{nullptr}; }
/// @returns the first instruction in the instruction list
Instruction* Front() { return instructions_.first; }
/// @returns the first instruction in the instruction list
const Instruction* Front() const { return instructions_.first; }
/// @returns the last instruction in the instruction list
Instruction* Back() { return instructions_.last; }
/// @returns the last instruction in the instruction list
const Instruction* Back() const { return instructions_.last; }
/// Adds the instruction to the beginning of the block
/// @param inst the instruction to add
/// @returns the instruction to allow calls to be chained
Instruction* Prepend(Instruction* inst);
/// Adds the instruction to the end of the block
/// @param inst the instruction to add
/// @returns the instruction to allow calls to be chained
Instruction* Append(Instruction* inst);
/// Adds the new instruction before the given instruction
/// @param before the instruction to insert before
/// @param inst the instruction to insert
void InsertBefore(Instruction* before, Instruction* inst);
/// Adds the new instruction after the given instruction
/// @param after the instruction to insert after
/// @param inst the instruction to insert
void InsertAfter(Instruction* after, Instruction* inst);
/// Replaces the target instruction with the new instruction
/// @param target the instruction to replace
/// @param inst the instruction to insert
void Replace(Instruction* target, Instruction* inst);
/// Removes the target instruction
/// @param inst the instruction to remove
void Remove(Instruction* inst);
/// @returns true if the block contains no instructions
bool IsEmpty() const { return Length() == 0; }
/// @returns the number of instructions in the block
size_t Length() const { return instructions_.count; }
/// @return the parent instruction that owns this block
ControlInstruction* Parent() { return parent_; }
/// @return the parent instruction that owns this block
const ControlInstruction* Parent() const { return parent_; }
/// @param parent the parent instruction that owns this block
void SetParent(ControlInstruction* parent) { parent_ = parent; }
/// Destroys the block and all of its instructions.
void Destroy();
private:
// The first and last pointers are null if and only if the list is empty.
struct {
Instruction* first = nullptr;
Instruction* last = nullptr;
size_t count = 0;
} instructions_;
ControlInstruction* parent_ = nullptr;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BLOCK_H_

View File

@@ -0,0 +1,54 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/block_param.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::BlockParam);
namespace tint::core::ir {
BlockParam::BlockParam(const core::type::Type* ty) : Base(ty) {
TINT_ASSERT(ty != nullptr);
}
BlockParam::~BlockParam() = default;
BlockParam* BlockParam::Clone(CloneContext& ctx) {
auto* new_bp = ctx.ir.CreateValue<BlockParam>(Type());
auto name = ctx.ir.NameOf(this);
if (name.IsValid()) {
ctx.ir.SetName(new_bp, ctx.ir.NameOf(this).Name());
}
return new_bp;
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,69 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BLOCK_PARAM_H_
#define SRC_TINT_LANG_CORE_IR_BLOCK_PARAM_H_
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
namespace tint::core::ir {
class MultiInBlock;
} // namespace tint::core::ir
namespace tint::core::ir {
/// A block parameter in the IR.
class BlockParam : public Castable<BlockParam, Value> {
public:
/// Constructor
/// @param type the type of the parameter
explicit BlockParam(const core::type::Type* type);
~BlockParam() override;
/// Sets the block that this parameter belongs to.
/// @param block the block
void SetBlock(MultiInBlock* block) { block_ = block; }
/// @returns the block that this parameter belongs to, or nullptr
MultiInBlock* Block() { return block_; }
/// @returns the block that this parameter belongs to, or nullptr
const MultiInBlock* Block() const { return block_; }
/// @copydoc Instruction::Clone()
BlockParam* Clone(CloneContext& ctx) override;
private:
/// the block that the parameter belongs to
MultiInBlock* block_ = nullptr;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BLOCK_PARAM_H_

View File

@@ -0,0 +1,90 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/break_if.h"
#include <utility>
#include "src/tint/lang/core/ir/block.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::BreakIf);
namespace tint::core::ir {
BreakIf::BreakIf(Id id) : Base(id) {}
BreakIf::BreakIf(Id id,
Value* condition,
ir::Loop* loop,
VectorRef<Value*> next_iter_values /* = tint::Empty */,
VectorRef<Value*> exit_values /* = tint::Empty */)
: Base(id), loop_(loop), num_next_iter_values_(next_iter_values.Length()) {
TINT_ASSERT(loop_);
AddOperand(BreakIf::kConditionOperandOffset, condition);
AddOperands(BreakIf::kArgsOperandOffset, std::move(next_iter_values));
AddOperands(BreakIf::kArgsOperandOffset + num_next_iter_values_, std::move(exit_values));
if (loop_) {
loop_->Body()->AddInboundSiblingBranch(this);
SetControlInstruction(loop_);
}
}
BreakIf::~BreakIf() = default;
void BreakIf::Destroy() {
if (loop_) {
loop_->Body()->RemoveInboundSiblingBranch(this);
}
Instruction::Destroy();
}
BreakIf* BreakIf::Clone(CloneContext& ctx) {
auto* loop = ctx.Remap(loop_);
auto* cond = ctx.Remap(Condition());
auto args = ctx.Remap<BreakIf::kDefaultNumOperands>(Args());
return ctx.ir.CreateInstruction<BreakIf>(cond, loop, args);
}
void BreakIf::SetLoop(ir::Loop* loop) {
if (loop_ && loop_->Body()) {
loop_->Body()->RemoveInboundSiblingBranch(this);
}
loop_ = loop;
SetControlInstruction(loop);
if (loop) {
loop->Body()->AddInboundSiblingBranch(this);
}
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,138 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BREAK_IF_H_
#define SRC_TINT_LANG_CORE_IR_BREAK_IF_H_
#include <span>
#include <string>
#include "src/tint/lang/core/ir/exit.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
namespace tint::core::ir {
class Loop;
} // namespace tint::core::ir
namespace tint::core::ir {
/// A break-if terminator instruction.
class BreakIf final : public Castable<BreakIf, Exit> {
public:
/// The offset in Operands() for the condition
static constexpr size_t kConditionOperandOffset = 0;
/// The base offset in Operands() for the arguments
static constexpr size_t kArgsOperandOffset = 1;
/// Constructor (no operands, no loop)
/// @param id the instruction id
explicit BreakIf(Id id);
/// Constructor
/// @param id the instruction id
/// @param condition the break condition
/// @param loop the loop containing the break-if
/// @param next_iter_values the arguments passed to the loop body MultiInBlock, if the break
/// condition evaluates to `false`.
/// @param exit_values the values returned by the loop, if the break condition evaluates to
/// `true`.
BreakIf(Id id,
Value* condition,
ir::Loop* loop,
VectorRef<Value*> next_iter_values = tint::Empty,
VectorRef<Value*> exit_values = tint::Empty);
~BreakIf() override;
/// @copydoc Instruction::Destroy()
void Destroy() override;
/// @copydoc Instruction::Clone()
BreakIf* Clone(CloneContext& ctx) override;
/// @returns the offset of the arguments in Operands()
size_t ArgsOperandOffset() const override { return kArgsOperandOffset; }
/// @returns the break condition
Value* Condition() { return Operand(kConditionOperandOffset); }
/// @returns the break condition
const Value* Condition() const { return Operand(kConditionOperandOffset); }
/// @returns the loop containing the break-if
ir::Loop* Loop() { return loop_; }
/// @returns the loop containing the break-if
const ir::Loop* Loop() const { return loop_; }
/// @param loop the new loop containing the continue
void SetLoop(ir::Loop* loop);
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "break_if"; }
/// @returns the arguments passed to the loop body MultiInBlock, if the break condition
/// evaluates to `false`.
std::span<Value* const> NextIterValues() {
return operands_.AsSpan().subspan(kArgsOperandOffset, num_next_iter_values_);
}
/// @returns the arguments passed to the loop body MultiInBlock, if the break condition
/// evaluates to `false`.
std::span<const Value* const> NextIterValues() const {
return operands_.AsSpan().subspan(kArgsOperandOffset, num_next_iter_values_);
}
/// @returns the values returned by the loop, if the break condition evaluates to `true`.
std::span<Value* const> ExitValues() {
return operands_.AsSpan().subspan(kArgsOperandOffset + num_next_iter_values_);
}
/// @returns the values returned by the loop, if the break condition evaluates to `true`.
std::span<const Value* const> ExitValues() const {
return operands_.AsSpan().subspan(kArgsOperandOffset + num_next_iter_values_);
}
/// Sets the number of operands used as the next iterator values.
/// The first @p num operands after kArgsOperandOffset are used as next iterator values,
/// subsequent operators are used as exit values.
void SetNumNextIterValues(size_t num) {
TINT_ASSERT(operands_.Length() >= num + kArgsOperandOffset);
num_next_iter_values_ = num;
}
private:
ir::Loop* loop_ = nullptr;
size_t num_next_iter_values_ = 0;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BREAK_IF_H_

View File

@@ -0,0 +1,154 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/builder.h"
#include <utility>
#include "src/tint/lang/core/constant/scalar.h"
#include "src/tint/lang/core/type/function.h"
#include "src/tint/lang/core/type/pointer.h"
#include "src/tint/lang/core/type/reference.h"
#include "src/tint/utils/ice/ice.h"
namespace tint::core::ir {
Builder::Builder(Module& mod) : ir(mod) {}
Builder::Builder(Module& mod, ir::Block* block)
: insertion_point_(InsertionPoints::AppendToBlock{block}), ir(mod) {}
Builder::~Builder() = default;
Block* Builder::Block() {
return ir.blocks.Create<ir::Block>();
}
MultiInBlock* Builder::MultiInBlock() {
return ir.blocks.Create<ir::MultiInBlock>();
}
Function* Builder::Function(const core::type::Type* return_type, Function::PipelineStage stage) {
auto* ir_func = ir.CreateValue<ir::Function>(ir.Types().function(), return_type, stage);
ir_func->SetBlock(Block());
ir.functions.Push(ir_func);
return ir_func;
}
Function* Builder::Function(std::string_view name,
const core::type::Type* return_type,
Function::PipelineStage stage) {
auto* ir_func = Function(return_type, stage);
ir.SetName(ir_func, name);
return ir_func;
}
ir::Loop* Builder::Loop() {
return Append(ir.CreateInstruction<ir::Loop>(Block(), MultiInBlock(), MultiInBlock()));
}
Block* Builder::Case(ir::Switch* s, VectorRef<ir::Constant*> values) {
auto* block = Block();
Switch::Case c;
c.block = block;
for (auto* value : values) {
c.selectors.Push(Switch::CaseSelector{value});
}
s->Cases().Push(std::move(c));
block->SetParent(s);
return block;
}
Block* Builder::DefaultCase(ir::Switch* s) {
return Case(s, Vector<ir::Constant*, 1>{nullptr});
}
Block* Builder::Case(ir::Switch* s, std::initializer_list<ir::Constant*> selectors) {
return Case(s, Vector<ir::Constant*, 4>(selectors));
}
ir::Discard* Builder::Discard() {
return Append(ir.CreateInstruction<ir::Discard>());
}
ir::Var* Builder::Var(const core::type::MemoryView* type) {
return Append(ir.CreateInstruction<ir::Var>(InstructionResult(type)));
}
ir::Var* Builder::Var(std::string_view name, const core::type::MemoryView* type) {
auto* var = Var(type);
ir.SetName(var, name);
return var;
}
ir::BlockParam* Builder::BlockParam(const core::type::Type* type) {
return ir.CreateValue<ir::BlockParam>(type);
}
ir::BlockParam* Builder::BlockParam(std::string_view name, const core::type::Type* type) {
auto* param = ir.CreateValue<ir::BlockParam>(type);
ir.SetName(param, name);
return param;
}
ir::FunctionParam* Builder::FunctionParam(const core::type::Type* type) {
return ir.CreateValue<ir::FunctionParam>(type);
}
ir::FunctionParam* Builder::FunctionParam(std::string_view name, const core::type::Type* type) {
auto* param = ir.CreateValue<ir::FunctionParam>(type);
ir.SetName(param, name);
return param;
}
ir::TerminateInvocation* Builder::TerminateInvocation() {
return Append(ir.CreateInstruction<ir::TerminateInvocation>());
}
ir::Unreachable* Builder::Unreachable() {
return Append(ir.CreateInstruction<ir::Unreachable>());
}
ir::Unused* Builder::Unused() {
return ir.CreateValue<ir::Unused>();
}
const core::type::Type* Builder::VectorPtrElementType(const core::type::Type* type) {
auto* vec_ptr_ty = type->As<core::type::Pointer>();
TINT_ASSERT(vec_ptr_ty);
if (DAWN_LIKELY(vec_ptr_ty)) {
auto* vec_ty = vec_ptr_ty->StoreType()->As<core::type::Vector>();
TINT_ASSERT(vec_ty);
if (DAWN_LIKELY(vec_ty)) {
return vec_ty->Type();
}
}
return ir.Types().i32();
}
} // namespace tint::core::ir

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/builtin_call.h"
#include <utility>
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::BuiltinCall);
namespace tint::core::ir {
BuiltinCall::BuiltinCall(Id id) : Base(id) {
flags_.Add(Flag::kSequenced);
}
BuiltinCall::BuiltinCall(Id id, InstructionResult* result, VectorRef<Value*> arguments) : Base(id) {
flags_.Add(Flag::kSequenced);
AddOperands(BuiltinCall::kArgsOperandOffset, std::move(arguments));
AddResult(result);
}
BuiltinCall::~BuiltinCall() = default;
} // namespace tint::core::ir

View File

@@ -0,0 +1,67 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_BUILTIN_CALL_H_
#define SRC_TINT_LANG_CORE_IR_BUILTIN_CALL_H_
#include "src/tint/lang/core/intrinsic/table_data.h"
#include "src/tint/lang/core/ir/call.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// The base class for builtin call instructions in the IR.
class BuiltinCall : public Castable<BuiltinCall, Call> {
public:
/// The fixed number of results returned by this instruction
static constexpr size_t kNumResults = 1;
/// The base offset in Operands() for the args
static constexpr size_t kArgsOperandOffset = 0;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit BuiltinCall(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param args the conversion arguments
BuiltinCall(Id id, InstructionResult* result, VectorRef<Value*> args = tint::Empty);
~BuiltinCall() override;
/// @returns the identifier for the function
virtual size_t FuncId() const = 0;
/// @returns the table data to validate this builtin
virtual const core::intrinsic::TableData& TableData() const = 0;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_BUILTIN_CALL_H_

View File

@@ -0,0 +1,38 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/call.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Call);
namespace tint::core::ir {
Call::Call(Id id) : Base(id) {}
Call::~Call() = default;
} // namespace tint::core::ir

View File

@@ -0,0 +1,84 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CALL_H_
#define SRC_TINT_LANG_CORE_IR_CALL_H_
#include <string>
#include "src/tint/lang/core/ir/operand_instruction.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// A Call instruction in the IR.
class Call : public Castable<Call, OperandInstruction<4, 1>> {
public:
~Call() override;
/// @returns the offset of the arguments in Operands()
virtual size_t ArgsOperandOffset() const { return 0; }
/// Sets the explicit template params for the call
void SetExplicitTemplateParams(VectorRef<const core::type::Type*> params) {
explicit_template_params_ = params;
}
/// Retrieves the explicit template params for the call
tint::VectorRef<const core::type::Type*> ExplicitTemplateParams() const {
return explicit_template_params_;
}
/// @returns the call arguments
tint::Slice<Value* const> Args() { return operands_.Slice().Offset(ArgsOperandOffset()); }
/// @returns the call arguments
tint::Slice<const Value* const> Args() const {
return operands_.Slice().Offset(ArgsOperandOffset());
}
/// Sets the argument at `idx` of `arg`. `idx` must be within bounds of the current argument
/// set.
void SetArg(size_t idx, ir::Value* arg) { SetOperand(ArgsOperandOffset() + idx, arg); }
/// Append a new argument to the argument list for this call instruction.
/// @param arg the argument value to append
void AppendArg(ir::Value* arg) { AddOperand(operands_.Length(), arg); }
/// @returns the side effects for this instruction
Accesses GetSideEffects() const override { return Accesses{Access::kLoad, Access::kStore}; }
protected:
/// Constructor
explicit Call(Id id);
Vector<const core::type::Type*, 1> explicit_template_params_;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CALL_H_

View File

@@ -0,0 +1,37 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/builder.h"
#include "src/tint/lang/core/ir/let.h"
namespace tint::core::ir {
CloneContext::CloneContext(Module& module) : ir(module) {}
} // namespace tint::core::ir

View File

@@ -0,0 +1,143 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CLONE_CONTEXT_H_
#define SRC_TINT_LANG_CORE_IR_CLONE_CONTEXT_H_
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/transform.h"
#include "src/tint/utils/rtti/traits.h"
namespace tint::core::ir {
class Block;
class Instruction;
class Module;
class Value;
} // namespace tint::core::ir
namespace tint::core::ir {
/// Constant in the IR.
class CloneContext {
public:
/// @param module the IR module
explicit CloneContext(Module& module);
/// The IR module
Module& ir;
/// Performs a clone of @p what.
/// @param what the item to clone
/// @return the cloned item
template <typename T>
T* Clone(T* what) {
if (auto replacement = replacements_.Get(what)) {
return (*replacement)->template As<T>();
}
T* result = what->Clone(*this);
Replace(what, result);
return result;
}
/// Performs a clone of all the elements in @p what.
/// @param what the elements to clone
/// @return the cloned elements
template <size_t N, typename T>
Vector<T*, N> Clone(Slice<T* const> what) {
return Transform<N>(what, [&](T* const p) { return Clone(p); });
}
/// Performs a clone of all the elements in @p what.
/// @param what the elements to clone
/// @return the cloned elements
template <size_t N, typename T>
Vector<T*, N> Clone(Slice<T*> what) {
return Transform<N>(what, [&](T* p) { return Clone(p); });
}
/// Performs a clone of all the elements in @p what.
/// @param what the elements to clone
/// @return the cloned elements
template <size_t N, typename T>
Vector<T*, N> Clone(Vector<T*, N> what) {
return Transform(what, [&](T* p) { return Clone(p); });
}
/// Obtains the (potentially) remapped pointer to @p what
/// @param what the item
/// @return the cloned item for @p what, or the original pointer if @p what has not been cloned.
template <typename T>
T* Remap(T* what) {
if (auto replacement = replacements_.Get(what)) {
return (*replacement)->template As<T>();
}
return what;
}
/// Obtains the (potentially) remapped pointer of all the elements in @p what.
/// @param what the item
/// @return the remapped elements
template <size_t N, typename T>
Vector<T*, N> Remap(Slice<T* const> what) {
return Transform<N>(what, [&](T* const p) { return Remap(p); });
}
/// Obtains the (potentially) remapped pointer of all the elements in @p what.
/// @param what the item
/// @return the remapped elements
template <size_t N, typename T>
Vector<T*, N> Remap(Slice<T*> what) {
return Transform<N>(what, [&](T* p) { return Remap(p); });
}
/// Obtains the (potentially) remapped pointer of all the elements in @p what.
/// @param what the item
/// @return the remapped elements
template <size_t N, typename T>
Vector<T*, N> Remap(Vector<T*, N> what) {
return Transform(what, [&](T* p) { return Remap(p); });
}
/// Registers the replacement of `what` with `with`
/// @param what the value or instruction to replace
/// @param with a pointer to a replacement value or instruction
template <typename WHAT, typename WITH>
void Replace(WHAT* what, WITH* with) {
static_assert(traits::IsTypeOrDerived<WHAT, ir::Instruction> ||
traits::IsTypeOrDerived<WHAT, ir::Value>);
static_assert(traits::IsTypeOrDerived<WITH, WHAT>);
TINT_ASSERT(with);
replacements_.Add(what, with);
}
private:
Hashmap<CastableBase*, CastableBase*, 8> replacements_;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CLONE_CONTEXT_H_

View File

@@ -0,0 +1,318 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/const_param_validator.h"
#include <cstdint>
#include <string>
#include <utility>
#include "src/tint/lang/core/enums.h"
#include "src/tint/lang/core/intrinsic/table.h"
#include "src/tint/lang/core/ir/constant.h"
#include "src/tint/lang/core/ir/core_binary.h"
#include "src/tint/lang/core/ir/core_builtin_call.h"
#include "src/tint/lang/core/ir/instruction.h"
#include "src/tint/lang/core/ir/instruction_result.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/switch.h"
#include "src/tint/lang/core/ir/type/array_count.h"
#include "src/tint/lang/core/ir/value.h"
#include "src/tint/lang/core/number.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/diagnostic/diagnostic.h"
#include "src/tint/utils/internal_limits.h"
#include "src/tint/utils/rtti/switch.h"
namespace tint::core::ir {
namespace {
/// The core IR const param validator.
class ConstParamValidator {
public:
/// Create a core const param validator
/// @param mod the module to be validated
explicit ConstParamValidator(Module& mod);
/// Destructor
~ConstParamValidator();
/// Runs the const param validator over the module provided during construction
/// @returns success or failure
Result<SuccessType> Run();
void CheckSubgroupCall(const CoreBuiltinCall* call);
void CheckBuiltinCall(const BuiltinCall* call);
void CheckCoreBinaryCall(const CoreBinary* inst);
void CheckExtractBitsCall(const CoreBuiltinCall* call);
void CheckInsertBitsCall(const CoreBuiltinCall* call);
void CheckLdexpCall(const CoreBuiltinCall* call);
void CheckQuantizeToF16(const CoreBuiltinCall* call);
void CheckClampCall(const CoreBuiltinCall* call);
void CheckPack2x16float(const CoreBuiltinCall* call);
void CheckSmoothstepCall(const CoreBuiltinCall* call);
void CheckBinaryDivModCall(const CoreBinary* call);
void CheckBinaryShiftCall(const CoreBinary* call);
diag::Diagnostic& AddError(const Instruction& inst);
private:
Module& mod_;
constant::Eval const_eval_;
diag::List diagnostics_;
};
ConstParamValidator::ConstParamValidator(Module& mod)
: mod_(mod), const_eval_(mod.constant_values, diagnostics_) {}
ConstParamValidator::~ConstParamValidator() = default;
diag::Diagnostic& ConstParamValidator::AddError(const Instruction& inst) {
auto src = mod_.SourceOf(&inst);
return diagnostics_.AddError(src);
}
const constant::Value* GetConstArg(const CoreBuiltinCall* call, uint32_t param_index) {
if (call->Args().Length() <= param_index) {
return nullptr;
}
if (call->Args()[param_index] == nullptr) {
return nullptr;
}
if (!call->Args()[param_index]->Is<ir::Constant>()) {
return nullptr;
}
return call->Args()[param_index]->As<ir::Constant>()->Value();
}
void ConstParamValidator::CheckExtractBitsCall(const CoreBuiltinCall* call) {
// This can be u32/i32 or vector of those types.
auto* param0 = call->Args()[0];
auto* const_val_offset = GetConstArg(call, 1);
auto* const_val_count = GetConstArg(call, 2);
if (const_val_count && const_val_offset) {
auto* zero = const_eval_.Zero(param0->Type(), {}, Source{}).Get();
auto fakeArgs = Vector{zero, const_val_offset, const_val_count};
[[maybe_unused]] auto result =
const_eval_.extractBits(param0->Type(), fakeArgs, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckInsertBitsCall(const CoreBuiltinCall* call) {
// This can be u32/i32 or vector of those types.
auto* param0 = call->Args()[0];
auto* const_val_offset = GetConstArg(call, 2);
auto* const_val_count = GetConstArg(call, 3);
if (const_val_count && const_val_offset) {
auto* zero = const_eval_.Zero(param0->Type(), {}, Source{}).Get();
auto fakeArgs = Vector{zero, zero, const_val_offset, const_val_count};
[[maybe_unused]] auto result =
const_eval_.insertBits(param0->Type(), fakeArgs, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckLdexpCall(const CoreBuiltinCall* call) {
auto* param0 = call->Args()[0];
if (auto const_val = GetConstArg(call, 1)) {
auto* zero = const_eval_.Zero(param0->Type(), {}, Source{}).Get();
auto fakeArgs = Vector{zero, const_val};
[[maybe_unused]] auto result =
const_eval_.ldexp(param0->Type(), fakeArgs, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckQuantizeToF16(const CoreBuiltinCall* call) {
if (auto const_val = GetConstArg(call, 0)) {
[[maybe_unused]] auto result = const_eval_.quantizeToF16(
call->Result()->Type(), Vector{const_val}, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckPack2x16float(const CoreBuiltinCall* call) {
if (auto const_val = GetConstArg(call, 0)) {
[[maybe_unused]] auto result = const_eval_.pack2x16float(
call->Result()->Type(), Vector{const_val}, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckSubgroupCall(const CoreBuiltinCall* call) {
if (auto const_val = GetConstArg(call, 1)) {
auto as_aint = const_val->ValueAs<AInt>();
// User friendly param name.
std::string paramName = "sourceLaneIndex";
switch (call->Func()) {
case core::BuiltinFn::kSubgroupShuffleXor:
paramName = "mask";
break;
case core::BuiltinFn::kSubgroupShuffleUp:
case core::BuiltinFn::kSubgroupShuffleDown:
paramName = "delta";
break;
default:
break;
}
if (as_aint >= tint::internal_limits::kMaxSubgroupSize) {
AddError(*call) << "The " << paramName << " argument of " << call->FriendlyName()
<< " must be less than " << tint::internal_limits::kMaxSubgroupSize;
} else if (as_aint < 0) {
AddError(*call) << "The " << paramName << " argument of " << call->FriendlyName()
<< " must be greater than or equal to zero";
}
}
}
void ConstParamValidator::CheckClampCall(const CoreBuiltinCall* call) {
auto* const_val_low = GetConstArg(call, 1);
auto* const_val_high = GetConstArg(call, 2);
if (const_val_low && const_val_high) {
auto fakeArgs = Vector{const_val_low, const_val_low, const_val_high};
[[maybe_unused]] auto result =
const_eval_.clamp(call->Result()->Type(), fakeArgs, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckSmoothstepCall(const CoreBuiltinCall* call) {
auto* const_val_low = GetConstArg(call, 0);
auto* const_val_high = GetConstArg(call, 1);
if (const_val_low && const_val_high) {
auto fakeArgs = Vector{const_val_low, const_val_high, const_val_high};
[[maybe_unused]] auto result =
const_eval_.smoothstep(call->Result()->Type(), fakeArgs, mod_.SourceOf(call));
}
}
void ConstParamValidator::CheckBuiltinCall(const BuiltinCall* inst) {
if (auto* call = inst->As<core::ir::CoreBuiltinCall>()) {
switch (call->Func()) {
case core::BuiltinFn::kSubgroupShuffle:
case core::BuiltinFn::kSubgroupShuffleXor:
case core::BuiltinFn::kSubgroupShuffleUp:
case core::BuiltinFn::kSubgroupShuffleDown:
CheckSubgroupCall(call);
break;
case core::BuiltinFn::kExtractBits:
CheckExtractBitsCall(call);
break;
case core::BuiltinFn::kInsertBits:
CheckInsertBitsCall(call);
break;
case core::BuiltinFn::kLdexp:
CheckLdexpCall(call);
break;
case core::BuiltinFn::kClamp:
CheckClampCall(call);
break;
case core::BuiltinFn::kSmoothstep:
CheckSmoothstepCall(call);
break;
case core::BuiltinFn::kQuantizeToF16:
CheckQuantizeToF16(call);
break;
case core::BuiltinFn::kPack2X16Float:
CheckPack2x16float(call);
break;
default:
break;
}
}
}
void ConstParamValidator::CheckBinaryDivModCall(const CoreBinary* call) {
// Integer division by zero should be checked for the partial evaluation case (only rhs
// is const). FP division by zero is only invalid when the whole expression is
// constant-evaluated.
if (call->RHS()->Type()->IsIntegerScalarOrVector()) {
auto rhs_constant = call->RHS()->As<ir::Constant>();
if (rhs_constant && rhs_constant->Value()->AnyZero()) {
AddError(*call) << "integer division by zero is invalid";
}
}
}
void ConstParamValidator::CheckBinaryShiftCall(const CoreBinary* call) {
// If lhs value is a concrete type, and rhs is a const-expression greater than or equal
// to the bit width of lhs, then it is a shader-creation error.
const auto* elem_type = call->LHS()->Type()->DeepestElement();
const uint32_t bit_width = elem_type->Size() * 8;
if (auto* rhs_val_as_const = call->RHS()->As<ir::Constant>()) {
auto* rhs_as_value = rhs_val_as_const->Value();
for (size_t i = 0, n = rhs_as_value->NumElements(); i < n; i++) {
auto* shift_val = n == 1 ? rhs_as_value : rhs_as_value->Index(i);
if (shift_val->ValueAs<u32>() >= bit_width) {
AddError(*call) << "shift "
<< (call->Op() == core::BinaryOp::kShiftLeft ? "left" : "right")
<< " value must be less than the bit width of the lhs, which is "
<< bit_width;
break;
}
}
}
}
void ConstParamValidator::CheckCoreBinaryCall(const CoreBinary* call) {
switch (call->Op()) {
case core::BinaryOp::kDivide:
case core::BinaryOp::kModulo:
CheckBinaryDivModCall(call);
break;
case core::BinaryOp::kShiftLeft:
case core::BinaryOp::kShiftRight:
CheckBinaryShiftCall(call);
break;
default:
break;
}
}
Result<SuccessType> ConstParamValidator::Run() {
auto instructions = this->mod_.Instructions();
for (auto inst : instructions) {
tint::Switch(
inst, //
[&](const BuiltinCall* c) { CheckBuiltinCall(c); }, //
[&](const CoreBinary* c) { CheckCoreBinaryCall(c); }, //
[&](Default) {});
}
if (diagnostics_.ContainsErrors()) {
return Failure{diagnostics_.Str()};
}
return Success;
}
} // namespace
Result<SuccessType> ValidateConstParam(Module& mod) {
ConstParamValidator v(mod);
return v.Run();
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,47 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONST_PARAM_VALIDATOR_H_
#define SRC_TINT_LANG_CORE_IR_CONST_PARAM_VALIDATOR_H_
#include "src/tint/utils/result.h"
// Forward declarations
namespace tint::core::ir {
class Module;
} // namespace tint::core::ir
namespace tint::core::ir {
/// Validates the constant params for all instructions in the IR.
/// @param mod the module to validate
/// @returns success or failure
Result<SuccessType> ValidateConstParam(Module& mod);
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONST_PARAM_VALIDATOR_H_

View File

@@ -0,0 +1,46 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/constant.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Constant);
namespace tint::core::ir {
Constant::Constant(const core::constant::Value* val) : Base(nullptr), value_(val) {
TINT_ASSERT(value_);
SetType(val->Type());
}
Constant::~Constant() = default;
Constant* Constant::Clone(CloneContext&) {
return this; // Constants are immutable so can just return ourselves.
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,56 @@
// Copyright 2022 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONSTANT_H_
#define SRC_TINT_LANG_CORE_IR_CONSTANT_H_
#include "src/tint/lang/core/constant/value.h"
#include "src/tint/lang/core/ir/value.h"
namespace tint::core::ir {
/// Constant in the IR.
class Constant : public Castable<Constant, Value> {
public:
/// Constructor
/// @param val the value stored in the constant
explicit Constant(const core::constant::Value* val);
~Constant() override;
/// @returns the constants value
const core::constant::Value* Value() const { return value_; }
/// @copydoc Value::Clone()
Constant* Clone(CloneContext& ctx) override;
private:
const core::constant::Value* const value_ = nullptr;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONSTANT_H_

View File

@@ -0,0 +1,57 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/constexpr_if.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::ConstExprIf);
namespace tint::core::ir {
ConstExprIf::ConstExprIf(Id id) : Base(id) {}
ConstExprIf::ConstExprIf(Id id, Value* cond, ir::Block* t, ir::Block* f) : Base(id, cond, t, f) {}
ConstExprIf* ConstExprIf::Clone(CloneContext& ctx) {
auto* cond = ctx.Remap(Condition());
auto* new_true = ctx.ir.blocks.Create<ir::Block>();
auto* new_false = ctx.ir.blocks.Create<ir::Block>();
auto* new_if = ctx.ir.CreateInstruction<ConstExprIf>(cond, new_true, new_false);
ctx.Replace(this, new_if);
True()->CloneInto(ctx, new_true);
False()->CloneInto(ctx, new_false);
new_if->SetResults(ctx.Clone(results_));
return new_if;
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,61 @@
// Copyright 2025 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONSTEXPR_IF_H_
#define SRC_TINT_LANG_CORE_IR_CONSTEXPR_IF_H_
#include <string>
#include "src/tint/lang/core/ir/if.h"
namespace tint::core::ir {
/// A `constexpr-if` is an `if` instruction which will always be evaluated during
/// const-eval processing. The `condition` must be a `const` or `override`
/// expression.
class ConstExprIf final : public Castable<ConstExprIf, If> {
public:
/// Constructor (no results, no operands, no blocks)
/// @param id the instruction id
explicit ConstExprIf(Id id);
/// Constructor
/// @param cond the if condition
/// @param t the true block
/// @param f the false block
ConstExprIf(Id id, Value* cond, ir::Block* t, ir::Block* f);
/// @copydoc Instruction::Clone()
ConstExprIf* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "constexpr_if"; }
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONSTEXPR_IF_H_

View File

@@ -0,0 +1,54 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/construct.h"
#include <utility>
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Construct);
namespace tint::core::ir {
Construct::Construct(Id id) : Base(id) {}
Construct::Construct(Id id, InstructionResult* result, VectorRef<Value*> arguments) : Base(id) {
AddOperands(Construct::kArgsOperandOffset, std::move(arguments));
AddResult(result);
}
Construct::~Construct() = default;
Construct* Construct::Clone(CloneContext& ctx) {
auto* new_result = ctx.Clone(Result());
auto args = ctx.Remap<Construct::kDefaultNumOperands>(Args());
return ctx.ir.CreateInstruction<Construct>(new_result, args);
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,71 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONSTRUCT_H_
#define SRC_TINT_LANG_CORE_IR_CONSTRUCT_H_
#include <string>
#include "src/tint/lang/core/ir/call.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// A constructor instruction in the IR.
class Construct final : public Castable<Construct, Call> {
public:
/// The base offset in Operands() for the args
static constexpr size_t kArgsOperandOffset = 0;
/// The fixed number of results returned by this instruction
static constexpr size_t kNumResults = 1;
/// The minimum number of operands expected for this instruction
static constexpr size_t kMinOperands = 0;
/// Constructor (no result, no operands)
/// @param id the instruction id
explicit Construct(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param args the constructor arguments
Construct(Id id, InstructionResult* result, VectorRef<Value*> args = tint::Empty);
~Construct() override;
/// @copydoc Instruction::Clone()
Construct* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "construct"; }
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONSTRUCT_H_

View File

@@ -0,0 +1,81 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/continue.h"
#include <utility>
#include "src/tint/lang/core/ir/block.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/loop.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/lang/core/ir/multi_in_block.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Continue);
namespace tint::core::ir {
Continue::Continue(Id id) : Base(id) {}
Continue::Continue(Id id, ir::Loop* loop, VectorRef<Value*> args) : Base(id), loop_(loop) {
TINT_ASSERT(loop_);
AddOperands(Continue::kArgsOperandOffset, std::move(args));
if (loop_) {
loop_->Continuing()->AddInboundSiblingBranch(this);
}
}
Continue::~Continue() = default;
void Continue::Destroy() {
if (loop_) {
loop_->Continuing()->RemoveInboundSiblingBranch(this);
}
Instruction::Destroy();
}
Continue* Continue::Clone(CloneContext& ctx) {
auto* loop = ctx.Remap(Loop());
auto args = ctx.Remap<Continue::kDefaultNumOperands>(Args());
return ctx.ir.CreateInstruction<Continue>(loop, args);
}
void Continue::SetLoop(ir::Loop* loop) {
if (loop_ && loop_->Body()) {
loop_->Continuing()->RemoveInboundSiblingBranch(this);
}
loop_ = loop;
if (loop) {
loop->Continuing()->AddInboundSiblingBranch(this);
}
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,84 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONTINUE_H_
#define SRC_TINT_LANG_CORE_IR_CONTINUE_H_
#include <string>
#include "src/tint/lang/core/ir/terminator.h"
#include "src/tint/utils/rtti/castable.h"
// Forward declarations
namespace tint::core::ir {
class Loop;
} // namespace tint::core::ir
namespace tint::core::ir {
/// A continue instruction.
class Continue final : public Castable<Continue, Terminator> {
public:
/// The base offset in Operands() for the args
static constexpr size_t kArgsOperandOffset = 0;
/// Constructor (no operands, no loop)
/// @param id the instruction id
explicit Continue(Id id);
/// Constructor
/// @param id the instruction id
/// @param loop the loop owning the continue block
/// @param args the arguments for the MultiInBlock
Continue(Id id, ir::Loop* loop, VectorRef<Value*> args = tint::Empty);
~Continue() override;
/// @copydoc Instruction::Clone()
Continue* Clone(CloneContext& ctx) override;
/// @copydoc Instruction::Destroy()
void Destroy() override;
/// @returns the loop owning the continue block
ir::Loop* Loop() { return loop_; }
/// @returns the loop owning the continue block
const ir::Loop* Loop() const { return loop_; }
/// @param loop the new loop owning the continue block
void SetLoop(ir::Loop* loop);
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "continue"; }
private:
ir::Loop* loop_ = nullptr;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONTINUE_H_

View File

@@ -0,0 +1,55 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/control_instruction.h"
#include "src/tint/lang/core/ir/block.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::ControlInstruction);
namespace tint::core::ir {
ControlInstruction::ControlInstruction(Id id) : Base(id) {
flags_.Add(Flag::kSequenced);
}
ControlInstruction::~ControlInstruction() = default;
void ControlInstruction::AddExit(Exit* exit) {
exits_.Add(exit);
}
void ControlInstruction::RemoveExit(Exit* exit) {
exits_.Remove(exit);
}
void ControlInstruction::Destroy() {
Base::Destroy();
ForeachBlock([](ir::Block* blk) { blk->Destroy(); });
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,83 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONTROL_INSTRUCTION_H_
#define SRC_TINT_LANG_CORE_IR_CONTROL_INSTRUCTION_H_
#include <utility>
#include "src/tint/lang/core/ir/operand_instruction.h"
// Forward declarations
namespace tint::core::ir {
class Block;
class Exit;
} // namespace tint::core::ir
namespace tint::core::ir {
/// Base class of instructions that perform control flow to two or more blocks, owned by the
/// ControlInstruction.
class ControlInstruction : public Castable<ControlInstruction, OperandInstruction<1, 1>> {
public:
/// Constructor
/// @param id the instruction id
explicit ControlInstruction(Id id);
/// Destructor
~ControlInstruction() override;
/// Calls @p cb for each block owned by this control instruction
/// @param cb the function to call once for each block
virtual void ForeachBlock(const std::function<void(ir::Block*)>& cb) = 0;
/// Calls @p cb for each block owned by this control instruction
/// @param cb the function to call once for each block
virtual void ForeachBlock(const std::function<void(const ir::Block*)>& cb) const = 0;
/// @return All the exits for the flow control instruction
const Hashset<Exit*, 2>& Exits() const { return exits_; }
/// Adds the exit to the flow control instruction
/// @param exit the exit instruction
void AddExit(Exit* exit);
/// Removes the exit to the flow control instruction
/// @param exit the exit instruction
void RemoveExit(Exit* exit);
/// @copydoc Instruction::Destroy
void Destroy() override;
protected:
/// The flow control exits
Hashset<Exit*, 2> exits_;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONTROL_INSTRUCTION_H_

View File

@@ -0,0 +1,54 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/convert.h"
#include <utility>
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::Convert);
namespace tint::core::ir {
Convert::Convert(Id id) : Base(id) {}
Convert::Convert(Id id, InstructionResult* result, Value* value) : Base(id) {
AddOperand(Convert::kValueOperandOffset, value);
AddResult(result);
}
Convert::~Convert() = default;
Convert* Convert::Clone(CloneContext& ctx) {
auto* new_result = ctx.Clone(Result());
auto* val = ctx.Remap(Args()[0]);
return ctx.ir.CreateInstruction<Convert>(new_result, val);
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,72 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CONVERT_H_
#define SRC_TINT_LANG_CORE_IR_CONVERT_H_
#include <string>
#include "src/tint/lang/core/ir/call.h"
#include "src/tint/lang/core/type/type.h"
#include "src/tint/utils/rtti/castable.h"
namespace tint::core::ir {
/// A value conversion instruction in the IR.
class Convert final : public Castable<Convert, Call> {
public:
/// The offset in Operands() for the value
static constexpr size_t kValueOperandOffset = 0;
/// The fixed number of results returned by this instruction
static constexpr size_t kNumResults = 1;
/// The fixed number of operands expected for this instruction
static constexpr size_t kNumOperands = 1;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit Convert(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param value the value to convert
Convert(Id id, InstructionResult* result, Value* value);
~Convert() override;
/// @copydoc Instruction::Clone()
Convert* Clone(CloneContext& ctx) override;
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "convert"; }
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CONVERT_H_

View File

@@ -0,0 +1,56 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/core_binary.h"
#include "src/tint/lang/core/intrinsic/dialect.h"
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::CoreBinary);
namespace tint::core::ir {
CoreBinary::CoreBinary(Id id) : Base(id) {}
CoreBinary::CoreBinary(Id id, InstructionResult* result, BinaryOp op, Value* lhs, Value* rhs)
: Base(id, result, op, lhs, rhs) {}
CoreBinary::~CoreBinary() = default;
CoreBinary* CoreBinary::Clone(CloneContext& ctx) {
auto* new_result = ctx.Clone(Result());
auto* lhs = ctx.Remap(LHS());
auto* rhs = ctx.Remap(RHS());
return ctx.ir.CreateInstruction<CoreBinary>(new_result, Op(), lhs, rhs);
}
const core::intrinsic::TableData& CoreBinary::TableData() const {
return core::intrinsic::Dialect::kData;
}
} // namespace tint::core::ir

View File

@@ -0,0 +1,64 @@
// Copyright 2024 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef SRC_TINT_LANG_CORE_IR_CORE_BINARY_H_
#define SRC_TINT_LANG_CORE_IR_CORE_BINARY_H_
#include "src/tint/lang/core/ir/binary.h"
namespace tint::core::ir {
/// A core-dialect binary-op instruction in the IR.
class CoreBinary final : public Castable<CoreBinary, Binary> {
public:
/// The offset in Operands() for the value
static constexpr size_t kValueOperandOffset = 0;
/// Constructor (no results, no operands)
/// @param id the instruction id
explicit CoreBinary(Id id);
/// Constructor
/// @param id the instruction id
/// @param result the result value
/// @param op the Binary operator
/// @param lhs the lhs of the instruction
/// @param rhs the rhs of the instruction
CoreBinary(Id id, InstructionResult* result, BinaryOp op, Value* lhs, Value* rhs);
~CoreBinary() override;
/// @copydoc Instruction::Clone()
CoreBinary* Clone(CloneContext& ctx) override;
/// @returns the table data to validate this builtin
const core::intrinsic::TableData& TableData() const override;
};
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_CORE_BINARY_H_

View File

@@ -0,0 +1,229 @@
// Copyright 2023 The Dawn & Tint Authors
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "src/tint/lang/core/ir/core_builtin_call.h"
#include <utility>
#include "src/tint/lang/core/ir/clone_context.h"
#include "src/tint/lang/core/ir/module.h"
#include "src/tint/utils/ice/ice.h"
TINT_INSTANTIATE_TYPEINFO(tint::core::ir::CoreBuiltinCall);
namespace tint::core::ir {
CoreBuiltinCall::CoreBuiltinCall(Id id) : Base(id) {}
CoreBuiltinCall::CoreBuiltinCall(Id id,
InstructionResult* result,
core::BuiltinFn func,
VectorRef<Value*> arguments)
: Base(id, result, arguments), func_(func) {
TINT_ASSERT(func != core::BuiltinFn::kNone);
}
CoreBuiltinCall::~CoreBuiltinCall() = default;
CoreBuiltinCall* CoreBuiltinCall::Clone(CloneContext& ctx) {
auto* new_result = ctx.Clone(Result());
auto args = ctx.Remap<CoreBuiltinCall::kDefaultNumOperands>(Args());
return ctx.ir.CreateInstruction<CoreBuiltinCall>(new_result, func_, args);
}
tint::core::ir::Instruction::Accesses CoreBuiltinCall::GetSideEffects() const {
switch (func_) {
case BuiltinFn::kAtomicLoad:
case BuiltinFn::kInputAttachmentLoad:
case BuiltinFn::kSubgroupMatrixLoad:
case BuiltinFn::kTextureSample:
case BuiltinFn::kTextureSampleBias:
case BuiltinFn::kTextureSampleCompare:
case BuiltinFn::kTextureSampleCompareLevel:
case BuiltinFn::kTextureSampleGrad:
case BuiltinFn::kTextureSampleLevel:
case BuiltinFn::kTextureSampleBaseClampToEdge:
case BuiltinFn::kTextureLoad:
case BuiltinFn::kGetResource:
return Accesses{Access::kLoad};
case BuiltinFn::kSubgroupMatrixStore:
case BuiltinFn::kTextureStore:
return Accesses{Access::kStore};
case BuiltinFn::kAtomicStore:
case BuiltinFn::kAtomicAdd:
case BuiltinFn::kAtomicSub:
case BuiltinFn::kAtomicMax:
case BuiltinFn::kAtomicMin:
case BuiltinFn::kAtomicAnd:
case BuiltinFn::kAtomicOr:
case BuiltinFn::kAtomicXor:
case BuiltinFn::kAtomicExchange:
case BuiltinFn::kAtomicCompareExchangeWeak:
case BuiltinFn::kDpdx:
case BuiltinFn::kDpdxCoarse:
case BuiltinFn::kDpdxFine:
case BuiltinFn::kDpdy:
case BuiltinFn::kDpdyCoarse:
case BuiltinFn::kDpdyFine:
case BuiltinFn::kFwidth:
case BuiltinFn::kFwidthCoarse:
case BuiltinFn::kFwidthFine:
case BuiltinFn::kSubgroupBallot:
case BuiltinFn::kSubgroupElect:
case BuiltinFn::kSubgroupBroadcast:
case BuiltinFn::kSubgroupBroadcastFirst:
case BuiltinFn::kSubgroupShuffle:
case BuiltinFn::kSubgroupShuffleXor:
case BuiltinFn::kSubgroupShuffleUp:
case BuiltinFn::kSubgroupShuffleDown:
case BuiltinFn::kSubgroupAdd:
case BuiltinFn::kSubgroupInclusiveAdd:
case BuiltinFn::kSubgroupExclusiveAdd:
case BuiltinFn::kSubgroupMul:
case BuiltinFn::kSubgroupInclusiveMul:
case BuiltinFn::kSubgroupExclusiveMul:
case BuiltinFn::kSubgroupAnd:
case BuiltinFn::kSubgroupOr:
case BuiltinFn::kSubgroupXor:
case BuiltinFn::kSubgroupMin:
case BuiltinFn::kSubgroupMax:
case BuiltinFn::kSubgroupAll:
case BuiltinFn::kSubgroupAny:
case BuiltinFn::kQuadBroadcast:
case BuiltinFn::kQuadSwapX:
case BuiltinFn::kQuadSwapY:
case BuiltinFn::kQuadSwapDiagonal:
case BuiltinFn::kStorageBarrier:
case BuiltinFn::kWorkgroupBarrier:
case BuiltinFn::kTextureBarrier:
case BuiltinFn::kPrint:
return Accesses{Access::kLoad, Access::kStore};
case BuiltinFn::kAbs:
case BuiltinFn::kAcos:
case BuiltinFn::kAcosh:
case BuiltinFn::kAll:
case BuiltinFn::kAny:
case BuiltinFn::kArrayLength:
case BuiltinFn::kAsin:
case BuiltinFn::kAsinh:
case BuiltinFn::kAtan:
case BuiltinFn::kAtan2:
case BuiltinFn::kAtanh:
case BuiltinFn::kCeil:
case BuiltinFn::kClamp:
case BuiltinFn::kCos:
case BuiltinFn::kCosh:
case BuiltinFn::kCountLeadingZeros:
case BuiltinFn::kCountOneBits:
case BuiltinFn::kCountTrailingZeros:
case BuiltinFn::kCross:
case BuiltinFn::kDegrees:
case BuiltinFn::kDeterminant:
case BuiltinFn::kDistance:
case BuiltinFn::kDot:
case BuiltinFn::kDot4I8Packed:
case BuiltinFn::kDot4U8Packed:
case BuiltinFn::kExp:
case BuiltinFn::kExp2:
case BuiltinFn::kExtractBits:
case BuiltinFn::kFaceForward:
case BuiltinFn::kFirstLeadingBit:
case BuiltinFn::kFirstTrailingBit:
case BuiltinFn::kFloor:
case BuiltinFn::kFma:
case BuiltinFn::kFract:
case BuiltinFn::kFrexp:
case BuiltinFn::kInsertBits:
case BuiltinFn::kInverseSqrt:
case BuiltinFn::kLdexp:
case BuiltinFn::kLength:
case BuiltinFn::kLog:
case BuiltinFn::kLog2:
case BuiltinFn::kMax:
case BuiltinFn::kMin:
case BuiltinFn::kMix:
case BuiltinFn::kModf:
case BuiltinFn::kNormalize:
case BuiltinFn::kPack2X16Float:
case BuiltinFn::kPack2X16Snorm:
case BuiltinFn::kPack2X16Unorm:
case BuiltinFn::kPack4X8Snorm:
case BuiltinFn::kPack4X8Unorm:
case BuiltinFn::kPack4XI8:
case BuiltinFn::kPack4XU8:
case BuiltinFn::kPack4XI8Clamp:
case BuiltinFn::kPack4XU8Clamp:
case BuiltinFn::kPow:
case BuiltinFn::kQuantizeToF16:
case BuiltinFn::kRadians:
case BuiltinFn::kReflect:
case BuiltinFn::kRefract:
case BuiltinFn::kReverseBits:
case BuiltinFn::kRound:
case BuiltinFn::kSaturate:
case BuiltinFn::kSelect:
case BuiltinFn::kSign:
case BuiltinFn::kSin:
case BuiltinFn::kSinh:
case BuiltinFn::kSmoothstep:
case BuiltinFn::kSqrt:
case BuiltinFn::kStep:
case BuiltinFn::kTan:
case BuiltinFn::kTanh:
case BuiltinFn::kTextureDimensions:
case BuiltinFn::kTextureGather:
case BuiltinFn::kTextureGatherCompare:
case BuiltinFn::kTextureNumLayers:
case BuiltinFn::kTextureNumLevels:
case BuiltinFn::kTextureNumSamples:
case BuiltinFn::kTranspose:
case BuiltinFn::kTrunc:
case BuiltinFn::kUnpack2X16Float:
case BuiltinFn::kUnpack2X16Snorm:
case BuiltinFn::kUnpack2X16Unorm:
case BuiltinFn::kUnpack4X8Snorm:
case BuiltinFn::kUnpack4X8Unorm:
case BuiltinFn::kUnpack4XI8:
case BuiltinFn::kUnpack4XU8:
case BuiltinFn::kSubgroupMatrixMultiply:
case BuiltinFn::kSubgroupMatrixMultiplyAccumulate:
case BuiltinFn::kSubgroupMatrixScalarAdd:
case BuiltinFn::kSubgroupMatrixScalarSubtract:
case BuiltinFn::kSubgroupMatrixScalarMultiply:
case BuiltinFn::kHasResource:
case BuiltinFn::kBufferView:
case BuiltinFn::kBufferLength:
case BuiltinFn::kNone:
break;
}
return Accesses{};
}
} // namespace tint::core::ir

Some files were not shown because too many files have changed in this diff Show More