mirror of
https://gitee.com/openharmony/third_party_spirv-tools
synced 2024-11-23 23:39:40 +00:00
Add libspirv::CapabilitySet
It's optimized for the common case, where capabilities have value at most 63.
This commit is contained in:
parent
76982706f9
commit
47f2a1414b
@ -129,6 +129,7 @@ set(SPIRV_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/util/hex_float.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/binary.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/capability_set.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/instruction.h
|
||||
@ -148,6 +149,7 @@ set(SPIRV_SOURCES
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/assembly_grammar.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/binary.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/capability_set.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/diagnostic.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/disassemble.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ext_inst.cpp
|
||||
|
75
source/capability_set.cpp
Normal file
75
source/capability_set.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include "capability_set.h"
|
||||
|
||||
#include "spirv/1.1/spirv.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
// Determines whether the given capability can be represented
|
||||
// as a bit in a uint64_t mask. If so, then returns that mask bit.
|
||||
// Otherwise, returns 0.
|
||||
uint64_t AsMask(uint32_t word) {
|
||||
if (word > 63) return 0;
|
||||
return uint64_t(1) << word;
|
||||
}
|
||||
}
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
void CapabilitySet::Add(uint32_t word) {
|
||||
if (auto new_bits = AsMask(word)) {
|
||||
mask_ |= new_bits;
|
||||
} else {
|
||||
Overflow().insert(word);
|
||||
}
|
||||
}
|
||||
|
||||
bool CapabilitySet::Contains(uint32_t word) const {
|
||||
// We shouldn't call Overflow() since this is a const method.
|
||||
if (auto bits = AsMask(word)) {
|
||||
return mask_ & bits;
|
||||
} else if (auto overflow = overflow_.get()) {
|
||||
return overflow->find(word) != overflow->end();
|
||||
}
|
||||
// The word is large, but the set doesn't have large members, so
|
||||
// it doesn't have an overflow set.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Applies f to each capability in the set, in order from smallest enum
|
||||
// value to largest.
|
||||
void CapabilitySet::ForEach(std::function<void(SpvCapability)> f) const {
|
||||
for (uint32_t i = 0; i < 64; ++i) {
|
||||
if (mask_ & AsMask(i)) f(static_cast<SpvCapability>(i));
|
||||
}
|
||||
if (overflow_) {
|
||||
for (uint32_t c : *overflow_) f(static_cast<SpvCapability>(c));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace libspirv
|
119
source/capability_set.h
Normal file
119
source/capability_set.h
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#ifndef LIBSPIRV_CAPABILITY_SET_H
|
||||
#define LIBSPIRV_CAPABILITY_SET_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
#include "spirv/1.1/spirv.h"
|
||||
|
||||
namespace libspirv {
|
||||
|
||||
// A set of values of type SpvCapability.
|
||||
// It is fast and compact for the common case, where capability values
|
||||
// are at most 63. But it can represent capabilities with larger values,
|
||||
// as may appear in extensions.
|
||||
class CapabilitySet {
|
||||
private:
|
||||
// The ForEach method will call the functor on capabilities in
|
||||
// enum value order (lowest to highest). To make that easier, use
|
||||
// an ordered set for the overflow values.
|
||||
using OverflowSetType = std::set<uint32_t>;
|
||||
|
||||
public:
|
||||
// Construct an empty set.
|
||||
CapabilitySet() = default;
|
||||
// Construct an set with just the given capability.
|
||||
explicit CapabilitySet(SpvCapability c) { Add(c); }
|
||||
// Construct an set from an initializer list of capabilities.
|
||||
CapabilitySet(std::initializer_list<SpvCapability> cs) {
|
||||
for (auto c : cs) Add(c);
|
||||
}
|
||||
// Copy constructor.
|
||||
CapabilitySet(const CapabilitySet& other) { *this = other; }
|
||||
// Move constructor. The moved-from set is emptied.
|
||||
CapabilitySet(CapabilitySet&& other) {
|
||||
mask_ = other.mask_;
|
||||
overflow_ = std::move(other.overflow_);
|
||||
other.mask_ = 0;
|
||||
other.overflow_.reset(nullptr);
|
||||
}
|
||||
// Assignment operator.
|
||||
CapabilitySet& operator=(const CapabilitySet& other) {
|
||||
if (&other != this) {
|
||||
mask_ = other.mask_;
|
||||
overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_)
|
||||
: nullptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Adds the given capability to the set. This has no effect if the
|
||||
// capability is already in the set.
|
||||
void Add(SpvCapability c) { Add(static_cast<uint32_t>(c)); }
|
||||
// Adds the given capability (as a 32-bit word) to the set. This has no
|
||||
// effect if the capability is already in the set.
|
||||
void Add(uint32_t);
|
||||
|
||||
// Returns true if this capability is in the set.
|
||||
bool Contains(SpvCapability c) const {
|
||||
return Contains(static_cast<uint32_t>(c));
|
||||
}
|
||||
// Returns true if the capability represented as a 32-bit word is in the set.
|
||||
bool Contains(uint32_t word) const;
|
||||
|
||||
// Applies f to each capability in the set, in order from smallest enum
|
||||
// value to largest.
|
||||
void ForEach(std::function<void(SpvCapability)> f) const;
|
||||
|
||||
private:
|
||||
// Returns true if the set has capabilities with value greater than 63.
|
||||
bool HasOverflow() { return overflow_ != nullptr; }
|
||||
|
||||
// Ensures that overflow_set_ references a set. A new empty set is
|
||||
// allocated if one doesn't exist yet. Returns overflow_set_.
|
||||
OverflowSetType& Overflow() {
|
||||
if (overflow_.get() == nullptr) {
|
||||
overflow_.reset(new OverflowSetType);
|
||||
}
|
||||
return *overflow_;
|
||||
}
|
||||
|
||||
// Capabilities with values up to 63 are stored as bits in this mask.
|
||||
uint64_t mask_ = 0;
|
||||
// Capabilities with values larger than 63 are stored in this set.
|
||||
// This set should normally be empty or very small.
|
||||
std::unique_ptr<OverflowSetType> overflow_ = {};
|
||||
};
|
||||
|
||||
} // namespace libspirv
|
||||
|
||||
#endif // LIBSPIRV_CAPABILITY_SET_H
|
@ -202,7 +202,7 @@ ValidationState_t::ValidationState_t(spv_diagnostic* diagnostic,
|
||||
operand_names_{},
|
||||
current_layout_section_(kLayoutCapabilities),
|
||||
module_functions_(),
|
||||
module_capabilities_(0u),
|
||||
module_capabilities_(),
|
||||
ordered_instructions_(),
|
||||
all_definitions_(),
|
||||
grammar_(context),
|
||||
|
@ -84,6 +84,7 @@ set(TEST_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BinaryParse.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BinaryToText.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/BinaryToText.Literal.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CapabilitySet.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Comment.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DiagnosticDestroy.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DiagnosticPrint.cpp
|
||||
|
164
test/CapabilitySet.cpp
Normal file
164
test/CapabilitySet.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
// Copyright (c) 2016 Google Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and/or associated documentation files (the
|
||||
// "Materials"), to deal in the Materials without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
// permit persons to whom the Materials are furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Materials.
|
||||
//
|
||||
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS
|
||||
// KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS
|
||||
// SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT
|
||||
// https://www.khronos.org/registry/
|
||||
//
|
||||
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
|
||||
#include "capability_set.h"
|
||||
|
||||
#include <vector>
|
||||
#include "gmock/gmock.h"
|
||||
|
||||
#include "UnitSPIRV.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using libspirv::CapabilitySet;
|
||||
using spvtest::ElementsIn;
|
||||
using ::testing::Eq;
|
||||
using ::testing::ValuesIn;
|
||||
|
||||
TEST(CapabilitySet, DefaultIsEmpty) {
|
||||
CapabilitySet c;
|
||||
for (uint32_t i = 0; i < 1000; ++i) {
|
||||
EXPECT_FALSE(c.Contains(i));
|
||||
EXPECT_FALSE(c.Contains(static_cast<SpvCapability>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMatrix) {
|
||||
CapabilitySet s(SpvCapabilityMatrix);
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(1000));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMaxInMask) {
|
||||
CapabilitySet s(static_cast<SpvCapability>(63));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_TRUE(s.Contains(63));
|
||||
EXPECT_FALSE(s.Contains(64));
|
||||
EXPECT_FALSE(s.Contains(1000));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMinOverflow) {
|
||||
// Check the first one that forces overflow beyond the mask.
|
||||
CapabilitySet s(static_cast<SpvCapability>(64));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(63));
|
||||
EXPECT_TRUE(s.Contains(64));
|
||||
EXPECT_FALSE(s.Contains(1000));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) {
|
||||
// Check the max 32-bit signed int.
|
||||
CapabilitySet s(SpvCapability(0x7fffffffu));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_FALSE(s.Contains(1000));
|
||||
EXPECT_TRUE(s.Contains(0x7fffffffu));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, AddEnum) {
|
||||
CapabilitySet s(SpvCapabilityShader);
|
||||
s.Add(SpvCapabilityKernel);
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityKernel));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, AddInt) {
|
||||
CapabilitySet s(SpvCapabilityShader);
|
||||
s.Add(42);
|
||||
EXPECT_FALSE(s.Contains(SpvCapabilityMatrix));
|
||||
EXPECT_TRUE(s.Contains(SpvCapabilityShader));
|
||||
EXPECT_TRUE(s.Contains(42));
|
||||
EXPECT_TRUE(s.Contains(static_cast<SpvCapability>(42)));
|
||||
}
|
||||
|
||||
TEST(CapabilitySet, InitializerListEmpty) {
|
||||
CapabilitySet s{};
|
||||
for (uint32_t i = 0; i < 1000; i++) {
|
||||
EXPECT_FALSE(s.Contains(i));
|
||||
}
|
||||
}
|
||||
|
||||
struct ForEachCase {
|
||||
CapabilitySet capabilities;
|
||||
std::vector<SpvCapability> expected;
|
||||
};
|
||||
|
||||
using CapabilitySetForEachTest = ::testing::TestWithParam<ForEachCase>;
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, CallsAsExpected) {
|
||||
EXPECT_THAT(ElementsIn(GetParam().capabilities), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, CopyConstructor) {
|
||||
CapabilitySet copy(GetParam().capabilities);
|
||||
EXPECT_THAT(ElementsIn(copy), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, MoveConstructor) {
|
||||
// We need a writable copy to move from.
|
||||
CapabilitySet copy(GetParam().capabilities);
|
||||
CapabilitySet moved(std::move(copy));
|
||||
EXPECT_THAT(ElementsIn(moved), Eq(GetParam().expected));
|
||||
|
||||
// The moved-from set is empty.
|
||||
EXPECT_THAT(ElementsIn(copy), Eq(std::vector<SpvCapability>{}));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, OperatorEquals) {
|
||||
CapabilitySet assigned = GetParam().capabilities;
|
||||
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
TEST_P(CapabilitySetForEachTest, OperatorEqualsSelfAssign) {
|
||||
CapabilitySet assigned{GetParam().capabilities};
|
||||
assigned = assigned;
|
||||
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Samples, CapabilitySetForEachTest,
|
||||
ValuesIn(std::vector<ForEachCase>{
|
||||
{{}, {}},
|
||||
{{SpvCapabilityMatrix}, {SpvCapabilityMatrix}},
|
||||
{{SpvCapabilityKernel, SpvCapabilityShader},
|
||||
{SpvCapabilityShader, SpvCapabilityKernel}},
|
||||
{{static_cast<SpvCapability>(999)},
|
||||
{static_cast<SpvCapability>(999)}},
|
||||
{{static_cast<SpvCapability>(0x7fffffff)},
|
||||
{static_cast<SpvCapability>(0x7fffffff)}},
|
||||
// Mixture and out of order
|
||||
{{static_cast<SpvCapability>(0x7fffffff),
|
||||
static_cast<SpvCapability>(100),
|
||||
SpvCapabilityShader, SpvCapabilityMatrix},
|
||||
{SpvCapabilityMatrix, SpvCapabilityShader,
|
||||
static_cast<SpvCapability>(100),
|
||||
static_cast<SpvCapability>(0x7fffffff)}},
|
||||
}), );
|
||||
|
||||
} // anonymous namespace
|
@ -30,9 +30,11 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
#include "source/assembly_grammar.h"
|
||||
#include "source/binary.h"
|
||||
#include "source/capability_set.h"
|
||||
#include "source/diagnostic.h"
|
||||
#include "source/opcode.h"
|
||||
#include "source/spirv_endian.h"
|
||||
@ -224,5 +226,13 @@ inline std::vector<spv_target_env> AllTargetEnvironments() {
|
||||
SPV_ENV_OPENGL_4_5};
|
||||
}
|
||||
|
||||
// Returns the capabilities in a CapabilitySet as an ordered vector.
|
||||
inline std::vector<SpvCapability> ElementsIn(
|
||||
const libspirv::CapabilitySet& capabilities) {
|
||||
std::vector<SpvCapability> result;
|
||||
capabilities.ForEach([&result](SpvCapability c) { result.push_back(c); });
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace spvtest
|
||||
#endif // LIBSPIRV_TEST_UNITSPIRV_H_
|
||||
|
Loading…
Reference in New Issue
Block a user