Commit ab51bbfa by Ben Clayton

Strongly type object / type identifiers.

Prevents you from mixing them up by mistake, and provides better self-documentation on function signatures. Bug: b/126126820 Change-Id: I21ce20ded434ca3d5d03ebf3f9027cf6f6b5386f Reviewed-on: https://swiftshader-review.googlesource.com/c/25068Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 377d493a
// Copyright 2019 The SwiftShader Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef sw_ID_hpp
#define sw_ID_hpp
#include <unordered_map>
#include <cstdint>
namespace sw
{
// SpirvID is a strongly-typed identifier backed by a uint32_t.
// The template parameter T is not actually used by the implementation of
// ID; instead it is used to prevent implicit casts between idenfitifers of
// different T types.
// IDs are typically used as a map key to value of type T.
template <typename T>
class SpirvID
{
public:
SpirvID() : id(0) {}
SpirvID(uint32_t id) : id(id) {}
bool operator == (const SpirvID<T>& rhs) const { return id == rhs.id; }
bool operator < (const SpirvID<T>& rhs) const { return id < rhs.id; }
// value returns the numerical value of the identifier.
uint32_t value() const { return id; }
private:
uint32_t id;
};
// HandleMap<T> is an unordered map of SpirvID<T> to T.
template <typename T>
using HandleMap = std::unordered_map<SpirvID<T>, T>;
}
namespace std
{
// std::hash implementation for sw::SpirvID<T>
template<typename T>
struct hash< sw::SpirvID<T> >
{
std::size_t operator()(const sw::SpirvID<T>& id) const noexcept
{
return std::hash<uint32_t>()(id.value());
}
};
}
#endif // sw_ID_hpp
...@@ -41,7 +41,7 @@ namespace sw ...@@ -41,7 +41,7 @@ namespace sw
case spv::OpDecorate: case spv::OpDecorate:
{ {
auto targetId = insn.word(1); TypeOrObjectID targetId = insn.word(1);
auto decoration = static_cast<spv::Decoration>(insn.word(2)); auto decoration = static_cast<spv::Decoration>(insn.word(2));
decorations[targetId].Apply( decorations[targetId].Apply(
decoration, decoration,
...@@ -54,7 +54,7 @@ namespace sw ...@@ -54,7 +54,7 @@ namespace sw
case spv::OpMemberDecorate: case spv::OpMemberDecorate:
{ {
auto targetId = insn.word(1); TypeID targetId = insn.word(1);
auto memberIndex = insn.word(2); auto memberIndex = insn.word(2);
auto &d = memberDecorations[targetId]; auto &d = memberDecorations[targetId];
if (memberIndex >= d.size()) if (memberIndex >= d.size())
...@@ -116,7 +116,7 @@ namespace sw ...@@ -116,7 +116,7 @@ namespace sw
case spv::OpTypePointer: case spv::OpTypePointer:
case spv::OpTypeFunction: case spv::OpTypeFunction:
{ {
auto resultId = insn.word(1); TypeID resultId = insn.word(1);
auto &type = types[resultId]; auto &type = types[resultId];
type.definition = insn; type.definition = insn;
type.sizeInComponents = ComputeTypeSize(insn); type.sizeInComponents = ComputeTypeSize(insn);
...@@ -140,7 +140,7 @@ namespace sw ...@@ -140,7 +140,7 @@ namespace sw
} }
else if (insn.opcode() == spv::OpTypePointer) else if (insn.opcode() == spv::OpTypePointer)
{ {
auto pointeeType = insn.word(3); TypeID pointeeType = insn.word(3);
type.isBuiltInBlock = getType(pointeeType).isBuiltInBlock; type.isBuiltInBlock = getType(pointeeType).isBuiltInBlock;
} }
break; break;
...@@ -148,8 +148,8 @@ namespace sw ...@@ -148,8 +148,8 @@ namespace sw
case spv::OpVariable: case spv::OpVariable:
{ {
auto typeId = insn.word(1); TypeID typeId = insn.word(1);
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto storageClass = static_cast<spv::StorageClass>(insn.word(3)); auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
if (insn.wordCount() > 4) if (insn.wordCount() > 4)
UNIMPLEMENTED("Variable initializers not yet supported"); UNIMPLEMENTED("Variable initializers not yet supported");
...@@ -244,8 +244,8 @@ namespace sw ...@@ -244,8 +244,8 @@ namespace sw
case spv::OpAccessChain: case spv::OpAccessChain:
// Instructions that yield an ssavalue. // Instructions that yield an ssavalue.
{ {
auto typeId = insn.word(1); TypeID typeId = insn.word(1);
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = defs[resultId]; auto &object = defs[resultId];
object.kind = Object::Kind::Value; object.kind = Object::Kind::Value;
object.definition = insn; object.definition = insn;
...@@ -279,8 +279,8 @@ namespace sw ...@@ -279,8 +279,8 @@ namespace sw
SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn) SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
{ {
auto typeId = insn.word(1); TypeID typeId = insn.word(1);
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = defs[resultId]; auto &object = defs[resultId];
object.kind = Object::Kind::Constant; object.kind = Object::Kind::Constant;
object.definition = insn; object.definition = insn;
...@@ -296,13 +296,13 @@ namespace sw ...@@ -296,13 +296,13 @@ namespace sw
auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins; auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs; auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs;
auto resultId = object.definition.word(2); ObjectID resultId = object.definition.word(2);
if (object.isBuiltInBlock) if (object.isBuiltInBlock)
{ {
// walk the builtin block, registering each of its members separately. // walk the builtin block, registering each of its members separately.
auto ptrType = getType(object.definition.word(1)).definition; auto ptrType = getType(object.definition.word(1)).definition;
assert(ptrType.opcode() == spv::OpTypePointer); assert(ptrType.opcode() == spv::OpTypePointer);
auto pointeeType = ptrType.word(3); TypeID pointeeType = ptrType.word(3);
auto m = memberDecorations.find(pointeeType); auto m = memberDecorations.find(pointeeType);
assert(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain assert(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
auto &structType = getType(pointeeType).definition; auto &structType = getType(pointeeType).definition;
...@@ -439,7 +439,7 @@ namespace sw ...@@ -439,7 +439,7 @@ namespace sw
} }
template<typename F> template<typename F>
int SpirvShader::VisitInterfaceInner(uint32_t id, Decorations d, F f) const int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
{ {
// Recursively walks variable definition and its type tree, taking into account // Recursively walks variable definition and its type tree, taking into account
// any explicit Location or Component decorations encountered; where explicit // any explicit Location or Component decorations encountered; where explicit
...@@ -510,7 +510,7 @@ namespace sw ...@@ -510,7 +510,7 @@ namespace sw
} }
template<typename F> template<typename F>
void SpirvShader::VisitInterface(uint32_t id, F f) const void SpirvShader::VisitInterface(ObjectID id, F f) const
{ {
// Walk a variable definition and call f for each component in it. // Walk a variable definition and call f for each component in it.
Decorations d{}; Decorations d{};
...@@ -521,7 +521,7 @@ namespace sw ...@@ -521,7 +521,7 @@ namespace sw
VisitInterfaceInner<F>(def.word(1), d, f); VisitInterfaceInner<F>(def.word(1), d, f);
} }
Int4 SpirvShader::WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const Int4 SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
{ {
// TODO: think about explicit layout (UBO/SSBO) storage classes // TODO: think about explicit layout (UBO/SSBO) storage classes
// TODO: avoid doing per-lane work in some cases if we can? // TODO: avoid doing per-lane work in some cases if we can?
...@@ -529,7 +529,7 @@ namespace sw ...@@ -529,7 +529,7 @@ namespace sw
int constantOffset = 0; int constantOffset = 0;
Int4 dynamicOffset = Int4(0); Int4 dynamicOffset = Int4(0);
auto & baseObject = getObject(id); auto & baseObject = getObject(id);
auto typeId = baseObject.definition.word(1); TypeID typeId = baseObject.definition.word(1);
// The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain. // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
// Start with its offset and build from there. // Start with its offset and build from there.
...@@ -646,14 +646,14 @@ namespace sw ...@@ -646,14 +646,14 @@ namespace sw
BufferBlock |= src.BufferBlock; BufferBlock |= src.BufferBlock;
} }
void SpirvShader::ApplyDecorationsForId(Decorations *d, uint32_t id) const void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
{ {
auto it = decorations.find(id); auto it = decorations.find(id);
if (it != decorations.end()) if (it != decorations.end())
d->Apply(it->second); d->Apply(it->second);
} }
void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, uint32_t id, uint32_t member) const void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
{ {
auto it = memberDecorations.find(id); auto it = memberDecorations.find(id);
if (it != memberDecorations.end() && member < it->second.size()) if (it != memberDecorations.end() && member < it->second.size())
...@@ -662,7 +662,7 @@ namespace sw ...@@ -662,7 +662,7 @@ namespace sw
} }
} }
uint32_t SpirvShader::GetConstantInt(uint32_t id) const uint32_t SpirvShader::GetConstantInt(ObjectID id) const
{ {
// Slightly hackish access to constants very early in translation. // Slightly hackish access to constants very early in translation.
// General consumption of constants by other instructions should // General consumption of constants by other instructions should
...@@ -686,7 +686,7 @@ namespace sw ...@@ -686,7 +686,7 @@ namespace sw
{ {
case spv::OpVariable: case spv::OpVariable:
{ {
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = getObject(resultId); auto &object = getObject(resultId);
// TODO: what to do about zero-slot objects? // TODO: what to do about zero-slot objects?
if (object.sizeInComponents > 0) if (object.sizeInComponents > 0)
...@@ -748,7 +748,7 @@ namespace sw ...@@ -748,7 +748,7 @@ namespace sw
case spv::OpVariable: case spv::OpVariable:
{ {
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = getObject(resultId); auto &object = getObject(resultId);
if (object.kind == Object::Kind::InterfaceVariable && object.storageClass == spv::StorageClassInput) if (object.kind == Object::Kind::InterfaceVariable && object.storageClass == spv::StorageClassInput)
{ {
...@@ -907,7 +907,7 @@ namespace sw ...@@ -907,7 +907,7 @@ namespace sw
{ {
case spv::OpVariable: case spv::OpVariable:
{ {
auto resultId = insn.word(2); ObjectID resultId = insn.word(2);
auto &object = getObject(resultId); auto &object = getObject(resultId);
if (object.kind == Object::Kind::InterfaceVariable && object.storageClass == spv::StorageClassOutput) if (object.kind == Object::Kind::InterfaceVariable && object.storageClass == spv::StorageClassOutput)
{ {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "System/Types.hpp" #include "System/Types.hpp"
#include "Vulkan/VkDebug.hpp" #include "Vulkan/VkDebug.hpp"
#include "ShaderCore.hpp" #include "ShaderCore.hpp"
#include "SpirvID.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -74,43 +75,7 @@ namespace sw ...@@ -74,43 +75,7 @@ namespace sw
uint32_t size; uint32_t size;
}; };
class SpirvRoutine class SpirvRoutine;
{
public:
using Value = Array<Float4>;
std::unordered_map<uint32_t, Value> lvalues;
std::unordered_map<uint32_t, Intermediate> intermediates;
Value inputs = Value{MAX_INTERFACE_COMPONENTS};
Value outputs = Value{MAX_INTERFACE_COMPONENTS};
void createLvalue(uint32_t id, uint32_t size)
{
lvalues.emplace(id, Value(size));
}
void createIntermediate(uint32_t id, uint32_t size)
{
intermediates.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(size));
}
Value& getValue(uint32_t id)
{
auto it = lvalues.find(id);
assert(it != lvalues.end());
return it->second;
}
Intermediate& getIntermediate(uint32_t id)
{
auto it = intermediates.find(id);
assert(it != intermediates.end());
return it->second;
}
};
class SpirvShader class SpirvShader
{ {
...@@ -218,6 +183,25 @@ namespace sw ...@@ -218,6 +183,25 @@ namespace sw
} kind = Kind::Unknown; } kind = Kind::Unknown;
}; };
using TypeID = SpirvID<Type>;
using ObjectID = SpirvID<Object>;
struct TypeOrObject {}; // Dummy struct to represent a Type or Object.
// TypeOrObjectID is an identifier that represents a Type or an Object,
// and supports implicit casting to and from TypeID or ObjectID.
class TypeOrObjectID : public SpirvID<TypeOrObject>
{
public:
using Hash = std::hash<SpirvID<TypeOrObject>>;
inline TypeOrObjectID(uint32_t id) : SpirvID(id) {}
inline TypeOrObjectID(TypeID id) : SpirvID(id.value()) {}
inline TypeOrObjectID(ObjectID id) : SpirvID(id.value()) {}
inline operator TypeID() const { return TypeID(value()); }
inline operator ObjectID() const { return ObjectID(value()); }
};
int getSerialID() const int getSerialID() const
{ {
return serialID; return serialID;
...@@ -288,8 +272,8 @@ namespace sw ...@@ -288,8 +272,8 @@ namespace sw
void Apply(spv::Decoration decoration, uint32_t arg); void Apply(spv::Decoration decoration, uint32_t arg);
}; };
std::unordered_map<uint32_t, Decorations> decorations; std::unordered_map<TypeOrObjectID, Decorations, TypeOrObjectID::Hash> decorations;
std::unordered_map<uint32_t, std::vector<Decorations>> memberDecorations; std::unordered_map<TypeID, std::vector<Decorations>> memberDecorations;
struct InterfaceComponent struct InterfaceComponent
{ {
...@@ -306,7 +290,7 @@ namespace sw ...@@ -306,7 +290,7 @@ namespace sw
struct BuiltinMapping struct BuiltinMapping
{ {
uint32_t Id; ObjectID Id;
uint32_t FirstComponent; uint32_t FirstComponent;
uint32_t SizeInComponents; uint32_t SizeInComponents;
}; };
...@@ -322,14 +306,14 @@ namespace sw ...@@ -322,14 +306,14 @@ namespace sw
std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins; std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> inputBuiltins;
std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins; std::unordered_map<spv::BuiltIn, BuiltinMapping, BuiltInHash> outputBuiltins;
Type const &getType(uint32_t id) const Type const &getType(TypeID id) const
{ {
auto it = types.find(id); auto it = types.find(id);
assert(it != types.end()); assert(it != types.end());
return it->second; return it->second;
} }
Object const &getObject(uint32_t id) const Object const &getObject(ObjectID id) const
{ {
auto it = defs.find(id); auto it = defs.find(id);
assert(it != defs.end()); assert(it != defs.end());
...@@ -340,28 +324,67 @@ namespace sw ...@@ -340,28 +324,67 @@ namespace sw
const int serialID; const int serialID;
static volatile int serialCounter; static volatile int serialCounter;
Modes modes; Modes modes;
std::unordered_map<uint32_t, Type> types; HandleMap<Type> types;
std::unordered_map<uint32_t, Object> defs; HandleMap<Object> defs;
void ProcessExecutionMode(InsnIterator it); void ProcessExecutionMode(InsnIterator it);
uint32_t ComputeTypeSize(InsnIterator insn); uint32_t ComputeTypeSize(InsnIterator insn);
void ApplyDecorationsForId(Decorations *d, uint32_t id) const; void ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const;
void ApplyDecorationsForIdMember(Decorations *d, uint32_t id, uint32_t member) const; void ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const;
template<typename F> template<typename F>
int VisitInterfaceInner(uint32_t id, Decorations d, F f) const; int VisitInterfaceInner(TypeID id, Decorations d, F f) const;
template<typename F> template<typename F>
void VisitInterface(uint32_t id, F f) const; void VisitInterface(ObjectID id, F f) const;
uint32_t GetConstantInt(uint32_t id) const; uint32_t GetConstantInt(ObjectID id) const;
Object& CreateConstant(InsnIterator it); Object& CreateConstant(InsnIterator it);
void ProcessInterfaceVariable(Object &object); void ProcessInterfaceVariable(Object &object);
Int4 WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const; Int4 WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
}; };
class SpirvRoutine
{
public:
using Value = Array<Float4>;
std::unordered_map<SpirvShader::ObjectID, Value> lvalues;
std::unordered_map<SpirvShader::ObjectID, Intermediate> intermediates;
Value inputs = Value{MAX_INTERFACE_COMPONENTS};
Value outputs = Value{MAX_INTERFACE_COMPONENTS};
void createLvalue(SpirvShader::ObjectID id, uint32_t size)
{
lvalues.emplace(id, Value(size));
}
void createIntermediate(SpirvShader::ObjectID id, uint32_t size)
{
intermediates.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(size));
}
Value& getValue(SpirvShader::ObjectID id)
{
auto it = lvalues.find(id);
assert(it != lvalues.end());
return it->second;
}
Intermediate& getIntermediate(SpirvShader::ObjectID id)
{
auto it = intermediates.find(id);
assert(it != intermediates.end());
return it->second;
}
};
} }
#endif // sw_SpirvShader_hpp #endif // sw_SpirvShader_hpp
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment