reader/spirv - add type hierarchy
Don't create disjoint AST type nodes. Instead use a new bespoke type hierarchy that can Build() the required AST nodes. Change-Id: I523f97054de2c553095056c0bafc17c48064cf53 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49966 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
c705b6caac
commit
cbbe576415
|
@ -590,6 +590,8 @@ libtint_source_set("libtint_spv_reader_src") {
|
|||
"reader/spirv/function.h",
|
||||
"reader/spirv/namer.cc",
|
||||
"reader/spirv/namer.h",
|
||||
"reader/spirv/parser_type.cc",
|
||||
"reader/spirv/parser_type.h",
|
||||
"reader/spirv/parser.cc",
|
||||
"reader/spirv/parser.h",
|
||||
"reader/spirv/parser_impl.cc",
|
||||
|
|
|
@ -360,6 +360,8 @@ if(${TINT_BUILD_SPV_READER})
|
|||
reader/spirv/function.h
|
||||
reader/spirv/namer.cc
|
||||
reader/spirv/namer.h
|
||||
reader/spirv/parser_type.cc
|
||||
reader/spirv/parser_type.h
|
||||
reader/spirv/parser.cc
|
||||
reader/spirv/parser.h
|
||||
reader/spirv/parser_impl.cc
|
||||
|
@ -627,6 +629,7 @@ if(${TINT_BUILD_TESTS})
|
|||
reader/spirv/parser_impl_test_helper.h
|
||||
reader/spirv/parser_impl_test.cc
|
||||
reader/spirv/parser_impl_user_name_test.cc
|
||||
reader/spirv/parser_type_test.cc
|
||||
reader/spirv/parser_test.cc
|
||||
reader/spirv/spirv_tools_helpers_test.cc
|
||||
reader/spirv/spirv_tools_helpers_test.h
|
||||
|
|
|
@ -617,26 +617,32 @@ class ProgramBuilder {
|
|||
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param stride the array stride
|
||||
/// @param stride the array stride. 0 represents implicit stride
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
ast::Array* array(typ::Type subtype, uint32_t n, uint32_t stride) const {
|
||||
subtype = MaybeCreateTypename(subtype);
|
||||
return array(subtype, n,
|
||||
{builder->create<ast::StrideDecoration>(stride)});
|
||||
ast::DecorationList decos;
|
||||
if (stride) {
|
||||
decos.emplace_back(builder->create<ast::StrideDecoration>(stride));
|
||||
}
|
||||
return array(subtype, n, std::move(decos));
|
||||
}
|
||||
|
||||
/// @param source the Source of the node
|
||||
/// @param subtype the array element type
|
||||
/// @param n the array size. 0 represents a runtime-array
|
||||
/// @param stride the array stride
|
||||
/// @param stride the array stride. 0 represents implicit stride
|
||||
/// @return the tint AST type for a array of size `n` of type `T`
|
||||
ast::Array* array(const Source& source,
|
||||
typ::Type subtype,
|
||||
uint32_t n,
|
||||
uint32_t stride) const {
|
||||
subtype = MaybeCreateTypename(subtype);
|
||||
return array(source, subtype, n,
|
||||
{builder->create<ast::StrideDecoration>(stride)});
|
||||
ast::DecorationList decos;
|
||||
if (stride) {
|
||||
decos.emplace_back(builder->create<ast::StrideDecoration>(stride));
|
||||
}
|
||||
return array(source, subtype, n, std::move(decos));
|
||||
}
|
||||
|
||||
/// @return the tint AST type for an array of size `N` of type `T`
|
||||
|
|
|
@ -713,6 +713,7 @@ FunctionEmitter::FunctionEmitter(ParserImpl* pi,
|
|||
const spvtools::opt::Function& function,
|
||||
const EntryPointInfo* ep_info)
|
||||
: parser_impl_(*pi),
|
||||
ty_(pi->type_manager()),
|
||||
builder_(pi->builder()),
|
||||
ir_context_(*(pi->ir_context())),
|
||||
def_use_mgr_(ir_context_.get_def_use_mgr()),
|
||||
|
@ -733,6 +734,7 @@ FunctionEmitter::FunctionEmitter(ParserImpl* pi,
|
|||
|
||||
FunctionEmitter::FunctionEmitter(FunctionEmitter&& other)
|
||||
: parser_impl_(other.parser_impl_),
|
||||
ty_(other.ty_),
|
||||
builder_(other.builder_),
|
||||
ir_context_(other.ir_context_),
|
||||
def_use_mgr_(ir_context_.get_def_use_mgr()),
|
||||
|
@ -875,7 +877,7 @@ bool FunctionEmitter::Emit() {
|
|||
auto* body = create<ast::BlockStatement>(Source{}, statements);
|
||||
builder_.AST().AddFunction(create<ast::Function>(
|
||||
decl.source, builder_.Symbols().Register(decl.name),
|
||||
std::move(decl.params), decl.return_type, body,
|
||||
std::move(decl.params), decl.return_type->Build(builder_), body,
|
||||
std::move(decl.decorations), ast::DecorationList{}));
|
||||
|
||||
// Maintain the invariant by repopulating the one and only element.
|
||||
|
@ -943,7 +945,7 @@ bool FunctionEmitter::ParseFunctionDeclaration(FunctionDeclaration* decl) {
|
|||
return success();
|
||||
}
|
||||
|
||||
ast::Type* FunctionEmitter::GetVariableStoreType(
|
||||
const Type* FunctionEmitter::GetVariableStoreType(
|
||||
const spvtools::opt::Instruction& var_decl_inst) {
|
||||
const auto type_id = var_decl_inst.type_id();
|
||||
auto* var_ref_type = type_mgr_->GetType(type_id);
|
||||
|
@ -2042,7 +2044,7 @@ TypedExpression FunctionEmitter::MakeExpression(uint32_t id) {
|
|||
<< id;
|
||||
return {};
|
||||
case SkipReason::kPointSizeBuiltinValue: {
|
||||
return {create<ast::F32>(),
|
||||
return {ty_.F32(),
|
||||
create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::FloatLiteral>(Source{}, 1.0f))};
|
||||
}
|
||||
|
@ -2072,7 +2074,7 @@ TypedExpression FunctionEmitter::MakeExpression(uint32_t id) {
|
|||
case SkipReason::kSampleMaskOutBuiltinPointer:
|
||||
// The result type is always u32.
|
||||
auto name = namer_.Name(sample_mask_out_id);
|
||||
return TypedExpression{builder_.ty.u32(),
|
||||
return TypedExpression{ty_.U32(),
|
||||
create<ast::IdentifierExpression>(
|
||||
Source{}, builder_.Symbols().Register(name))};
|
||||
}
|
||||
|
@ -2348,14 +2350,10 @@ bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) {
|
|||
const std::string guard_name = block_info.flow_guard_name;
|
||||
if (!guard_name.empty()) {
|
||||
// Declare the guard variable just before the "if", initialized to true.
|
||||
auto* guard_var = create<ast::Variable>(
|
||||
Source{}, // source
|
||||
builder_.Symbols().Register(guard_name), // symbol
|
||||
ast::StorageClass::kFunction, // storage_class
|
||||
builder_.ty.bool_(), // type
|
||||
false, // is_const
|
||||
MakeTrue(Source{}), // constructor
|
||||
ast::DecorationList{}); // decorations
|
||||
auto* guard_var =
|
||||
create<ast::Variable>(Source{}, builder_.Symbols().Register(guard_name),
|
||||
ast::StorageClass::kFunction, builder_.ty.bool_(),
|
||||
false, MakeTrue(Source{}), ast::DecorationList{});
|
||||
auto* guard_decl = create<ast::VariableDeclStatement>(Source{}, guard_var);
|
||||
AddStatement(guard_decl);
|
||||
}
|
||||
|
@ -2557,7 +2555,7 @@ bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
|
|||
// The rest of this module can handle up to 64 bit switch values.
|
||||
// The Tint AST handles 32-bit values.
|
||||
const uint32_t value32 = uint32_t(value & 0xFFFFFFFF);
|
||||
if (selector.type->is_unsigned_scalar_or_vector()) {
|
||||
if (selector.type->IsUnsignedScalarOrVector()) {
|
||||
selectors.emplace_back(create<ast::UintLiteral>(Source{}, value32));
|
||||
} else {
|
||||
selectors.emplace_back(create<ast::SintLiteral>(Source{}, value32));
|
||||
|
@ -2914,13 +2912,10 @@ bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
|
|||
const auto phi_var_name = GetDefInfo(id)->phi_var;
|
||||
TINT_ASSERT(!phi_var_name.empty());
|
||||
auto* var = create<ast::Variable>(
|
||||
Source{}, // source
|
||||
builder_.Symbols().Register(phi_var_name), // symbol
|
||||
ast::StorageClass::kFunction, // storage_class
|
||||
parser_impl_.ConvertType(def_inst->type_id()), // type
|
||||
false, // is_const
|
||||
nullptr, // constructor
|
||||
ast::DecorationList{}); // decorations
|
||||
Source{}, builder_.Symbols().Register(phi_var_name),
|
||||
ast::StorageClass::kFunction,
|
||||
parser_impl_.ConvertType(def_inst->type_id())->Build(builder_), false,
|
||||
nullptr, ast::DecorationList{});
|
||||
AddStatement(create<ast::VariableDeclStatement>(Source{}, var));
|
||||
}
|
||||
|
||||
|
@ -3102,9 +3097,9 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
|
||||
case SkipReason::kSampleMaskOutBuiltinPointer:
|
||||
ptr_id = sample_mask_out_id;
|
||||
if (!rhs.type->Is<ast::U32>()) {
|
||||
if (!rhs.type->Is<U32>()) {
|
||||
// WGSL requires sample_mask_out to be signed.
|
||||
rhs = TypedExpression{builder_.ty.u32(),
|
||||
rhs = TypedExpression{ty_.U32(),
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.u32(),
|
||||
ast::ExpressionList{rhs.expr})};
|
||||
|
@ -3148,7 +3143,7 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
ast::Expression* id_expr = create<ast::IdentifierExpression>(
|
||||
Source{}, builder_.Symbols().Register(name));
|
||||
auto expr = TypedExpression{
|
||||
builder_.ty.i32(),
|
||||
ty_.I32(),
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.i32(), ast::ExpressionList{id_expr})};
|
||||
return EmitConstDefinition(inst, expr);
|
||||
|
@ -3159,10 +3154,10 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
Source{}, builder_.Symbols().Register(name));
|
||||
auto* load_result_type = parser_impl_.ConvertType(inst.type_id());
|
||||
ast::Expression* ast_expr = nullptr;
|
||||
if (load_result_type->Is<ast::I32>()) {
|
||||
if (load_result_type->Is<I32>()) {
|
||||
ast_expr = create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.i32(), ast::ExpressionList{id_expr});
|
||||
} else if (load_result_type->Is<ast::U32>()) {
|
||||
} else if (load_result_type->Is<U32>()) {
|
||||
ast_expr = id_expr;
|
||||
} else {
|
||||
return Fail() << "loading the whole SampleMask input array is not "
|
||||
|
@ -3181,8 +3176,8 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
|
||||
// The load result type is the pointee type of its operand.
|
||||
TINT_ASSERT(expr.type->Is<ast::Pointer>());
|
||||
expr.type = expr.type->As<ast::Pointer>()->type();
|
||||
TINT_ASSERT(expr.type->Is<Pointer>());
|
||||
expr.type = expr.type->As<Pointer>()->type;
|
||||
return EmitConstDefOrWriteToHoistedVar(inst, expr);
|
||||
}
|
||||
|
||||
|
@ -3284,7 +3279,7 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||
|
||||
const auto opcode = inst.opcode();
|
||||
|
||||
ast::Type* ast_type =
|
||||
const Type* ast_type =
|
||||
inst.type_id() != 0 ? parser_impl_.ConvertType(inst.type_id()) : nullptr;
|
||||
|
||||
auto binary_op = ConvertBinaryOp(opcode);
|
||||
|
@ -3329,8 +3324,9 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||
}
|
||||
|
||||
if (opcode == SpvOpBitcast) {
|
||||
return {ast_type, create<ast::BitcastExpression>(
|
||||
Source{}, ast_type, MakeOperand(inst, 0).expr)};
|
||||
return {ast_type,
|
||||
create<ast::BitcastExpression>(Source{}, ast_type->Build(builder_),
|
||||
MakeOperand(inst, 0).expr)};
|
||||
}
|
||||
|
||||
if (opcode == SpvOpShiftLeftLogical || opcode == SpvOpShiftRightLogical ||
|
||||
|
@ -3390,9 +3386,9 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
|
|||
for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
|
||||
operands.emplace_back(MakeOperand(inst, iarg).expr);
|
||||
}
|
||||
return {ast_type, create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(ast_type),
|
||||
std::move(operands))};
|
||||
return {ast_type,
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, ast_type->Build(builder_), std::move(operands))};
|
||||
}
|
||||
|
||||
if (opcode == SpvOpCompositeExtract) {
|
||||
|
@ -3457,7 +3453,7 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
|
|||
auto* func = create<ast::IdentifierExpression>(
|
||||
Source{}, builder_.Symbols().Register(name));
|
||||
ast::ExpressionList operands;
|
||||
ast::Type* first_operand_type = nullptr;
|
||||
const Type* first_operand_type = nullptr;
|
||||
// All parameters to GLSL.std.450 extended instructions are IDs.
|
||||
for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
|
||||
TypedExpression operand = MakeOperand(inst, iarg);
|
||||
|
@ -3703,7 +3699,7 @@ TypedExpression FunctionEmitter::MakeAccessChain(
|
|||
type_mgr_->FindPointerToType(pointee_type_id, storage_class);
|
||||
auto* ast_pointer_type = parser_impl_.ConvertType(pointer_type_id);
|
||||
TINT_ASSERT(ast_pointer_type);
|
||||
TINT_ASSERT(ast_pointer_type->Is<ast::Pointer>());
|
||||
TINT_ASSERT(ast_pointer_type->Is<Pointer>());
|
||||
current_expr = TypedExpression{ast_pointer_type, next_expr};
|
||||
}
|
||||
return current_expr;
|
||||
|
@ -3887,8 +3883,8 @@ TypedExpression FunctionEmitter::MakeVectorShuffle(
|
|||
// Generate an ast::TypeConstructor expression.
|
||||
// Assume the literal indices are valid, and there is a valid number of them.
|
||||
auto source = GetSourceForInst(inst);
|
||||
ast::Vector* result_type =
|
||||
parser_impl_.ConvertType(inst.type_id())->As<ast::Vector>();
|
||||
const Vector* result_type =
|
||||
As<Vector>(parser_impl_.ConvertType(inst.type_id()));
|
||||
ast::ExpressionList values;
|
||||
for (uint32_t i = 2; i < inst.NumInOperands(); ++i) {
|
||||
const auto index = inst.GetSingleWordInOperand(i);
|
||||
|
@ -3910,16 +3906,15 @@ TypedExpression FunctionEmitter::MakeVectorShuffle(
|
|||
source, expr.expr, Swizzle(sub_index)));
|
||||
} else if (index == 0xFFFFFFFF) {
|
||||
// By rule, this maps to OpUndef. Instead, make it zero.
|
||||
values.emplace_back(parser_impl_.MakeNullValue(result_type->type()));
|
||||
values.emplace_back(parser_impl_.MakeNullValue(result_type->type));
|
||||
} else {
|
||||
Fail() << "invalid vectorshuffle ID %" << inst.result_id()
|
||||
<< ": index too large: " << index;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {result_type,
|
||||
create<ast::TypeConstructorExpression>(
|
||||
source, builder_.ty.MaybeCreateTypename(result_type), values)};
|
||||
return {result_type, create<ast::TypeConstructorExpression>(
|
||||
source, result_type->Build(builder_), values)};
|
||||
}
|
||||
|
||||
bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
|
||||
|
@ -3988,8 +3983,8 @@ bool FunctionEmitter::RegisterLocallyDefinedValues() {
|
|||
if (type) {
|
||||
if (type->AsPointer()) {
|
||||
if (auto* ast_type = parser_impl_.ConvertType(inst.type_id())) {
|
||||
if (auto* ptr = ast_type->As<ast::Pointer>()) {
|
||||
info->storage_class = ptr->storage_class();
|
||||
if (auto* ptr = ast_type->As<Pointer>()) {
|
||||
info->storage_class = ptr->storage_class;
|
||||
}
|
||||
}
|
||||
switch (inst.opcode()) {
|
||||
|
@ -4033,21 +4028,21 @@ ast::StorageClass FunctionEmitter::GetStorageClassForPointerValue(uint32_t id) {
|
|||
const auto type_id = def_use_mgr_->GetDef(id)->type_id();
|
||||
if (type_id) {
|
||||
auto* ast_type = parser_impl_.ConvertType(type_id);
|
||||
if (auto* ptr = As<ast::Pointer>(ast_type)) {
|
||||
return ptr->storage_class();
|
||||
if (auto* ptr = As<Pointer>(ast_type)) {
|
||||
return ptr->storage_class;
|
||||
}
|
||||
}
|
||||
return ast::StorageClass::kNone;
|
||||
}
|
||||
|
||||
ast::Type* FunctionEmitter::RemapStorageClass(ast::Type* type,
|
||||
const Type* FunctionEmitter::RemapStorageClass(const Type* type,
|
||||
uint32_t result_id) {
|
||||
if (auto* ast_ptr_type = type->As<ast::Pointer>()) {
|
||||
if (auto* ast_ptr_type = As<Pointer>(type)) {
|
||||
// Remap an old-style storage buffer pointer to a new-style storage
|
||||
// buffer pointer.
|
||||
const auto sc = GetStorageClassForPointerValue(result_id);
|
||||
if (ast_ptr_type->storage_class() != sc) {
|
||||
return builder_.ty.pointer(ast_ptr_type->type(), sc);
|
||||
if (ast_ptr_type->storage_class != sc) {
|
||||
return ty_.Pointer(ast_ptr_type->type, sc);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
|
@ -4230,30 +4225,27 @@ TypedExpression FunctionEmitter::MakeNumericConversion(
|
|||
return {};
|
||||
}
|
||||
|
||||
ast::Type* expr_type = nullptr;
|
||||
const Type* expr_type = nullptr;
|
||||
if ((opcode == SpvOpConvertSToF) || (opcode == SpvOpConvertUToF)) {
|
||||
if (arg_expr.type->is_integer_scalar_or_vector()) {
|
||||
if (arg_expr.type->IsIntegerScalarOrVector()) {
|
||||
expr_type = requested_type;
|
||||
} else {
|
||||
Fail() << "operand for conversion to floating point must be integral "
|
||||
"scalar or vector, but got: "
|
||||
<< arg_expr.type->type_name();
|
||||
"scalar or vector";
|
||||
}
|
||||
} else if (inst.opcode() == SpvOpConvertFToU) {
|
||||
if (arg_expr.type->is_float_scalar_or_vector()) {
|
||||
if (arg_expr.type->IsFloatScalarOrVector()) {
|
||||
expr_type = parser_impl_.GetUnsignedIntMatchingShape(arg_expr.type);
|
||||
} else {
|
||||
Fail() << "operand for conversion to unsigned integer must be floating "
|
||||
"point scalar or vector, but got: "
|
||||
<< arg_expr.type->type_name();
|
||||
"point scalar or vector";
|
||||
}
|
||||
} else if (inst.opcode() == SpvOpConvertFToS) {
|
||||
if (arg_expr.type->is_float_scalar_or_vector()) {
|
||||
if (arg_expr.type->IsFloatScalarOrVector()) {
|
||||
expr_type = parser_impl_.GetSignedIntMatchingShape(arg_expr.type);
|
||||
} else {
|
||||
Fail() << "operand for conversion to signed integer must be floating "
|
||||
"point scalar or vector, but got: "
|
||||
<< arg_expr.type->type_name();
|
||||
"point scalar or vector";
|
||||
}
|
||||
}
|
||||
if (expr_type == nullptr) {
|
||||
|
@ -4265,14 +4257,14 @@ TypedExpression FunctionEmitter::MakeNumericConversion(
|
|||
params.push_back(arg_expr.expr);
|
||||
TypedExpression result{
|
||||
expr_type, create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(expr_type),
|
||||
std::move(params))};
|
||||
Source{}, expr_type->Build(builder_), std::move(params))};
|
||||
|
||||
if (AstTypesEquivalent(requested_type, expr_type)) {
|
||||
if (requested_type == expr_type) {
|
||||
return result;
|
||||
}
|
||||
return {requested_type, create<ast::BitcastExpression>(
|
||||
Source{}, requested_type, result.expr)};
|
||||
return {requested_type,
|
||||
create<ast::BitcastExpression>(
|
||||
Source{}, requested_type->Build(builder_), result.expr)};
|
||||
}
|
||||
|
||||
bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
|
||||
|
@ -4296,7 +4288,7 @@ bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
|
|||
<< inst.PrettyPrint();
|
||||
}
|
||||
|
||||
if (result_type->Is<ast::Void>()) {
|
||||
if (result_type->Is<Void>()) {
|
||||
return nullptr !=
|
||||
AddStatement(create<ast::CallStatement>(Source{}, call_expr));
|
||||
}
|
||||
|
@ -4359,7 +4351,7 @@ TypedExpression FunctionEmitter::MakeIntrinsicCall(
|
|||
Source{}, builder_.Symbols().Register(name));
|
||||
|
||||
ast::ExpressionList params;
|
||||
ast::Type* first_operand_type = nullptr;
|
||||
const Type* first_operand_type = nullptr;
|
||||
for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
|
||||
TypedExpression operand = MakeOperand(inst, iarg);
|
||||
if (first_operand_type == nullptr) {
|
||||
|
@ -4391,8 +4383,8 @@ TypedExpression FunctionEmitter::MakeSimpleSelect(
|
|||
// - you can't select over pointers or pointer vectors, unless you also have
|
||||
// a VariablePointers* capability, which is not allowed in by WebGPU.
|
||||
auto* op_ty = operand1.type;
|
||||
if (op_ty->Is<ast::Vector>() || op_ty->is_float_scalar() ||
|
||||
op_ty->is_integer_scalar() || op_ty->Is<ast::Bool>()) {
|
||||
if (op_ty->Is<Vector>() || op_ty->IsFloatScalar() ||
|
||||
op_ty->IsIntegerScalar() || op_ty->Is<Bool>()) {
|
||||
ast::ExpressionList params;
|
||||
params.push_back(operand1.expr);
|
||||
params.push_back(operand2.expr);
|
||||
|
@ -4430,9 +4422,9 @@ const spvtools::opt::Instruction* FunctionEmitter::GetImage(
|
|||
return image;
|
||||
}
|
||||
|
||||
ast::Texture* FunctionEmitter::GetImageType(
|
||||
const Texture* FunctionEmitter::GetImageType(
|
||||
const spvtools::opt::Instruction& image) {
|
||||
ast::Pointer* ptr_type = parser_impl_.GetTypeForHandleVar(image);
|
||||
const Pointer* ptr_type = parser_impl_.GetTypeForHandleVar(image);
|
||||
if (!parser_impl_.success()) {
|
||||
Fail();
|
||||
return {};
|
||||
|
@ -4441,7 +4433,7 @@ ast::Texture* FunctionEmitter::GetImageType(
|
|||
Fail() << "invalid texture type for " << image.PrettyPrint();
|
||||
return {};
|
||||
}
|
||||
auto* result = ptr_type->type()->UnwrapAll()->As<ast::Texture>();
|
||||
auto* result = ptr_type->type->UnwrapAll()->As<Texture>();
|
||||
if (!result) {
|
||||
Fail() << "invalid texture type for " << image.PrettyPrint();
|
||||
return {};
|
||||
|
@ -4496,12 +4488,12 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
}
|
||||
|
||||
ast::Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image);
|
||||
const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image);
|
||||
if (!texture_ptr_type) {
|
||||
return Fail();
|
||||
}
|
||||
ast::Texture* texture_type =
|
||||
texture_ptr_type->type()->UnwrapAll()->As<ast::Texture>();
|
||||
const Texture* texture_type =
|
||||
texture_ptr_type->type->UnwrapAll()->As<Texture>();
|
||||
|
||||
if (!texture_type) {
|
||||
return Fail();
|
||||
|
@ -4604,7 +4596,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
TypedExpression lod = MakeOperand(inst, arg_index);
|
||||
// When sampling from a depth texture, the Lod operand must be an I32.
|
||||
if (texture_type->Is<ast::DepthTexture>()) {
|
||||
if (texture_type->Is<DepthTexture>()) {
|
||||
// Convert it to a signed integer type.
|
||||
lod = ToI32(lod);
|
||||
}
|
||||
|
@ -4612,11 +4604,11 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
image_operands_mask ^= SpvImageOperandsLodMask;
|
||||
arg_index++;
|
||||
} else if ((opcode == SpvOpImageFetch) &&
|
||||
(texture_type->Is<ast::SampledTexture>() ||
|
||||
texture_type->Is<ast::DepthTexture>())) {
|
||||
(texture_type->Is<SampledTexture>() ||
|
||||
texture_type->Is<DepthTexture>())) {
|
||||
// textureLoad on sampled texture and depth texture requires an explicit
|
||||
// level-of-detail parameter.
|
||||
params.push_back(parser_impl_.MakeNullValue(builder_.ty.i32()));
|
||||
params.push_back(parser_impl_.MakeNullValue(ty_.I32()));
|
||||
}
|
||||
if (arg_index + 1 < num_args &&
|
||||
(image_operands_mask & SpvImageOperandsGradMask)) {
|
||||
|
@ -4637,7 +4629,7 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
return Fail() << "ConstOffset is only permitted for sampling operations: "
|
||||
<< inst.PrettyPrint();
|
||||
}
|
||||
switch (texture_type->dim()) {
|
||||
switch (texture_type->dims) {
|
||||
case ast::TextureDimension::k2d:
|
||||
case ast::TextureDimension::k2dArray:
|
||||
case ast::TextureDimension::k3d:
|
||||
|
@ -4676,8 +4668,8 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
// The result type, derived from the SPIR-V instruction.
|
||||
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
||||
auto* result_component_type = result_type;
|
||||
if (auto* result_vector_type = result_type->As<ast::Vector>()) {
|
||||
result_component_type = result_vector_type->type();
|
||||
if (auto* result_vector_type = As<Vector>(result_type)) {
|
||||
result_component_type = result_vector_type->type;
|
||||
}
|
||||
|
||||
// For depth textures, the arity might mot match WGSL:
|
||||
|
@ -4691,11 +4683,11 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
// dref gather vec4 ImageFetch vec4 TODO(dneto)
|
||||
// Construct a 4-element vector with the result from the builtin in the
|
||||
// first component.
|
||||
if (texture_type->Is<ast::DepthTexture>()) {
|
||||
if (texture_type->Is<DepthTexture>()) {
|
||||
if (is_non_dref_sample || (opcode == SpvOpImageFetch)) {
|
||||
value = create<ast::TypeConstructorExpression>(
|
||||
Source{},
|
||||
builder_.ty.MaybeCreateTypename(result_type), // a vec4
|
||||
result_type->Build(builder_), // a vec4
|
||||
ast::ExpressionList{
|
||||
value, parser_impl_.MakeNullValue(result_component_type),
|
||||
parser_impl_.MakeNullValue(result_component_type),
|
||||
|
@ -4714,13 +4706,13 @@ bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
auto* expected_component_type =
|
||||
parser_impl_.ConvertType(spirv_image_type->GetSingleWordInOperand(0));
|
||||
if (!AstTypesEquivalent(expected_component_type, result_component_type)) {
|
||||
if (expected_component_type != result_component_type) {
|
||||
// This occurs if one is signed integer and the other is unsigned integer,
|
||||
// or vice versa. Perform a bitcast.
|
||||
value = create<ast::BitcastExpression>(Source{}, result_type, call_expr);
|
||||
value = create<ast::BitcastExpression>(
|
||||
Source{}, result_type->Build(builder_), call_expr);
|
||||
}
|
||||
if (!expected_component_type->Is<ast::F32>() &&
|
||||
IsSampledImageAccess(opcode)) {
|
||||
if (!expected_component_type->Is<F32>() && IsSampledImageAccess(opcode)) {
|
||||
// WGSL permits sampled image access only on float textures.
|
||||
// Reject this case in the SPIR-V reader, at least until SPIR-V validation
|
||||
// catches up with this rule and can reject it earlier in the workflow.
|
||||
|
@ -4763,7 +4755,7 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
exprs.push_back(
|
||||
create<ast::CallExpression>(Source{}, dims_ident, dims_args));
|
||||
if (ast::IsTextureArray(texture_type->dim())) {
|
||||
if (ast::IsTextureArray(texture_type->dims)) {
|
||||
auto* layers_ident = create<ast::IdentifierExpression>(
|
||||
Source{}, builder_.Symbols().Register("textureNumLayers"));
|
||||
exprs.push_back(create<ast::CallExpression>(
|
||||
|
@ -4772,9 +4764,8 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
|
|||
}
|
||||
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
||||
TypedExpression expr = {
|
||||
result_type,
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(result_type), exprs)};
|
||||
result_type, create<ast::TypeConstructorExpression>(
|
||||
Source{}, result_type->Build(builder_), exprs)};
|
||||
return EmitConstDefOrWriteToHoistedVar(inst, expr);
|
||||
}
|
||||
case SpvOpImageQueryLod:
|
||||
|
@ -4794,9 +4785,9 @@ bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
|
|||
auto* result_type = parser_impl_.ConvertType(inst.type_id());
|
||||
// The SPIR-V result type must be integer scalar. The WGSL bulitin
|
||||
// returns i32. If they aren't the same then convert the result.
|
||||
if (!result_type->Is<ast::I32>()) {
|
||||
if (!result_type->Is<I32>()) {
|
||||
ast_expr = create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(result_type),
|
||||
Source{}, result_type->Build(builder_),
|
||||
ast::ExpressionList{ast_expr});
|
||||
}
|
||||
TypedExpression expr{result_type, ast_expr};
|
||||
|
@ -4840,28 +4831,27 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
|
|||
if (!raw_coords.type) {
|
||||
return {};
|
||||
}
|
||||
ast::Texture* texture_type = GetImageType(*image);
|
||||
const Texture* texture_type = GetImageType(*image);
|
||||
if (!texture_type) {
|
||||
return {};
|
||||
}
|
||||
ast::TextureDimension dim = texture_type->dim();
|
||||
ast::TextureDimension dim = texture_type->dims;
|
||||
// Number of regular coordinates.
|
||||
uint32_t num_axes = ast::NumCoordinateAxes(dim);
|
||||
bool is_arrayed = ast::IsTextureArray(dim);
|
||||
if ((num_axes == 0) || (num_axes > 3)) {
|
||||
Fail() << "unsupported image dimensionality for "
|
||||
<< texture_type->type_name() << " prompted by "
|
||||
<< texture_type->TypeInfo().name << " prompted by "
|
||||
<< inst.PrettyPrint();
|
||||
}
|
||||
const auto num_coords_required = num_axes + (is_arrayed ? 1 : 0);
|
||||
uint32_t num_coords_supplied = 0;
|
||||
auto* component_type = raw_coords.type;
|
||||
if (component_type->is_float_scalar() ||
|
||||
component_type->is_integer_scalar()) {
|
||||
if (component_type->IsFloatScalar() || component_type->IsIntegerScalar()) {
|
||||
num_coords_supplied = 1;
|
||||
} else if (auto* vec_type = raw_coords.type->As<ast::Vector>()) {
|
||||
component_type = vec_type->type();
|
||||
num_coords_supplied = vec_type->size();
|
||||
} else if (auto* vec_type = As<Vector>(raw_coords.type)) {
|
||||
component_type = vec_type->type;
|
||||
num_coords_supplied = vec_type->size;
|
||||
}
|
||||
if (num_coords_supplied == 0) {
|
||||
Fail() << "bad or unsupported coordinate type for image access: "
|
||||
|
@ -4884,10 +4874,8 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
|
|||
// will actually use them.
|
||||
auto prefix_swizzle_expr = [this, num_axes, component_type,
|
||||
raw_coords]() -> ast::Expression* {
|
||||
auto* swizzle_type = (num_axes == 1)
|
||||
? component_type
|
||||
: static_cast<ast::Type*>(
|
||||
builder_.ty.vec(component_type, num_axes));
|
||||
auto* swizzle_type =
|
||||
(num_axes == 1) ? component_type : ty_.Vector(component_type, num_axes);
|
||||
auto* swizzle = create<ast::MemberAccessorExpression>(
|
||||
Source{}, raw_coords.expr, PrefixSwizzle(num_axes));
|
||||
return ToSignedIfUnsigned({swizzle_type, swizzle}).expr;
|
||||
|
@ -4921,32 +4909,32 @@ ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
|
|||
ast::Expression* FunctionEmitter::ConvertTexelForStorage(
|
||||
const spvtools::opt::Instruction& inst,
|
||||
TypedExpression texel,
|
||||
ast::Texture* texture_type) {
|
||||
auto* storage_texture_type = texture_type->As<ast::StorageTexture>();
|
||||
const Texture* texture_type) {
|
||||
auto* storage_texture_type = As<StorageTexture>(texture_type);
|
||||
auto* src_type = texel.type;
|
||||
if (!storage_texture_type) {
|
||||
Fail() << "writing to other than storage texture: " << inst.PrettyPrint();
|
||||
return nullptr;
|
||||
}
|
||||
const auto format = storage_texture_type->image_format();
|
||||
const auto format = storage_texture_type->format;
|
||||
auto* dest_type = parser_impl_.GetTexelTypeForFormat(format);
|
||||
if (!dest_type) {
|
||||
Fail();
|
||||
return nullptr;
|
||||
}
|
||||
if (AstTypesEquivalent(src_type, dest_type)) {
|
||||
if (src_type == dest_type) {
|
||||
return texel.expr;
|
||||
}
|
||||
|
||||
const uint32_t dest_count =
|
||||
dest_type->is_scalar() ? 1 : dest_type->As<ast::Vector>()->size();
|
||||
dest_type->IsScalar() ? 1 : dest_type->As<Vector>()->size;
|
||||
if (dest_count == 3) {
|
||||
Fail() << "3-channel storage textures are not supported: "
|
||||
<< inst.PrettyPrint();
|
||||
return nullptr;
|
||||
}
|
||||
const uint32_t src_count =
|
||||
src_type->is_scalar() ? 1 : src_type->As<ast::Vector>()->size();
|
||||
src_type->IsScalar() ? 1 : src_type->As<Vector>()->size;
|
||||
if (src_count < dest_count) {
|
||||
Fail() << "texel has too few components for storage texture: " << src_count
|
||||
<< " provided but " << dest_count
|
||||
|
@ -4961,29 +4949,29 @@ ast::Expression* FunctionEmitter::ConvertTexelForStorage(
|
|||
: create<ast::MemberAccessorExpression>(Source{}, texel.expr,
|
||||
PrefixSwizzle(dest_count));
|
||||
|
||||
if (!(dest_type->is_float_scalar_or_vector() ||
|
||||
dest_type->is_unsigned_scalar_or_vector() ||
|
||||
dest_type->is_signed_scalar_or_vector())) {
|
||||
if (!(dest_type->IsFloatScalarOrVector() ||
|
||||
dest_type->IsUnsignedScalarOrVector() ||
|
||||
dest_type->IsSignedScalarOrVector())) {
|
||||
Fail() << "invalid destination type for storage texture write: "
|
||||
<< dest_type->type_name();
|
||||
<< dest_type->TypeInfo().name;
|
||||
return nullptr;
|
||||
}
|
||||
if (!(src_type->is_float_scalar_or_vector() ||
|
||||
src_type->is_unsigned_scalar_or_vector() ||
|
||||
src_type->is_signed_scalar_or_vector())) {
|
||||
if (!(src_type->IsFloatScalarOrVector() ||
|
||||
src_type->IsUnsignedScalarOrVector() ||
|
||||
src_type->IsSignedScalarOrVector())) {
|
||||
Fail() << "invalid texel type for storage texture write: "
|
||||
<< inst.PrettyPrint();
|
||||
return nullptr;
|
||||
}
|
||||
if (dest_type->is_float_scalar_or_vector() &&
|
||||
!src_type->is_float_scalar_or_vector()) {
|
||||
if (dest_type->IsFloatScalarOrVector() &&
|
||||
!src_type->IsFloatScalarOrVector()) {
|
||||
Fail() << "can only write float or float vector to a storage image with "
|
||||
"floating texel format: "
|
||||
<< inst.PrettyPrint();
|
||||
return nullptr;
|
||||
}
|
||||
if (!dest_type->is_float_scalar_or_vector() &&
|
||||
src_type->is_float_scalar_or_vector()) {
|
||||
if (!dest_type->IsFloatScalarOrVector() &&
|
||||
src_type->IsFloatScalarOrVector()) {
|
||||
Fail()
|
||||
<< "float or float vector can only be written to a storage image with "
|
||||
"floating texel format: "
|
||||
|
@ -4991,36 +4979,37 @@ ast::Expression* FunctionEmitter::ConvertTexelForStorage(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (dest_type->is_float_scalar_or_vector()) {
|
||||
if (dest_type->IsFloatScalarOrVector()) {
|
||||
return texel_prefix;
|
||||
}
|
||||
// The only remaining cases are signed/unsigned source, and signed/unsigned
|
||||
// destination.
|
||||
if (dest_type->is_unsigned_scalar_or_vector() ==
|
||||
src_type->is_unsigned_scalar_or_vector()) {
|
||||
if (dest_type->IsUnsignedScalarOrVector() ==
|
||||
src_type->IsUnsignedScalarOrVector()) {
|
||||
return texel_prefix;
|
||||
}
|
||||
// We must do a bitcast conversion.
|
||||
return create<ast::BitcastExpression>(Source{}, dest_type, texel_prefix);
|
||||
return create<ast::BitcastExpression>(Source{}, dest_type->Build(builder_),
|
||||
texel_prefix);
|
||||
}
|
||||
|
||||
TypedExpression FunctionEmitter::ToI32(TypedExpression value) {
|
||||
if (!value.type || value.type->Is<ast::I32>()) {
|
||||
if (!value.type || value.type->Is<I32>()) {
|
||||
return value;
|
||||
}
|
||||
return {builder_.ty.i32(),
|
||||
return {ty_.I32(),
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.i32(), ast::ExpressionList{value.expr})};
|
||||
}
|
||||
|
||||
TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
|
||||
if (!value.type || !value.type->is_unsigned_scalar_or_vector()) {
|
||||
if (!value.type || !value.type->IsUnsignedScalarOrVector()) {
|
||||
return value;
|
||||
}
|
||||
if (auto* vec_type = value.type->As<ast::Vector>()) {
|
||||
auto new_type = builder_.ty.vec(builder_.ty.i32(), vec_type->size());
|
||||
return {new_type,
|
||||
builder_.Construct(new_type, ast::ExpressionList{value.expr})};
|
||||
if (auto* vec_type = value.type->As<Vector>()) {
|
||||
auto* new_type = ty_.Vector(ty_.I32(), vec_type->size);
|
||||
return {new_type, builder_.Construct(new_type->Build(builder_),
|
||||
ast::ExpressionList{value.expr})};
|
||||
}
|
||||
return ToI32(value);
|
||||
}
|
||||
|
@ -5073,14 +5062,12 @@ TypedExpression FunctionEmitter::MakeOuterProduct(
|
|||
// Synthesize the result.
|
||||
auto col = MakeOperand(inst, 0);
|
||||
auto row = MakeOperand(inst, 1);
|
||||
auto* col_ty = col.type->As<ast::Vector>();
|
||||
auto* row_ty = row.type->As<ast::Vector>();
|
||||
auto* result_ty = parser_impl_.ConvertType(inst.type_id())->As<ast::Matrix>();
|
||||
if (!col_ty || !col_ty || !result_ty ||
|
||||
!AstTypesEquivalent(result_ty->type(), col_ty->type()) ||
|
||||
!AstTypesEquivalent(result_ty->type(), row_ty->type()) ||
|
||||
result_ty->columns() != row_ty->size() ||
|
||||
result_ty->rows() != col_ty->size()) {
|
||||
auto* col_ty = As<Vector>(col.type);
|
||||
auto* row_ty = As<Vector>(row.type);
|
||||
auto* result_ty = As<Matrix>(parser_impl_.ConvertType(inst.type_id()));
|
||||
if (!col_ty || !col_ty || !result_ty || result_ty->type != col_ty->type ||
|
||||
result_ty->type != row_ty->type || result_ty->columns != row_ty->size ||
|
||||
result_ty->rows != col_ty->size) {
|
||||
Fail() << "invalid outer product instruction: bad types "
|
||||
<< inst.PrettyPrint();
|
||||
return {};
|
||||
|
@ -5096,11 +5083,11 @@ TypedExpression FunctionEmitter::MakeOuterProduct(
|
|||
// | c.z * r.x c.z * r.y |
|
||||
|
||||
ast::ExpressionList result_columns;
|
||||
for (uint32_t icol = 0; icol < result_ty->columns(); icol++) {
|
||||
for (uint32_t icol = 0; icol < result_ty->columns; icol++) {
|
||||
ast::ExpressionList result_row;
|
||||
auto* row_factor = create<ast::MemberAccessorExpression>(Source{}, row.expr,
|
||||
Swizzle(icol));
|
||||
for (uint32_t irow = 0; irow < result_ty->rows(); irow++) {
|
||||
for (uint32_t irow = 0; irow < result_ty->rows; irow++) {
|
||||
auto* column_factor = create<ast::MemberAccessorExpression>(
|
||||
Source{}, col.expr, Swizzle(irow));
|
||||
auto* elem = create<ast::BinaryExpression>(
|
||||
|
@ -5108,11 +5095,10 @@ TypedExpression FunctionEmitter::MakeOuterProduct(
|
|||
result_row.push_back(elem);
|
||||
}
|
||||
result_columns.push_back(create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(col_ty), result_row));
|
||||
Source{}, col_ty->Build(builder_), result_row));
|
||||
}
|
||||
return {result_ty, create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(result_ty),
|
||||
result_columns)};
|
||||
Source{}, result_ty->Build(builder_), result_columns)};
|
||||
}
|
||||
|
||||
bool FunctionEmitter::MakeVectorInsertDynamic(
|
||||
|
@ -5142,8 +5128,7 @@ bool FunctionEmitter::MakeVectorInsertDynamic(
|
|||
|
||||
auto* temp_var = create<ast::Variable>(
|
||||
Source{}, registered_temp_name, ast::StorageClass::kFunction,
|
||||
builder_.ty.MaybeCreateTypename(ast_type), false, src_vector.expr,
|
||||
ast::DecorationList{});
|
||||
ast_type->Build(builder_), false, src_vector.expr, ast::DecorationList{});
|
||||
AddStatement(create<ast::VariableDeclStatement>(Source{}, temp_var));
|
||||
|
||||
auto* lhs = create<ast::ArrayAccessorExpression>(
|
||||
|
@ -5189,7 +5174,7 @@ bool FunctionEmitter::MakeCompositeInsert(
|
|||
|
||||
auto* temp_var = create<ast::Variable>(
|
||||
Source{}, registered_temp_name, ast::StorageClass::kFunction,
|
||||
builder_.ty.MaybeCreateTypename(ast_type), false, src_composite.expr,
|
||||
ast_type->Build(builder_), false, src_composite.expr,
|
||||
ast::DecorationList{});
|
||||
AddStatement(create<ast::VariableDeclStatement>(Source{}, temp_var));
|
||||
|
||||
|
|
|
@ -515,7 +515,7 @@ class FunctionEmitter {
|
|||
/// @param type the AST type
|
||||
/// @param result_id the SPIR-V ID for the locally defined value
|
||||
/// @returns an possibly updated type
|
||||
ast::Type* RemapStorageClass(ast::Type* type, uint32_t result_id);
|
||||
const Type* RemapStorageClass(const Type* type, uint32_t result_id);
|
||||
|
||||
/// Marks locally defined values when they should get a 'const'
|
||||
/// definition in WGSL, or a 'var' definition at an outer scope.
|
||||
|
@ -856,7 +856,7 @@ class FunctionEmitter {
|
|||
/// Function parameters
|
||||
ast::VariableList params;
|
||||
/// Function return type
|
||||
ast::Type* return_type;
|
||||
const Type* return_type;
|
||||
/// Function decorations
|
||||
ast::DecorationList decorations;
|
||||
};
|
||||
|
@ -869,7 +869,7 @@ class FunctionEmitter {
|
|||
|
||||
/// @returns the store type for the OpVariable instruction, or
|
||||
/// null on failure.
|
||||
ast::Type* GetVariableStoreType(
|
||||
const Type* GetVariableStoreType(
|
||||
const spvtools::opt::Instruction& var_decl_inst);
|
||||
|
||||
/// Returns an expression for an instruction operand. Signedness conversion is
|
||||
|
@ -937,7 +937,7 @@ class FunctionEmitter {
|
|||
/// Get the AST texture the SPIR-V image memory object declaration.
|
||||
/// @param inst the SPIR-V memory object declaration for the image.
|
||||
/// @returns a texture type, or null on error
|
||||
ast::Texture* GetImageType(const spvtools::opt::Instruction& inst);
|
||||
const Texture* GetImageType(const spvtools::opt::Instruction& inst);
|
||||
|
||||
/// Get the expression for the image operand from the first operand to the
|
||||
/// given instruction.
|
||||
|
@ -974,7 +974,7 @@ class FunctionEmitter {
|
|||
ast::Expression* ConvertTexelForStorage(
|
||||
const spvtools::opt::Instruction& inst,
|
||||
TypedExpression texel,
|
||||
ast::Texture* texture_type);
|
||||
const Texture* texture_type);
|
||||
|
||||
/// Returns an expression for an OpSelect, if its operands are scalars
|
||||
/// or vectors. These translate directly to WGSL select. Otherwise, return
|
||||
|
@ -1128,6 +1128,7 @@ class FunctionEmitter {
|
|||
using StatementsStack = std::vector<StatementBlock>;
|
||||
|
||||
ParserImpl& parser_impl_;
|
||||
TypeManager& ty_;
|
||||
ProgramBuilder& builder_;
|
||||
spvtools::opt::IRContext& ir_context_;
|
||||
spvtools::opt::analysis::DefUseManager* def_use_mgr_;
|
||||
|
|
|
@ -202,7 +202,7 @@ TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
HasSubstr("operand for conversion to floating point must be "
|
||||
"integral scalar or vector, but got: __bool"));
|
||||
"integral scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_BadArgType) {
|
||||
|
@ -220,7 +220,7 @@ TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_BadArgType) {
|
|||
EXPECT_THAT(
|
||||
p->error(),
|
||||
HasSubstr("operand for conversion to floating point must be integral "
|
||||
"scalar or vector, but got: __vec_2__bool"));
|
||||
"scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromSigned) {
|
||||
|
@ -344,7 +344,7 @@ TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_BadArgType) {
|
|||
auto fe = p->function_emitter(100);
|
||||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(), Eq("operand for conversion to floating point must be "
|
||||
"integral scalar or vector, but got: __bool"));
|
||||
"integral scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_BadArgType) {
|
||||
|
@ -361,7 +361,7 @@ TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("operand for conversion to floating point must be integral "
|
||||
"scalar or vector, but got: __vec_2__bool"));
|
||||
"scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromSigned) {
|
||||
|
@ -486,7 +486,7 @@ TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("operand for conversion to signed integer must be floating "
|
||||
"point scalar or vector, but got: __u32"));
|
||||
"point scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_BadArgType) {
|
||||
|
@ -503,7 +503,7 @@ TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("operand for conversion to signed integer must be floating "
|
||||
"point scalar or vector, but got: __vec_2__bool"));
|
||||
"point scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_ToSigned) {
|
||||
|
@ -628,7 +628,7 @@ TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("operand for conversion to unsigned integer must be floating "
|
||||
"point scalar or vector, but got: __u32"));
|
||||
"point scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_BadArgType) {
|
||||
|
@ -645,7 +645,7 @@ TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_BadArgType) {
|
|||
EXPECT_FALSE(fe.EmitBody());
|
||||
EXPECT_THAT(p->error(),
|
||||
Eq("operand for conversion to unsigned integer must be floating "
|
||||
"point scalar or vector, but got: __vec_2__bool"));
|
||||
"point scalar or vector"));
|
||||
}
|
||||
|
||||
TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_ToSigned_IsError) {
|
||||
|
|
|
@ -836,7 +836,7 @@ TEST_F(SpvParserMemoryTest, RemapStorageBuffer_TypesAndVarDeclarations) {
|
|||
Struct S {
|
||||
[[block]]
|
||||
StructMember{[[ offset 0 ]] field0: __u32}
|
||||
StructMember{[[ offset 4 ]] field1: __alias_RTArr__array__u32_stride_4}
|
||||
StructMember{[[ offset 4 ]] field1: __type_name_RTArr}
|
||||
}
|
||||
Variable{
|
||||
Decorations{
|
||||
|
|
|
@ -240,7 +240,7 @@ TypedExpression::TypedExpression(const TypedExpression&) = default;
|
|||
|
||||
TypedExpression& TypedExpression::operator=(const TypedExpression&) = default;
|
||||
|
||||
TypedExpression::TypedExpression(ast::Type* type_in, ast::Expression* expr_in)
|
||||
TypedExpression::TypedExpression(const Type* type_in, ast::Expression* expr_in)
|
||||
: type(type_in), expr(expr_in) {}
|
||||
|
||||
ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
|
||||
|
@ -305,7 +305,7 @@ Program ParserImpl::program() {
|
|||
return tint::Program(std::move(builder_));
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(uint32_t type_id) {
|
||||
const Type* ParserImpl::ConvertType(uint32_t type_id) {
|
||||
if (!success_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -322,18 +322,18 @@ ast::Type* ParserImpl::ConvertType(uint32_t type_id) {
|
|||
}
|
||||
|
||||
auto maybe_generate_alias = [this, type_id,
|
||||
spirv_type](ast::Type* type) -> ast::Type* {
|
||||
spirv_type](const Type* type) -> const Type* {
|
||||
if (type != nullptr) {
|
||||
return MaybeGenerateAlias(type_id, spirv_type, type);
|
||||
}
|
||||
return {};
|
||||
return type;
|
||||
};
|
||||
|
||||
switch (spirv_type->kind()) {
|
||||
case spvtools::opt::analysis::Type::kVoid:
|
||||
return maybe_generate_alias(builder_.ty.void_());
|
||||
return maybe_generate_alias(ty_.Void());
|
||||
case spvtools::opt::analysis::Type::kBool:
|
||||
return maybe_generate_alias(builder_.ty.bool_());
|
||||
return maybe_generate_alias(ty_.Bool());
|
||||
case spvtools::opt::analysis::Type::kInteger:
|
||||
return maybe_generate_alias(ConvertType(spirv_type->AsInteger()));
|
||||
case spvtools::opt::analysis::Type::kFloat:
|
||||
|
@ -362,7 +362,7 @@ ast::Type* ParserImpl::ConvertType(uint32_t type_id) {
|
|||
case spvtools::opt::analysis::Type::kImage:
|
||||
// Fake it for sampler and texture types. These are handled in an
|
||||
// entirely different way.
|
||||
return maybe_generate_alias(builder_.ty.void_());
|
||||
return maybe_generate_alias(ty_.Void());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -774,36 +774,36 @@ bool ParserImpl::RegisterEntryPoints() {
|
|||
return success_;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::Integer* int_ty) {
|
||||
if (int_ty->width() == 32) {
|
||||
return int_ty->IsSigned() ? static_cast<ast::Type*>(builder_.ty.i32())
|
||||
: static_cast<ast::Type*>(builder_.ty.u32());
|
||||
return int_ty->IsSigned() ? static_cast<const Type*>(ty_.I32())
|
||||
: static_cast<const Type*>(ty_.U32());
|
||||
}
|
||||
Fail() << "unhandled integer width: " << int_ty->width();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::Float* float_ty) {
|
||||
if (float_ty->width() == 32) {
|
||||
return builder_.ty.f32();
|
||||
return ty_.F32();
|
||||
}
|
||||
Fail() << "unhandled float width: " << float_ty->width();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::Vector* vec_ty) {
|
||||
const auto num_elem = vec_ty->element_count();
|
||||
auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type()));
|
||||
if (ast_elem_ty == nullptr) {
|
||||
return nullptr;
|
||||
return ast_elem_ty;
|
||||
}
|
||||
return builder_.ty.vec(ast_elem_ty, num_elem);
|
||||
return ty_.Vector(ast_elem_ty, num_elem);
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::Matrix* mat_ty) {
|
||||
const auto* vec_ty = mat_ty->element_type()->AsVector();
|
||||
const auto* scalar_ty = vec_ty->element_type();
|
||||
|
@ -813,23 +813,23 @@ ast::Type* ParserImpl::ConvertType(
|
|||
if (ast_scalar_ty == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return builder_.ty.mat(ast_scalar_ty, num_columns, num_rows);
|
||||
return ty_.Matrix(ast_scalar_ty, num_columns, num_rows);
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::RuntimeArray* rtarr_ty) {
|
||||
auto* ast_elem_ty = ConvertType(type_mgr_->GetId(rtarr_ty->element_type()));
|
||||
if (ast_elem_ty == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
ast::DecorationList decorations;
|
||||
if (!ParseArrayDecorations(rtarr_ty, &decorations)) {
|
||||
uint32_t array_stride = 0;
|
||||
if (!ParseArrayDecorations(rtarr_ty, &array_stride)) {
|
||||
return nullptr;
|
||||
}
|
||||
return builder_.ty.array(ast_elem_ty, 0, std::move(decorations));
|
||||
return ty_.Array(ast_elem_ty, 0, array_stride);
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
const spvtools::opt::analysis::Array* arr_ty) {
|
||||
const auto elem_type_id = type_mgr_->GetId(arr_ty->element_type());
|
||||
auto* ast_elem_ty = ConvertType(elem_type_id);
|
||||
|
@ -863,21 +863,19 @@ ast::Type* ParserImpl::ConvertType(
|
|||
<< num_elem;
|
||||
return nullptr;
|
||||
}
|
||||
ast::DecorationList decorations;
|
||||
if (!ParseArrayDecorations(arr_ty, &decorations)) {
|
||||
uint32_t array_stride = 0;
|
||||
if (!ParseArrayDecorations(arr_ty, &array_stride)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (remap_buffer_block_type_.count(elem_type_id)) {
|
||||
remap_buffer_block_type_.insert(type_mgr_->GetId(arr_ty));
|
||||
}
|
||||
return builder_.ty.array(ast_elem_ty, static_cast<uint32_t>(num_elem),
|
||||
std::move(decorations));
|
||||
return ty_.Array(ast_elem_ty, static_cast<uint32_t>(num_elem), array_stride);
|
||||
}
|
||||
|
||||
bool ParserImpl::ParseArrayDecorations(
|
||||
const spvtools::opt::analysis::Type* spv_type,
|
||||
ast::DecorationList* decorations) {
|
||||
uint32_t* array_stride) {
|
||||
bool has_array_stride = false;
|
||||
const auto type_id = type_mgr_->GetId(spv_type);
|
||||
for (auto& decoration : this->GetDecorationsFor(type_id)) {
|
||||
|
@ -892,7 +890,7 @@ bool ParserImpl::ParseArrayDecorations(
|
|||
<< ": multiple ArrayStride decorations";
|
||||
}
|
||||
has_array_stride = true;
|
||||
decorations->push_back(create<ast::StrideDecoration>(Source{}, stride));
|
||||
*array_stride = stride;
|
||||
} else {
|
||||
return Fail() << "invalid array type ID " << type_id
|
||||
<< ": unknown decoration "
|
||||
|
@ -904,7 +902,7 @@ bool ParserImpl::ParseArrayDecorations(
|
|||
return true;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(
|
||||
const Type* ParserImpl::ConvertType(
|
||||
uint32_t type_id,
|
||||
const spvtools::opt::analysis::Struct* struct_ty) {
|
||||
// Compute the struct decoration.
|
||||
|
@ -930,6 +928,7 @@ ast::Type* ParserImpl::ConvertType(
|
|||
// Compute members
|
||||
ast::StructMemberList ast_members;
|
||||
const auto members = struct_ty->element_types();
|
||||
TypeList ast_member_types;
|
||||
unsigned num_non_writable_members = 0;
|
||||
for (uint32_t member_index = 0; member_index < members.size();
|
||||
++member_index) {
|
||||
|
@ -940,6 +939,8 @@ ast::Type* ParserImpl::ConvertType(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ast_member_types.emplace_back(ast_member_ty);
|
||||
|
||||
// Scan member for built-in decorations. Some vertex built-ins are handled
|
||||
// specially, and should not generate a structure member.
|
||||
bool create_ast_member = true;
|
||||
|
@ -1003,8 +1004,8 @@ ast::Type* ParserImpl::ConvertType(
|
|||
}
|
||||
const auto member_name = namer_.GetMemberName(type_id, member_index);
|
||||
auto* ast_struct_member = create<ast::StructMember>(
|
||||
Source{}, builder_.Symbols().Register(member_name), ast_member_ty,
|
||||
std::move(ast_member_decorations));
|
||||
Source{}, builder_.Symbols().Register(member_name),
|
||||
ast_member_ty->Build(builder_), std::move(ast_member_decorations));
|
||||
ast_members.push_back(ast_struct_member);
|
||||
}
|
||||
|
||||
|
@ -1030,7 +1031,7 @@ ast::Type* ParserImpl::ConvertType(
|
|||
read_only_struct_types_.insert(ast_struct->name());
|
||||
}
|
||||
AddConstructedType(sym, ast_struct);
|
||||
return ast_struct;
|
||||
return ty_.Struct(sym, std::move(ast_member_types));
|
||||
}
|
||||
|
||||
void ParserImpl::AddConstructedType(Symbol name, ast::NamedType* type) {
|
||||
|
@ -1040,7 +1041,7 @@ void ParserImpl::AddConstructedType(Symbol name, ast::NamedType* type) {
|
|||
}
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ConvertType(uint32_t type_id,
|
||||
const Type* ParserImpl::ConvertType(uint32_t type_id,
|
||||
const spvtools::opt::analysis::Pointer*) {
|
||||
const auto* inst = def_use_mgr_->GetDef(type_id);
|
||||
const auto pointee_type_id = inst->GetSingleWordInOperand(1);
|
||||
|
@ -1080,8 +1081,7 @@ ast::Type* ParserImpl::ConvertType(uint32_t type_id,
|
|||
}
|
||||
}
|
||||
|
||||
ast_elem_ty = builder_.ty.MaybeCreateTypename(ast_elem_ty);
|
||||
return builder_.ty.pointer(ast_elem_ty, ast_storage_class);
|
||||
return ty_.Pointer(ast_elem_ty, ast_storage_class);
|
||||
}
|
||||
|
||||
bool ParserImpl::RegisterTypes() {
|
||||
|
@ -1114,7 +1114,7 @@ bool ParserImpl::EmitScalarSpecConstants() {
|
|||
// that is OpSpecConstantTrue, OpSpecConstantFalse, or OpSpecConstant.
|
||||
for (auto& inst : module_->types_values()) {
|
||||
// These will be populated for a valid scalar spec constant.
|
||||
ast::Type* ast_type = nullptr;
|
||||
const Type* ast_type = nullptr;
|
||||
ast::ScalarConstructorExpression* ast_expr = nullptr;
|
||||
|
||||
switch (inst.opcode()) {
|
||||
|
@ -1129,15 +1129,15 @@ bool ParserImpl::EmitScalarSpecConstants() {
|
|||
case SpvOpSpecConstant: {
|
||||
ast_type = ConvertType(inst.type_id());
|
||||
const uint32_t literal_value = inst.GetSingleWordInOperand(0);
|
||||
if (ast_type->Is<ast::I32>()) {
|
||||
if (ast_type->Is<I32>()) {
|
||||
ast_expr = create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::SintLiteral>(
|
||||
Source{}, static_cast<int32_t>(literal_value)));
|
||||
} else if (ast_type->Is<ast::U32>()) {
|
||||
} else if (ast_type->Is<U32>()) {
|
||||
ast_expr = create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::UintLiteral>(
|
||||
Source{}, static_cast<uint32_t>(literal_value)));
|
||||
} else if (ast_type->Is<ast::F32>()) {
|
||||
} else if (ast_type->Is<F32>()) {
|
||||
float float_value;
|
||||
// Copy the bits so we can read them as a float.
|
||||
std::memcpy(&float_value, &literal_value, sizeof(float_value));
|
||||
|
@ -1173,12 +1173,12 @@ bool ParserImpl::EmitScalarSpecConstants() {
|
|||
return success_;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::MaybeGenerateAlias(
|
||||
const Type* ParserImpl::MaybeGenerateAlias(
|
||||
uint32_t type_id,
|
||||
const spvtools::opt::analysis::Type* type,
|
||||
ast::Type* ast_type) {
|
||||
const Type* ast_type) {
|
||||
if (!success_) {
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We only care about arrays, and runtime arrays.
|
||||
|
@ -1202,16 +1202,17 @@ ast::Type* ParserImpl::MaybeGenerateAlias(
|
|||
auto* ast_underlying_type = ast_type;
|
||||
if (ast_underlying_type == nullptr) {
|
||||
Fail() << "internal error: no type registered for SPIR-V ID: " << type_id;
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
const auto name = namer_.GetName(type_id);
|
||||
const auto sym = builder_.Symbols().Register(name);
|
||||
auto ast_alias_type = builder_.ty.alias(sym, ast_underlying_type);
|
||||
auto ast_alias_type =
|
||||
builder_.ty.alias(sym, ast_underlying_type->Build(builder_));
|
||||
|
||||
// Record this new alias as the AST type for this SPIR-V ID.
|
||||
AddConstructedType(sym, ast_alias_type);
|
||||
|
||||
return ast_alias_type;
|
||||
return ty_.Alias(sym, ast_underlying_type);
|
||||
}
|
||||
|
||||
bool ParserImpl::EmitModuleScopeVariables() {
|
||||
|
@ -1252,7 +1253,7 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||
if (!success_) {
|
||||
return false;
|
||||
}
|
||||
ast::Type* ast_type;
|
||||
const Type* ast_type = nullptr;
|
||||
if (spirv_storage_class == SpvStorageClassUniformConstant) {
|
||||
// These are opaque handles: samplers or textures
|
||||
ast_type = GetTypeForHandleVar(var);
|
||||
|
@ -1266,14 +1267,14 @@ bool ParserImpl::EmitModuleScopeVariables() {
|
|||
"SPIR-V type with ID: "
|
||||
<< var.type_id();
|
||||
}
|
||||
if (!ast_type->Is<ast::Pointer>()) {
|
||||
if (!ast_type->Is<Pointer>()) {
|
||||
return Fail() << "variable with ID " << var.result_id()
|
||||
<< " has non-pointer type " << var.type_id();
|
||||
}
|
||||
}
|
||||
|
||||
auto* ast_store_type = ast_type->As<ast::Pointer>()->type();
|
||||
auto ast_storage_class = ast_type->As<ast::Pointer>()->storage_class();
|
||||
auto* ast_store_type = ast_type->As<Pointer>()->type;
|
||||
auto ast_storage_class = ast_type->As<Pointer>()->storage_class;
|
||||
ast::Expression* ast_constructor = nullptr;
|
||||
if (var.NumInOperands() > 1) {
|
||||
// SPIR-V initializers are always constants.
|
||||
|
@ -1336,7 +1337,7 @@ const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(
|
|||
|
||||
ast::Variable* ParserImpl::MakeVariable(uint32_t id,
|
||||
ast::StorageClass sc,
|
||||
ast::Type* type,
|
||||
const Type* type,
|
||||
bool is_const,
|
||||
ast::Expression* constructor,
|
||||
ast::DecorationList decorations) {
|
||||
|
@ -1347,14 +1348,14 @@ ast::Variable* ParserImpl::MakeVariable(uint32_t id,
|
|||
|
||||
if (sc == ast::StorageClass::kStorage) {
|
||||
bool read_only = false;
|
||||
if (auto* tn = type->As<ast::TypeName>()) {
|
||||
read_only = read_only_struct_types_.count(tn->name()) > 0;
|
||||
if (auto* tn = type->As<Named>()) {
|
||||
read_only = read_only_struct_types_.count(tn->name) > 0;
|
||||
}
|
||||
|
||||
// Apply the access(read) or access(read_write) modifier.
|
||||
auto access = read_only ? ast::AccessControl::kReadOnly
|
||||
: ast::AccessControl::kReadWrite;
|
||||
type = builder_.ty.access(access, type);
|
||||
type = ty_.AccessControl(type, access);
|
||||
}
|
||||
|
||||
for (auto& deco : GetDecorationsFor(id)) {
|
||||
|
@ -1396,7 +1397,7 @@ ast::Variable* ParserImpl::MakeVariable(uint32_t id,
|
|||
"SampleMask must be an array of 1 element.";
|
||||
}
|
||||
special_builtins_[id] = spv_builtin;
|
||||
type = builder_.ty.u32();
|
||||
type = ty_.U32();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -1439,8 +1440,8 @@ ast::Variable* ParserImpl::MakeVariable(uint32_t id,
|
|||
|
||||
std::string name = namer_.Name(id);
|
||||
return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
|
||||
builder_.ty.MaybeCreateTypename(type), is_const,
|
||||
constructor, decorations);
|
||||
type->Build(builder_), is_const, constructor,
|
||||
decorations);
|
||||
}
|
||||
|
||||
TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
||||
|
@ -1476,26 +1477,26 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
|||
// So canonicalization should map that way too.
|
||||
// Currently "null<type>" is missing from the WGSL parser.
|
||||
// See https://bugs.chromium.org/p/tint/issues/detail?id=34
|
||||
if (ast_type->Is<ast::U32>()) {
|
||||
return {ast_type, create<ast::ScalarConstructorExpression>(
|
||||
if (ast_type->Is<U32>()) {
|
||||
return {ty_.U32(), create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::UintLiteral>(
|
||||
source, spirv_const->GetU32()))};
|
||||
}
|
||||
if (ast_type->Is<ast::I32>()) {
|
||||
return {ast_type, create<ast::ScalarConstructorExpression>(
|
||||
if (ast_type->Is<I32>()) {
|
||||
return {ty_.I32(), create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::SintLiteral>(
|
||||
source, spirv_const->GetS32()))};
|
||||
}
|
||||
if (ast_type->Is<ast::F32>()) {
|
||||
return {ast_type, create<ast::ScalarConstructorExpression>(
|
||||
if (ast_type->Is<F32>()) {
|
||||
return {ty_.F32(), create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::FloatLiteral>(
|
||||
source, spirv_const->GetFloat()))};
|
||||
}
|
||||
if (ast_type->Is<ast::Bool>()) {
|
||||
if (ast_type->Is<Bool>()) {
|
||||
const bool value = spirv_const->AsNullConstant()
|
||||
? false
|
||||
: spirv_const->AsBoolConstant()->value();
|
||||
return {ast_type, create<ast::ScalarConstructorExpression>(
|
||||
return {ty_.Bool(), create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::BoolLiteral>(source, value))};
|
||||
}
|
||||
auto* spirv_composite_const = spirv_const->AsCompositeConstant();
|
||||
|
@ -1521,9 +1522,8 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
|||
}
|
||||
ast_components.emplace_back(ast_component.expr);
|
||||
}
|
||||
return {original_ast_type,
|
||||
create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(original_ast_type),
|
||||
return {original_ast_type, create<ast::TypeConstructorExpression>(
|
||||
Source{}, original_ast_type->Build(builder_),
|
||||
std::move(ast_components))};
|
||||
}
|
||||
auto* spirv_null_const = spirv_const->AsNullConstant();
|
||||
|
@ -1535,7 +1535,7 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
|
|||
return {};
|
||||
}
|
||||
|
||||
ast::Expression* ParserImpl::MakeNullValue(ast::Type* type) {
|
||||
ast::Expression* ParserImpl::MakeNullValue(const Type* type) {
|
||||
// TODO(dneto): Use the no-operands constructor syntax when it becomes
|
||||
// available in Tint.
|
||||
// https://github.com/gpuweb/gpuweb/issues/685
|
||||
|
@ -1549,93 +1549,89 @@ ast::Expression* ParserImpl::MakeNullValue(ast::Type* type) {
|
|||
auto* original_type = type;
|
||||
type = type->UnwrapIfNeeded();
|
||||
|
||||
if (type->Is<ast::Bool>()) {
|
||||
if (type->Is<Bool>()) {
|
||||
return create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::BoolLiteral>(Source{}, false));
|
||||
}
|
||||
if (type->Is<ast::U32>()) {
|
||||
if (type->Is<U32>()) {
|
||||
return create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::UintLiteral>(Source{}, 0u));
|
||||
}
|
||||
if (type->Is<ast::I32>()) {
|
||||
if (type->Is<I32>()) {
|
||||
return create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::SintLiteral>(Source{}, 0));
|
||||
}
|
||||
if (type->Is<ast::F32>()) {
|
||||
if (type->Is<F32>()) {
|
||||
return create<ast::ScalarConstructorExpression>(
|
||||
Source{}, create<ast::FloatLiteral>(Source{}, 0.0f));
|
||||
}
|
||||
if (type->Is<ast::TypeName>()) {
|
||||
if (type->Is<Alias>()) {
|
||||
// TODO(amaiorano): No type constructor for TypeName (yet?)
|
||||
ast::ExpressionList ast_components;
|
||||
return create<ast::TypeConstructorExpression>(Source{}, original_type,
|
||||
std::move(ast_components));
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
Source{}, original_type->Build(builder_), std::move(ast_components));
|
||||
}
|
||||
if (auto* vec_ty = type->As<ast::Vector>()) {
|
||||
if (auto* vec_ty = type->As<Vector>()) {
|
||||
ast::ExpressionList ast_components;
|
||||
for (size_t i = 0; i < vec_ty->size(); ++i) {
|
||||
ast_components.emplace_back(MakeNullValue(vec_ty->type()));
|
||||
for (size_t i = 0; i < vec_ty->size; ++i) {
|
||||
ast_components.emplace_back(MakeNullValue(vec_ty->type));
|
||||
}
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(type),
|
||||
std::move(ast_components));
|
||||
Source{}, type->Build(builder_), std::move(ast_components));
|
||||
}
|
||||
if (auto* mat_ty = type->As<ast::Matrix>()) {
|
||||
if (auto* mat_ty = type->As<Matrix>()) {
|
||||
// Matrix components are columns
|
||||
auto column_ty = builder_.ty.vec(mat_ty->type(), mat_ty->rows());
|
||||
auto* column_ty = ty_.Vector(mat_ty->type, mat_ty->rows);
|
||||
ast::ExpressionList ast_components;
|
||||
for (size_t i = 0; i < mat_ty->columns(); ++i) {
|
||||
for (size_t i = 0; i < mat_ty->columns; ++i) {
|
||||
ast_components.emplace_back(MakeNullValue(column_ty));
|
||||
}
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(type),
|
||||
std::move(ast_components));
|
||||
Source{}, type->Build(builder_), std::move(ast_components));
|
||||
}
|
||||
if (auto* arr_ty = type->As<ast::Array>()) {
|
||||
if (auto* arr_ty = type->As<Array>()) {
|
||||
ast::ExpressionList ast_components;
|
||||
for (size_t i = 0; i < arr_ty->size(); ++i) {
|
||||
ast_components.emplace_back(MakeNullValue(arr_ty->type()));
|
||||
for (size_t i = 0; i < arr_ty->size; ++i) {
|
||||
ast_components.emplace_back(MakeNullValue(arr_ty->type));
|
||||
}
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(original_type),
|
||||
std::move(ast_components));
|
||||
Source{}, original_type->Build(builder_), std::move(ast_components));
|
||||
}
|
||||
if (auto* struct_ty = type->As<ast::Struct>()) {
|
||||
if (auto* struct_ty = type->As<Struct>()) {
|
||||
ast::ExpressionList ast_components;
|
||||
for (auto* member : struct_ty->members()) {
|
||||
ast_components.emplace_back(MakeNullValue(member->type()));
|
||||
for (auto* member : struct_ty->members) {
|
||||
ast_components.emplace_back(MakeNullValue(member));
|
||||
}
|
||||
return create<ast::TypeConstructorExpression>(
|
||||
Source{}, builder_.ty.MaybeCreateTypename(original_type),
|
||||
std::move(ast_components));
|
||||
Source{}, original_type->Build(builder_), std::move(ast_components));
|
||||
}
|
||||
Fail() << "can't make null value for type: " << type->type_name();
|
||||
Fail() << "can't make null value for type: " << type->TypeInfo().name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedExpression ParserImpl::MakeNullExpression(ast::Type* type) {
|
||||
TypedExpression ParserImpl::MakeNullExpression(const Type* type) {
|
||||
return {type, MakeNullValue(type)};
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::UnsignedTypeFor(ast::Type* type) {
|
||||
if (type->Is<ast::I32>()) {
|
||||
return builder_.ty.u32();
|
||||
const Type* ParserImpl::UnsignedTypeFor(const Type* type) {
|
||||
if (type->Is<I32>()) {
|
||||
return ty_.U32();
|
||||
}
|
||||
if (auto* v = type->As<ast::Vector>()) {
|
||||
if (v->type()->Is<ast::I32>()) {
|
||||
return builder_.ty.vec(builder_.ty.u32(), v->size());
|
||||
if (auto* v = type->As<Vector>()) {
|
||||
if (v->type->Is<I32>()) {
|
||||
return ty_.Vector(ty_.U32(), v->size);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::SignedTypeFor(ast::Type* type) {
|
||||
if (type->Is<ast::U32>()) {
|
||||
return builder_.ty.i32();
|
||||
const Type* ParserImpl::SignedTypeFor(const Type* type) {
|
||||
if (type->Is<U32>()) {
|
||||
return ty_.I32();
|
||||
}
|
||||
if (auto* v = type->As<ast::Vector>()) {
|
||||
if (v->type()->Is<ast::U32>()) {
|
||||
return builder_.ty.vec(builder_.ty.i32(), v->size());
|
||||
if (auto* v = type->As<Vector>()) {
|
||||
if (v->type->Is<U32>()) {
|
||||
return ty_.Vector(ty_.I32(), v->size);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
@ -1674,13 +1670,14 @@ TypedExpression ParserImpl::RectifyOperandSignedness(
|
|||
if (auto* unsigned_ty = UnsignedTypeFor(type)) {
|
||||
// Conversion is required.
|
||||
return {unsigned_ty,
|
||||
create<ast::BitcastExpression>(Source{}, unsigned_ty, expr.expr)};
|
||||
create<ast::BitcastExpression>(
|
||||
Source{}, unsigned_ty->Build(builder_), expr.expr)};
|
||||
}
|
||||
} else if (requires_signed) {
|
||||
if (auto* signed_ty = SignedTypeFor(type)) {
|
||||
// Conversion is required.
|
||||
return {signed_ty,
|
||||
create<ast::BitcastExpression>(Source{}, signed_ty, expr.expr)};
|
||||
return {signed_ty, create<ast::BitcastExpression>(
|
||||
Source{}, signed_ty->Build(builder_), expr.expr)};
|
||||
}
|
||||
}
|
||||
// We should not reach here.
|
||||
|
@ -1689,21 +1686,22 @@ TypedExpression ParserImpl::RectifyOperandSignedness(
|
|||
|
||||
TypedExpression ParserImpl::RectifySecondOperandSignedness(
|
||||
const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type,
|
||||
const Type* first_operand_type,
|
||||
TypedExpression&& second_operand_expr) {
|
||||
if (!AstTypesEquivalent(first_operand_type, second_operand_expr.type) &&
|
||||
if ((first_operand_type != second_operand_expr.type) &&
|
||||
AssumesSecondOperandSignednessMatchesFirstOperand(inst.opcode())) {
|
||||
// Conversion is required.
|
||||
return {first_operand_type,
|
||||
create<ast::BitcastExpression>(Source{}, first_operand_type,
|
||||
create<ast::BitcastExpression>(Source{},
|
||||
first_operand_type->Build(builder_),
|
||||
second_operand_expr.expr)};
|
||||
}
|
||||
// No conversion necessary.
|
||||
return std::move(second_operand_expr);
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type) {
|
||||
const Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
|
||||
const Type* first_operand_type) {
|
||||
const auto opcode = inst.opcode();
|
||||
if (AssumesResultSignednessMatchesFirstOperand(opcode)) {
|
||||
return first_operand_type;
|
||||
|
@ -1718,66 +1716,63 @@ ast::Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::GetSignedIntMatchingShape(ast::Type* other) {
|
||||
const Type* ParserImpl::GetSignedIntMatchingShape(const Type* other) {
|
||||
if (other == nullptr) {
|
||||
Fail() << "no type provided";
|
||||
}
|
||||
auto i32 = builder_.ty.i32();
|
||||
if (other->Is<ast::F32>() || other->Is<ast::U32>() || other->Is<ast::I32>()) {
|
||||
return i32;
|
||||
if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
|
||||
return ty_.I32();
|
||||
}
|
||||
auto* vec_ty = other->As<ast::Vector>();
|
||||
if (vec_ty) {
|
||||
return builder_.ty.vec(i32, vec_ty->size());
|
||||
if (auto* vec_ty = other->As<Vector>()) {
|
||||
return ty_.Vector(ty_.I32(), vec_ty->size);
|
||||
}
|
||||
Fail() << "required numeric scalar or vector, but got " << other->type_name();
|
||||
Fail() << "required numeric scalar or vector, but got "
|
||||
<< other->TypeInfo().name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::GetUnsignedIntMatchingShape(ast::Type* other) {
|
||||
const Type* ParserImpl::GetUnsignedIntMatchingShape(const Type* other) {
|
||||
if (other == nullptr) {
|
||||
Fail() << "no type provided";
|
||||
return nullptr;
|
||||
}
|
||||
auto u32 = builder_.ty.u32();
|
||||
if (other->Is<ast::F32>() || other->Is<ast::U32>() || other->Is<ast::I32>()) {
|
||||
return u32;
|
||||
if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
|
||||
return ty_.U32();
|
||||
}
|
||||
auto* vec_ty = other->As<ast::Vector>();
|
||||
if (vec_ty) {
|
||||
return builder_.ty.vec(u32, vec_ty->size());
|
||||
if (auto* vec_ty = other->As<Vector>()) {
|
||||
return ty_.Vector(ty_.U32(), vec_ty->size);
|
||||
}
|
||||
Fail() << "required numeric scalar or vector, but got " << other->type_name();
|
||||
Fail() << "required numeric scalar or vector, but got "
|
||||
<< other->TypeInfo().name;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypedExpression ParserImpl::RectifyForcedResultType(
|
||||
TypedExpression expr,
|
||||
const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type) {
|
||||
const Type* first_operand_type) {
|
||||
auto* forced_result_ty = ForcedResultType(inst, first_operand_type);
|
||||
if ((forced_result_ty == nullptr) ||
|
||||
AstTypesEquivalent(forced_result_ty, expr.type)) {
|
||||
if ((!forced_result_ty) || (forced_result_ty == expr.type)) {
|
||||
return expr;
|
||||
}
|
||||
return {expr.type,
|
||||
create<ast::BitcastExpression>(Source{}, expr.type, expr.expr)};
|
||||
return {expr.type, create<ast::BitcastExpression>(
|
||||
Source{}, expr.type->Build(builder_), expr.expr)};
|
||||
}
|
||||
|
||||
TypedExpression ParserImpl::AsUnsigned(TypedExpression expr) {
|
||||
if (expr.type && expr.type->is_signed_scalar_or_vector()) {
|
||||
if (expr.type && expr.type->IsSignedScalarOrVector()) {
|
||||
auto* new_type = GetUnsignedIntMatchingShape(expr.type);
|
||||
return {new_type,
|
||||
create<ast::BitcastExpression>(Source{}, new_type, expr.expr)};
|
||||
return {new_type, create<ast::BitcastExpression>(
|
||||
Source{}, new_type->Build(builder_), expr.expr)};
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
TypedExpression ParserImpl::AsSigned(TypedExpression expr) {
|
||||
if (expr.type && expr.type->is_unsigned_scalar_or_vector()) {
|
||||
if (expr.type && expr.type->IsUnsignedScalarOrVector()) {
|
||||
auto* new_type = GetSignedIntMatchingShape(expr.type);
|
||||
return {new_type,
|
||||
create<ast::BitcastExpression>(Source{}, new_type, expr.expr)};
|
||||
return {new_type, create<ast::BitcastExpression>(
|
||||
Source{}, new_type->Build(builder_), expr.expr)};
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
@ -1952,7 +1947,7 @@ ParserImpl::GetSpirvTypeForHandleMemoryObjectDeclaration(
|
|||
return raw_handle_type;
|
||||
}
|
||||
|
||||
ast::Pointer* ParserImpl::GetTypeForHandleVar(
|
||||
const Pointer* ParserImpl::GetTypeForHandleVar(
|
||||
const spvtools::opt::Instruction& var) {
|
||||
auto where = handle_type_.find(&var);
|
||||
if (where != handle_type_.end()) {
|
||||
|
@ -2036,10 +2031,10 @@ ast::Pointer* ParserImpl::GetTypeForHandleVar(
|
|||
}
|
||||
|
||||
// Construct the Tint handle type.
|
||||
ast::Type* ast_store_type;
|
||||
const Type* ast_store_type = nullptr;
|
||||
if (usage.IsSampler()) {
|
||||
ast_store_type = builder_.ty.sampler(
|
||||
usage.IsComparisonSampler() ? ast::SamplerKind::kComparisonSampler
|
||||
ast_store_type = ty_.Sampler(usage.IsComparisonSampler()
|
||||
? ast::SamplerKind::kComparisonSampler
|
||||
: ast::SamplerKind::kSampler);
|
||||
} else if (usage.IsTexture()) {
|
||||
const spvtools::opt::analysis::Image* image_type =
|
||||
|
@ -2069,14 +2064,13 @@ ast::Pointer* ParserImpl::GetTypeForHandleVar(
|
|||
// OpImage variable with an OpImage*Dref* instruction. In WGSL we must
|
||||
// treat that as a depth texture.
|
||||
if (image_type->depth() || usage.IsDepthTexture()) {
|
||||
ast_store_type = builder_.ty.depth_texture(dim);
|
||||
ast_store_type = ty_.DepthTexture(dim);
|
||||
} else if (image_type->is_multisampled()) {
|
||||
// Multisampled textures are never depth textures.
|
||||
ast_store_type =
|
||||
builder_.ty.multisampled_texture(dim, ast_sampled_component_type);
|
||||
ty_.MultisampledTexture(dim, ast_sampled_component_type);
|
||||
} else {
|
||||
ast_store_type =
|
||||
builder_.ty.sampled_texture(dim, ast_sampled_component_type);
|
||||
ast_store_type = ty_.SampledTexture(dim, ast_sampled_component_type);
|
||||
}
|
||||
} else {
|
||||
const auto access = usage.IsStorageReadTexture()
|
||||
|
@ -2087,7 +2081,7 @@ ast::Pointer* ParserImpl::GetTypeForHandleVar(
|
|||
return nullptr;
|
||||
}
|
||||
ast_store_type =
|
||||
builder_.ty.access(access, builder_.ty.storage_texture(dim, format));
|
||||
ty_.AccessControl(ty_.StorageTexture(dim, format), access);
|
||||
}
|
||||
} else {
|
||||
Fail() << "unsupported: UniformConstant variable is not a recognized "
|
||||
|
@ -2097,14 +2091,14 @@ ast::Pointer* ParserImpl::GetTypeForHandleVar(
|
|||
}
|
||||
|
||||
// Form the pointer type.
|
||||
auto result =
|
||||
builder_.ty.pointer(ast_store_type, ast::StorageClass::kUniformConstant);
|
||||
auto* result =
|
||||
ty_.Pointer(ast_store_type, ast::StorageClass::kUniformConstant);
|
||||
// Remember it for later.
|
||||
handle_type_[&var] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
||||
const Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
||||
switch (format) {
|
||||
case ast::ImageFormat::kR8Uint:
|
||||
case ast::ImageFormat::kR16Uint:
|
||||
|
@ -2115,7 +2109,7 @@ ast::Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
|||
case ast::ImageFormat::kRg32Uint:
|
||||
case ast::ImageFormat::kRgba16Uint:
|
||||
case ast::ImageFormat::kRgba32Uint:
|
||||
return builder_.ty.u32();
|
||||
return ty_.U32();
|
||||
|
||||
case ast::ImageFormat::kR8Sint:
|
||||
case ast::ImageFormat::kR16Sint:
|
||||
|
@ -2126,7 +2120,7 @@ ast::Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
|||
case ast::ImageFormat::kRg32Sint:
|
||||
case ast::ImageFormat::kRgba16Sint:
|
||||
case ast::ImageFormat::kRgba32Sint:
|
||||
return builder_.ty.i32();
|
||||
return ty_.I32();
|
||||
|
||||
case ast::ImageFormat::kR8Unorm:
|
||||
case ast::ImageFormat::kRg8Unorm:
|
||||
|
@ -2145,7 +2139,7 @@ ast::Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
|||
case ast::ImageFormat::kRg32Float:
|
||||
case ast::ImageFormat::kRgba16Float:
|
||||
case ast::ImageFormat::kRgba32Float:
|
||||
return builder_.ty.f32();
|
||||
return ty_.F32();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -2153,7 +2147,7 @@ ast::Type* ParserImpl::GetComponentTypeForFormat(ast::ImageFormat format) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ast::Type* ParserImpl::GetTexelTypeForFormat(ast::ImageFormat format) {
|
||||
const Type* ParserImpl::GetTexelTypeForFormat(ast::ImageFormat format) {
|
||||
auto* component_type = GetComponentTypeForFormat(format);
|
||||
if (!component_type) {
|
||||
return nullptr;
|
||||
|
@ -2185,7 +2179,7 @@ ast::Type* ParserImpl::GetTexelTypeForFormat(ast::ImageFormat format) {
|
|||
case ast::ImageFormat::kRg8Uint:
|
||||
case ast::ImageFormat::kRg8Unorm:
|
||||
// Two channels
|
||||
return builder_.ty.vec(component_type, 2);
|
||||
return ty_.Vector(component_type, 2);
|
||||
|
||||
case ast::ImageFormat::kBgra8Unorm:
|
||||
case ast::ImageFormat::kBgra8UnormSrgb:
|
||||
|
@ -2202,7 +2196,7 @@ ast::Type* ParserImpl::GetTexelTypeForFormat(ast::ImageFormat format) {
|
|||
case ast::ImageFormat::kRgba8Unorm:
|
||||
case ast::ImageFormat::kRgba8UnormSrgb:
|
||||
// Four channels
|
||||
return builder_.ty.vec(component_type, 4);
|
||||
return ty_.Vector(component_type, 4);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "src/reader/spirv/entry_point_info.h"
|
||||
#include "src/reader/spirv/enum_converter.h"
|
||||
#include "src/reader/spirv/namer.h"
|
||||
#include "src/reader/spirv/parser_type.h"
|
||||
#include "src/reader/spirv/usage.h"
|
||||
|
||||
/// This is the implementation of the SPIR-V parser for Tint.
|
||||
|
@ -51,14 +52,6 @@ namespace tint {
|
|||
namespace reader {
|
||||
namespace spirv {
|
||||
|
||||
/// Returns true of the two input ast types are semantically equivalent
|
||||
/// @param lhs first type to compare
|
||||
/// @param rhs other type to compare
|
||||
/// @returns true if both types are semantically equivalent
|
||||
inline bool AstTypesEquivalent(ast::Type* lhs, ast::Type* rhs) {
|
||||
return lhs->type_name() == rhs->type_name();
|
||||
}
|
||||
|
||||
/// The binary representation of a SPIR-V decoration enum followed by its
|
||||
/// operands, if any.
|
||||
/// Example: { SpvDecorationBlock }
|
||||
|
@ -81,10 +74,10 @@ struct TypedExpression {
|
|||
/// Constructor
|
||||
/// @param type_in the type of the expression
|
||||
/// @param expr_in the expression
|
||||
TypedExpression(ast::Type* type_in, ast::Expression* expr_in);
|
||||
TypedExpression(const Type* type_in, ast::Expression* expr_in);
|
||||
|
||||
/// The type
|
||||
ast::Type* type;
|
||||
Type const* type = nullptr;
|
||||
/// The expression
|
||||
ast::Expression* expr = nullptr;
|
||||
};
|
||||
|
@ -110,6 +103,9 @@ class ParserImpl : Reader {
|
|||
/// program. To be used only for testing.
|
||||
ProgramBuilder& builder() { return builder_; }
|
||||
|
||||
/// @returns the type manager
|
||||
TypeManager& type_manager() { return ty_; }
|
||||
|
||||
/// Logs failure, ands return a failure stream to accumulate diagnostic
|
||||
/// messages. By convention, a failure should only be logged along with
|
||||
/// a non-empty string diagnostic.
|
||||
|
@ -163,7 +159,7 @@ class ParserImpl : Reader {
|
|||
/// after the internal representation of the module has been built.
|
||||
/// @param type_id the SPIR-V ID of a type.
|
||||
/// @returns a Tint type, or nullptr
|
||||
ast::Type* ConvertType(uint32_t type_id);
|
||||
const Type* ConvertType(uint32_t type_id);
|
||||
|
||||
/// Emits an alias type declaration for the given type, if necessary, and
|
||||
/// also updates the mapping of the SPIR-V type ID to the alias type.
|
||||
|
@ -176,9 +172,9 @@ class ParserImpl : Reader {
|
|||
/// @param type the type that might get an alias
|
||||
/// @param ast_type the ast type that might get an alias
|
||||
/// @returns an alias type or `ast_type` if no alias was created
|
||||
ast::Type* MaybeGenerateAlias(uint32_t type_id,
|
||||
const Type* MaybeGenerateAlias(uint32_t type_id,
|
||||
const spvtools::opt::analysis::Type* type,
|
||||
ast::Type* ast_type);
|
||||
const Type* ast_type);
|
||||
|
||||
/// @returns the fail stream object
|
||||
FailStream& fail_stream() { return fail_stream_; }
|
||||
|
@ -328,7 +324,7 @@ class ParserImpl : Reader {
|
|||
/// in the error case
|
||||
ast::Variable* MakeVariable(uint32_t id,
|
||||
ast::StorageClass sc,
|
||||
ast::Type* type,
|
||||
const Type* type,
|
||||
bool is_const,
|
||||
ast::Expression* constructor,
|
||||
ast::DecorationList decorations);
|
||||
|
@ -341,12 +337,12 @@ class ParserImpl : Reader {
|
|||
/// Creates an AST expression node for the null value for the given type.
|
||||
/// @param type the AST type
|
||||
/// @returns a new expression
|
||||
ast::Expression* MakeNullValue(ast::Type* type);
|
||||
ast::Expression* MakeNullValue(const Type* type);
|
||||
|
||||
/// Make a typed expression for the null value for the given type.
|
||||
/// @param type the AST type
|
||||
/// @returns a new typed expression
|
||||
TypedExpression MakeNullExpression(ast::Type* type);
|
||||
TypedExpression MakeNullExpression(const Type* type);
|
||||
|
||||
/// Converts a given expression to the signedness demanded for an operand
|
||||
/// of the given SPIR-V instruction, if required. If the instruction assumes
|
||||
|
@ -371,7 +367,7 @@ class ParserImpl : Reader {
|
|||
/// @returns second_operand_expr, or a cast of it
|
||||
TypedExpression RectifySecondOperandSignedness(
|
||||
const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type,
|
||||
const Type* first_operand_type,
|
||||
TypedExpression&& second_operand_expr);
|
||||
|
||||
/// Returns the "forced" result type for the given SPIR-V instruction.
|
||||
|
@ -382,8 +378,8 @@ class ParserImpl : Reader {
|
|||
/// @param inst the SPIR-V instruction
|
||||
/// @param first_operand_type the AST type for the first operand.
|
||||
/// @returns the forced AST result type, or nullptr if no forcing is required.
|
||||
ast::Type* ForcedResultType(const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type);
|
||||
const Type* ForcedResultType(const spvtools::opt::Instruction& inst,
|
||||
const Type* first_operand_type);
|
||||
|
||||
/// Returns a signed integer scalar or vector type matching the shape (scalar,
|
||||
/// vector, and component bit width) of another type, which itself is a
|
||||
|
@ -391,7 +387,7 @@ class ParserImpl : Reader {
|
|||
/// requirement.
|
||||
/// @param other the type whose shape must be matched
|
||||
/// @returns the signed scalar or vector type
|
||||
ast::Type* GetSignedIntMatchingShape(ast::Type* other);
|
||||
const Type* GetSignedIntMatchingShape(const Type* other);
|
||||
|
||||
/// Returns a signed integer scalar or vector type matching the shape (scalar,
|
||||
/// vector, and component bit width) of another type, which itself is a
|
||||
|
@ -399,7 +395,7 @@ class ParserImpl : Reader {
|
|||
/// requirement.
|
||||
/// @param other the type whose shape must be matched
|
||||
/// @returns the unsigned scalar or vector type
|
||||
ast::Type* GetUnsignedIntMatchingShape(ast::Type* other);
|
||||
const Type* GetUnsignedIntMatchingShape(const Type* other);
|
||||
|
||||
/// Wraps the given expression in an as-cast to the given expression's type,
|
||||
/// when the underlying operation produces a forced result type different
|
||||
|
@ -412,18 +408,20 @@ class ParserImpl : Reader {
|
|||
TypedExpression RectifyForcedResultType(
|
||||
TypedExpression expr,
|
||||
const spvtools::opt::Instruction& inst,
|
||||
ast::Type* first_operand_type);
|
||||
const Type* first_operand_type);
|
||||
|
||||
/// @returns the given expression, but ensuring it's an unsigned type of the
|
||||
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||
/// Returns the given expression, but ensuring it's an unsigned type of the
|
||||
/// same shape as the operand. Wraps the expression with a bitcast if needed.
|
||||
/// Assumes the given expresion is a integer scalar or vector.
|
||||
/// @param expr an integer scalar or integer vector expression.
|
||||
/// @return the potentially cast TypedExpression
|
||||
TypedExpression AsUnsigned(TypedExpression expr);
|
||||
|
||||
/// @returns the given expression, but ensuring it's a signed type of the
|
||||
/// same shape as the operand. Wraps the expresion with a bitcast if needed.
|
||||
/// Returns the given expression, but ensuring it's a signed type of the
|
||||
/// same shape as the operand. Wraps the expression with a bitcast if needed.
|
||||
/// Assumes the given expresion is a integer scalar or vector.
|
||||
/// @param expr an integer scalar or integer vector expression.
|
||||
/// @return the potentially cast TypedExpression
|
||||
TypedExpression AsSigned(TypedExpression expr);
|
||||
|
||||
/// Bookkeeping used for tracking the "position" builtin variable.
|
||||
|
@ -512,18 +510,18 @@ class ParserImpl : Reader {
|
|||
/// @param var the OpVariable instruction
|
||||
/// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
|
||||
/// error
|
||||
ast::Pointer* GetTypeForHandleVar(const spvtools::opt::Instruction& var);
|
||||
const Pointer* GetTypeForHandleVar(const spvtools::opt::Instruction& var);
|
||||
|
||||
/// Returns the channel component type corresponding to the given image
|
||||
/// format.
|
||||
/// @param format image texel format
|
||||
/// @returns the component type, one of f32, i32, u32
|
||||
ast::Type* GetComponentTypeForFormat(ast::ImageFormat format);
|
||||
const Type* GetComponentTypeForFormat(ast::ImageFormat format);
|
||||
|
||||
/// Returns texel type corresponding to the given image format.
|
||||
/// @param format image texel format
|
||||
/// @returns the texel format
|
||||
ast::Type* GetTexelTypeForFormat(ast::ImageFormat format);
|
||||
const Type* GetTexelTypeForFormat(ast::ImageFormat format);
|
||||
|
||||
/// Returns the SPIR-V instruction with the given ID, or nullptr.
|
||||
/// @param id the SPIR-V result ID
|
||||
|
@ -561,19 +559,20 @@ class ParserImpl : Reader {
|
|||
|
||||
private:
|
||||
/// Converts a specific SPIR-V type to a Tint type. Integer case
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
|
||||
const Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Float case
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::Float* float_ty);
|
||||
const Type* ConvertType(const spvtools::opt::analysis::Float* float_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Vector case
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::Vector* vec_ty);
|
||||
const Type* ConvertType(const spvtools::opt::analysis::Vector* vec_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Matrix case
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::Matrix* mat_ty);
|
||||
const Type* ConvertType(const spvtools::opt::analysis::Matrix* mat_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. RuntimeArray case
|
||||
/// @param rtarr_ty the Tint type
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::RuntimeArray* rtarr_ty);
|
||||
const Type* ConvertType(
|
||||
const spvtools::opt::analysis::RuntimeArray* rtarr_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Array case
|
||||
/// @param arr_ty the Tint type
|
||||
ast::Type* ConvertType(const spvtools::opt::analysis::Array* arr_ty);
|
||||
const Type* ConvertType(const spvtools::opt::analysis::Array* arr_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Struct case.
|
||||
/// SPIR-V allows distinct struct type definitions for two OpTypeStruct
|
||||
/// that otherwise have the same set of members (and struct and member
|
||||
|
@ -585,34 +584,34 @@ class ParserImpl : Reader {
|
|||
/// not significant to the optimizer's module representation.
|
||||
/// @param type_id the SPIR-V ID for the type.
|
||||
/// @param struct_ty the Tint type
|
||||
ast::Type* ConvertType(uint32_t type_id,
|
||||
const Type* ConvertType(uint32_t type_id,
|
||||
const spvtools::opt::analysis::Struct* struct_ty);
|
||||
/// Converts a specific SPIR-V type to a Tint type. Pointer case
|
||||
/// The pointer to gl_PerVertex maps to nullptr, and instead is recorded
|
||||
/// in member #builtin_position_.
|
||||
/// @param type_id the SPIR-V ID for the type.
|
||||
/// @param ptr_ty the Tint type
|
||||
ast::Type* ConvertType(uint32_t type_id,
|
||||
const Type* ConvertType(uint32_t type_id,
|
||||
const spvtools::opt::analysis::Pointer* ptr_ty);
|
||||
|
||||
/// If `type` is a signed integral, or vector of signed integral,
|
||||
/// returns the unsigned type, otherwise returns `type`.
|
||||
/// @param type the possibly signed type
|
||||
/// @returns the unsigned type
|
||||
ast::Type* UnsignedTypeFor(ast::Type* type);
|
||||
const Type* UnsignedTypeFor(const Type* type);
|
||||
|
||||
/// If `type` is a unsigned integral, or vector of unsigned integral,
|
||||
/// returns the signed type, otherwise returns `type`.
|
||||
/// @param type the possibly unsigned type
|
||||
/// @returns the signed type
|
||||
ast::Type* SignedTypeFor(ast::Type* type);
|
||||
const Type* SignedTypeFor(const Type* type);
|
||||
|
||||
/// Parses the array or runtime-array decorations.
|
||||
/// @param spv_type the SPIR-V array or runtime-array type.
|
||||
/// @param decorations the populated decoration list
|
||||
/// @param array_stride pointer to the array stride
|
||||
/// @returns true on success.
|
||||
bool ParseArrayDecorations(const spvtools::opt::analysis::Type* spv_type,
|
||||
ast::DecorationList* decorations);
|
||||
uint32_t* array_stride);
|
||||
|
||||
/// Adds `type` as a constructed type if it hasn't been added yet.
|
||||
/// @param name the type's unique name
|
||||
|
@ -633,6 +632,9 @@ class ParserImpl : Reader {
|
|||
// The program builder.
|
||||
ProgramBuilder builder_;
|
||||
|
||||
// The type manager.
|
||||
TypeManager ty_;
|
||||
|
||||
// Is the parse successful?
|
||||
bool success_ = true;
|
||||
// Collector for diagnostic messages.
|
||||
|
@ -716,7 +718,7 @@ class ParserImpl : Reader {
|
|||
// usages implied by usages of the memory-object-declaration.
|
||||
std::unordered_map<const spvtools::opt::Instruction*, Usage> handle_usage_;
|
||||
// The inferred pointer type for the given handle variable.
|
||||
std::unordered_map<const spvtools::opt::Instruction*, ast::Pointer*>
|
||||
std::unordered_map<const spvtools::opt::Instruction*, const Pointer*>
|
||||
handle_type_;
|
||||
|
||||
// Set of symbols of constructed types that have been added, used to avoid
|
||||
|
|
|
@ -75,7 +75,7 @@ TEST_F(SpvParserTest, ConvertType_Void) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(1);
|
||||
EXPECT_TRUE(type->Is<ast::Void>());
|
||||
EXPECT_TRUE(type->Is<Void>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ TEST_F(SpvParserTest, ConvertType_Bool) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(100);
|
||||
EXPECT_TRUE(type->Is<ast::Bool>());
|
||||
EXPECT_TRUE(type->Is<Bool>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ TEST_F(SpvParserTest, ConvertType_I32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(2);
|
||||
EXPECT_TRUE(type->Is<ast::I32>());
|
||||
EXPECT_TRUE(type->Is<I32>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ TEST_F(SpvParserTest, ConvertType_U32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::U32>());
|
||||
EXPECT_TRUE(type->Is<U32>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ TEST_F(SpvParserTest, ConvertType_F32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(4);
|
||||
EXPECT_TRUE(type->Is<ast::F32>());
|
||||
EXPECT_TRUE(type->Is<F32>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -155,19 +155,19 @@ TEST_F(SpvParserTest, ConvertType_VecOverF32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* v2xf32 = p->ConvertType(20);
|
||||
EXPECT_TRUE(v2xf32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v2xf32->As<ast::Vector>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(v2xf32->As<ast::Vector>()->size(), 2u);
|
||||
EXPECT_TRUE(v2xf32->Is<Vector>());
|
||||
EXPECT_TRUE(v2xf32->As<Vector>()->type->Is<F32>());
|
||||
EXPECT_EQ(v2xf32->As<Vector>()->size, 2u);
|
||||
|
||||
auto* v3xf32 = p->ConvertType(30);
|
||||
EXPECT_TRUE(v3xf32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v3xf32->As<ast::Vector>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(v3xf32->As<ast::Vector>()->size(), 3u);
|
||||
EXPECT_TRUE(v3xf32->Is<Vector>());
|
||||
EXPECT_TRUE(v3xf32->As<Vector>()->type->Is<F32>());
|
||||
EXPECT_EQ(v3xf32->As<Vector>()->size, 3u);
|
||||
|
||||
auto* v4xf32 = p->ConvertType(40);
|
||||
EXPECT_TRUE(v4xf32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v4xf32->As<ast::Vector>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(v4xf32->As<ast::Vector>()->size(), 4u);
|
||||
EXPECT_TRUE(v4xf32->Is<Vector>());
|
||||
EXPECT_TRUE(v4xf32->As<Vector>()->type->Is<F32>());
|
||||
EXPECT_EQ(v4xf32->As<Vector>()->size, 4u);
|
||||
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
@ -182,19 +182,19 @@ TEST_F(SpvParserTest, ConvertType_VecOverI32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* v2xi32 = p->ConvertType(20);
|
||||
EXPECT_TRUE(v2xi32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v2xi32->As<ast::Vector>()->type()->Is<ast::I32>());
|
||||
EXPECT_EQ(v2xi32->As<ast::Vector>()->size(), 2u);
|
||||
EXPECT_TRUE(v2xi32->Is<Vector>());
|
||||
EXPECT_TRUE(v2xi32->As<Vector>()->type->Is<I32>());
|
||||
EXPECT_EQ(v2xi32->As<Vector>()->size, 2u);
|
||||
|
||||
auto* v3xi32 = p->ConvertType(30);
|
||||
EXPECT_TRUE(v3xi32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v3xi32->As<ast::Vector>()->type()->Is<ast::I32>());
|
||||
EXPECT_EQ(v3xi32->As<ast::Vector>()->size(), 3u);
|
||||
EXPECT_TRUE(v3xi32->Is<Vector>());
|
||||
EXPECT_TRUE(v3xi32->As<Vector>()->type->Is<I32>());
|
||||
EXPECT_EQ(v3xi32->As<Vector>()->size, 3u);
|
||||
|
||||
auto* v4xi32 = p->ConvertType(40);
|
||||
EXPECT_TRUE(v4xi32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v4xi32->As<ast::Vector>()->type()->Is<ast::I32>());
|
||||
EXPECT_EQ(v4xi32->As<ast::Vector>()->size(), 4u);
|
||||
EXPECT_TRUE(v4xi32->Is<Vector>());
|
||||
EXPECT_TRUE(v4xi32->As<Vector>()->type->Is<I32>());
|
||||
EXPECT_EQ(v4xi32->As<Vector>()->size, 4u);
|
||||
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
@ -209,19 +209,19 @@ TEST_F(SpvParserTest, ConvertType_VecOverU32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* v2xu32 = p->ConvertType(20);
|
||||
EXPECT_TRUE(v2xu32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v2xu32->As<ast::Vector>()->type()->Is<ast::U32>());
|
||||
EXPECT_EQ(v2xu32->As<ast::Vector>()->size(), 2u);
|
||||
EXPECT_TRUE(v2xu32->Is<Vector>());
|
||||
EXPECT_TRUE(v2xu32->As<Vector>()->type->Is<U32>());
|
||||
EXPECT_EQ(v2xu32->As<Vector>()->size, 2u);
|
||||
|
||||
auto* v3xu32 = p->ConvertType(30);
|
||||
EXPECT_TRUE(v3xu32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v3xu32->As<ast::Vector>()->type()->Is<ast::U32>());
|
||||
EXPECT_EQ(v3xu32->As<ast::Vector>()->size(), 3u);
|
||||
EXPECT_TRUE(v3xu32->Is<Vector>());
|
||||
EXPECT_TRUE(v3xu32->As<Vector>()->type->Is<U32>());
|
||||
EXPECT_EQ(v3xu32->As<Vector>()->size, 3u);
|
||||
|
||||
auto* v4xu32 = p->ConvertType(40);
|
||||
EXPECT_TRUE(v4xu32->Is<ast::Vector>());
|
||||
EXPECT_TRUE(v4xu32->As<ast::Vector>()->type()->Is<ast::U32>());
|
||||
EXPECT_EQ(v4xu32->As<ast::Vector>()->size(), 4u);
|
||||
EXPECT_TRUE(v4xu32->Is<Vector>());
|
||||
EXPECT_TRUE(v4xu32->As<Vector>()->type->Is<U32>());
|
||||
EXPECT_EQ(v4xu32->As<Vector>()->size, 4u);
|
||||
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
@ -261,58 +261,58 @@ TEST_F(SpvParserTest, ConvertType_MatrixOverF32) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* m22 = p->ConvertType(22);
|
||||
EXPECT_TRUE(m22->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m22->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m22->As<ast::Matrix>()->rows(), 2u);
|
||||
EXPECT_EQ(m22->As<ast::Matrix>()->columns(), 2u);
|
||||
EXPECT_TRUE(m22->Is<Matrix>());
|
||||
EXPECT_TRUE(m22->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m22->As<Matrix>()->rows, 2u);
|
||||
EXPECT_EQ(m22->As<Matrix>()->columns, 2u);
|
||||
|
||||
auto* m23 = p->ConvertType(23);
|
||||
EXPECT_TRUE(m23->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m23->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m23->As<ast::Matrix>()->rows(), 2u);
|
||||
EXPECT_EQ(m23->As<ast::Matrix>()->columns(), 3u);
|
||||
EXPECT_TRUE(m23->Is<Matrix>());
|
||||
EXPECT_TRUE(m23->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m23->As<Matrix>()->rows, 2u);
|
||||
EXPECT_EQ(m23->As<Matrix>()->columns, 3u);
|
||||
|
||||
auto* m24 = p->ConvertType(24);
|
||||
EXPECT_TRUE(m24->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m24->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m24->As<ast::Matrix>()->rows(), 2u);
|
||||
EXPECT_EQ(m24->As<ast::Matrix>()->columns(), 4u);
|
||||
EXPECT_TRUE(m24->Is<Matrix>());
|
||||
EXPECT_TRUE(m24->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m24->As<Matrix>()->rows, 2u);
|
||||
EXPECT_EQ(m24->As<Matrix>()->columns, 4u);
|
||||
|
||||
auto* m32 = p->ConvertType(32);
|
||||
EXPECT_TRUE(m32->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m32->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m32->As<ast::Matrix>()->rows(), 3u);
|
||||
EXPECT_EQ(m32->As<ast::Matrix>()->columns(), 2u);
|
||||
EXPECT_TRUE(m32->Is<Matrix>());
|
||||
EXPECT_TRUE(m32->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m32->As<Matrix>()->rows, 3u);
|
||||
EXPECT_EQ(m32->As<Matrix>()->columns, 2u);
|
||||
|
||||
auto* m33 = p->ConvertType(33);
|
||||
EXPECT_TRUE(m33->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m33->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m33->As<ast::Matrix>()->rows(), 3u);
|
||||
EXPECT_EQ(m33->As<ast::Matrix>()->columns(), 3u);
|
||||
EXPECT_TRUE(m33->Is<Matrix>());
|
||||
EXPECT_TRUE(m33->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m33->As<Matrix>()->rows, 3u);
|
||||
EXPECT_EQ(m33->As<Matrix>()->columns, 3u);
|
||||
|
||||
auto* m34 = p->ConvertType(34);
|
||||
EXPECT_TRUE(m34->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m34->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m34->As<ast::Matrix>()->rows(), 3u);
|
||||
EXPECT_EQ(m34->As<ast::Matrix>()->columns(), 4u);
|
||||
EXPECT_TRUE(m34->Is<Matrix>());
|
||||
EXPECT_TRUE(m34->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m34->As<Matrix>()->rows, 3u);
|
||||
EXPECT_EQ(m34->As<Matrix>()->columns, 4u);
|
||||
|
||||
auto* m42 = p->ConvertType(42);
|
||||
EXPECT_TRUE(m42->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m42->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m42->As<ast::Matrix>()->rows(), 4u);
|
||||
EXPECT_EQ(m42->As<ast::Matrix>()->columns(), 2u);
|
||||
EXPECT_TRUE(m42->Is<Matrix>());
|
||||
EXPECT_TRUE(m42->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m42->As<Matrix>()->rows, 4u);
|
||||
EXPECT_EQ(m42->As<Matrix>()->columns, 2u);
|
||||
|
||||
auto* m43 = p->ConvertType(43);
|
||||
EXPECT_TRUE(m43->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m43->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m43->As<ast::Matrix>()->rows(), 4u);
|
||||
EXPECT_EQ(m43->As<ast::Matrix>()->columns(), 3u);
|
||||
EXPECT_TRUE(m43->Is<Matrix>());
|
||||
EXPECT_TRUE(m43->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m43->As<Matrix>()->rows, 4u);
|
||||
EXPECT_EQ(m43->As<Matrix>()->columns, 3u);
|
||||
|
||||
auto* m44 = p->ConvertType(44);
|
||||
EXPECT_TRUE(m44->Is<ast::Matrix>());
|
||||
EXPECT_TRUE(m44->As<ast::Matrix>()->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(m44->As<ast::Matrix>()->rows(), 4u);
|
||||
EXPECT_EQ(m44->As<ast::Matrix>()->columns(), 4u);
|
||||
EXPECT_TRUE(m44->Is<Matrix>());
|
||||
EXPECT_TRUE(m44->As<Matrix>()->type->Is<F32>());
|
||||
EXPECT_EQ(m44->As<Matrix>()->rows, 4u);
|
||||
EXPECT_EQ(m44->As<Matrix>()->columns, 4u);
|
||||
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
@ -326,15 +326,14 @@ TEST_F(SpvParserTest, ConvertType_RuntimeArray) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->UnwrapAliasIfNeeded()->Is<ast::Array>());
|
||||
auto* arr_type = type->UnwrapAliasIfNeeded()->As<ast::Array>();
|
||||
EXPECT_TRUE(arr_type->IsRuntimeArray());
|
||||
EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
|
||||
auto* arr_type = type->UnwrapAll()->As<Array>();
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
EXPECT_EQ(arr_type->size(), 0u);
|
||||
EXPECT_EQ(arr_type->decorations().size(), 0u);
|
||||
auto* elem_type = arr_type->type();
|
||||
EXPECT_EQ(arr_type->size, 0u);
|
||||
EXPECT_EQ(arr_type->stride, 0u);
|
||||
auto* elem_type = arr_type->type;
|
||||
ASSERT_NE(elem_type, nullptr);
|
||||
EXPECT_TRUE(elem_type->Is<ast::U32>());
|
||||
EXPECT_TRUE(elem_type->Is<U32>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -361,14 +360,10 @@ TEST_F(SpvParserTest, ConvertType_RuntimeArray_ArrayStride_Valid) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
auto* arr_type = type->UnwrapAliasIfNeeded()->As<ast::Array>();
|
||||
EXPECT_TRUE(arr_type->IsRuntimeArray());
|
||||
auto* arr_type = type->UnwrapAll()->As<Array>();
|
||||
EXPECT_EQ(arr_type->size, 0u);
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
ASSERT_EQ(arr_type->decorations().size(), 1u);
|
||||
auto* stride = arr_type->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
ASSERT_EQ(stride->As<ast::StrideDecoration>()->stride(), 64u);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
EXPECT_EQ(arr_type->stride, 64u);
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_RuntimeArray_ArrayStride_ZeroIsError) {
|
||||
|
@ -409,15 +404,14 @@ TEST_F(SpvParserTest, ConvertType_Array) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->Is<ast::Array>());
|
||||
auto* arr_type = type->As<ast::Array>();
|
||||
EXPECT_FALSE(arr_type->IsRuntimeArray());
|
||||
EXPECT_TRUE(type->Is<Array>());
|
||||
auto* arr_type = type->As<Array>();
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
EXPECT_EQ(arr_type->size(), 42u);
|
||||
EXPECT_EQ(arr_type->decorations().size(), 0u);
|
||||
auto* elem_type = arr_type->type();
|
||||
EXPECT_EQ(arr_type->size, 42u);
|
||||
EXPECT_EQ(arr_type->stride, 0u);
|
||||
auto* elem_type = arr_type->type;
|
||||
ASSERT_NE(elem_type, nullptr);
|
||||
EXPECT_TRUE(elem_type->Is<ast::U32>());
|
||||
EXPECT_TRUE(elem_type->Is<U32>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -496,15 +490,10 @@ TEST_F(SpvParserTest, ConvertType_ArrayStride_Valid) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->UnwrapAliasIfNeeded()->Is<ast::Array>());
|
||||
auto* arr_type = type->UnwrapAliasIfNeeded()->As<ast::Array>();
|
||||
EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
|
||||
auto* arr_type = type->UnwrapAll()->As<Array>();
|
||||
ASSERT_NE(arr_type, nullptr);
|
||||
|
||||
ASSERT_EQ(arr_type->decorations().size(), 1u);
|
||||
auto* stride = arr_type->decorations()[0];
|
||||
ASSERT_TRUE(stride->Is<ast::StrideDecoration>());
|
||||
ASSERT_EQ(stride->As<ast::StrideDecoration>()->stride(), 8u);
|
||||
|
||||
EXPECT_EQ(arr_type->stride, 8u);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -550,14 +539,11 @@ TEST_F(SpvParserTest, ConvertType_StructTwoMembers) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->Is<ast::Struct>());
|
||||
EXPECT_TRUE(type->Is<Struct>());
|
||||
|
||||
auto* str = type->Build(p->builder());
|
||||
Program program = p->program();
|
||||
EXPECT_THAT(program.str(type->As<ast::Struct>()), Eq(R"(Struct S {
|
||||
StructMember{field0: __u32}
|
||||
StructMember{field1: __f32}
|
||||
}
|
||||
)"));
|
||||
EXPECT_THAT(program.str(str), Eq(R"(__type_name_S)"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_StructWithBlockDecoration) {
|
||||
|
@ -571,14 +557,11 @@ TEST_F(SpvParserTest, ConvertType_StructWithBlockDecoration) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->Is<ast::Struct>());
|
||||
EXPECT_TRUE(type->Is<Struct>());
|
||||
|
||||
auto* str = type->Build(p->builder());
|
||||
Program program = p->program();
|
||||
EXPECT_THAT(program.str(type->As<ast::Struct>()), Eq(R"(Struct S {
|
||||
[[block]]
|
||||
StructMember{field0: __u32}
|
||||
}
|
||||
)"));
|
||||
EXPECT_THAT(program.str(str), Eq(R"(__type_name_S)"));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, ConvertType_StructWithMemberDecorations) {
|
||||
|
@ -596,15 +579,11 @@ TEST_F(SpvParserTest, ConvertType_StructWithMemberDecorations) {
|
|||
|
||||
auto* type = p->ConvertType(10);
|
||||
ASSERT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->Is<ast::Struct>());
|
||||
EXPECT_TRUE(type->Is<Struct>());
|
||||
|
||||
auto* str = type->Build(p->builder());
|
||||
Program program = p->program();
|
||||
EXPECT_THAT(program.str(type->As<ast::Struct>()), Eq(R"(Struct S {
|
||||
StructMember{[[ offset 0 ]] field0: __f32}
|
||||
StructMember{[[ offset 8 ]] field1: __vec_2__f32}
|
||||
StructMember{[[ offset 16 ]] field2: __mat_2_2__f32}
|
||||
}
|
||||
)"));
|
||||
EXPECT_THAT(program.str(str), Eq(R"(__type_name_S)"));
|
||||
}
|
||||
|
||||
// TODO(dneto): Demonstrate other member decorations. Blocked on
|
||||
|
@ -645,11 +624,11 @@ TEST_F(SpvParserTest, ConvertType_PointerInput) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kInput);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -661,11 +640,11 @@ TEST_F(SpvParserTest, ConvertType_PointerOutput) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kOutput);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kOutput);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -677,11 +656,11 @@ TEST_F(SpvParserTest, ConvertType_PointerUniform) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniform);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniform);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -693,11 +672,11 @@ TEST_F(SpvParserTest, ConvertType_PointerWorkgroup) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kWorkgroup);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kWorkgroup);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -709,11 +688,11 @@ TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniformConstant);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniformConstant);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -725,11 +704,11 @@ TEST_F(SpvParserTest, ConvertType_PointerStorageBuffer) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kStorage);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kStorage);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -741,11 +720,11 @@ TEST_F(SpvParserTest, ConvertType_PointerImage) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kImage);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kImage);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -757,11 +736,11 @@ TEST_F(SpvParserTest, ConvertType_PointerPrivate) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -773,11 +752,11 @@ TEST_F(SpvParserTest, ConvertType_PointerFunction) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kFunction);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<F32>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kFunction);
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -792,17 +771,17 @@ TEST_F(SpvParserTest, ConvertType_PointerToPointer) {
|
|||
|
||||
auto* type = p->ConvertType(3);
|
||||
EXPECT_NE(type, nullptr);
|
||||
EXPECT_TRUE(type->Is<ast::Pointer>());
|
||||
EXPECT_TRUE(type->Is<Pointer>());
|
||||
|
||||
auto* ptr_ty = type->As<ast::Pointer>();
|
||||
auto* ptr_ty = type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ty, nullptr);
|
||||
EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput);
|
||||
EXPECT_TRUE(ptr_ty->type()->Is<ast::Pointer>());
|
||||
EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kInput);
|
||||
EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
|
||||
|
||||
auto* ptr_ptr_ty = ptr_ty->type()->As<ast::Pointer>();
|
||||
auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
|
||||
EXPECT_NE(ptr_ptr_ty, nullptr);
|
||||
EXPECT_EQ(ptr_ptr_ty->storage_class(), ast::StorageClass::kOutput);
|
||||
EXPECT_TRUE(ptr_ptr_ty->type()->Is<ast::F32>());
|
||||
EXPECT_EQ(ptr_ptr_ty->storage_class, ast::StorageClass::kOutput);
|
||||
EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
|
||||
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
@ -815,7 +794,7 @@ TEST_F(SpvParserTest, ConvertType_Sampler_PretendVoid) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(1);
|
||||
EXPECT_TRUE(type->Is<ast::Void>());
|
||||
EXPECT_TRUE(type->Is<Void>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -828,7 +807,7 @@ TEST_F(SpvParserTest, ConvertType_Image_PretendVoid) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(1);
|
||||
EXPECT_TRUE(type->Is<ast::Void>());
|
||||
EXPECT_TRUE(type->Is<Void>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
@ -841,7 +820,7 @@ TEST_F(SpvParserTest, ConvertType_SampledImage_PretendVoid) {
|
|||
EXPECT_TRUE(p->BuildInternalModule());
|
||||
|
||||
auto* type = p->ConvertType(1);
|
||||
EXPECT_TRUE(type->Is<ast::Void>());
|
||||
EXPECT_TRUE(type->Is<Void>());
|
||||
EXPECT_TRUE(p->error().empty());
|
||||
}
|
||||
|
||||
|
|
|
@ -1772,7 +1772,7 @@ TEST_F(SpvModuleScopeVarParserTest,
|
|||
[[block]]
|
||||
StructMember{[[ offset 0 ]] field0: __u32}
|
||||
StructMember{[[ offset 4 ]] field1: __f32}
|
||||
StructMember{[[ offset 8 ]] field2: __alias_Arr__array__u32_2_stride_4}
|
||||
StructMember{[[ offset 8 ]] field2: __type_name_Arr}
|
||||
}
|
||||
Variable{
|
||||
x_1
|
||||
|
|
|
@ -158,7 +158,7 @@ class ParserImplWrapperForTest {
|
|||
/// after the internal representation of the module has been built.
|
||||
/// @param id the SPIR-V ID of a type.
|
||||
/// @returns a Tint type, or nullptr
|
||||
ast::Type* ConvertType(uint32_t id) { return impl_.ConvertType(id); }
|
||||
const Type* ConvertType(uint32_t id) { return impl_.ConvertType(id); }
|
||||
|
||||
/// Gets the list of decorations for a SPIR-V result ID. Returns an empty
|
||||
/// vector if the ID is not a result ID, or if no decorations target that ID.
|
||||
|
|
|
@ -0,0 +1,514 @@
|
|||
// Copyright 2021 The Tint Authors.
|
||||
//
|
||||
// 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 stateied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "src/reader/spirv/parser_type.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "src/program_builder.h"
|
||||
#include "src/utils/get_or_create.h"
|
||||
#include "src/utils/hash.h"
|
||||
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Type);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Void);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Bool);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::U32);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::F32);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::I32);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Pointer);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Vector);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Matrix);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Array);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::AccessControl);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Sampler);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Texture);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::DepthTexture);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::MultisampledTexture);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::SampledTexture);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::StorageTexture);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Named);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Alias);
|
||||
TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Struct);
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
namespace spirv {
|
||||
|
||||
namespace {
|
||||
struct PointerHasher {
|
||||
size_t operator()(const Pointer& t) const {
|
||||
return utils::Hash(t.type, t.storage_class);
|
||||
}
|
||||
};
|
||||
|
||||
struct VectorHasher {
|
||||
size_t operator()(const Vector& t) const {
|
||||
return utils::Hash(t.type, t.size);
|
||||
}
|
||||
};
|
||||
|
||||
struct MatrixHasher {
|
||||
size_t operator()(const Matrix& t) const {
|
||||
return utils::Hash(t.type, t.columns, t.rows);
|
||||
}
|
||||
};
|
||||
|
||||
struct ArrayHasher {
|
||||
size_t operator()(const Array& t) const {
|
||||
return utils::Hash(t.type, t.size, t.stride);
|
||||
}
|
||||
};
|
||||
|
||||
struct AccessControlHasher {
|
||||
size_t operator()(const AccessControl& t) const {
|
||||
return utils::Hash(t.type, t.access);
|
||||
}
|
||||
};
|
||||
|
||||
struct MultisampledTextureHasher {
|
||||
size_t operator()(const MultisampledTexture& t) const {
|
||||
return utils::Hash(t.dims, t.type);
|
||||
}
|
||||
};
|
||||
|
||||
struct SampledTextureHasher {
|
||||
size_t operator()(const SampledTexture& t) const {
|
||||
return utils::Hash(t.dims, t.type);
|
||||
}
|
||||
};
|
||||
|
||||
struct StorageTextureHasher {
|
||||
size_t operator()(const StorageTexture& t) const {
|
||||
return utils::Hash(t.dims, t.format);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static bool operator==(const Pointer& a, const Pointer& b) {
|
||||
return a.type == b.type && a.storage_class == b.storage_class;
|
||||
}
|
||||
|
||||
static bool operator==(const Vector& a, const Vector& b) {
|
||||
return a.type == b.type && a.size == b.size;
|
||||
}
|
||||
|
||||
static bool operator==(const Matrix& a, const Matrix& b) {
|
||||
return a.type == b.type && a.columns == b.columns && a.rows == b.rows;
|
||||
}
|
||||
|
||||
static bool operator==(const Array& a, const Array& b) {
|
||||
return a.type == b.type && a.size == b.size && a.stride == b.stride;
|
||||
}
|
||||
|
||||
static bool operator==(const AccessControl& a, const AccessControl& b) {
|
||||
return a.type == b.type && a.access == b.access;
|
||||
}
|
||||
|
||||
static bool operator==(const MultisampledTexture& a,
|
||||
const MultisampledTexture& b) {
|
||||
return a.dims == b.dims && a.type == b.type;
|
||||
}
|
||||
|
||||
static bool operator==(const SampledTexture& a, const SampledTexture& b) {
|
||||
return a.dims == b.dims && a.type == b.type;
|
||||
}
|
||||
|
||||
static bool operator==(const StorageTexture& a, const StorageTexture& b) {
|
||||
return a.dims == b.dims && a.format == b.format;
|
||||
}
|
||||
|
||||
ast::Type* Void::Build(ProgramBuilder& b) const {
|
||||
return b.ty.void_();
|
||||
}
|
||||
|
||||
ast::Type* Bool::Build(ProgramBuilder& b) const {
|
||||
return b.ty.bool_();
|
||||
}
|
||||
|
||||
ast::Type* U32::Build(ProgramBuilder& b) const {
|
||||
return b.ty.u32();
|
||||
}
|
||||
|
||||
ast::Type* F32::Build(ProgramBuilder& b) const {
|
||||
return b.ty.f32();
|
||||
}
|
||||
|
||||
ast::Type* I32::Build(ProgramBuilder& b) const {
|
||||
return b.ty.i32();
|
||||
}
|
||||
|
||||
Pointer::Pointer(const Type* t, ast::StorageClass s)
|
||||
: type(t), storage_class(s) {}
|
||||
Pointer::Pointer(const Pointer&) = default;
|
||||
|
||||
ast::Type* Pointer::Build(ProgramBuilder& b) const {
|
||||
return b.ty.pointer(type->Build(b), storage_class);
|
||||
}
|
||||
|
||||
Vector::Vector(const Type* t, uint32_t s) : type(t), size(s) {}
|
||||
Vector::Vector(const Vector&) = default;
|
||||
|
||||
ast::Type* Vector::Build(ProgramBuilder& b) const {
|
||||
return b.ty.vec(type->Build(b), size);
|
||||
}
|
||||
|
||||
Matrix::Matrix(const Type* t, uint32_t c, uint32_t r)
|
||||
: type(t), columns(c), rows(r) {}
|
||||
Matrix::Matrix(const Matrix&) = default;
|
||||
|
||||
ast::Type* Matrix::Build(ProgramBuilder& b) const {
|
||||
return b.ty.mat(type->Build(b), columns, rows);
|
||||
}
|
||||
|
||||
Array::Array(const Type* t, uint32_t sz, uint32_t st)
|
||||
: type(t), size(sz), stride(st) {}
|
||||
Array::Array(const Array&) = default;
|
||||
|
||||
ast::Type* Array::Build(ProgramBuilder& b) const {
|
||||
return b.ty.array(type->Build(b), size, stride);
|
||||
}
|
||||
|
||||
AccessControl::AccessControl(const Type* t, ast::AccessControl::Access a)
|
||||
: type(t), access(a) {}
|
||||
AccessControl::AccessControl(const AccessControl&) = default;
|
||||
|
||||
ast::Type* AccessControl::Build(ProgramBuilder& b) const {
|
||||
return b.ty.access(access, type->Build(b));
|
||||
}
|
||||
|
||||
Sampler::Sampler(ast::SamplerKind k) : kind(k) {}
|
||||
Sampler::Sampler(const Sampler&) = default;
|
||||
|
||||
ast::Type* Sampler::Build(ProgramBuilder& b) const {
|
||||
return b.ty.sampler(kind);
|
||||
}
|
||||
|
||||
Texture::Texture(ast::TextureDimension d) : dims(d) {}
|
||||
Texture::Texture(const Texture&) = default;
|
||||
|
||||
DepthTexture::DepthTexture(ast::TextureDimension d) : Base(d) {}
|
||||
DepthTexture::DepthTexture(const DepthTexture&) = default;
|
||||
|
||||
ast::Type* DepthTexture::Build(ProgramBuilder& b) const {
|
||||
return b.ty.depth_texture(dims);
|
||||
}
|
||||
|
||||
MultisampledTexture::MultisampledTexture(ast::TextureDimension d, const Type* t)
|
||||
: Base(d), type(t) {}
|
||||
MultisampledTexture::MultisampledTexture(const MultisampledTexture&) = default;
|
||||
|
||||
ast::Type* MultisampledTexture::Build(ProgramBuilder& b) const {
|
||||
return b.ty.multisampled_texture(dims, type->Build(b));
|
||||
}
|
||||
|
||||
SampledTexture::SampledTexture(ast::TextureDimension d, const Type* t)
|
||||
: Base(d), type(t) {}
|
||||
SampledTexture::SampledTexture(const SampledTexture&) = default;
|
||||
|
||||
ast::Type* SampledTexture::Build(ProgramBuilder& b) const {
|
||||
return b.ty.sampled_texture(dims, type->Build(b));
|
||||
}
|
||||
|
||||
StorageTexture::StorageTexture(ast::TextureDimension d, ast::ImageFormat f)
|
||||
: Base(d), format(f) {}
|
||||
StorageTexture::StorageTexture(const StorageTexture&) = default;
|
||||
|
||||
ast::Type* StorageTexture::Build(ProgramBuilder& b) const {
|
||||
return b.ty.storage_texture(dims, format);
|
||||
}
|
||||
|
||||
Named::Named(Symbol n) : name(n) {}
|
||||
Named::Named(const Named&) = default;
|
||||
Named::~Named() = default;
|
||||
|
||||
Alias::Alias(Symbol n, const Type* ty) : Base(n), type(ty) {}
|
||||
Alias::Alias(const Alias&) = default;
|
||||
|
||||
ast::Type* Alias::Build(ProgramBuilder& b) const {
|
||||
return b.ty.type_name(name);
|
||||
}
|
||||
|
||||
Struct::Struct(Symbol n, TypeList m) : Base(n), members(std::move(m)) {}
|
||||
Struct::Struct(const Struct&) = default;
|
||||
Struct::~Struct() = default;
|
||||
|
||||
ast::Type* Struct::Build(ProgramBuilder& b) const {
|
||||
return b.ty.type_name(name);
|
||||
}
|
||||
|
||||
/// The PIMPL state of the Types object.
|
||||
struct TypeManager::State {
|
||||
/// The allocator of types
|
||||
BlockAllocator<Type> allocator_;
|
||||
/// The lazily-created Void type
|
||||
spirv::Void const* void_ = nullptr;
|
||||
/// The lazily-created Bool type
|
||||
spirv::Bool const* bool_ = nullptr;
|
||||
/// The lazily-created U32 type
|
||||
spirv::U32 const* u32_ = nullptr;
|
||||
/// The lazily-created F32 type
|
||||
spirv::F32 const* f32_ = nullptr;
|
||||
/// The lazily-created I32 type
|
||||
spirv::I32 const* i32_ = nullptr;
|
||||
/// Map of Pointer to the returned Pointer type instance
|
||||
std::unordered_map<spirv::Pointer, const spirv::Pointer*, PointerHasher>
|
||||
pointers_;
|
||||
/// Map of Vector to the returned Vector type instance
|
||||
std::unordered_map<spirv::Vector, const spirv::Vector*, VectorHasher>
|
||||
vectors_;
|
||||
/// Map of Matrix to the returned Matrix type instance
|
||||
std::unordered_map<spirv::Matrix, const spirv::Matrix*, MatrixHasher>
|
||||
matrices_;
|
||||
/// Map of Array to the returned Array type instance
|
||||
std::unordered_map<spirv::Array, const spirv::Array*, ArrayHasher> arrays_;
|
||||
/// Map of AccessControl to the returned AccessControl type instance
|
||||
std::unordered_map<spirv::AccessControl,
|
||||
const spirv::AccessControl*,
|
||||
AccessControlHasher>
|
||||
access_controls_;
|
||||
/// Map of type name to returned Alias instance
|
||||
std::unordered_map<Symbol, const spirv::Alias*> aliases_;
|
||||
/// Map of type name to returned Struct instance
|
||||
std::unordered_map<Symbol, const spirv::Struct*> structs_;
|
||||
/// Map of ast::SamplerKind to returned Sampler instance
|
||||
std::unordered_map<ast::SamplerKind, const spirv::Sampler*> samplers_;
|
||||
/// Map of ast::TextureDimension to returned DepthTexture instance
|
||||
std::unordered_map<ast::TextureDimension, const spirv::DepthTexture*>
|
||||
depth_textures_;
|
||||
/// Map of MultisampledTexture to the returned MultisampledTexture type
|
||||
/// instance
|
||||
std::unordered_map<spirv::MultisampledTexture,
|
||||
const spirv::MultisampledTexture*,
|
||||
MultisampledTextureHasher>
|
||||
multisampled_textures_;
|
||||
/// Map of SampledTexture to the returned SampledTexture type instance
|
||||
std::unordered_map<spirv::SampledTexture,
|
||||
const spirv::SampledTexture*,
|
||||
SampledTextureHasher>
|
||||
sampled_textures_;
|
||||
/// Map of StorageTexture to the returned StorageTexture type instance
|
||||
std::unordered_map<spirv::StorageTexture,
|
||||
const spirv::StorageTexture*,
|
||||
StorageTextureHasher>
|
||||
storage_textures_;
|
||||
};
|
||||
|
||||
const Type* Type::UnwrapPtrIfNeeded() const {
|
||||
if (auto* ptr = As<Pointer>()) {
|
||||
return ptr->type;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapAliasIfNeeded() const {
|
||||
const Type* unwrapped = this;
|
||||
while (auto* ptr = unwrapped->As<Alias>()) {
|
||||
unwrapped = ptr->type;
|
||||
}
|
||||
return unwrapped;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapIfNeeded() const {
|
||||
auto* where = this;
|
||||
while (true) {
|
||||
if (auto* alias = where->As<Alias>()) {
|
||||
where = alias->type;
|
||||
} else if (auto* access = where->As<AccessControl>()) {
|
||||
where = access->type;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
const Type* Type::UnwrapAll() const {
|
||||
return UnwrapIfNeeded()->UnwrapPtrIfNeeded()->UnwrapIfNeeded();
|
||||
}
|
||||
|
||||
bool Type::IsFloatScalar() const {
|
||||
return Is<F32>();
|
||||
}
|
||||
|
||||
bool Type::IsFloatScalarOrVector() const {
|
||||
return IsFloatScalar() || IsFloatVector();
|
||||
}
|
||||
|
||||
bool Type::IsFloatVector() const {
|
||||
return Is<Vector>([](const Vector* v) { return v->type->IsFloatScalar(); });
|
||||
}
|
||||
|
||||
bool Type::IsIntegerScalar() const {
|
||||
return IsAnyOf<U32, I32>();
|
||||
}
|
||||
|
||||
bool Type::IsIntegerScalarOrVector() const {
|
||||
return IsUnsignedScalarOrVector() || IsSignedScalarOrVector();
|
||||
}
|
||||
|
||||
bool Type::IsScalar() const {
|
||||
return IsAnyOf<F32, U32, I32, Bool>();
|
||||
}
|
||||
|
||||
bool Type::IsSignedIntegerVector() const {
|
||||
return Is<Vector>([](const Vector* v) { return v->type->Is<I32>(); });
|
||||
}
|
||||
|
||||
bool Type::IsSignedScalarOrVector() const {
|
||||
return Is<I32>() || IsSignedIntegerVector();
|
||||
}
|
||||
|
||||
bool Type::IsUnsignedIntegerVector() const {
|
||||
return Is<Vector>([](const Vector* v) { return v->type->Is<U32>(); });
|
||||
}
|
||||
|
||||
bool Type::IsUnsignedScalarOrVector() const {
|
||||
return Is<U32>() || IsUnsignedIntegerVector();
|
||||
}
|
||||
|
||||
TypeManager::TypeManager() {
|
||||
state = std::make_unique<State>();
|
||||
}
|
||||
|
||||
TypeManager::~TypeManager() = default;
|
||||
|
||||
const spirv::Void* TypeManager::Void() {
|
||||
if (!state->void_) {
|
||||
state->void_ = state->allocator_.Create<spirv::Void>();
|
||||
}
|
||||
return state->void_;
|
||||
}
|
||||
|
||||
const spirv::Bool* TypeManager::Bool() {
|
||||
if (!state->bool_) {
|
||||
state->bool_ = state->allocator_.Create<spirv::Bool>();
|
||||
}
|
||||
return state->bool_;
|
||||
}
|
||||
|
||||
const spirv::U32* TypeManager::U32() {
|
||||
if (!state->u32_) {
|
||||
state->u32_ = state->allocator_.Create<spirv::U32>();
|
||||
}
|
||||
return state->u32_;
|
||||
}
|
||||
|
||||
const spirv::F32* TypeManager::F32() {
|
||||
if (!state->f32_) {
|
||||
state->f32_ = state->allocator_.Create<spirv::F32>();
|
||||
}
|
||||
return state->f32_;
|
||||
}
|
||||
|
||||
const spirv::I32* TypeManager::I32() {
|
||||
if (!state->i32_) {
|
||||
state->i32_ = state->allocator_.Create<spirv::I32>();
|
||||
}
|
||||
return state->i32_;
|
||||
}
|
||||
|
||||
const spirv::Pointer* TypeManager::Pointer(const Type* el,
|
||||
ast::StorageClass sc) {
|
||||
return utils::GetOrCreate(state->pointers_, spirv::Pointer(el, sc), [&] {
|
||||
return state->allocator_.Create<spirv::Pointer>(el, sc);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::Vector* TypeManager::Vector(const Type* el, uint32_t size) {
|
||||
return utils::GetOrCreate(state->vectors_, spirv::Vector(el, size), [&] {
|
||||
return state->allocator_.Create<spirv::Vector>(el, size);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::Matrix* TypeManager::Matrix(const Type* el,
|
||||
uint32_t columns,
|
||||
uint32_t rows) {
|
||||
return utils::GetOrCreate(
|
||||
state->matrices_, spirv::Matrix(el, columns, rows), [&] {
|
||||
return state->allocator_.Create<spirv::Matrix>(el, columns, rows);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::Array* TypeManager::Array(const Type* el,
|
||||
uint32_t size,
|
||||
uint32_t stride) {
|
||||
return utils::GetOrCreate(
|
||||
state->arrays_, spirv::Array(el, size, stride),
|
||||
[&] { return state->allocator_.Create<spirv::Array>(el, size, stride); });
|
||||
}
|
||||
|
||||
const spirv::AccessControl* TypeManager::AccessControl(
|
||||
const Type* ty,
|
||||
ast::AccessControl::Access ac) {
|
||||
return utils::GetOrCreate(
|
||||
state->access_controls_, spirv::AccessControl(ty, ac),
|
||||
[&] { return state->allocator_.Create<spirv::AccessControl>(ty, ac); });
|
||||
}
|
||||
|
||||
const spirv::Alias* TypeManager::Alias(Symbol name, const Type* ty) {
|
||||
return utils::GetOrCreate(state->aliases_, name, [&] {
|
||||
return state->allocator_.Create<spirv::Alias>(name, ty);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::Struct* TypeManager::Struct(Symbol name, TypeList members) {
|
||||
return utils::GetOrCreate(state->structs_, name, [&] {
|
||||
return state->allocator_.Create<spirv::Struct>(name, std::move(members));
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::Sampler* TypeManager::Sampler(ast::SamplerKind kind) {
|
||||
return utils::GetOrCreate(state->samplers_, kind, [&] {
|
||||
return state->allocator_.Create<spirv::Sampler>(kind);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::DepthTexture* TypeManager::DepthTexture(
|
||||
ast::TextureDimension dims) {
|
||||
return utils::GetOrCreate(state->depth_textures_, dims, [&] {
|
||||
return state->allocator_.Create<spirv::DepthTexture>(dims);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::MultisampledTexture* TypeManager::MultisampledTexture(
|
||||
ast::TextureDimension dims,
|
||||
const Type* ty) {
|
||||
return utils::GetOrCreate(
|
||||
state->multisampled_textures_, spirv::MultisampledTexture(dims, ty), [&] {
|
||||
return state->allocator_.Create<spirv::MultisampledTexture>(dims, ty);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::SampledTexture* TypeManager::SampledTexture(
|
||||
ast::TextureDimension dims,
|
||||
const Type* ty) {
|
||||
return utils::GetOrCreate(
|
||||
state->sampled_textures_, spirv::SampledTexture(dims, ty), [&] {
|
||||
return state->allocator_.Create<spirv::SampledTexture>(dims, ty);
|
||||
});
|
||||
}
|
||||
|
||||
const spirv::StorageTexture* TypeManager::StorageTexture(
|
||||
ast::TextureDimension dims,
|
||||
ast::ImageFormat fmt) {
|
||||
return utils::GetOrCreate(
|
||||
state->storage_textures_, spirv::StorageTexture(dims, fmt), [&] {
|
||||
return state->allocator_.Create<spirv::StorageTexture>(dims, fmt);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
|
@ -0,0 +1,498 @@
|
|||
// Copyright 2021 The Tint Authors.
|
||||
//
|
||||
// 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 SRC_READER_SPIRV_PARSER_TYPE_H_
|
||||
#define SRC_READER_SPIRV_PARSER_TYPE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "src/ast/access_control.h"
|
||||
#include "src/ast/sampler.h"
|
||||
#include "src/ast/storage_class.h"
|
||||
#include "src/ast/storage_texture.h"
|
||||
#include "src/ast/texture.h"
|
||||
#include "src/block_allocator.h"
|
||||
#include "src/castable.h"
|
||||
|
||||
// Forward declarations
|
||||
namespace tint {
|
||||
class ProgramBuilder;
|
||||
namespace ast {
|
||||
class Type;
|
||||
} // namespace ast
|
||||
} // namespace tint
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
namespace spirv {
|
||||
|
||||
/// Type is the base class for all types
|
||||
class Type : public Castable<Type> {
|
||||
public:
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
virtual ast::Type* Build(ProgramBuilder& b) const = 0;
|
||||
|
||||
/// @returns the pointee type if this is a pointer, `this` otherwise
|
||||
const Type* UnwrapPtrIfNeeded() const;
|
||||
|
||||
/// @returns the most deeply nested aliased type if this is an alias, `this`
|
||||
/// otherwise
|
||||
const Type* UnwrapAliasIfNeeded() const;
|
||||
|
||||
/// Removes all levels of aliasing and access control.
|
||||
/// This is just enough to assist with WGSL translation
|
||||
/// in that you want see through one level of pointer to get from an
|
||||
/// identifier-like expression as an l-value to its corresponding r-value,
|
||||
/// plus see through the wrappers on either side.
|
||||
/// @returns the completely unaliased type.
|
||||
const Type* UnwrapIfNeeded() const;
|
||||
|
||||
/// Returns the type found after:
|
||||
/// - removing all layers of aliasing and access control if they exist, then
|
||||
/// - removing the pointer, if it exists, then
|
||||
/// - removing all further layers of aliasing or access control, if they exist
|
||||
/// @returns the unwrapped type
|
||||
const Type* UnwrapAll() const;
|
||||
|
||||
/// @returns true if this type is a float scalar
|
||||
bool IsFloatScalar() const;
|
||||
/// @returns true if this type is a float scalar or vector
|
||||
bool IsFloatScalarOrVector() const;
|
||||
/// @returns true if this type is a float vector
|
||||
bool IsFloatVector() const;
|
||||
/// @returns true if this type is an integer scalar
|
||||
bool IsIntegerScalar() const;
|
||||
/// @returns true if this type is an integer scalar or vector
|
||||
bool IsIntegerScalarOrVector() const;
|
||||
/// @returns true if this type is a scalar
|
||||
bool IsScalar() const;
|
||||
/// @returns true if this type is a signed integer vector
|
||||
bool IsSignedIntegerVector() const;
|
||||
/// @returns true if this type is a signed scalar or vector
|
||||
bool IsSignedScalarOrVector() const;
|
||||
/// @returns true if this type is an unsigned integer vector
|
||||
bool IsUnsignedIntegerVector() const;
|
||||
/// @returns true if this type is an unsigned scalar or vector
|
||||
bool IsUnsignedScalarOrVector() const;
|
||||
};
|
||||
|
||||
using TypeList = std::vector<const Type*>;
|
||||
|
||||
/// `void` type
|
||||
struct Void : public Castable<Void, Type> {
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `bool` type
|
||||
struct Bool : public Castable<Bool, Type> {
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `u32` type
|
||||
struct U32 : public Castable<U32, Type> {
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `f32` type
|
||||
struct F32 : public Castable<F32, Type> {
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `i32` type
|
||||
struct I32 : public Castable<I32, Type> {
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `ptr<SC, T>` type
|
||||
struct Pointer : public Castable<Pointer, Type> {
|
||||
/// Constructor
|
||||
/// @param ty the pointee type
|
||||
/// @param sc the pointer storage class
|
||||
Pointer(const Type* ty, ast::StorageClass sc);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Pointer(const Pointer& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the pointee type
|
||||
Type const* const type;
|
||||
/// the pointer storage class
|
||||
ast::StorageClass const storage_class;
|
||||
};
|
||||
|
||||
/// `vecN<T>` type
|
||||
struct Vector : public Castable<Vector, Type> {
|
||||
/// Constructor
|
||||
/// @param ty the element type
|
||||
/// @param sz the number of elements in the vector
|
||||
Vector(const Type* ty, uint32_t sz);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Vector(const Vector& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the element type
|
||||
Type const* const type;
|
||||
/// the number of elements in the vector
|
||||
uint32_t const size;
|
||||
};
|
||||
|
||||
/// `matNxM<T>` type
|
||||
struct Matrix : public Castable<Matrix, Type> {
|
||||
/// Constructor
|
||||
/// @param ty the matrix element type
|
||||
/// @param c the number of columns in the matrix
|
||||
/// @param r the number of rows in the matrix
|
||||
Matrix(const Type* ty, uint32_t c, uint32_t r);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Matrix(const Matrix& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the matrix element type
|
||||
Type const* const type;
|
||||
/// the number of columns in the matrix
|
||||
uint32_t const columns;
|
||||
/// the number of rows in the matrix
|
||||
uint32_t const rows;
|
||||
};
|
||||
|
||||
/// `array<T, N>` type
|
||||
struct Array : public Castable<Array, Type> {
|
||||
/// Constructor
|
||||
/// @param el the element type
|
||||
/// @param sz the number of elements in the array. 0 represents runtime-sized
|
||||
/// array.
|
||||
/// @param st the byte stride of the array
|
||||
Array(const Type* el, uint32_t sz, uint32_t st);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Array(const Array& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the element type
|
||||
Type const* const type;
|
||||
/// the number of elements in the array. 0 represents runtime-sized array.
|
||||
uint32_t const size;
|
||||
/// the byte stride of the array
|
||||
uint32_t const stride;
|
||||
};
|
||||
|
||||
/// `[[access]]` type
|
||||
struct AccessControl : public Castable<AccessControl, Type> {
|
||||
/// Constructor
|
||||
/// @param ty the inner type
|
||||
/// @param ac the access control
|
||||
AccessControl(const Type* ty, ast::AccessControl::Access ac);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
AccessControl(const AccessControl& other);
|
||||
|
||||
/// @return the
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the inner type
|
||||
Type const* const type;
|
||||
/// the access control
|
||||
ast::AccessControl::Access const access;
|
||||
};
|
||||
|
||||
/// `sampler` type
|
||||
struct Sampler : public Castable<Sampler, Type> {
|
||||
/// Constructor
|
||||
/// @param k the sampler kind
|
||||
explicit Sampler(ast::SamplerKind k);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Sampler(const Sampler& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the sampler kind
|
||||
ast::SamplerKind const kind;
|
||||
};
|
||||
|
||||
/// Base class for texture types
|
||||
struct Texture : public Castable<Texture, Type> {
|
||||
/// Constructor
|
||||
/// @param d the texture dimensions
|
||||
explicit Texture(ast::TextureDimension d);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Texture(const Texture& other);
|
||||
|
||||
/// the texture dimensions
|
||||
ast::TextureDimension const dims;
|
||||
};
|
||||
|
||||
/// `texture_depth_D` type
|
||||
struct DepthTexture : public Castable<DepthTexture, Texture> {
|
||||
/// Constructor
|
||||
/// @param d the texture dimensions
|
||||
explicit DepthTexture(ast::TextureDimension d);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
DepthTexture(const DepthTexture& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
};
|
||||
|
||||
/// `texture_multisampled_D<T>` type
|
||||
struct MultisampledTexture : public Castable<MultisampledTexture, Texture> {
|
||||
/// Constructor
|
||||
/// @param d the texture dimensions
|
||||
/// @param t the multisampled texture type
|
||||
MultisampledTexture(ast::TextureDimension d, const Type* t);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
MultisampledTexture(const MultisampledTexture& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the multisampled texture type
|
||||
Type const* const type;
|
||||
};
|
||||
|
||||
/// `texture_D<T>` type
|
||||
struct SampledTexture : public Castable<SampledTexture, Texture> {
|
||||
/// Constructor
|
||||
/// @param d the texture dimensions
|
||||
/// @param t the sampled texture type
|
||||
SampledTexture(ast::TextureDimension d, const Type* t);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
SampledTexture(const SampledTexture& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the sampled texture type
|
||||
Type const* const type;
|
||||
};
|
||||
|
||||
/// `texture_storage_D<F>` type
|
||||
struct StorageTexture : public Castable<StorageTexture, Texture> {
|
||||
/// Constructor
|
||||
/// @param d the texture dimensions
|
||||
/// @param f the storage image format
|
||||
StorageTexture(ast::TextureDimension d, ast::ImageFormat f);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
StorageTexture(const StorageTexture& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the storage image format
|
||||
ast::ImageFormat const format;
|
||||
};
|
||||
|
||||
/// Base class for named types
|
||||
struct Named : public Castable<Named, Type> {
|
||||
/// Constructor
|
||||
/// @param n the type name
|
||||
explicit Named(Symbol n);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Named(const Named& other);
|
||||
|
||||
/// Destructor
|
||||
~Named() override;
|
||||
|
||||
/// the type name
|
||||
Symbol const name;
|
||||
};
|
||||
|
||||
/// `type T = N` type
|
||||
struct Alias : public Castable<Alias, Named> {
|
||||
/// Constructor
|
||||
/// @param n the alias name
|
||||
/// @param t the aliased type
|
||||
Alias(Symbol n, const Type* t);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Alias(const Alias& other);
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the aliased type
|
||||
Type const* const type;
|
||||
};
|
||||
|
||||
/// `struct N { ... };` type
|
||||
struct Struct : public Castable<Struct, Named> {
|
||||
/// Constructor
|
||||
/// @param n the struct name
|
||||
/// @param m the member types
|
||||
Struct(Symbol n, TypeList m);
|
||||
|
||||
/// Copy constructor
|
||||
/// @param other the other type to copy
|
||||
Struct(const Struct& other);
|
||||
|
||||
/// Destructor
|
||||
~Struct() override;
|
||||
|
||||
/// @param b the ProgramBuilder used to construct the AST types
|
||||
/// @returns the constructed ast::Type node for the given type
|
||||
ast::Type* Build(ProgramBuilder& b) const override;
|
||||
|
||||
/// the member types
|
||||
TypeList const members;
|
||||
};
|
||||
|
||||
/// A manager of types
|
||||
class TypeManager {
|
||||
public:
|
||||
/// Constructor
|
||||
TypeManager();
|
||||
|
||||
/// Destructor
|
||||
~TypeManager();
|
||||
|
||||
/// @return a Void type. Repeated calls will return the same pointer.
|
||||
const spirv::Void* Void();
|
||||
/// @return a Bool type. Repeated calls will return the same pointer.
|
||||
const spirv::Bool* Bool();
|
||||
/// @return a U32 type. Repeated calls will return the same pointer.
|
||||
const spirv::U32* U32();
|
||||
/// @return a F32 type. Repeated calls will return the same pointer.
|
||||
const spirv::F32* F32();
|
||||
/// @return a I32 type. Repeated calls will return the same pointer.
|
||||
const spirv::I32* I32();
|
||||
/// @param ty the pointee type
|
||||
/// @param sc the pointer storage class
|
||||
/// @return a Pointer type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Pointer* Pointer(const Type* ty, ast::StorageClass sc);
|
||||
/// @param ty the element type
|
||||
/// @param sz the number of elements in the vector
|
||||
/// @return a Vector type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Vector* Vector(const Type* ty, uint32_t sz);
|
||||
/// @param ty the matrix element type
|
||||
/// @param c the number of columns in the matrix
|
||||
/// @param r the number of rows in the matrix
|
||||
/// @return a Matrix type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Matrix* Matrix(const Type* ty, uint32_t c, uint32_t r);
|
||||
/// @param el the element type
|
||||
/// @param sz the number of elements in the array. 0 represents runtime-sized
|
||||
/// array.
|
||||
/// @param st the byte stride of the array
|
||||
/// @return a Array type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Array* Array(const Type* el, uint32_t sz, uint32_t st);
|
||||
/// @param ty the inner type
|
||||
/// @param ac the access control
|
||||
/// @return a AccessControl type. Repeated calls with the same arguments will
|
||||
/// return the same pointer.
|
||||
const spirv::AccessControl* AccessControl(const Type* ty,
|
||||
ast::AccessControl::Access ac);
|
||||
/// @param n the alias name
|
||||
/// @param t the aliased type
|
||||
/// @return a Alias type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Alias* Alias(Symbol n, const Type* t);
|
||||
/// @param n the struct name
|
||||
/// @param m the member types
|
||||
/// @return a Struct type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Struct* Struct(Symbol n, TypeList m);
|
||||
/// @param k the sampler kind
|
||||
/// @return a Sampler type. Repeated calls with the same arguments will return
|
||||
/// the same pointer.
|
||||
const spirv::Sampler* Sampler(ast::SamplerKind k);
|
||||
/// @param d the texture dimensions
|
||||
/// @return a DepthTexture type. Repeated calls with the same arguments will
|
||||
/// return the same pointer.
|
||||
const spirv::DepthTexture* DepthTexture(ast::TextureDimension d);
|
||||
/// @param d the texture dimensions
|
||||
/// @param t the multisampled texture type
|
||||
/// @return a MultisampledTexture type. Repeated calls with the same arguments
|
||||
/// will return the same pointer.
|
||||
const spirv::MultisampledTexture* MultisampledTexture(ast::TextureDimension d,
|
||||
const Type* t);
|
||||
/// @param d the texture dimensions
|
||||
/// @param t the sampled texture type
|
||||
/// @return a SampledTexture type. Repeated calls with the same arguments will
|
||||
/// return the same pointer.
|
||||
const spirv::SampledTexture* SampledTexture(ast::TextureDimension d,
|
||||
const Type* t);
|
||||
/// @param d the texture dimensions
|
||||
/// @param f the storage image format
|
||||
/// @return a StorageTexture type. Repeated calls with the same arguments will
|
||||
/// return the same pointer.
|
||||
const spirv::StorageTexture* StorageTexture(ast::TextureDimension d,
|
||||
ast::ImageFormat f);
|
||||
|
||||
private:
|
||||
struct State;
|
||||
std::unique_ptr<State> state;
|
||||
};
|
||||
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
||||
|
||||
#endif // SRC_READER_SPIRV_PARSER_TYPE_H_
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2020 The Tint Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "src/reader/spirv/parser_type.h"
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
namespace spirv {
|
||||
namespace {
|
||||
|
||||
TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
|
||||
Symbol sym(Symbol(1, {}));
|
||||
|
||||
TypeManager ty;
|
||||
EXPECT_EQ(ty.Void(), ty.Void());
|
||||
EXPECT_EQ(ty.Bool(), ty.Bool());
|
||||
EXPECT_EQ(ty.U32(), ty.U32());
|
||||
EXPECT_EQ(ty.F32(), ty.F32());
|
||||
EXPECT_EQ(ty.I32(), ty.I32());
|
||||
EXPECT_EQ(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
||||
ty.Pointer(ty.I32(), ast::StorageClass::kNone));
|
||||
EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
|
||||
EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
|
||||
EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
|
||||
EXPECT_EQ(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly));
|
||||
EXPECT_EQ(ty.Alias(sym, ty.I32()), ty.Alias(sym, ty.I32()));
|
||||
EXPECT_EQ(ty.Struct(sym, {ty.I32()}), ty.Struct(sym, {ty.I32()}));
|
||||
EXPECT_EQ(ty.Sampler(ast::SamplerKind::kSampler),
|
||||
ty.Sampler(ast::SamplerKind::kSampler));
|
||||
EXPECT_EQ(ty.DepthTexture(ast::TextureDimension::k2d),
|
||||
ty.DepthTexture(ast::TextureDimension::k2d));
|
||||
EXPECT_EQ(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()));
|
||||
EXPECT_EQ(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()));
|
||||
EXPECT_EQ(
|
||||
ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
|
||||
ty.StorageTexture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR16Sint));
|
||||
}
|
||||
|
||||
TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
|
||||
Symbol sym_a(Symbol(1, {}));
|
||||
Symbol sym_b(Symbol(2, {}));
|
||||
|
||||
TypeManager ty;
|
||||
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
||||
ty.Pointer(ty.U32(), ast::StorageClass::kNone));
|
||||
EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
|
||||
ty.Pointer(ty.I32(), ast::StorageClass::kInput));
|
||||
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
|
||||
EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
|
||||
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
|
||||
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 2, 2));
|
||||
EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 3));
|
||||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.U32(), 3, 2));
|
||||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 2, 2));
|
||||
EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 3));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.U32(), ast::AccessControl::Access::kReadOnly));
|
||||
EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::Access::kReadOnly),
|
||||
ty.AccessControl(ty.I32(), ast::AccessControl::Access::kWriteOnly));
|
||||
EXPECT_NE(ty.Alias(sym_a, ty.I32()), ty.Alias(sym_b, ty.I32()));
|
||||
EXPECT_NE(ty.Struct(sym_a, {ty.I32()}), ty.Struct(sym_b, {ty.I32()}));
|
||||
EXPECT_NE(ty.Sampler(ast::SamplerKind::kSampler),
|
||||
ty.Sampler(ast::SamplerKind::kComparisonSampler));
|
||||
EXPECT_NE(ty.DepthTexture(ast::TextureDimension::k2d),
|
||||
ty.DepthTexture(ast::TextureDimension::k1d));
|
||||
EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.MultisampledTexture(ast::TextureDimension::k3d, ty.I32()));
|
||||
EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.MultisampledTexture(ast::TextureDimension::k2d, ty.U32()));
|
||||
EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.SampledTexture(ast::TextureDimension::k3d, ty.I32()));
|
||||
EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
|
||||
ty.SampledTexture(ast::TextureDimension::k2d, ty.U32()));
|
||||
EXPECT_NE(
|
||||
ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
|
||||
ty.StorageTexture(ast::TextureDimension::k3d,
|
||||
ast::ImageFormat::kR16Sint));
|
||||
EXPECT_NE(
|
||||
ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
|
||||
ty.StorageTexture(ast::TextureDimension::k2d,
|
||||
ast::ImageFormat::kR32Sint));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
} // namespace tint
|
|
@ -349,6 +349,7 @@ tint_unittests_source_set("tint_unittests_spv_reader_src") {
|
|||
"../src/reader/spirv/parser_impl_test_helper.cc",
|
||||
"../src/reader/spirv/parser_impl_test_helper.h",
|
||||
"../src/reader/spirv/parser_impl_user_name_test.cc",
|
||||
"../src/reader/spirv/parser_type_test.cc",
|
||||
"../src/reader/spirv/parser_test.cc",
|
||||
"../src/reader/spirv/spirv_tools_helpers_test.cc",
|
||||
"../src/reader/spirv/spirv_tools_helpers_test.h",
|
||||
|
|
Loading…
Reference in New Issue