mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-27 05:40:06 +00:00
Optimization: Add type manager.
Type manager will construct a map of types gradually from instructions.
This commit is contained in:
parent
6d4d15b9d0
commit
c562e231e3
@ -11,6 +11,7 @@ add_library(SPIRV-Tools-opt
|
|||||||
passes.h
|
passes.h
|
||||||
pass_manager.h
|
pass_manager.h
|
||||||
types.h
|
types.h
|
||||||
|
type_manager.h
|
||||||
|
|
||||||
def_use_manager.cpp
|
def_use_manager.cpp
|
||||||
function.cpp
|
function.cpp
|
||||||
@ -20,6 +21,7 @@ add_library(SPIRV-Tools-opt
|
|||||||
module.cpp
|
module.cpp
|
||||||
passes.cpp
|
passes.cpp
|
||||||
types.cpp
|
types.cpp
|
||||||
|
type_manager.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
spvtools_default_compile_options(SPIRV-Tools-opt)
|
spvtools_default_compile_options(SPIRV-Tools-opt)
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
namespace spvtools {
|
namespace spvtools {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
std::vector<Instruction*> Module::types() {
|
std::vector<Instruction*> Module::GetTypes() {
|
||||||
std::vector<Instruction*> insts;
|
std::vector<Instruction*> insts;
|
||||||
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
||||||
if (IsTypeInst(types_values_[i]->opcode()))
|
if (IsTypeInst(types_values_[i]->opcode()))
|
||||||
@ -39,6 +39,15 @@ std::vector<Instruction*> Module::types() {
|
|||||||
return insts;
|
return insts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<const Instruction*> Module::GetTypes() const {
|
||||||
|
std::vector<const Instruction*> insts;
|
||||||
|
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
||||||
|
if (IsTypeInst(types_values_[i]->opcode()))
|
||||||
|
insts.push_back(types_values_[i].get());
|
||||||
|
}
|
||||||
|
return insts;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<Instruction*> Module::GetConstants() {
|
std::vector<Instruction*> Module::GetConstants() {
|
||||||
std::vector<Instruction*> insts;
|
std::vector<Instruction*> insts;
|
||||||
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
for (uint32_t i = 0; i < types_values_.size(); ++i) {
|
||||||
|
@ -83,7 +83,8 @@ class Module {
|
|||||||
|
|
||||||
// Returns a vector of pointers to type-declaration instructions in this
|
// Returns a vector of pointers to type-declaration instructions in this
|
||||||
// module.
|
// module.
|
||||||
std::vector<Instruction*> types();
|
std::vector<Instruction*> GetTypes();
|
||||||
|
std::vector<const Instruction*> GetTypes() const;
|
||||||
// Returns the constant-defining instructions.
|
// Returns the constant-defining instructions.
|
||||||
std::vector<Instruction*> GetConstants();
|
std::vector<Instruction*> GetConstants();
|
||||||
const std::vector<std::unique_ptr<Instruction>>& debugs() const {
|
const std::vector<std::unique_ptr<Instruction>>& debugs() const {
|
||||||
|
226
source/opt/type_manager.cpp
Normal file
226
source/opt/type_manager.cpp
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
// 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 <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "reflect.h"
|
||||||
|
#include "type_manager.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace opt {
|
||||||
|
namespace analysis {
|
||||||
|
|
||||||
|
Type* TypeManager::GetType(uint32_t id) const {
|
||||||
|
if (id_to_type_.count(id) != 0) return id_to_type_.at(id).get();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ForwardPointer* TypeManager::GetForwardPointer(uint32_t index) const {
|
||||||
|
if (index >= forward_pointers_.size()) return nullptr;
|
||||||
|
return forward_pointers_.at(index).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeManager::AnalyzeType(const spvtools::ir::Module& module) {
|
||||||
|
for (const auto* inst : module.GetTypes()) RecordIfTypeDefinition(*inst);
|
||||||
|
for (const auto& inst : module.annotations()) AttachIfTypeDecoration(*inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
Type* TypeManager::RecordIfTypeDefinition(const spvtools::ir::Instruction& inst) {
|
||||||
|
if (!spvtools::ir::IsTypeInst(inst.opcode())) return nullptr;
|
||||||
|
|
||||||
|
Type* type = nullptr;
|
||||||
|
switch (inst.opcode()) {
|
||||||
|
case SpvOpTypeVoid:
|
||||||
|
type = new Void();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeBool:
|
||||||
|
type = new Bool();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeInt:
|
||||||
|
type = new Integer(inst.GetSingleWordInOperand(0),
|
||||||
|
inst.GetSingleWordInOperand(1));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeFloat:
|
||||||
|
type = new Float(inst.GetSingleWordInOperand(0));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeVector:
|
||||||
|
type = new Vector(GetType(inst.GetSingleWordInOperand(0)),
|
||||||
|
inst.GetSingleWordInOperand(1));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeMatrix:
|
||||||
|
type = new Matrix(GetType(inst.GetSingleWordInOperand(0)),
|
||||||
|
inst.GetSingleWordInOperand(1));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeImage: {
|
||||||
|
const SpvAccessQualifier access =
|
||||||
|
inst.NumInOperands() < 8
|
||||||
|
? SpvAccessQualifierReadOnly
|
||||||
|
: static_cast<SpvAccessQualifier>(inst.GetSingleWordInOperand(7));
|
||||||
|
type = new Image(
|
||||||
|
GetType(inst.GetSingleWordInOperand(0)),
|
||||||
|
static_cast<SpvDim>(inst.GetSingleWordInOperand(1)),
|
||||||
|
inst.GetSingleWordInOperand(2), inst.GetSingleWordInOperand(3),
|
||||||
|
inst.GetSingleWordInOperand(4), inst.GetSingleWordInOperand(5),
|
||||||
|
static_cast<SpvImageFormat>(inst.GetSingleWordInOperand(6)), access);
|
||||||
|
} break;
|
||||||
|
case SpvOpTypeSampler:
|
||||||
|
type = new Sampler();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeSampledImage:
|
||||||
|
type = new SampledImage(GetType(inst.GetSingleWordInOperand(0)));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeArray:
|
||||||
|
type = new Array(GetType(inst.GetSingleWordInOperand(0)),
|
||||||
|
inst.GetSingleWordInOperand(1));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeRuntimeArray:
|
||||||
|
type = new RuntimeArray(GetType(inst.GetSingleWordInOperand(0)));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeStruct: {
|
||||||
|
std::vector<Type*> element_types;
|
||||||
|
for (uint32_t i = 0; i < inst.NumInOperands(); ++i) {
|
||||||
|
element_types.push_back(GetType(inst.GetSingleWordInOperand(i)));
|
||||||
|
}
|
||||||
|
type = new Struct(element_types);
|
||||||
|
} break;
|
||||||
|
case SpvOpTypeOpaque: {
|
||||||
|
const uint32_t* data = inst.GetInOperand(0).words.data();
|
||||||
|
type = new Opaque(reinterpret_cast<const char*>(data));
|
||||||
|
} break;
|
||||||
|
case SpvOpTypePointer: {
|
||||||
|
auto* ptr = new Pointer(
|
||||||
|
GetType(inst.GetSingleWordInOperand(1)),
|
||||||
|
static_cast<SpvStorageClass>(inst.GetSingleWordInOperand(0)));
|
||||||
|
// Let's see if somebody forward references this pointer.
|
||||||
|
for (auto* fp : unresolved_forward_pointers_) {
|
||||||
|
if (fp->target_id() == inst.result_id()) {
|
||||||
|
fp->SetTargetPointer(ptr);
|
||||||
|
unresolved_forward_pointers_.erase(fp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type = ptr;
|
||||||
|
} break;
|
||||||
|
case SpvOpTypeFunction: {
|
||||||
|
Type* return_type = GetType(inst.GetSingleWordInOperand(0));
|
||||||
|
std::vector<Type*> param_types;
|
||||||
|
for (uint32_t i = 1; i < inst.NumInOperands(); ++i) {
|
||||||
|
param_types.push_back(GetType(inst.GetSingleWordInOperand(i)));
|
||||||
|
}
|
||||||
|
type = new Function(return_type, param_types);
|
||||||
|
} break;
|
||||||
|
case SpvOpTypeEvent:
|
||||||
|
type = new Event();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeDeviceEvent:
|
||||||
|
type = new DeviceEvent();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeReserveId:
|
||||||
|
type = new ReserveId();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeQueue:
|
||||||
|
type = new Queue();
|
||||||
|
break;
|
||||||
|
case SpvOpTypePipe:
|
||||||
|
type = new Pipe(
|
||||||
|
static_cast<SpvAccessQualifier>(inst.GetSingleWordInOperand(0)));
|
||||||
|
break;
|
||||||
|
case SpvOpTypeForwardPointer: {
|
||||||
|
// Handling of forward pointers is different from the other types.
|
||||||
|
auto* fp = new ForwardPointer(
|
||||||
|
inst.GetSingleWordInOperand(0),
|
||||||
|
static_cast<SpvStorageClass>(inst.GetSingleWordInOperand(1)));
|
||||||
|
forward_pointers_.emplace_back(fp);
|
||||||
|
unresolved_forward_pointers_.insert(fp);
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
case SpvOpTypePipeStorage:
|
||||||
|
type = new PipeStorage();
|
||||||
|
break;
|
||||||
|
case SpvOpTypeNamedBarrier:
|
||||||
|
type = new NamedBarrier();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "unhandled type found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t id = inst.result_id();
|
||||||
|
if (id == 0) {
|
||||||
|
assert(inst.opcode() == SpvOpTypeForwardPointer &&
|
||||||
|
"instruction without result id found");
|
||||||
|
} else {
|
||||||
|
assert(type != nullptr && "type should not be nullptr at this point");
|
||||||
|
id_to_type_[id].reset(type);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TypeManager::AttachIfTypeDecoration(const ir::Instruction& inst) {
|
||||||
|
const SpvOp opcode = inst.opcode();
|
||||||
|
if (!ir::IsAnnotationInst(opcode)) return;
|
||||||
|
const uint32_t id = inst.GetSingleWordOperand(0);
|
||||||
|
// Do nothing if the id to be decorated is not for a known type.
|
||||||
|
if (!id_to_type_.count(id)) return;
|
||||||
|
|
||||||
|
Type* target_type = id_to_type_[id].get();
|
||||||
|
switch (opcode) {
|
||||||
|
case SpvOpDecorate: {
|
||||||
|
const auto count = inst.NumOperands();
|
||||||
|
std::vector<uint32_t> data;
|
||||||
|
for (uint32_t i = 1; i < count; ++i) {
|
||||||
|
data.push_back(inst.GetSingleWordOperand(i));
|
||||||
|
}
|
||||||
|
target_type->AddDecoration(std::move(data));
|
||||||
|
} break;
|
||||||
|
case SpvOpMemberDecorate: {
|
||||||
|
const auto count = inst.NumOperands();
|
||||||
|
const uint32_t index = inst.GetSingleWordOperand(1);
|
||||||
|
std::vector<uint32_t> data;
|
||||||
|
for (uint32_t i = 2; i < count; ++i) {
|
||||||
|
data.push_back(inst.GetSingleWordOperand(i));
|
||||||
|
}
|
||||||
|
if (Struct* st = target_type->AsStruct()) {
|
||||||
|
st->AddMemeberDecoration(index, std::move(data));
|
||||||
|
} else {
|
||||||
|
assert(0 && "OpMemberDecorate on non-struct type");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case SpvOpDecorationGroup:
|
||||||
|
case SpvOpGroupDecorate:
|
||||||
|
case SpvOpGroupMemberDecorate:
|
||||||
|
assert(0 && "unhandled decoration");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0 && "unreachable");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace analysis
|
||||||
|
} // namespace opt
|
||||||
|
} // namespace spvtools
|
86
source/opt/type_manager.h
Normal file
86
source/opt/type_manager.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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_OPT_TYPE_MANAGER_H_
|
||||||
|
#define LIBSPIRV_OPT_TYPE_MANAGER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "module.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
namespace spvtools {
|
||||||
|
namespace opt {
|
||||||
|
namespace analysis {
|
||||||
|
|
||||||
|
// A class for managing the SPIR-V type hierarchy.
|
||||||
|
class TypeManager {
|
||||||
|
public:
|
||||||
|
using IdToTypeMap = std::unordered_map<uint32_t, std::unique_ptr<Type>>;
|
||||||
|
using ForwardPointerVector = std::vector<std::unique_ptr<ForwardPointer>>;
|
||||||
|
|
||||||
|
TypeManager() = default;
|
||||||
|
TypeManager(const TypeManager&) = delete;
|
||||||
|
TypeManager(TypeManager&&) = delete;
|
||||||
|
TypeManager& operator=(const TypeManager&) = delete;
|
||||||
|
TypeManager& operator=(TypeManager&&) = delete;
|
||||||
|
|
||||||
|
// Returns the type for the given type |id|. Returns nullptr if the given |id|
|
||||||
|
// does not define a type.
|
||||||
|
Type* GetType(uint32_t id) const;
|
||||||
|
// Returns the number of types hold in this manager.
|
||||||
|
size_t NumTypes() const { return id_to_type_.size(); }
|
||||||
|
|
||||||
|
// Returns the forward pointer type at the given |index|.
|
||||||
|
ForwardPointer* GetForwardPointer(uint32_t index) const;
|
||||||
|
// Returns the number of forward pointer types hold in this manager.
|
||||||
|
size_t NumForwardPointers() const { return forward_pointers_.size(); }
|
||||||
|
|
||||||
|
// Analyzes the types and decorations on types in the given |module|.
|
||||||
|
void AnalyzeType(const spvtools::ir::Module& module);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Creates and returns a type from the given SPIR-V |inst|. Returns nullptr if
|
||||||
|
// the given instruction is not for defining a type.
|
||||||
|
Type* RecordIfTypeDefinition(const spvtools::ir::Instruction& inst);
|
||||||
|
// Attaches the decoration encoded in |inst| to a type. Does nothing if the
|
||||||
|
// given instruction is not a decoration instruction or not decorating a type.
|
||||||
|
void AttachIfTypeDecoration(const spvtools::ir::Instruction& inst);
|
||||||
|
|
||||||
|
IdToTypeMap id_to_type_; // Mapping from ids to their type representations.
|
||||||
|
ForwardPointerVector forward_pointers_; // All forward pointer declarations.
|
||||||
|
// All unresolved forward pointer declarations.
|
||||||
|
// Refers the contents in the above vector.
|
||||||
|
std::unordered_set<ForwardPointer*> unresolved_forward_pointers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace analysis
|
||||||
|
} // namespace opt
|
||||||
|
} // namespace spvtools
|
||||||
|
|
||||||
|
#endif // LIBSPIRV_OPT_TYPE_MANAGER_H_
|
@ -68,3 +68,8 @@ add_spvtools_unittest(TARGET types
|
|||||||
SRCS test_types.cpp
|
SRCS test_types.cpp
|
||||||
LIBS SPIRV-Tools-opt
|
LIBS SPIRV-Tools-opt
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_spvtools_unittest(TARGET type_manager
|
||||||
|
SRCS test_type_manager.cpp
|
||||||
|
LIBS SPIRV-Tools-opt ${SPIRV_TOOLS}
|
||||||
|
)
|
||||||
|
212
test/opt/test_type_manager.cpp
Normal file
212
test/opt/test_type_manager.cpp
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// 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 <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "opt/instruction.h"
|
||||||
|
#include "opt/libspirv.hpp"
|
||||||
|
#include "opt/type_manager.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace spvtools;
|
||||||
|
|
||||||
|
TEST(TypeManager, TypeStrings) {
|
||||||
|
const std::string text = R"(
|
||||||
|
OpTypeForwardPointer !20 !2 ; id for %p is 20, Uniform is 2
|
||||||
|
OpTypeForwardPointer !10000 !1
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%bool = OpTypeBool
|
||||||
|
%u32 = OpTypeInt 32 0
|
||||||
|
%id4 = OpConstant %u32 4
|
||||||
|
%s32 = OpTypeInt 32 1
|
||||||
|
%f64 = OpTypeFloat 64
|
||||||
|
%v3u32 = OpTypeVector %u32 3
|
||||||
|
%m3x3 = OpTypeMatrix %v3u32 3
|
||||||
|
%img1 = OpTypeImage %s32 Cube 0 1 1 0 R32f ReadWrite
|
||||||
|
%img2 = OpTypeImage %s32 Cube 0 1 1 0 R32f
|
||||||
|
%sampler = OpTypeSampler
|
||||||
|
%si1 = OpTypeSampledImage %img1
|
||||||
|
%si2 = OpTypeSampledImage %img2
|
||||||
|
%a5u32 = OpTypeArray %u32 %id4
|
||||||
|
%af64 = OpTypeRuntimeArray %f64
|
||||||
|
%st1 = OpTypeStruct %u32
|
||||||
|
%st2 = OpTypeStruct %f64 %s32 %v3u32
|
||||||
|
%opaque1 = OpTypeOpaque ""
|
||||||
|
%opaque2 = OpTypeOpaque "opaque"
|
||||||
|
%p = OpTypePointer Uniform %st1
|
||||||
|
%f = OpTypeFunction %void %u32 %u32
|
||||||
|
%event = OpTypeEvent
|
||||||
|
%de = OpTypeDeviceEvent
|
||||||
|
%ri = OpTypeReserveId
|
||||||
|
%queue = OpTypeQueue
|
||||||
|
%pipe = OpTypePipe ReadOnly
|
||||||
|
%ps = OpTypePipeStorage
|
||||||
|
%nb = OpTypeNamedBarrier
|
||||||
|
)";
|
||||||
|
|
||||||
|
std::vector<std::pair<uint32_t, std::string>> type_id_strs = {
|
||||||
|
{1, "void"},
|
||||||
|
{2, "bool"},
|
||||||
|
{3, "uint32"},
|
||||||
|
// Id 4 is used by the constant.
|
||||||
|
{5, "sint32"},
|
||||||
|
{6, "float64"},
|
||||||
|
{7, "<uint32, 3>"},
|
||||||
|
{8, "<<uint32, 3>, 3>"},
|
||||||
|
{9, "image(sint32, 3, 0, 1, 1, 0, 3, 2)"},
|
||||||
|
{10, "image(sint32, 3, 0, 1, 1, 0, 3, 0)"},
|
||||||
|
{11, "sampler"},
|
||||||
|
{12, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 2))"},
|
||||||
|
{13, "sampled_image(image(sint32, 3, 0, 1, 1, 0, 3, 0))"},
|
||||||
|
{14, "[uint32, id(4)]"},
|
||||||
|
{15, "[float64]"},
|
||||||
|
{16, "{uint32}"},
|
||||||
|
{17, "{float64, sint32, <uint32, 3>}"},
|
||||||
|
{18, "opaque('')"},
|
||||||
|
{19, "opaque('opaque')"},
|
||||||
|
{20, "{uint32}*"},
|
||||||
|
{21, "(uint32, uint32) -> void"},
|
||||||
|
{22, "event"},
|
||||||
|
{23, "device_event"},
|
||||||
|
{24, "reserve_id"},
|
||||||
|
{25, "queue"},
|
||||||
|
{26, "pipe(0)"},
|
||||||
|
{27, "pipe_storage"},
|
||||||
|
{28, "named_barrier"},
|
||||||
|
};
|
||||||
|
|
||||||
|
opt::analysis::TypeManager manager;
|
||||||
|
std::unique_ptr<ir::Module> module =
|
||||||
|
SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text);
|
||||||
|
manager.AnalyzeType(*module);
|
||||||
|
|
||||||
|
EXPECT_EQ(type_id_strs.size(), manager.NumTypes());
|
||||||
|
EXPECT_EQ(2u, manager.NumForwardPointers());
|
||||||
|
|
||||||
|
for (const auto& p : type_id_strs) {
|
||||||
|
EXPECT_EQ(p.second, manager.GetType(p.first)->str());
|
||||||
|
}
|
||||||
|
EXPECT_EQ("forward_pointer({uint32}*)", manager.GetForwardPointer(0)->str());
|
||||||
|
EXPECT_EQ("forward_pointer(10000)", manager.GetForwardPointer(1)->str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Struct, DecorationOnStruct) {
|
||||||
|
const std::string text = R"(
|
||||||
|
OpDecorate %struct1 Block
|
||||||
|
OpDecorate %struct2 Block
|
||||||
|
OpDecorate %struct3 Block
|
||||||
|
OpDecorate %struct4 Block
|
||||||
|
|
||||||
|
%u32 = OpTypeInt 32 0 ; id: 5
|
||||||
|
%f32 = OpTypeFloat 32 ; id: 6
|
||||||
|
%struct1 = OpTypeStruct %u32 %f32 ; base
|
||||||
|
%struct2 = OpTypeStruct %f32 %u32 ; different member order
|
||||||
|
%struct3 = OpTypeStruct %f32 ; different member list
|
||||||
|
%struct4 = OpTypeStruct %u32 %f32 ; the same
|
||||||
|
%struct7 = OpTypeStruct %f32 ; no decoration
|
||||||
|
)";
|
||||||
|
opt::analysis::TypeManager manager;
|
||||||
|
std::unique_ptr<ir::Module> module =
|
||||||
|
SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text);
|
||||||
|
manager.AnalyzeType(*module);
|
||||||
|
|
||||||
|
ASSERT_EQ(7u, manager.NumTypes());
|
||||||
|
ASSERT_EQ(0u, manager.NumForwardPointers());
|
||||||
|
// Make sure we get ids correct.
|
||||||
|
ASSERT_EQ("uint32", manager.GetType(5)->str());
|
||||||
|
ASSERT_EQ("float32", manager.GetType(6)->str());
|
||||||
|
|
||||||
|
// Try all combinations of pairs. Expect to be the same type only when the
|
||||||
|
// same id or (1, 4).
|
||||||
|
for (const auto id1 : {1, 2, 3, 4, 7}) {
|
||||||
|
for (const auto id2 : {1, 2, 3, 4, 7}) {
|
||||||
|
if (id1 == id2 || (id1 == 1 && id2 == 4) || (id1 == 4 && id2 == 1)) {
|
||||||
|
EXPECT_TRUE(manager.GetType(id1)->IsSame(manager.GetType(id2)))
|
||||||
|
<< "%struct" << id1 << " is expected to be the same as %struct"
|
||||||
|
<< id2;
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(manager.GetType(id1)->IsSame(manager.GetType(id2)))
|
||||||
|
<< "%struct" << id1 << " is expected to be different with %struct"
|
||||||
|
<< id2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Struct, DecorationOnMember) {
|
||||||
|
const std::string text = R"(
|
||||||
|
OpMemberDecorate %struct1 0 Offset 0
|
||||||
|
OpMemberDecorate %struct2 0 Offset 0
|
||||||
|
OpMemberDecorate %struct3 0 Offset 0
|
||||||
|
OpMemberDecorate %struct4 0 Offset 0
|
||||||
|
OpMemberDecorate %struct5 1 Offset 0
|
||||||
|
OpMemberDecorate %struct6 0 Offset 4
|
||||||
|
|
||||||
|
OpDecorate %struct7 Block
|
||||||
|
OpMemberDecorate %struct7 0 Offset 0
|
||||||
|
|
||||||
|
%u32 = OpTypeInt 32 0 ; id: 8
|
||||||
|
%f32 = OpTypeFloat 32 ; id: 9
|
||||||
|
%struct1 = OpTypeStruct %u32 %f32 ; base
|
||||||
|
%struct2 = OpTypeStruct %f32 %u32 ; different member order
|
||||||
|
%struct3 = OpTypeStruct %f32 ; different member list
|
||||||
|
%struct4 = OpTypeStruct %u32 %f32 ; the same
|
||||||
|
%struct5 = OpTypeStruct %u32 %f32 ; member decorate different field
|
||||||
|
%struct6 = OpTypeStruct %u32 %f32 ; different member decoration parameter
|
||||||
|
%struct7 = OpTypeStruct %u32 %f32 ; extra decoration on the struct
|
||||||
|
%struct10 = OpTypeStruct %u32 %f32 ; no member decoration
|
||||||
|
)";
|
||||||
|
opt::analysis::TypeManager manager;
|
||||||
|
std::unique_ptr<ir::Module> module =
|
||||||
|
SpvTools(SPV_ENV_UNIVERSAL_1_1).BuildModule(text);
|
||||||
|
manager.AnalyzeType(*module);
|
||||||
|
|
||||||
|
ASSERT_EQ(10u, manager.NumTypes());
|
||||||
|
ASSERT_EQ(0u, manager.NumForwardPointers());
|
||||||
|
// Make sure we get ids correct.
|
||||||
|
ASSERT_EQ("uint32", manager.GetType(8)->str());
|
||||||
|
ASSERT_EQ("float32", manager.GetType(9)->str());
|
||||||
|
|
||||||
|
// Try all combinations of pairs. Expect to be the same type only when the
|
||||||
|
// same id or (1, 4).
|
||||||
|
for (const auto id1 : {1, 2, 3, 4, 5, 6, 7, 10}) {
|
||||||
|
for (const auto id2 : {1, 2, 3, 4, 5, 6, 7, 10}) {
|
||||||
|
if (id1 == id2 || (id1 == 1 && id2 == 4) || (id1 == 4 && id2 == 1)) {
|
||||||
|
EXPECT_TRUE(manager.GetType(id1)->IsSame(manager.GetType(id2)))
|
||||||
|
<< "%struct" << id1 << " is expected to be the same as %struct"
|
||||||
|
<< id2;
|
||||||
|
} else {
|
||||||
|
EXPECT_FALSE(manager.GetType(id1)->IsSame(manager.GetType(id2)))
|
||||||
|
<< "%struct" << id1 << " is expected to be different with %struct"
|
||||||
|
<< id2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
Loading…
Reference in New Issue
Block a user