tint: Fix HLSL emission for out-of-order storage / uniform buffers
Recent changes to DecomposeMemoryAccess meant we lost the dependency information between the user of a module-scope variable of the storage / uniform address space and the variable. Add dependency information to ast::InternalAttribute so this can be tracked. This change also means that symbol renaming after the DecomposeMemoryAccess should work. Fixed: tint:1860 Change-Id: Icfa2925f95c2ac50702522df514cd11bde727546 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122660 Reviewed-by: James Price <jrprice@google.com> Commit-Queue: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
fd387a37c3
commit
63d0fabeb1
|
@ -23,7 +23,7 @@ namespace tint::ast {
|
||||||
DisableValidationAttribute::DisableValidationAttribute(ProgramID pid,
|
DisableValidationAttribute::DisableValidationAttribute(ProgramID pid,
|
||||||
NodeID nid,
|
NodeID nid,
|
||||||
DisabledValidation val)
|
DisabledValidation val)
|
||||||
: Base(pid, nid), validation(val) {}
|
: Base(pid, nid, utils::Empty), validation(val) {}
|
||||||
|
|
||||||
DisableValidationAttribute::~DisableValidationAttribute() = default;
|
DisableValidationAttribute::~DisableValidationAttribute() = default;
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,16 @@
|
||||||
|
|
||||||
#include "src/tint/ast/internal_attribute.h"
|
#include "src/tint/ast/internal_attribute.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::ast::InternalAttribute);
|
TINT_INSTANTIATE_TYPEINFO(tint::ast::InternalAttribute);
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
||||||
InternalAttribute::InternalAttribute(ProgramID pid, NodeID nid) : Base(pid, nid, Source{}) {}
|
InternalAttribute::InternalAttribute(ProgramID pid,
|
||||||
|
NodeID nid,
|
||||||
|
utils::VectorRef<const IdentifierExpression*> deps)
|
||||||
|
: Base(pid, nid, Source{}), dependencies(std::move(deps)) {}
|
||||||
|
|
||||||
InternalAttribute::~InternalAttribute() = default;
|
InternalAttribute::~InternalAttribute() = default;
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "src/tint/ast/attribute.h"
|
#include "src/tint/ast/attribute.h"
|
||||||
|
#include "src/tint/utils/vector.h"
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
namespace tint::ast {
|
||||||
|
class IdentifierExpression;
|
||||||
|
} // namespace tint::ast
|
||||||
|
|
||||||
namespace tint::ast {
|
namespace tint::ast {
|
||||||
|
|
||||||
|
@ -29,7 +35,10 @@ class InternalAttribute : public Castable<InternalAttribute, Attribute> {
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param program_id the identifier of the program that owns this node
|
/// @param program_id the identifier of the program that owns this node
|
||||||
/// @param nid the unique node identifier
|
/// @param nid the unique node identifier
|
||||||
explicit InternalAttribute(ProgramID program_id, NodeID nid);
|
/// @param deps a list of identifiers that this attribute is dependent on
|
||||||
|
InternalAttribute(ProgramID program_id,
|
||||||
|
NodeID nid,
|
||||||
|
utils::VectorRef<const IdentifierExpression*> deps);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~InternalAttribute() override;
|
~InternalAttribute() override;
|
||||||
|
@ -40,6 +49,9 @@ class InternalAttribute : public Castable<InternalAttribute, Attribute> {
|
||||||
|
|
||||||
/// @returns the WGSL name for the attribute
|
/// @returns the WGSL name for the attribute
|
||||||
std::string Name() const override;
|
std::string Name() const override;
|
||||||
|
|
||||||
|
/// A list of identifiers that this attribute is dependent on
|
||||||
|
const utils::Vector<const IdentifierExpression*, 1> dependencies;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace tint::ast
|
} // namespace tint::ast
|
||||||
|
|
|
@ -1977,4 +1977,40 @@ TEST_F(MustUseAttributeTest, UsedOnFnWithNoReturnValue) {
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace MustUseTests
|
} // namespace MustUseTests
|
||||||
|
|
||||||
|
namespace InternalAttributeDeps {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class TestAttribute : public Castable<TestAttribute, ast::InternalAttribute> {
|
||||||
|
public:
|
||||||
|
TestAttribute(ProgramID pid, ast::NodeID nid, const ast::IdentifierExpression* dep)
|
||||||
|
: Base(pid, nid, utils::Vector{dep}) {}
|
||||||
|
std::string InternalName() const override { return "test_attribute"; }
|
||||||
|
const Cloneable* Clone(CloneContext*) const override { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
using InternalAttributeDepsTest = ResolverTest;
|
||||||
|
TEST_F(InternalAttributeDepsTest, Dependency) {
|
||||||
|
auto* ident = Expr("v");
|
||||||
|
auto* attr = ASTNodes().Create<TestAttribute>(ID(), AllocateNodeID(), ident);
|
||||||
|
auto* f = Func("f", utils::Empty, ty.void_(), utils::Empty, utils::Vector{attr});
|
||||||
|
auto* v = GlobalVar("v", ty.i32(), builtin::AddressSpace::kPrivate);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* user = As<sem::VariableUser>(Sem().Get(ident));
|
||||||
|
ASSERT_NE(user, nullptr);
|
||||||
|
|
||||||
|
auto* var = Sem().Get(v);
|
||||||
|
EXPECT_EQ(user->Variable(), var);
|
||||||
|
|
||||||
|
auto* fn = Sem().Get(f);
|
||||||
|
EXPECT_THAT(fn->DirectlyReferencedGlobals(), testing::ElementsAre(var));
|
||||||
|
EXPECT_THAT(fn->TransitivelyReferencedGlobals(), testing::ElementsAre(var));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace InternalAttributeDeps
|
||||||
|
|
||||||
} // namespace tint::resolver
|
} // namespace tint::resolver
|
||||||
|
|
||||||
|
TINT_INSTANTIATE_TYPEINFO(tint::resolver::InternalAttributeDeps::TestAttribute);
|
||||||
|
|
|
@ -414,12 +414,18 @@ class DependencyScanner {
|
||||||
TraverseExpression(wg->y);
|
TraverseExpression(wg->y);
|
||||||
TraverseExpression(wg->z);
|
TraverseExpression(wg->z);
|
||||||
return true;
|
return true;
|
||||||
|
},
|
||||||
|
[&](const ast::InternalAttribute* i) {
|
||||||
|
for (auto* dep : i->dependencies) {
|
||||||
|
TraverseExpression(dep);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
if (handled) {
|
if (handled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attr->IsAnyOf<ast::BuiltinAttribute, ast::DiagnosticAttribute, ast::InternalAttribute,
|
if (attr->IsAnyOf<ast::BuiltinAttribute, ast::DiagnosticAttribute,
|
||||||
ast::InterpolateAttribute, ast::InvariantAttribute, ast::MustUseAttribute,
|
ast::InterpolateAttribute, ast::InvariantAttribute, ast::MustUseAttribute,
|
||||||
ast::StageAttribute, ast::StrideAttribute,
|
ast::StageAttribute, ast::StrideAttribute,
|
||||||
ast::StructMemberOffsetAttribute>()) {
|
ast::StructMemberOffsetAttribute>()) {
|
||||||
|
|
|
@ -1495,7 +1495,7 @@ IntrinsicTable::CtorOrConv Impl::Lookup(CtorConvIntrinsic type,
|
||||||
|
|
||||||
// Was this overload a constructor or conversion?
|
// Was this overload a constructor or conversion?
|
||||||
if (match.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
|
if (match.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
|
||||||
utils::Vector<const sem::Parameter*, 8> params;
|
utils::Vector<sem::Parameter*, 8> params;
|
||||||
params.Reserve(match.parameters.Length());
|
params.Reserve(match.parameters.Length());
|
||||||
for (auto& p : match.parameters) {
|
for (auto& p : match.parameters) {
|
||||||
params.Push(builder.create<sem::Parameter>(
|
params.Push(builder.create<sem::Parameter>(
|
||||||
|
|
|
@ -856,9 +856,9 @@ sem::Statement* Resolver::ConstAssert(const ast::ConstAssert* assertion) {
|
||||||
sem::Function* Resolver::Function(const ast::Function* decl) {
|
sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
Mark(decl->name);
|
Mark(decl->name);
|
||||||
|
|
||||||
uint32_t parameter_index = 0;
|
auto* func = builder_->create<sem::Function>(decl);
|
||||||
utils::Hashmap<Symbol, Source, 8> parameter_names;
|
builder_->Sem().Add(decl, func);
|
||||||
utils::Vector<sem::Parameter*, 8> parameters;
|
TINT_SCOPED_ASSIGNMENT(current_function_, func);
|
||||||
|
|
||||||
validator_.DiagnosticFilters().Push();
|
validator_.DiagnosticFilters().Push();
|
||||||
TINT_DEFER(validator_.DiagnosticFilters().Pop());
|
TINT_DEFER(validator_.DiagnosticFilters().Pop());
|
||||||
|
@ -872,6 +872,8 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve all the parameters
|
// Resolve all the parameters
|
||||||
|
uint32_t parameter_index = 0;
|
||||||
|
utils::Hashmap<Symbol, Source, 8> parameter_names;
|
||||||
for (auto* param : decl->params) {
|
for (auto* param : decl->params) {
|
||||||
Mark(param);
|
Mark(param);
|
||||||
|
|
||||||
|
@ -893,7 +895,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters.Push(p);
|
func->AddParameter(p);
|
||||||
|
|
||||||
auto* p_ty = const_cast<type::Type*>(p->Type());
|
auto* p_ty = const_cast<type::Type*>(p->Type());
|
||||||
if (auto* str = p_ty->As<sem::Struct>()) {
|
if (auto* str = p_ty->As<sem::Struct>()) {
|
||||||
|
@ -923,9 +925,9 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
} else {
|
} else {
|
||||||
return_type = builder_->create<type::Void>();
|
return_type = builder_->create<type::Void>();
|
||||||
}
|
}
|
||||||
|
func->SetReturnType(return_type);
|
||||||
|
|
||||||
// Determine if the return type has a location
|
// Determine if the return type has a location
|
||||||
std::optional<uint32_t> return_location;
|
|
||||||
for (auto* attr : decl->return_type_attributes) {
|
for (auto* attr : decl->return_type_attributes) {
|
||||||
if (!Attribute(attr)) {
|
if (!Attribute(attr)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -936,7 +938,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return_location = value.Get();
|
func->SetReturnLocation(value.Get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,12 +965,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* func =
|
|
||||||
builder_->create<sem::Function>(decl, return_type, return_location, std::move(parameters));
|
|
||||||
ApplyDiagnosticSeverities(func);
|
ApplyDiagnosticSeverities(func);
|
||||||
builder_->Sem().Add(decl, func);
|
|
||||||
|
|
||||||
TINT_SCOPED_ASSIGNMENT(current_function_, func);
|
|
||||||
|
|
||||||
if (!WorkgroupSize(decl)) {
|
if (!WorkgroupSize(decl)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2089,7 +2086,7 @@ sem::Call* Resolver::Call(const ast::CallExpression* expr) {
|
||||||
auto* call_target = struct_ctors_.GetOrCreate(
|
auto* call_target = struct_ctors_.GetOrCreate(
|
||||||
StructConstructorSig{{str, args.Length(), args_stage}},
|
StructConstructorSig{{str, args.Length(), args_stage}},
|
||||||
[&]() -> sem::ValueConstructor* {
|
[&]() -> sem::ValueConstructor* {
|
||||||
utils::Vector<const sem::Parameter*, 8> params;
|
utils::Vector<sem::Parameter*, 8> params;
|
||||||
params.Resize(std::min(args.Length(), str->Members().Length()));
|
params.Resize(std::min(args.Length(), str->Members().Length()));
|
||||||
for (size_t i = 0, n = params.Length(); i < n; i++) {
|
for (size_t i = 0, n = params.Length(); i < n; i++) {
|
||||||
params[i] = builder_->create<sem::Parameter>(
|
params[i] = builder_->create<sem::Parameter>(
|
||||||
|
@ -3436,6 +3433,7 @@ bool Resolver::Attribute(const ast::Attribute* attr) {
|
||||||
[&](const ast::BuiltinAttribute* b) { return BuiltinAttribute(b); },
|
[&](const ast::BuiltinAttribute* b) { return BuiltinAttribute(b); },
|
||||||
[&](const ast::DiagnosticAttribute* d) { return DiagnosticControl(d->control); },
|
[&](const ast::DiagnosticAttribute* d) { return DiagnosticControl(d->control); },
|
||||||
[&](const ast::InterpolateAttribute* i) { return InterpolateAttribute(i); },
|
[&](const ast::InterpolateAttribute* i) { return InterpolateAttribute(i); },
|
||||||
|
[&](const ast::InternalAttribute* i) { return InternalAttribute(i); },
|
||||||
[&](Default) { return true; });
|
[&](Default) { return true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3460,6 +3458,15 @@ bool Resolver::InterpolateAttribute(const ast::InterpolateAttribute* attr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Resolver::InternalAttribute(const ast::InternalAttribute* attr) {
|
||||||
|
for (auto* dep : attr->dependencies) {
|
||||||
|
if (!Expression(dep)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
|
bool Resolver::DiagnosticControl(const ast::DiagnosticControl& control) {
|
||||||
Mark(control.rule_name);
|
Mark(control.rule_name);
|
||||||
|
|
||||||
|
|
|
@ -321,6 +321,10 @@ class Resolver {
|
||||||
/// @returns true on success, false on failure
|
/// @returns true on success, false on failure
|
||||||
bool InterpolateAttribute(const ast::InterpolateAttribute* attr);
|
bool InterpolateAttribute(const ast::InterpolateAttribute* attr);
|
||||||
|
|
||||||
|
/// Resolves the internal attribute @p attr
|
||||||
|
/// @returns true on success, false on failure
|
||||||
|
bool InternalAttribute(const ast::InternalAttribute* attr);
|
||||||
|
|
||||||
/// @param control the diagnostic control
|
/// @param control the diagnostic control
|
||||||
/// @returns true on success, false on failure
|
/// @returns true on success, false on failure
|
||||||
bool DiagnosticControl(const ast::DiagnosticControl& control);
|
bool DiagnosticControl(const ast::DiagnosticControl& control);
|
||||||
|
|
|
@ -25,17 +25,6 @@
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::sem::Builtin);
|
TINT_INSTANTIATE_TYPEINFO(tint::sem::Builtin);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
namespace {
|
|
||||||
|
|
||||||
utils::VectorRef<const Parameter*> SetOwner(utils::VectorRef<Parameter*> parameters,
|
|
||||||
const tint::sem::CallTarget* owner) {
|
|
||||||
for (auto* parameter : parameters) {
|
|
||||||
parameter->SetOwner(owner);
|
|
||||||
}
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
const char* Builtin::str() const {
|
const char* Builtin::str() const {
|
||||||
return sem::str(type_);
|
return sem::str(type_);
|
||||||
|
@ -112,7 +101,7 @@ Builtin::Builtin(BuiltinType type,
|
||||||
PipelineStageSet supported_stages,
|
PipelineStageSet supported_stages,
|
||||||
bool is_deprecated,
|
bool is_deprecated,
|
||||||
bool must_use)
|
bool must_use)
|
||||||
: Base(return_type, SetOwner(std::move(parameters), this), eval_stage, must_use),
|
: Base(return_type, std::move(parameters), eval_stage, must_use),
|
||||||
type_(type),
|
type_(type),
|
||||||
supported_stages_(supported_stages),
|
supported_stages_(supported_stages),
|
||||||
is_deprecated_(is_deprecated) {}
|
is_deprecated_(is_deprecated) {}
|
||||||
|
|
|
@ -23,17 +23,25 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::CallTarget);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
|
CallTarget::CallTarget(EvaluationStage stage, bool must_use) : stage_(stage), must_use_(must_use) {}
|
||||||
|
|
||||||
CallTarget::CallTarget(const type::Type* return_type,
|
CallTarget::CallTarget(const type::Type* return_type,
|
||||||
utils::VectorRef<const Parameter*> parameters,
|
utils::VectorRef<Parameter*> parameters,
|
||||||
EvaluationStage stage,
|
EvaluationStage stage,
|
||||||
bool must_use)
|
bool must_use)
|
||||||
: signature_{return_type, std::move(parameters)}, stage_(stage), must_use_(must_use) {
|
: stage_(stage), must_use_(must_use) {
|
||||||
|
SetReturnType(return_type);
|
||||||
|
for (auto* param : parameters) {
|
||||||
|
AddParameter(param);
|
||||||
|
}
|
||||||
TINT_ASSERT(Semantic, return_type);
|
TINT_ASSERT(Semantic, return_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
CallTarget::CallTarget(const CallTarget&) = default;
|
CallTarget::CallTarget(const CallTarget&) = default;
|
||||||
CallTarget::~CallTarget() = default;
|
CallTarget::~CallTarget() = default;
|
||||||
|
|
||||||
|
CallTargetSignature::CallTargetSignature() = default;
|
||||||
|
|
||||||
CallTargetSignature::CallTargetSignature(const type::Type* ret_ty,
|
CallTargetSignature::CallTargetSignature(const type::Type* ret_ty,
|
||||||
utils::VectorRef<const sem::Parameter*> params)
|
utils::VectorRef<const sem::Parameter*> params)
|
||||||
: return_type(ret_ty), parameters(std::move(params)) {}
|
: return_type(ret_ty), parameters(std::move(params)) {}
|
||||||
|
|
|
@ -27,6 +27,9 @@ namespace tint::sem {
|
||||||
|
|
||||||
/// CallTargetSignature holds the return type and parameters for a call target
|
/// CallTargetSignature holds the return type and parameters for a call target
|
||||||
struct CallTargetSignature {
|
struct CallTargetSignature {
|
||||||
|
/// Constructor
|
||||||
|
CallTargetSignature();
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param ret_ty the call target return type
|
/// @param ret_ty the call target return type
|
||||||
/// @param params the call target parameters
|
/// @param params the call target parameters
|
||||||
|
@ -39,9 +42,9 @@ struct CallTargetSignature {
|
||||||
~CallTargetSignature();
|
~CallTargetSignature();
|
||||||
|
|
||||||
/// The type of the call target return value
|
/// The type of the call target return value
|
||||||
const type::Type* const return_type = nullptr;
|
const type::Type* return_type = nullptr;
|
||||||
/// The parameters of the call target
|
/// The parameters of the call target
|
||||||
const utils::Vector<const sem::Parameter*, 8> parameters;
|
utils::Vector<const sem::Parameter*, 8> parameters;
|
||||||
|
|
||||||
/// Equality operator
|
/// Equality operator
|
||||||
/// @param other the signature to compare this to
|
/// @param other the signature to compare this to
|
||||||
|
@ -66,6 +69,12 @@ struct CallTargetSignature {
|
||||||
/// conversions.
|
/// conversions.
|
||||||
class CallTarget : public Castable<CallTarget, Node> {
|
class CallTarget : public Castable<CallTarget, Node> {
|
||||||
public:
|
public:
|
||||||
|
/// Constructor
|
||||||
|
/// @param stage the earliest evaluation stage for a call to this target
|
||||||
|
/// @param must_use the result of the call target must be used, i.e. it cannot be used as a call
|
||||||
|
/// statement.
|
||||||
|
CallTarget(EvaluationStage stage, bool must_use);
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param return_type the return type of the call target
|
/// @param return_type the return type of the call target
|
||||||
/// @param parameters the parameters for the call target
|
/// @param parameters the parameters for the call target
|
||||||
|
@ -73,7 +82,7 @@ class CallTarget : public Castable<CallTarget, Node> {
|
||||||
/// @param must_use the result of the call target must be used, i.e. it cannot be used as a call
|
/// @param must_use the result of the call target must be used, i.e. it cannot be used as a call
|
||||||
/// statement.
|
/// statement.
|
||||||
CallTarget(const type::Type* return_type,
|
CallTarget(const type::Type* return_type,
|
||||||
utils::VectorRef<const Parameter*> parameters,
|
utils::VectorRef<Parameter*> parameters,
|
||||||
EvaluationStage stage,
|
EvaluationStage stage,
|
||||||
bool must_use);
|
bool must_use);
|
||||||
|
|
||||||
|
@ -83,9 +92,20 @@ class CallTarget : public Castable<CallTarget, Node> {
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~CallTarget() override;
|
~CallTarget() override;
|
||||||
|
|
||||||
|
/// Sets the call target's return type
|
||||||
|
/// @param ty the parameter
|
||||||
|
void SetReturnType(const type::Type* ty) { signature_.return_type = ty; }
|
||||||
|
|
||||||
/// @return the return type of the call target
|
/// @return the return type of the call target
|
||||||
const type::Type* ReturnType() const { return signature_.return_type; }
|
const type::Type* ReturnType() const { return signature_.return_type; }
|
||||||
|
|
||||||
|
/// Adds a parameter to the call target
|
||||||
|
/// @param parameter the parameter
|
||||||
|
void AddParameter(Parameter* parameter) {
|
||||||
|
parameter->SetOwner(this);
|
||||||
|
signature_.parameters.Push(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
/// @return the parameters of the call target
|
/// @return the parameters of the call target
|
||||||
auto& Parameters() const { return signature_.parameters; }
|
auto& Parameters() const { return signature_.parameters; }
|
||||||
|
|
||||||
|
|
|
@ -28,29 +28,12 @@
|
||||||
TINT_INSTANTIATE_TYPEINFO(tint::sem::Function);
|
TINT_INSTANTIATE_TYPEINFO(tint::sem::Function);
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
namespace {
|
|
||||||
|
|
||||||
utils::VectorRef<const Parameter*> SetOwner(utils::VectorRef<Parameter*> parameters,
|
Function::Function(const ast::Function* declaration)
|
||||||
const tint::sem::CallTarget* owner) {
|
: Base(EvaluationStage::kRuntime,
|
||||||
for (auto* parameter : parameters) {
|
|
||||||
parameter->SetOwner(owner);
|
|
||||||
}
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Function::Function(const ast::Function* declaration,
|
|
||||||
type::Type* return_type,
|
|
||||||
std::optional<uint32_t> return_location,
|
|
||||||
utils::VectorRef<Parameter*> parameters)
|
|
||||||
: Base(return_type,
|
|
||||||
SetOwner(std::move(parameters), this),
|
|
||||||
EvaluationStage::kRuntime,
|
|
||||||
ast::HasAttribute<ast::MustUseAttribute>(declaration->attributes)),
|
ast::HasAttribute<ast::MustUseAttribute>(declaration->attributes)),
|
||||||
declaration_(declaration),
|
declaration_(declaration),
|
||||||
workgroup_size_{1, 1, 1},
|
workgroup_size_{1, 1, 1} {}
|
||||||
return_location_(return_location) {}
|
|
||||||
|
|
||||||
Function::~Function() = default;
|
Function::~Function() = default;
|
||||||
|
|
||||||
|
|
|
@ -54,17 +54,15 @@ class Function final : public Castable<Function, CallTarget> {
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// @param declaration the ast::Function
|
/// @param declaration the ast::Function
|
||||||
/// @param return_type the return type of the function
|
explicit Function(const ast::Function* declaration);
|
||||||
/// @param return_location the location value for the return, if provided
|
|
||||||
/// @param parameters the parameters to the function
|
|
||||||
Function(const ast::Function* declaration,
|
|
||||||
type::Type* return_type,
|
|
||||||
std::optional<uint32_t> return_location,
|
|
||||||
utils::VectorRef<Parameter*> parameters);
|
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Function() override;
|
~Function() override;
|
||||||
|
|
||||||
|
/// Sets the function's return location
|
||||||
|
/// @param return_location the location value
|
||||||
|
void SetReturnLocation(uint32_t return_location) { return_location_ = return_location; }
|
||||||
|
|
||||||
/// @returns the ast::Function declaration
|
/// @returns the ast::Function declaration
|
||||||
const ast::Function* Declaration() const { return declaration_; }
|
const ast::Function* Declaration() const { return declaration_; }
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::ValueConstructor);
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
ValueConstructor::ValueConstructor(const type::Type* type,
|
ValueConstructor::ValueConstructor(const type::Type* type,
|
||||||
utils::VectorRef<const Parameter*> parameters,
|
utils::VectorRef<Parameter*> parameters,
|
||||||
EvaluationStage stage)
|
EvaluationStage stage)
|
||||||
: Base(type, std::move(parameters), stage, /* must_use */ true) {}
|
: Base(type, std::move(parameters), stage, /* must_use */ true) {}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ValueConstructor final : public Castable<ValueConstructor, CallTarget> {
|
||||||
/// @param parameters the constructor parameters
|
/// @param parameters the constructor parameters
|
||||||
/// @param stage the earliest evaluation stage for the expression
|
/// @param stage the earliest evaluation stage for the expression
|
||||||
ValueConstructor(const type::Type* type,
|
ValueConstructor(const type::Type* type,
|
||||||
utils::VectorRef<const Parameter*> parameters,
|
utils::VectorRef<Parameter*> parameters,
|
||||||
EvaluationStage stage);
|
EvaluationStage stage);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
|
|
|
@ -19,9 +19,9 @@ TINT_INSTANTIATE_TYPEINFO(tint::sem::ValueConversion);
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
|
||||||
ValueConversion::ValueConversion(const type::Type* type,
|
ValueConversion::ValueConversion(const type::Type* type,
|
||||||
const sem::Parameter* parameter,
|
sem::Parameter* parameter,
|
||||||
EvaluationStage stage)
|
EvaluationStage stage)
|
||||||
: Base(type, utils::Vector<const sem::Parameter*, 1>{parameter}, stage, /* must_use */ true) {}
|
: Base(type, utils::Vector<sem::Parameter*, 1>{parameter}, stage, /* must_use */ true) {}
|
||||||
|
|
||||||
ValueConversion::~ValueConversion() = default;
|
ValueConversion::~ValueConversion() = default;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ class ValueConversion final : public Castable<ValueConversion, CallTarget> {
|
||||||
/// @param type the target type of the cast
|
/// @param type the target type of the cast
|
||||||
/// @param parameter the type cast parameter
|
/// @param parameter the type cast parameter
|
||||||
/// @param stage the earliest evaluation stage for the expression
|
/// @param stage the earliest evaluation stage for the expression
|
||||||
ValueConversion(const type::Type* type, const sem::Parameter* parameter, EvaluationStage stage);
|
ValueConversion(const type::Type* type, sem::Parameter* parameter, EvaluationStage stage);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~ValueConversion() override;
|
~ValueConversion() override;
|
||||||
|
|
|
@ -102,7 +102,7 @@ Transform::ApplyResult AddBlockAttribute::Apply(const Program* src,
|
||||||
}
|
}
|
||||||
|
|
||||||
AddBlockAttribute::BlockAttribute::BlockAttribute(ProgramID pid, ast::NodeID nid)
|
AddBlockAttribute::BlockAttribute::BlockAttribute(ProgramID pid, ast::NodeID nid)
|
||||||
: Base(pid, nid) {}
|
: Base(pid, nid, utils::Empty) {}
|
||||||
AddBlockAttribute::BlockAttribute::~BlockAttribute() = default;
|
AddBlockAttribute::BlockAttribute::~BlockAttribute() = default;
|
||||||
std::string AddBlockAttribute::BlockAttribute::InternalName() const {
|
std::string AddBlockAttribute::BlockAttribute::InternalName() const {
|
||||||
return "block";
|
return "block";
|
||||||
|
|
|
@ -71,7 +71,7 @@ struct ArrayUsage {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, ast::NodeID nid)
|
CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, ast::NodeID nid)
|
||||||
: Base(pid, nid) {}
|
: Base(pid, nid, utils::Empty) {}
|
||||||
CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
|
CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
|
||||||
std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
|
std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
|
||||||
return "intrinsic_buffer_size";
|
return "intrinsic_buffer_size";
|
||||||
|
|
|
@ -228,7 +228,7 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
|
||||||
}
|
}
|
||||||
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
||||||
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, type,
|
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, type,
|
||||||
address_space, buffer);
|
address_space, builder->Expr(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
|
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function to
|
||||||
|
@ -242,7 +242,7 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
|
||||||
}
|
}
|
||||||
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
||||||
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
|
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
|
||||||
type, builtin::AddressSpace::kStorage, buffer);
|
type, builtin::AddressSpace::kStorage, builder->Expr(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
|
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
|
||||||
|
@ -299,7 +299,7 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
|
||||||
}
|
}
|
||||||
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
||||||
builder->ID(), builder->AllocateNodeID(), op, type, builtin::AddressSpace::kStorage,
|
builder->ID(), builder->AllocateNodeID(), op, type, builtin::AddressSpace::kStorage,
|
||||||
buffer);
|
builder->Expr(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BufferAccess describes a single storage or uniform buffer access
|
/// BufferAccess describes a single storage or uniform buffer access
|
||||||
|
@ -692,8 +692,8 @@ DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
|
||||||
Op o,
|
Op o,
|
||||||
DataType ty,
|
DataType ty,
|
||||||
builtin::AddressSpace as,
|
builtin::AddressSpace as,
|
||||||
const Symbol& buf)
|
const ast::IdentifierExpression* buf)
|
||||||
: Base(pid, nid), op(o), type(ty), address_space(as), buffer(buf) {}
|
: Base(pid, nid, utils::Vector{buf}), op(o), type(ty), address_space(as) {}
|
||||||
DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
|
DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
|
||||||
std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
|
std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
|
||||||
utils::StringStream ss;
|
utils::StringStream ss;
|
||||||
|
@ -794,7 +794,7 @@ std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
|
||||||
|
|
||||||
const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
|
const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
|
||||||
CloneContext* ctx) const {
|
CloneContext* ctx) const {
|
||||||
auto buf = ctx->Clone(buffer);
|
auto buf = ctx->Clone(Buffer());
|
||||||
return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
|
||||||
ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, type, address_space, buf);
|
ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, type, address_space, buf);
|
||||||
}
|
}
|
||||||
|
@ -803,6 +803,10 @@ bool DecomposeMemoryAccess::Intrinsic::IsAtomic() const {
|
||||||
return op != Op::kLoad && op != Op::kStore;
|
return op != Op::kLoad && op != Op::kStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ast::IdentifierExpression* DecomposeMemoryAccess::Intrinsic::Buffer() const {
|
||||||
|
return dependencies[0];
|
||||||
|
}
|
||||||
|
|
||||||
DecomposeMemoryAccess::DecomposeMemoryAccess() = default;
|
DecomposeMemoryAccess::DecomposeMemoryAccess() = default;
|
||||||
DecomposeMemoryAccess::~DecomposeMemoryAccess() = default;
|
DecomposeMemoryAccess::~DecomposeMemoryAccess() = default;
|
||||||
|
|
||||||
|
|
|
@ -80,13 +80,13 @@ class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Trans
|
||||||
/// @param o the op of the intrinsic
|
/// @param o the op of the intrinsic
|
||||||
/// @param type the data type of the intrinsic
|
/// @param type the data type of the intrinsic
|
||||||
/// @param address_space the address space of the buffer
|
/// @param address_space the address space of the buffer
|
||||||
/// @param buffer the storage or uniform buffer name
|
/// @param buffer the storage or uniform buffer identifier
|
||||||
Intrinsic(ProgramID pid,
|
Intrinsic(ProgramID pid,
|
||||||
ast::NodeID nid,
|
ast::NodeID nid,
|
||||||
Op o,
|
Op o,
|
||||||
DataType type,
|
DataType type,
|
||||||
builtin::AddressSpace address_space,
|
builtin::AddressSpace address_space,
|
||||||
const Symbol& buffer);
|
const ast::IdentifierExpression* buffer);
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Intrinsic() override;
|
~Intrinsic() override;
|
||||||
|
|
||||||
|
@ -102,6 +102,9 @@ class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Trans
|
||||||
/// @return true if op is atomic
|
/// @return true if op is atomic
|
||||||
bool IsAtomic() const;
|
bool IsAtomic() const;
|
||||||
|
|
||||||
|
/// @return the buffer that this intrinsic operates on
|
||||||
|
const ast::IdentifierExpression* Buffer() const;
|
||||||
|
|
||||||
/// The op of the intrinsic
|
/// The op of the intrinsic
|
||||||
const Op op;
|
const Op op;
|
||||||
|
|
||||||
|
@ -110,9 +113,6 @@ class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Trans
|
||||||
|
|
||||||
/// The address space of the buffer this intrinsic operates on
|
/// The address space of the buffer this intrinsic operates on
|
||||||
const builtin::AddressSpace address_space;
|
const builtin::AddressSpace address_space;
|
||||||
|
|
||||||
/// The buffer name
|
|
||||||
const Symbol buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
|
|
@ -294,7 +294,7 @@ SpirvAtomic::SpirvAtomic() = default;
|
||||||
SpirvAtomic::~SpirvAtomic() = default;
|
SpirvAtomic::~SpirvAtomic() = default;
|
||||||
|
|
||||||
SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType b)
|
SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType b)
|
||||||
: Base(pid, nid), builtin(b) {}
|
: Base(pid, nid, utils::Empty), builtin(b) {}
|
||||||
SpirvAtomic::Stub::~Stub() = default;
|
SpirvAtomic::Stub::~Stub() = default;
|
||||||
std::string SpirvAtomic::Stub::InternalName() const {
|
std::string SpirvAtomic::Stub::InternalName() const {
|
||||||
return "@internal(spirv-atomic " + std::string(sem::str(builtin)) + ")";
|
return "@internal(spirv-atomic " + std::string(sem::str(builtin)) + ")";
|
||||||
|
|
|
@ -30,6 +30,9 @@ namespace tint::utils {
|
||||||
/// Attempting to add a duplicate is a no-op.
|
/// Attempting to add a duplicate is a no-op.
|
||||||
template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
|
template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
|
||||||
struct UniqueVector {
|
struct UniqueVector {
|
||||||
|
/// STL-friendly alias to T. Used by gmock.
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
UniqueVector() = default;
|
UniqueVector() = default;
|
||||||
|
|
||||||
|
|
|
@ -156,13 +156,12 @@ const sem::Call* AppendVector(ProgramBuilder* b,
|
||||||
}));
|
}));
|
||||||
auto* ctor_target = b->create<sem::ValueConstructor>(
|
auto* ctor_target = b->create<sem::ValueConstructor>(
|
||||||
packed_sem_ty,
|
packed_sem_ty,
|
||||||
utils::Transform(
|
utils::Transform(packed,
|
||||||
packed,
|
[&](const tint::sem::ValueExpression* arg, size_t i) {
|
||||||
[&](const tint::sem::ValueExpression* arg, size_t i) -> const sem::Parameter* {
|
return b->create<sem::Parameter>(
|
||||||
return b->create<sem::Parameter>(
|
nullptr, static_cast<uint32_t>(i), arg->Type()->UnwrapRef(),
|
||||||
nullptr, static_cast<uint32_t>(i), arg->Type()->UnwrapRef(),
|
builtin::AddressSpace::kUndefined, builtin::Access::kUndefined);
|
||||||
builtin::AddressSpace::kUndefined, builtin::Access::kUndefined);
|
}),
|
||||||
}),
|
|
||||||
sem::EvaluationStage::kRuntime);
|
sem::EvaluationStage::kRuntime);
|
||||||
auto* ctor_sem = b->create<sem::Call>(ctor_ast, ctor_target, sem::EvaluationStage::kRuntime,
|
auto* ctor_sem = b->create<sem::Call>(ctor_ast, ctor_target, sem::EvaluationStage::kRuntime,
|
||||||
std::move(packed), statement,
|
std::move(packed), statement,
|
||||||
|
|
|
@ -1125,7 +1125,7 @@ bool GeneratorImpl::EmitUniformBufferAccess(
|
||||||
utils::StringStream& out,
|
utils::StringStream& out,
|
||||||
const ast::CallExpression* expr,
|
const ast::CallExpression* expr,
|
||||||
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
||||||
auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
|
auto const buffer = program_->Symbols().NameFor(intrinsic->Buffer()->identifier->symbol);
|
||||||
auto* const offset = expr->args[0];
|
auto* const offset = expr->args[0];
|
||||||
|
|
||||||
// offset in bytes
|
// offset in bytes
|
||||||
|
@ -1413,7 +1413,7 @@ bool GeneratorImpl::EmitStorageBufferAccess(
|
||||||
utils::StringStream& out,
|
utils::StringStream& out,
|
||||||
const ast::CallExpression* expr,
|
const ast::CallExpression* expr,
|
||||||
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
|
||||||
auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
|
auto const buffer = program_->Symbols().NameFor(intrinsic->Buffer()->identifier->symbol);
|
||||||
auto* const offset = expr->args[0];
|
auto* const offset = expr->args[0];
|
||||||
auto* const value = expr->args[1];
|
auto* const value = expr->args[1];
|
||||||
|
|
||||||
|
@ -1581,7 +1581,7 @@ bool GeneratorImpl::EmitStorageAtomicIntrinsic(
|
||||||
const auto name = builder_.Symbols().NameFor(func->name->symbol);
|
const auto name = builder_.Symbols().NameFor(func->name->symbol);
|
||||||
auto& buf = *current_buffer_;
|
auto& buf = *current_buffer_;
|
||||||
|
|
||||||
auto const buffer = program_->Symbols().NameFor(intrinsic->buffer);
|
auto const buffer = program_->Symbols().NameFor(intrinsic->Buffer()->identifier->symbol);
|
||||||
|
|
||||||
auto rmw = [&](const char* hlsl) -> bool {
|
auto rmw = [&](const char* hlsl) -> bool {
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
@vertex
|
||||||
|
fn main() -> @builtin(position) vec4<f32> {
|
||||||
|
return vec4(declared_after_usage.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeclaredAfterUsage {
|
||||||
|
f : f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var <uniform> declared_after_usage : DeclaredAfterUsage;
|
|
@ -0,0 +1,18 @@
|
||||||
|
struct tint_symbol {
|
||||||
|
float4 value : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
cbuffer cbuffer_declared_after_usage : register(b0, space0) {
|
||||||
|
uint4 declared_after_usage[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 main_inner() {
|
||||||
|
return float4((asfloat(declared_after_usage[0].x)).xxxx);
|
||||||
|
}
|
||||||
|
|
||||||
|
tint_symbol main() {
|
||||||
|
const float4 inner_result = main_inner();
|
||||||
|
tint_symbol wrapper_result = (tint_symbol)0;
|
||||||
|
wrapper_result.value = inner_result;
|
||||||
|
return wrapper_result;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
struct tint_symbol {
|
||||||
|
float4 value : SV_Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
cbuffer cbuffer_declared_after_usage : register(b0, space0) {
|
||||||
|
uint4 declared_after_usage[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 main_inner() {
|
||||||
|
return float4((asfloat(declared_after_usage[0].x)).xxxx);
|
||||||
|
}
|
||||||
|
|
||||||
|
tint_symbol main() {
|
||||||
|
const float4 inner_result = main_inner();
|
||||||
|
tint_symbol wrapper_result = (tint_symbol)0;
|
||||||
|
wrapper_result.value = inner_result;
|
||||||
|
return wrapper_result;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#version 310 es
|
||||||
|
|
||||||
|
struct DeclaredAfterUsage {
|
||||||
|
float f;
|
||||||
|
uint pad;
|
||||||
|
uint pad_1;
|
||||||
|
uint pad_2;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(binding = 0, std140) uniform declared_after_usage_block_ubo {
|
||||||
|
DeclaredAfterUsage inner;
|
||||||
|
} declared_after_usage;
|
||||||
|
|
||||||
|
vec4 tint_symbol() {
|
||||||
|
return vec4(declared_after_usage.inner.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_PointSize = 1.0;
|
||||||
|
vec4 inner_result = tint_symbol();
|
||||||
|
gl_Position = inner_result;
|
||||||
|
gl_Position.y = -(gl_Position.y);
|
||||||
|
gl_Position.z = ((2.0f * gl_Position.z) - gl_Position.w);
|
||||||
|
return;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <metal_stdlib>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
struct tint_symbol_1 {
|
||||||
|
float4 value [[position]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeclaredAfterUsage {
|
||||||
|
/* 0x0000 */ float f;
|
||||||
|
};
|
||||||
|
|
||||||
|
float4 tint_symbol_inner(const constant DeclaredAfterUsage* const tint_symbol_2) {
|
||||||
|
return float4((*(tint_symbol_2)).f);
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex tint_symbol_1 tint_symbol(const constant DeclaredAfterUsage* tint_symbol_3 [[buffer(0)]]) {
|
||||||
|
float4 const inner_result = tint_symbol_inner(tint_symbol_3);
|
||||||
|
tint_symbol_1 wrapper_result = {};
|
||||||
|
wrapper_result.value = inner_result;
|
||||||
|
return wrapper_result;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
; SPIR-V
|
||||||
|
; Version: 1.3
|
||||||
|
; Generator: Google Tint Compiler; 0
|
||||||
|
; Bound: 28
|
||||||
|
; Schema: 0
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %main "main" %value %vertex_point_size
|
||||||
|
OpName %value "value"
|
||||||
|
OpName %vertex_point_size "vertex_point_size"
|
||||||
|
OpName %declared_after_usage_block "declared_after_usage_block"
|
||||||
|
OpMemberName %declared_after_usage_block 0 "inner"
|
||||||
|
OpName %DeclaredAfterUsage "DeclaredAfterUsage"
|
||||||
|
OpMemberName %DeclaredAfterUsage 0 "f"
|
||||||
|
OpName %declared_after_usage "declared_after_usage"
|
||||||
|
OpName %main_inner "main_inner"
|
||||||
|
OpName %main "main"
|
||||||
|
OpDecorate %value BuiltIn Position
|
||||||
|
OpDecorate %vertex_point_size BuiltIn PointSize
|
||||||
|
OpDecorate %declared_after_usage_block Block
|
||||||
|
OpMemberDecorate %declared_after_usage_block 0 Offset 0
|
||||||
|
OpMemberDecorate %DeclaredAfterUsage 0 Offset 0
|
||||||
|
OpDecorate %declared_after_usage NonWritable
|
||||||
|
OpDecorate %declared_after_usage DescriptorSet 0
|
||||||
|
OpDecorate %declared_after_usage Binding 0
|
||||||
|
%float = OpTypeFloat 32
|
||||||
|
%v4float = OpTypeVector %float 4
|
||||||
|
%_ptr_Output_v4float = OpTypePointer Output %v4float
|
||||||
|
%5 = OpConstantNull %v4float
|
||||||
|
%value = OpVariable %_ptr_Output_v4float Output %5
|
||||||
|
%_ptr_Output_float = OpTypePointer Output %float
|
||||||
|
%8 = OpConstantNull %float
|
||||||
|
%vertex_point_size = OpVariable %_ptr_Output_float Output %8
|
||||||
|
%DeclaredAfterUsage = OpTypeStruct %float
|
||||||
|
%declared_after_usage_block = OpTypeStruct %DeclaredAfterUsage
|
||||||
|
%_ptr_Uniform_declared_after_usage_block = OpTypePointer Uniform %declared_after_usage_block
|
||||||
|
%declared_after_usage = OpVariable %_ptr_Uniform_declared_after_usage_block Uniform
|
||||||
|
%13 = OpTypeFunction %v4float
|
||||||
|
%uint = OpTypeInt 32 0
|
||||||
|
%uint_0 = OpConstant %uint 0
|
||||||
|
%_ptr_Uniform_float = OpTypePointer Uniform %float
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%22 = OpTypeFunction %void
|
||||||
|
%float_1 = OpConstant %float 1
|
||||||
|
%main_inner = OpFunction %v4float None %13
|
||||||
|
%15 = OpLabel
|
||||||
|
%19 = OpAccessChain %_ptr_Uniform_float %declared_after_usage %uint_0 %uint_0
|
||||||
|
%20 = OpLoad %float %19
|
||||||
|
%21 = OpCompositeConstruct %v4float %20 %20 %20 %20
|
||||||
|
OpReturnValue %21
|
||||||
|
OpFunctionEnd
|
||||||
|
%main = OpFunction %void None %22
|
||||||
|
%25 = OpLabel
|
||||||
|
%26 = OpFunctionCall %v4float %main_inner
|
||||||
|
OpStore %value %26
|
||||||
|
OpStore %vertex_point_size %float_1
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
|
@ -0,0 +1,10 @@
|
||||||
|
@vertex
|
||||||
|
fn main() -> @builtin(position) vec4<f32> {
|
||||||
|
return vec4(declared_after_usage.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DeclaredAfterUsage {
|
||||||
|
f : f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var<uniform> declared_after_usage : DeclaredAfterUsage;
|
Loading…
Reference in New Issue