writer/hlsl: Begin migration to ast::Types
The HLSL writer doesn't really care much for ast::Types, so most of the work here is repointing the logic to fetch the resolved, semantic type. Output for aliases has changed, as the semantic type resolves away aliases. Bug: tint:724 Change-Id: I6eb9d5c2fbcd62eef0f9dd145360714db649e13f Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/49530 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
ccab6bd694
commit
1a492a27db
|
@ -226,7 +226,8 @@ bool GeneratorImpl::EmitConstructedType(std::ostream& out,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
diagnostics_.add_error("unknown constructed type: " + ty->type_name());
|
TINT_UNREACHABLE(diagnostics_)
|
||||||
|
<< "constructed type: " << ty->TypeInfo().name;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,14 +253,14 @@ bool GeneratorImpl::EmitArrayAccessor(std::ostream& pre,
|
||||||
bool GeneratorImpl::EmitBitcast(std::ostream& pre,
|
bool GeneratorImpl::EmitBitcast(std::ostream& pre,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::BitcastExpression* expr) {
|
ast::BitcastExpression* expr) {
|
||||||
if (!expr->type()->is_integer_scalar() && !expr->type()->is_float_scalar()) {
|
auto* type = TypeOf(expr);
|
||||||
diagnostics_.add_error("Unable to do bitcast to type " +
|
if (!type->is_integer_scalar() && !type->is_float_scalar()) {
|
||||||
expr->type()->type_name());
|
diagnostics_.add_error("Unable to do bitcast to type " + type->type_name());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "as";
|
out << "as";
|
||||||
if (!EmitType(out, expr->type(), ast::StorageClass::kNone, "")) {
|
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out << "(";
|
out << "(";
|
||||||
|
@ -1312,20 +1313,21 @@ bool GeneratorImpl::EmitScalarConstructor(
|
||||||
bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
bool GeneratorImpl::EmitTypeConstructor(std::ostream& pre,
|
||||||
std::ostream& out,
|
std::ostream& out,
|
||||||
ast::TypeConstructorExpression* expr) {
|
ast::TypeConstructorExpression* expr) {
|
||||||
|
auto* type = TypeOf(expr);
|
||||||
|
|
||||||
// If the type constructor is empty then we need to construct with the zero
|
// If the type constructor is empty then we need to construct with the zero
|
||||||
// value for all components.
|
// value for all components.
|
||||||
if (expr->values().empty()) {
|
if (expr->values().empty()) {
|
||||||
return EmitZeroValue(out, expr->type());
|
return EmitZeroValue(out, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool brackets = expr->type()
|
bool brackets =
|
||||||
->UnwrapAliasIfNeeded()
|
type->UnwrapAliasIfNeeded()->IsAnyOf<sem::ArrayType, sem::StructType>();
|
||||||
->IsAnyOf<sem::ArrayType, sem::StructType>();
|
|
||||||
|
|
||||||
if (brackets) {
|
if (brackets) {
|
||||||
out << "{";
|
out << "{";
|
||||||
} else {
|
} else {
|
||||||
if (!EmitType(out, expr->type(), ast::StorageClass::kNone, "")) {
|
if (!EmitType(out, type, ast::StorageClass::kNone, "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out << "(";
|
out << "(";
|
||||||
|
@ -1578,27 +1580,27 @@ bool GeneratorImpl::EmitFunction(std::ostream& out, ast::Function* func) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
||||||
ast::Function* func,
|
ast::Function* func_ast,
|
||||||
bool emit_duplicate_functions,
|
bool emit_duplicate_functions,
|
||||||
Symbol ep_sym) {
|
Symbol ep_sym) {
|
||||||
auto name = func->symbol().to_str();
|
auto* func = builder_.Sem().Get(func_ast);
|
||||||
|
|
||||||
if (!EmitType(out, func->return_type(), ast::StorageClass::kNone, "")) {
|
if (!EmitType(out, func->ReturnType(), ast::StorageClass::kNone, "")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << " ";
|
out << " ";
|
||||||
|
|
||||||
|
std::string name;
|
||||||
if (emit_duplicate_functions) {
|
if (emit_duplicate_functions) {
|
||||||
auto func_name = name;
|
|
||||||
auto ep_name = ep_sym.to_str();
|
auto ep_name = ep_sym.to_str();
|
||||||
// TODO(dsinclair): The SymbolToName should go away and just use
|
// TODO(dsinclair): The SymbolToName should go away and just use
|
||||||
// to_str() here when the conversion is complete.
|
// to_str() here when the conversion is complete.
|
||||||
name = generate_name(builder_.Symbols().NameFor(func->symbol()) + "_" +
|
name = generate_name(builder_.Symbols().NameFor(func_ast->symbol()) + "_" +
|
||||||
builder_.Symbols().NameFor(ep_sym));
|
builder_.Symbols().NameFor(ep_sym));
|
||||||
ep_func_name_remapped_[ep_name + "_" + func_name] = name;
|
ep_func_name_remapped_[ep_name + "_" + func_ast->symbol().to_str()] = name;
|
||||||
} else {
|
} else {
|
||||||
name = builder_.Symbols().NameFor(func->symbol());
|
name = builder_.Symbols().NameFor(func_ast->symbol());
|
||||||
}
|
}
|
||||||
|
|
||||||
out << name << "(";
|
out << name << "(";
|
||||||
|
@ -1628,27 +1630,26 @@ bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* v : func->params()) {
|
for (auto* v : func->Parameters()) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
auto* sem = builder_.Sem().Get(v);
|
auto* type = v->Type();
|
||||||
auto* type = sem->Type();
|
|
||||||
|
|
||||||
// Note: WGSL only allows for StorageClass::kNone on parameters, however the
|
// Note: WGSL only allows for StorageClass::kNone on parameters, however the
|
||||||
// sanitizer transforms generates load / store functions for storage
|
// sanitizer transforms generates load / store functions for storage
|
||||||
// buffers. These functions have a storage buffer parameter with
|
// buffers. These functions have a storage buffer parameter with
|
||||||
// StorageClass::kStorage. This is required to correctly translate the
|
// StorageClass::kStorage. This is required to correctly translate the
|
||||||
// parameter to [RW]ByteAddressBuffer.
|
// parameter to [RW]ByteAddressBuffer.
|
||||||
if (!EmitType(out, type, sem->StorageClass(),
|
if (!EmitType(out, type, v->StorageClass(),
|
||||||
builder_.Symbols().NameFor(v->symbol()))) {
|
builder_.Symbols().NameFor(v->Declaration()->symbol()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Array name is output as part of the type
|
// Array name is output as part of the type
|
||||||
if (!type->Is<sem::ArrayType>()) {
|
if (!type->Is<sem::ArrayType>()) {
|
||||||
out << " " << builder_.Symbols().NameFor(v->symbol());
|
out << " " << builder_.Symbols().NameFor(v->Declaration()->symbol());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1656,7 +1657,7 @@ bool GeneratorImpl::EmitFunctionInternal(std::ostream& out,
|
||||||
|
|
||||||
current_ep_sym_ = ep_sym;
|
current_ep_sym_ = ep_sym;
|
||||||
|
|
||||||
if (!EmitBlockAndNewline(out, func->body())) {
|
if (!EmitBlockAndNewline(out, func_ast->body())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1885,7 +1886,7 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
for (auto* var : func_sem->ReferencedModuleVariables()) {
|
for (auto* var : func_sem->ReferencedModuleVariables()) {
|
||||||
auto* decl = var->Declaration();
|
auto* decl = var->Declaration();
|
||||||
|
|
||||||
auto* unwrapped_type = var->DeclaredType()->UnwrapAll();
|
auto* unwrapped_type = var->Type()->UnwrapAll();
|
||||||
if (!emitted_globals.emplace(decl->symbol()).second) {
|
if (!emitted_globals.emplace(decl->symbol()).second) {
|
||||||
continue; // Global already emitted
|
continue; // Global already emitted
|
||||||
}
|
}
|
||||||
|
@ -1911,10 +1912,10 @@ bool GeneratorImpl::EmitEntryPointData(
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name = builder_.Symbols().NameFor(decl->symbol());
|
auto name = builder_.Symbols().NameFor(decl->symbol());
|
||||||
if (!EmitType(out, var->DeclaredType(), var->StorageClass(), name)) {
|
if (!EmitType(out, var->Type(), var->StorageClass(), name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!var->DeclaredType()->UnwrapAliasIfNeeded()->Is<sem::ArrayType>()) {
|
if (!var->Type()->UnwrapAliasIfNeeded()->Is<sem::ArrayType>()) {
|
||||||
out << " " << name;
|
out << " " << name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2139,12 +2140,12 @@ bool GeneratorImpl::EmitZeroValue(std::ostream& out, sem::Type* type) {
|
||||||
} else if (auto* str = type->As<sem::StructType>()) {
|
} else if (auto* str = type->As<sem::StructType>()) {
|
||||||
out << "{";
|
out << "{";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto* member : str->impl()->members()) {
|
for (auto* member : builder_.Sem().Get(str)->Members()) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
if (!EmitZeroValue(out, member->type())) {
|
if (!EmitZeroValue(out, member->Type())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2559,21 +2560,21 @@ bool GeneratorImpl::EmitStructType(std::ostream& out,
|
||||||
out << "struct " << name << " {" << std::endl;
|
out << "struct " << name << " {" << std::endl;
|
||||||
|
|
||||||
increment_indent();
|
increment_indent();
|
||||||
for (auto* mem : str->impl()->members()) {
|
for (auto* mem : sem_str->Members()) {
|
||||||
make_indent(out);
|
make_indent(out);
|
||||||
// TODO(dsinclair): Handle [[offset]] annotation on structs
|
// TODO(dsinclair): Handle [[offset]] annotation on structs
|
||||||
// https://bugs.chromium.org/p/tint/issues/detail?id=184
|
// https://bugs.chromium.org/p/tint/issues/detail?id=184
|
||||||
|
|
||||||
if (!EmitType(out, mem->type(), ast::StorageClass::kNone,
|
auto mem_name = builder_.Symbols().NameFor(mem->Declaration()->symbol());
|
||||||
builder_.Symbols().NameFor(mem->symbol()))) {
|
if (!EmitType(out, mem->Type(), ast::StorageClass::kNone, mem_name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Array member name will be output with the type
|
// Array member name will be output with the type
|
||||||
if (!mem->type()->Is<sem::ArrayType>()) {
|
if (!mem->Type()->Is<sem::ArrayType>()) {
|
||||||
out << " " << builder_.Symbols().NameFor(mem->symbol());
|
out << " " << mem_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* deco : mem->decorations()) {
|
for (auto* deco : mem->Declaration()->decorations()) {
|
||||||
if (auto* location = deco->As<ast::LocationDecoration>()) {
|
if (auto* location = deco->As<ast::LocationDecoration>()) {
|
||||||
auto& pipeline_stage_uses =
|
auto& pipeline_stage_uses =
|
||||||
builder_.Sem().Get(str)->PipelineStageUses();
|
builder_.Sem().Get(str)->PipelineStageUses();
|
||||||
|
|
|
@ -379,6 +379,12 @@ class GeneratorImpl : public TextGenerator {
|
||||||
return builder_.TypeOf(expr);
|
return builder_.TypeOf(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @returns the resolved type of the ast::Type `type`
|
||||||
|
/// @param type the type
|
||||||
|
const sem::Type* TypeOf(ast::Type* type) const {
|
||||||
|
return builder_.TypeOf(type);
|
||||||
|
}
|
||||||
|
|
||||||
ProgramBuilder builder_;
|
ProgramBuilder builder_;
|
||||||
Symbol current_ep_sym_;
|
Symbol current_ep_sym_;
|
||||||
bool generating_entry_point_ = false;
|
bool generating_entry_point_ = false;
|
||||||
|
|
|
@ -34,16 +34,6 @@ TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_F32) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_NameCollision) {
|
|
||||||
AST().AddConstructedType(ty.alias("float", ty.f32()));
|
|
||||||
|
|
||||||
GeneratorImpl& gen = SanitizeAndBuild();
|
|
||||||
|
|
||||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
|
||||||
EXPECT_THAT(result(), HasSubstr(R"(typedef float tint_symbol;
|
|
||||||
)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_Struct) {
|
TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_Struct) {
|
||||||
auto s = Structure("A", {
|
auto s = Structure("A", {
|
||||||
Member("a", ty.f32()),
|
Member("a", ty.f32()),
|
||||||
|
|
|
@ -32,7 +32,7 @@ inline typ::Type ty_i32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.i32();
|
return ty.i32();
|
||||||
}
|
}
|
||||||
inline typ::Type ty_u32(const ProgramBuilder::TypesBuilder& ty) {
|
inline typ::Type ty_u32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.u32();
|
return ty.builder->create<sem::U32>();
|
||||||
}
|
}
|
||||||
inline typ::Type ty_f32(const ProgramBuilder::TypesBuilder& ty) {
|
inline typ::Type ty_f32(const ProgramBuilder::TypesBuilder& ty) {
|
||||||
return ty.f32();
|
return ty.f32();
|
||||||
|
@ -250,15 +250,14 @@ TEST_P(HlslGeneratorImplTest_MemberAccessor_StorageBufferStore, Test) {
|
||||||
|
|
||||||
auto p = GetParam();
|
auto p = GetParam();
|
||||||
|
|
||||||
auto type = p.member_type(ty);
|
|
||||||
|
|
||||||
SetupStorageBuffer({
|
SetupStorageBuffer({
|
||||||
Member("a", ty.i32()),
|
Member("a", ty.i32()),
|
||||||
Member("b", type),
|
Member("b", p.member_type(ty)),
|
||||||
});
|
});
|
||||||
|
|
||||||
SetupFunction({
|
SetupFunction({
|
||||||
Decl(Var("value", type, ast::StorageClass::kFunction, Construct(type))),
|
Decl(Var("value", p.member_type(ty), ast::StorageClass::kFunction,
|
||||||
|
Construct(p.member_type(ty)))),
|
||||||
Assign(MemberAccessor("data", "b"), Expr("value")),
|
Assign(MemberAccessor("data", "b"), Expr("value")),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ TEST_F(HlslGeneratorImplTest_WorkgroupVar, Aliased) {
|
||||||
GeneratorImpl& gen = Build();
|
GeneratorImpl& gen = Build();
|
||||||
|
|
||||||
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
ASSERT_TRUE(gen.Generate(out)) << gen.error();
|
||||||
EXPECT_THAT(result(), HasSubstr("groupshared F32 wg;\n"));
|
EXPECT_THAT(result(), HasSubstr("groupshared float wg;\n"));
|
||||||
|
|
||||||
Validate();
|
Validate();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue