From e5228407f42b616ec6accdb6988b115b45c301b0 Mon Sep 17 00:00:00 2001 From: dan sinclair Date: Tue, 21 Jul 2020 14:51:33 +0000 Subject: [PATCH] [hlsl-writer] Add emission of identifiers This CL adds identifier emission and an HLSL namer to guard against names using reserved words. Bug: tint:7 Change-Id: Id3d73ff683048c26ac99451d21c3dd7ef3c620a3 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25001 Reviewed-by: David Neto --- BUILD.gn | 8 +- src/CMakeLists.txt | 4 + src/writer/hlsl/generator.cc | 5 +- src/writer/hlsl/generator_impl.cc | 70 +- src/writer/hlsl/generator_impl.h | 40 +- .../hlsl/generator_impl_identifier_test.cc | 67 ++ src/writer/hlsl/generator_impl_test.cc | 5 +- src/writer/hlsl/namer.cc | 692 ++++++++++++++++++ src/writer/hlsl/namer.h | 58 ++ src/writer/hlsl/namer_test.cc | 666 +++++++++++++++++ 10 files changed, 1603 insertions(+), 12 deletions(-) create mode 100644 src/writer/hlsl/generator_impl_identifier_test.cc create mode 100644 src/writer/hlsl/namer.cc create mode 100644 src/writer/hlsl/namer.h create mode 100644 src/writer/hlsl/namer_test.cc diff --git a/BUILD.gn b/BUILD.gn index e6c7e62876..f6f1a9b9a9 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -527,6 +527,8 @@ source_set("libtint_hlsl_writer_src") { "src/writer/hlsl/generator.h", "src/writer/hlsl/generator_impl.cc", "src/writer/hlsl/generator_impl.h", + "src/writer/hlsl/namer.cc", + "src/writer/hlsl/namer.h", ] configs += [ ":tint_common_config" ] @@ -1014,7 +1016,11 @@ source_set("tint_unittests_msl_writer_src") { } source_set("tint_unittests_hlsl_writer_src") { - sources = [ "src/writer/hlsl/generator_impl_test.cc" ] + sources = [ + "src/writer/hlsl/generator_impl_identifier_test.cc", + "src/writer/hlsl/generator_impl_test.cc", + "src/writer/hlsl/namer_test.cc", + ] configs += [ ":tint_common_config", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c0c107f63..06b02ebdb8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -268,6 +268,8 @@ if(${TINT_BUILD_HLSL_WRITER}) writer/hlsl/generator.h writer/hlsl/generator_impl.cc writer/hlsl/generator_impl.h + writer/hlsl/namer.cc + writer/hlsl/namer.h ) endif() @@ -539,7 +541,9 @@ endif() if (${TINT_BUILD_HLSL_WRITER}) list(APPEND TINT_TEST_SRCS + writer/hlsl/generator_impl_identifier_test.cc writer/hlsl/generator_impl_test.cc + writer/hlsl/namer_test.cc ) endif() diff --git a/src/writer/hlsl/generator.cc b/src/writer/hlsl/generator.cc index b0f1566356..03d68ac0a8 100644 --- a/src/writer/hlsl/generator.cc +++ b/src/writer/hlsl/generator.cc @@ -20,12 +20,13 @@ namespace tint { namespace writer { namespace hlsl { -Generator::Generator(ast::Module module) : Text(std::move(module)) {} +Generator::Generator(ast::Module module) + : Text(std::move(module)), impl_(&module_) {} Generator::~Generator() = default; bool Generator::Generate() { - auto ret = impl_.Generate(module_); + auto ret = impl_.Generate(); if (!ret) { error_ = impl_.error(); } diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index 7bcabcda11..ad891da86d 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc @@ -14,15 +14,81 @@ #include "src/writer/hlsl/generator_impl.h" +#include "src/ast/identifier_expression.h" + namespace tint { namespace writer { namespace hlsl { -GeneratorImpl::GeneratorImpl() = default; +GeneratorImpl::GeneratorImpl(ast::Module* module) : module_(module) {} GeneratorImpl::~GeneratorImpl() = default; -bool GeneratorImpl::Generate(const ast::Module&) { +bool GeneratorImpl::Generate() { + for (const auto& global : module_->global_variables()) { + global_variables_.set(global->name(), global.get()); + } + return true; +} + +std::string GeneratorImpl::current_ep_var_name(VarType type) { + std::string name = ""; + switch (type) { + case VarType::kIn: { + auto in_it = ep_name_to_in_data_.find(current_ep_name_); + if (in_it != ep_name_to_in_data_.end()) { + name = in_it->second.var_name; + } + break; + } + case VarType::kOut: { + auto out_it = ep_name_to_out_data_.find(current_ep_name_); + if (out_it != ep_name_to_out_data_.end()) { + name = out_it->second.var_name; + } + break; + } + } + return name; +} + +bool GeneratorImpl::EmitExpression(ast::Expression* expr) { + if (expr->IsIdentifier()) { + return EmitIdentifier(expr->AsIdentifier()); + } + + error_ = "unknown expression type: " + expr->str(); + return false; +} + +bool GeneratorImpl::global_is_in_struct(ast::Variable*) const { + return false; +} + +bool GeneratorImpl::EmitIdentifier(ast::IdentifierExpression* expr) { + auto* ident = expr->AsIdentifier(); + if (ident->has_path()) { + // TODO(dsinclair): Handle identifier with path + error_ = "Identifier paths not handled yet."; + return false; + } + + ast::Variable* var = nullptr; + if (global_variables_.get(ident->name(), &var)) { + if (global_is_in_struct(var)) { + auto var_type = var->storage_class() == ast::StorageClass::kInput + ? VarType::kIn + : VarType::kOut; + auto name = current_ep_var_name(var_type); + if (name.empty()) { + error_ = "unable to find entry point data for variable"; + return false; + } + out_ << name << "."; + } + } + out_ << namer_.NameFor(ident->name()); + return true; } diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h index 2c78a014de..e9e3028533 100644 --- a/src/writer/hlsl/generator_impl.h +++ b/src/writer/hlsl/generator_impl.h @@ -16,6 +16,8 @@ #define SRC_WRITER_HLSL_GENERATOR_IMPL_H_ #include "src/ast/module.h" +#include "src/scope_stack.h" +#include "src/writer/hlsl/namer.h" #include "src/writer/text_generator.h" namespace tint { @@ -26,13 +28,43 @@ namespace hlsl { class GeneratorImpl : public TextGenerator { public: /// Constructor - GeneratorImpl(); + /// @param module the module to generate + explicit GeneratorImpl(ast::Module* module); ~GeneratorImpl(); - /// Generates the result data - /// @param module the module to generate /// @returns true on successful generation; false otherwise - bool Generate(const ast::Module& module); + bool Generate(); + + /// Handles generate an Expression + /// @param expr the expression + /// @returns true if the expression was emitted + bool EmitExpression(ast::Expression* expr); + /// Handles generating an identifier expression + /// @param expr the identifier expression + /// @returns true if the identifeir was emitted + bool EmitIdentifier(ast::IdentifierExpression* expr); + + /// Checks if the global variable is in an input or output struct + /// @param var the variable to check + /// @returns true if the global is in an input or output struct + bool global_is_in_struct(ast::Variable* var) const; + + private: + enum class VarType { kIn, kOut }; + + struct EntryPointData { + std::string struct_name; + std::string var_name; + }; + + std::string current_ep_var_name(VarType type); + + Namer namer_; + ast::Module* module_ = nullptr; + std::string current_ep_name_; + ScopeStack global_variables_; + std::unordered_map ep_name_to_in_data_; + std::unordered_map ep_name_to_out_data_; }; } // namespace hlsl diff --git a/src/writer/hlsl/generator_impl_identifier_test.cc b/src/writer/hlsl/generator_impl_identifier_test.cc new file mode 100644 index 0000000000..7f45efd5da --- /dev/null +++ b/src/writer/hlsl/generator_impl_identifier_test.cc @@ -0,0 +1,67 @@ +// 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/ast/identifier_expression.h" +#include "src/ast/module.h" +#include "src/writer/hlsl/generator_impl.h" + +namespace tint { +namespace writer { +namespace hlsl { +namespace { + +using HlslGeneratorImplTest = testing::Test; + +TEST_F(HlslGeneratorImplTest, DISABLED_EmitExpression_Identifier) { + ast::IdentifierExpression i(std::vector{"std", "glsl"}); + + ast::Module m; + GeneratorImpl g(&m); + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "std::glsl"); +} + +TEST_F(HlslGeneratorImplTest, EmitIdentifierExpression_Single) { + ast::IdentifierExpression i("foo"); + + ast::Module m; + GeneratorImpl g(&m); + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "foo"); +} + +TEST_F(HlslGeneratorImplTest, EmitIdentifierExpression_Single_WithCollision) { + ast::IdentifierExpression i("virtual"); + + ast::Module m; + GeneratorImpl g(&m); + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "virtual_tint_0"); +} + +// TODO(dsinclair): Handle import names +TEST_F(HlslGeneratorImplTest, DISABLED_EmitIdentifierExpression_MultipleNames) { + ast::IdentifierExpression i({"std", "glsl", "init"}); + + ast::Module m; + GeneratorImpl g(&m); + ASSERT_TRUE(g.EmitExpression(&i)) << g.error(); + EXPECT_EQ(g.result(), "std::glsl::init"); +} + +} // namespace +} // namespace hlsl +} // namespace writer +} // namespace tint diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc index 0b68755f43..df128ad93f 100644 --- a/src/writer/hlsl/generator_impl_test.cc +++ b/src/writer/hlsl/generator_impl_test.cc @@ -37,9 +37,8 @@ TEST_F(HlslGeneratorImplTest, DISABLED_Generate) { m.AddEntryPoint(std::make_unique( ast::PipelineStage::kFragment, "my_func", "")); - GeneratorImpl g; - - ASSERT_TRUE(g.Generate(m)) << g.error(); + GeneratorImpl g(&m); + ASSERT_TRUE(g.Generate()) << g.error(); EXPECT_EQ(g.result(), R"(#import void my_func() { diff --git a/src/writer/hlsl/namer.cc b/src/writer/hlsl/namer.cc new file mode 100644 index 0000000000..8c04e9152e --- /dev/null +++ b/src/writer/hlsl/namer.cc @@ -0,0 +1,692 @@ +// 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 "src/writer/hlsl/namer.h" + +#include + +namespace tint { +namespace writer { +namespace hlsl { +namespace { + +// This list is used for a binary search and must be kept in sorted order. +const char* kNames[] = {"AddressU", + "AddressV", + "AddressW", + "AllMemoryBarrier", + "AllMemoryBarrierWithGroupSync", + "AppendStructuredBuffer", + "BINORMAL", + "BLENDINDICES", + "BLENDWEIGHT", + "BlendState", + "BorderColor", + "Buffer", + "ByteAddressBuffer", + "COLOR", + "CheckAccessFullyMapped", + "ComparisonFunc", + "CompileShader", + "ComputeShader", + "ConsumeStructuredBuffer", + "D3DCOLORtoUBYTE4", + "DEPTH", + "DepthStencilState", + "DepthStencilView", + "DeviceMemoryBarrier", + "DeviceMemroyBarrierWithGroupSync", + "DomainShader", + "EvaluateAttributeAtCentroid", + "EvaluateAttributeAtSample", + "EvaluateAttributeSnapped", + "FOG", + "Filter", + "GeometryShader", + "GetRenderTargetSampleCount", + "GetRenderTargetSamplePosition", + "GroupMemoryBarrier", + "GroupMemroyBarrierWithGroupSync", + "Hullshader", + "InputPatch", + "InterlockedAdd", + "InterlockedAnd", + "InterlockedCompareExchange", + "InterlockedCompareStore", + "InterlockedExchange", + "InterlockedMax", + "InterlockedMin", + "InterlockedOr", + "InterlockedXor", + "LineStream", + "MaxAnisotropy", + "MaxLOD", + "MinLOD", + "MipLODBias", + "NORMAL", + "NULL", + "Normal", + "OutputPatch", + "POSITION", + "POSITIONT", + "PSIZE", + "PixelShader", + "PointStream", + "Process2DQuadTessFactorsAvg", + "Process2DQuadTessFactorsMax", + "Process2DQuadTessFactorsMin", + "ProcessIsolineTessFactors", + "ProcessQuadTessFactorsAvg", + "ProcessQuadTessFactorsMax", + "ProcessQuadTessFactorsMin", + "ProcessTriTessFactorsAvg", + "ProcessTriTessFactorsMax", + "ProcessTriTessFactorsMin", + "RWBuffer", + "RWByteAddressBuffer", + "RWStructuredBuffer", + "RWTexture1D", + "RWTexture1DArray", + "RWTexture2D", + "RWTexture2DArray", + "RWTexture3D", + "RasterizerState", + "RenderTargetView", + "SV_ClipDistance", + "SV_Coverage", + "SV_CullDistance", + "SV_Depth", + "SV_DepthGreaterEqual", + "SV_DepthLessEqual", + "SV_DispatchThreadID", + "SV_DomainLocation", + "SV_GSInstanceID", + "SV_GroupID", + "SV_GroupIndex", + "SV_GroupThreadID", + "SV_InnerCoverage", + "SV_InsideTessFactor", + "SV_InstanceID", + "SV_IsFrontFace", + "SV_OutputControlPointID", + "SV_Position", + "SV_PrimitiveID", + "SV_RenderTargetArrayIndex", + "SV_SampleIndex", + "SV_StencilRef", + "SV_Target", + "SV_TessFactor", + "SV_VertexArrayIndex", + "SV_VertexID", + "Sampler", + "Sampler1D", + "Sampler2D", + "Sampler3D", + "SamplerCUBE", + "StructuredBuffer", + "TANGENT", + "TESSFACTOR", + "TEXCOORD", + "Texcoord", + "Texture", + "Texture1D", + "Texture1DArray", + "Texture2D", + "Texture2DArray", + "Texture2DMS", + "Texture2DMSArray", + "Texture3D", + "TextureCube", + "TextureCubeArray", + "TriangleStream", + "VFACE", + "VPOS", + "VertexShader", + "abort", + "abs", + "acos", + "all", + "allow_uav_condition", + "any", + "asdouble", + "asfloat", + "asin", + "asint", + "asm", + "asm_fragment", + "asuint", + "atan", + "atan2", + "auto", + "bool", + "bool1", + "bool1x1", + "bool1x2", + "bool1x3", + "bool1x4", + "bool2", + "bool2x1", + "bool2x2", + "bool2x3", + "bool2x4", + "bool3", + "bool3x1", + "bool3x2", + "bool3x3", + "bool3x4", + "bool4", + "bool4x1", + "bool4x2", + "bool4x3", + "bool4x4", + "branch", + "break", + "call", + "case", + "catch", + "cbuffer", + "ceil", + "centroid", + "char", + "clamp", + "class", + "clip", + "column_major", + "compile_fragment", + "const", + "const_cast", + "continue", + "cos", + "cosh", + "countbits", + "cross", + "ddx", + "ddx_coarse", + "ddx_fine", + "ddy", + "ddy_coarse", + "ddy_fine", + "degrees", + "delete", + "determinant", + "discard", + "distance", + "do", + "dot", + "double", + "double1", + "double1x1", + "double1x2", + "double1x3", + "double1x4", + "double2", + "double2x1", + "double2x2", + "double2x3", + "double2x4", + "double3", + "double3x1", + "double3x2", + "double3x3", + "double3x4", + "double4", + "double4x1", + "double4x2", + "double4x3", + "double4x4", + "dst", + "dword", + "dword1", + "dword1x1", + "dword1x2", + "dword1x3", + "dword1x4", + "dword2", + "dword2x1", + "dword2x2", + "dword2x3", + "dword2x4", + "dword3", + "dword3x1", + "dword3x2", + "dword3x3", + "dword3x4", + "dword4", + "dword4x1", + "dword4x2", + "dword4x3", + "dword4x4", + "dynamic_cast", + "else", + "enum", + "errorf", + "exp", + "exp2", + "explicit", + "export", + "extern", + "f16to32", + "f32tof16", + "faceforward", + "false", + "fastopt", + "firstbithigh", + "firstbitlow", + "flatten", + "float", + "float1", + "float1x1", + "float1x2", + "float1x3", + "float1x4", + "float2", + "float2x1", + "float2x2", + "float2x3", + "float2x4", + "float3", + "float3x1", + "float3x2", + "float3x3", + "float3x4", + "float4", + "float4x1", + "float4x2", + "float4x3", + "float4x4", + "floor", + "fma", + "fmod", + "for", + "forcecase", + "frac", + "frexp", + "friend", + "fwidth", + "fxgroup", + "goto", + "groupshared", + "half", + "half1", + "half1x1", + "half1x2", + "half1x3", + "half1x4", + "half2", + "half2x1", + "half2x2", + "half2x3", + "half2x4", + "half3", + "half3x1", + "half3x2", + "half3x3", + "half3x4", + "half4", + "half4x1", + "half4x2", + "half4x3", + "half4x4", + "if", + "in", + "inline", + "inout", + "int", + "int1", + "int1x1", + "int1x2", + "int1x3", + "int1x4", + "int2", + "int2x1", + "int2x2", + "int2x3", + "int2x4", + "int3", + "int3x1", + "int3x2", + "int3x3", + "int3x4", + "int4", + "int4x1", + "int4x2", + "int4x3", + "int4x4", + "interface", + "isfinite", + "isinf", + "isnan", + "ldexp", + "length", + "lerp", + "lineadj", + "linear", + "lit", + "log", + "log10", + "log2", + "long", + "loop", + "mad", + "matrix", + "max", + "min", + "min10float", + "min10float1", + "min10float1x1", + "min10float1x2", + "min10float1x3", + "min10float1x4", + "min10float2", + "min10float2x1", + "min10float2x2", + "min10float2x3", + "min10float2x4", + "min10float3", + "min10float3x1", + "min10float3x2", + "min10float3x3", + "min10float3x4", + "min10float4", + "min10float4x1", + "min10float4x2", + "min10float4x3", + "min10float4x4", + "min12int", + "min12int1", + "min12int1x1", + "min12int1x2", + "min12int1x3", + "min12int1x4", + "min12int2", + "min12int2x1", + "min12int2x2", + "min12int2x3", + "min12int2x4", + "min12int3", + "min12int3x1", + "min12int3x2", + "min12int3x3", + "min12int3x4", + "min12int4", + "min12int4x1", + "min12int4x2", + "min12int4x3", + "min12int4x4", + "min16float", + "min16float1", + "min16float1x1", + "min16float1x2", + "min16float1x3", + "min16float1x4", + "min16float2", + "min16float2x1", + "min16float2x2", + "min16float2x3", + "min16float2x4", + "min16float3", + "min16float3x1", + "min16float3x2", + "min16float3x3", + "min16float3x4", + "min16float4", + "min16float4x1", + "min16float4x2", + "min16float4x3", + "min16float4x4", + "min16int", + "min16int1", + "min16int1x1", + "min16int1x2", + "min16int1x3", + "min16int1x4", + "min16int2", + "min16int2x1", + "min16int2x2", + "min16int2x3", + "min16int2x4", + "min16int3", + "min16int3x1", + "min16int3x2", + "min16int3x3", + "min16int3x4", + "min16int4", + "min16int4x1", + "min16int4x2", + "min16int4x3", + "min16int4x4", + "min16uint", + "min16uint1", + "min16uint1x1", + "min16uint1x2", + "min16uint1x3", + "min16uint1x4", + "min16uint2", + "min16uint2x1", + "min16uint2x2", + "min16uint2x3", + "min16uint2x4", + "min16uint3", + "min16uint3x1", + "min16uint3x2", + "min16uint3x3", + "min16uint3x4", + "min16uint4", + "min16uint4x1", + "min16uint4x2", + "min16uint4x3", + "min16uint4x4", + "modf", + "msad4", + "mul", + "mutable", + "namespace", + "new", + "nointerpolation", + "noise", + "noperspective", + "normalize", + "numthreads", + "operator", + "out", + "packoffset", + "pass", + "pixelfragment", + "pixelshader", + "point", + "pow", + "precise", + "printf", + "private", + "protected", + "public", + "radians", + "rcp", + "reflect", + "refract", + "register", + "reinterpret_cast", + "return", + "reversebits", + "round", + "row_major", + "rsqrt", + "sample", + "sampler", + "sampler1D", + "sampler2D", + "sampler3D", + "samplerCUBE", + "sampler_state", + "saturate", + "shared", + "short", + "sign", + "signed", + "sin", + "sincos", + "sinh", + "sizeof", + "smoothstep", + "snorm", + "sqrt", + "stateblock", + "stateblock_state", + "static", + "static_cast", + "step", + "string", + "struct", + "switch", + "tan", + "tanh", + "tbuffer", + "technique", + "technique10", + "technique11", + "template", + "tex1D", + "tex1Dbias", + "tex1Dgrad", + "tex1Dlod", + "tex1Dproj", + "tex2D", + "tex2Dbias", + "tex2Dgrad", + "tex2Dlod", + "tex2Dproj", + "tex3D", + "tex3Dbias", + "tex3Dgrad", + "tex3Dlod", + "tex3Dproj", + "texCUBE", + "texCUBEbias", + "texCUBEgrad", + "texCUBElod", + "texCUBEproj", + "texture", + "texture1D", + "texture1DArray", + "texture2D", + "texture2DArray", + "texture2DMS", + "texture2DMSArray", + "texture3D", + "textureCube", + "textureCubeArray", + "this", + "throw", + "transpose", + "triangle", + "triangleadj", + "true", + "trunc", + "try", + "typedef", + "typename", + "uint", + "uint1", + "uint1x1", + "uint1x2", + "uint1x3", + "uint1x4", + "uint2", + "uint2x1", + "uint2x2", + "uint2x3", + "uint2x4", + "uint3", + "uint3x1", + "uint3x2", + "uint3x3", + "uint3x4", + "uint4", + "uint4x1", + "uint4x2", + "uint4x3", + "uint4x4", + "uniform", + "union", + "unorm", + "unroll", + "unsigned", + "using", + "vector", + "vertexfragment", + "vertexshader", + "virtual", + "void", + "volatile", + "while"}; + +} // namespace + +Namer::Namer() = default; + +Namer::~Namer() = default; + +std::string Namer::NameFor(const std::string& name) { + // If it's in the name map we can just return it. There are no shadow names + // in WGSL so this has to be unique in the WGSL names, and we've already + // checked the name collisions with HLSL. + auto it = name_map_.find(name); + if (it != name_map_.end()) { + return it->second; + } + + std::string ret_name = name; + if (std::binary_search(std::begin(kNames), std::end(kNames), ret_name)) { + uint32_t i = 0; + // Make sure there wasn't already a tint variable with the new name we've + // now created. + while (true) { + ret_name = name + "_tint_" + std::to_string(i); + it = name_map_.find(ret_name); + if (it == name_map_.end()) { + break; + } + i++; + } + RegisterRemappedName(ret_name); + } else { + uint32_t i = 0; + // Make sure the ident name wasn't assigned by a remapping. + while (true) { + auto remap_it = remapped_names_.find(ret_name); + if (remap_it == remapped_names_.end()) { + break; + } + ret_name = name + "_" + std::to_string(i); + i++; + } + RegisterRemappedName(ret_name); + } + + name_map_[name] = ret_name; + return ret_name; +} + +bool Namer::IsMapped(const std::string& name) { + auto it = name_map_.find(name); + return it != name_map_.end(); +} + +void Namer::RegisterRemappedName(const std::string& name) { + remapped_names_.insert(name); +} + +} // namespace hlsl +} // namespace writer +} // namespace tint diff --git a/src/writer/hlsl/namer.h b/src/writer/hlsl/namer.h new file mode 100644 index 0000000000..be3b521572 --- /dev/null +++ b/src/writer/hlsl/namer.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef SRC_WRITER_HLSL_NAMER_H_ +#define SRC_WRITER_HLSL_NAMER_H_ + +#include +#include +#include + +namespace tint { +namespace writer { +namespace hlsl { + +/// Remaps maps names to avoid reserved words and collisions for HLSL. +class Namer { + public: + /// Constructor + Namer(); + ~Namer(); + + /// Returns a sanitized version of |name| + /// @param name the name to sanitize + /// @returns the sanitized version of |name| + std::string NameFor(const std::string& name); + + /// Registers a remapped name. + /// @param name the name to register + void RegisterRemappedName(const std::string& name); + + /// Returns if the given name has been mapped alread + /// @param name the name to check + /// @returns true if the name has been mapped + bool IsMapped(const std::string& name); + + private: + /// Map of original name to new name. The two names may be the same. + std::unordered_map name_map_; + // The list of names taken by the remapper + std::unordered_set remapped_names_; +}; + +} // namespace hlsl +} // namespace writer +} // namespace tint + +#endif // SRC_WRITER_HLSL_NAMER_H_ diff --git a/src/writer/hlsl/namer_test.cc b/src/writer/hlsl/namer_test.cc new file mode 100644 index 0000000000..cd5a1ce855 --- /dev/null +++ b/src/writer/hlsl/namer_test.cc @@ -0,0 +1,666 @@ +// 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 "src/writer/hlsl/namer.h" +#include "gtest/gtest.h" + +namespace tint { +namespace writer { +namespace hlsl { +namespace { + +using HlslNamerTest = testing::Test; + +TEST_F(HlslNamerTest, ReturnsName) { + Namer n; + EXPECT_EQ("my_name", n.NameFor("my_name")); + EXPECT_EQ("my_name", n.NameFor("my_name")); +} + +TEST_F(HlslNamerTest, HandlesConflictWithRenamedReservedWordAfterIdentSeen) { + Namer n; + EXPECT_EQ("float_tint_0", n.NameFor("float_tint_0")); + EXPECT_EQ("float_tint_1", n.NameFor("float")); + EXPECT_EQ("float_tint_0", n.NameFor("float_tint_0")); +} + +TEST_F(HlslNamerTest, HandlesConflictWithRenamedReservedWordBeforeIdentSeen) { + Namer n; + EXPECT_EQ("float_tint_0", n.NameFor("float")); + EXPECT_EQ("float_tint_0_0", n.NameFor("float_tint_0")); + EXPECT_EQ("float_tint_0_0_0", n.NameFor("float_tint_0_0")); + EXPECT_EQ("float_tint_0_0", n.NameFor("float_tint_0")); +} + +using HlslReservedNameTest = testing::TestWithParam; +TEST_P(HlslReservedNameTest, Emit) { + auto name = GetParam(); + + Namer n; + EXPECT_EQ(name + "_tint_0", n.NameFor(name)); +} +INSTANTIATE_TEST_SUITE_P(HlslNamerTest, + HlslReservedNameTest, + testing::Values("AddressU", + "AddressV", + "AddressW", + "AllMemoryBarrier", + "AllMemoryBarrierWithGroupSync", + "AppendStructuredBuffer", + "BINORMAL", + "BLENDINDICES", + "BLENDWEIGHT", + "BlendState", + "BorderColor", + "Buffer", + "ByteAddressBuffer", + "COLOR", + "CheckAccessFullyMapped", + "ComparisonFunc", + "CompileShader", + "ComputeShader", + "ConsumeStructuredBuffer", + "D3DCOLORtoUBYTE4", + "DEPTH", + "DepthStencilState", + "DepthStencilView", + "DeviceMemoryBarrier", + "DeviceMemroyBarrierWithGroupSync", + "DomainShader", + "EvaluateAttributeAtCentroid", + "EvaluateAttributeAtSample", + "EvaluateAttributeSnapped", + "FOG", + "Filter", + "GeometryShader", + "GetRenderTargetSampleCount", + "GetRenderTargetSamplePosition", + "GroupMemoryBarrier", + "GroupMemroyBarrierWithGroupSync", + "Hullshader", + "InputPatch", + "InterlockedAdd", + "InterlockedAnd", + "InterlockedCompareExchange", + "InterlockedCompareStore", + "InterlockedExchange", + "InterlockedMax", + "InterlockedMin", + "InterlockedOr", + "InterlockedXor", + "LineStream", + "MaxAnisotropy", + "MaxLOD", + "MinLOD", + "MipLODBias", + "NORMAL", + "NULL", + "Normal", + "OutputPatch", + "POSITION", + "POSITIONT", + "PSIZE", + "PixelShader", + "PointStream", + "Process2DQuadTessFactorsAvg", + "Process2DQuadTessFactorsMax", + "Process2DQuadTessFactorsMin", + "ProcessIsolineTessFactors", + "ProcessQuadTessFactorsAvg", + "ProcessQuadTessFactorsMax", + "ProcessQuadTessFactorsMin", + "ProcessTriTessFactorsAvg", + "ProcessTriTessFactorsMax", + "ProcessTriTessFactorsMin", + "RWBuffer", + "RWByteAddressBuffer", + "RWStructuredBuffer", + "RWTexture1D", + "RWTexture1DArray", + "RWTexture2D", + "RWTexture2DArray", + "RWTexture3D", + "RasterizerState", + "RenderTargetView", + "SV_ClipDistance", + "SV_Coverage", + "SV_CullDistance", + "SV_Depth", + "SV_DepthGreaterEqual", + "SV_DepthLessEqual", + "SV_DispatchThreadID", + "SV_DomainLocation", + "SV_GSInstanceID", + "SV_GroupID", + "SV_GroupIndex", + "SV_GroupThreadID", + "SV_InnerCoverage", + "SV_InsideTessFactor", + "SV_InstanceID", + "SV_IsFrontFace", + "SV_OutputControlPointID", + "SV_Position", + "SV_PrimitiveID", + "SV_RenderTargetArrayIndex", + "SV_SampleIndex", + "SV_StencilRef", + "SV_Target", + "SV_TessFactor", + "SV_VertexArrayIndex", + "SV_VertexID", + "Sampler", + "Sampler1D", + "Sampler2D", + "Sampler3D", + "SamplerCUBE", + "StructuredBuffer", + "TANGENT", + "TESSFACTOR", + "TEXCOORD", + "Texcoord", + "Texture", + "Texture1D", + "Texture1DArray", + "Texture2D", + "Texture2DArray", + "Texture2DMS", + "Texture2DMSArray", + "Texture3D", + "TextureCube", + "TextureCubeArray", + "TriangleStream", + "VFACE", + "VPOS", + "VertexShader", + "abort", + "abs", + "acos", + "all", + "allow_uav_condition", + "any", + "asdouble", + "asfloat", + "asin", + "asint", + "asm", + "asm_fragment", + "asuint", + "atan", + "atan2", + "auto", + "bool", + "bool1", + "bool1x1", + "bool1x2", + "bool1x3", + "bool1x4", + "bool2", + "bool2x1", + "bool2x2", + "bool2x3", + "bool2x4", + "bool3", + "bool3x1", + "bool3x2", + "bool3x3", + "bool3x4", + "bool4", + "bool4x1", + "bool4x2", + "bool4x3", + "bool4x4", + "branch", + "break", + "call", + "case", + "catch", + "cbuffer", + "ceil", + "centroid", + "char", + "clamp", + "class", + "clip", + "column_major", + "compile_fragment", + "const", + "const_cast", + "continue", + "cos", + "cosh", + "countbits", + "cross", + "ddx", + "ddx_coarse", + "ddx_fine", + "ddy", + "ddy_coarse", + "ddy_fine", + "degrees", + "delete", + "determinant", + "discard", + "distance", + "do", + "dot", + "double", + "double1", + "double1x1", + "double1x2", + "double1x3", + "double1x4", + "double2", + "double2x1", + "double2x2", + "double2x3", + "double2x4", + "double3", + "double3x1", + "double3x2", + "double3x3", + "double3x4", + "double4", + "double4x1", + "double4x2", + "double4x3", + "double4x4", + "dst", + "dword", + "dword1", + "dword1x1", + "dword1x2", + "dword1x3", + "dword1x4", + "dword2", + "dword2x1", + "dword2x2", + "dword2x3", + "dword2x4", + "dword3", + "dword3x1", + "dword3x2", + "dword3x3", + "dword3x4", + "dword4", + "dword4x1", + "dword4x2", + "dword4x3", + "dword4x4", + "dynamic_cast", + "else", + "enum", + "errorf", + "exp", + "exp2", + "explicit", + "export", + "extern", + "f16to32", + "f32tof16", + "faceforward", + "false", + "fastopt", + "firstbithigh", + "firstbitlow", + "flatten", + "float", + "float1", + "float1x1", + "float1x2", + "float1x3", + "float1x4", + "float2", + "float2x1", + "float2x2", + "float2x3", + "float2x4", + "float3", + "float3x1", + "float3x2", + "float3x3", + "float3x4", + "float4", + "float4x1", + "float4x2", + "float4x3", + "float4x4", + "floor", + "fma", + "fmod", + "for", + "forcecase", + "frac", + "frexp", + "friend", + "fwidth", + "fxgroup", + "goto", + "groupshared", + "half", + "half1", + "half1x1", + "half1x2", + "half1x3", + "half1x4", + "half2", + "half2x1", + "half2x2", + "half2x3", + "half2x4", + "half3", + "half3x1", + "half3x2", + "half3x3", + "half3x4", + "half4", + "half4x1", + "half4x2", + "half4x3", + "half4x4", + "if", + "in", + "inline", + "inout", + "int", + "int1", + "int1x1", + "int1x2", + "int1x3", + "int1x4", + "int2", + "int2x1", + "int2x2", + "int2x3", + "int2x4", + "int3", + "int3x1", + "int3x2", + "int3x3", + "int3x4", + "int4", + "int4x1", + "int4x2", + "int4x3", + "int4x4", + "interface", + "isfinite", + "isinf", + "isnan", + "ldexp", + "length", + "lerp", + "lineadj", + "linear", + "lit", + "log", + "log10", + "log2", + "long", + "loop", + "mad", + "matrix", + "max", + "min", + "min10float", + "min10float1", + "min10float1x1", + "min10float1x2", + "min10float1x3", + "min10float1x4", + "min10float2", + "min10float2x1", + "min10float2x2", + "min10float2x3", + "min10float2x4", + "min10float3", + "min10float3x1", + "min10float3x2", + "min10float3x3", + "min10float3x4", + "min10float4", + "min10float4x1", + "min10float4x2", + "min10float4x3", + "min10float4x4", + "min12int", + "min12int1", + "min12int1x1", + "min12int1x2", + "min12int1x3", + "min12int1x4", + "min12int2", + "min12int2x1", + "min12int2x2", + "min12int2x3", + "min12int2x4", + "min12int3", + "min12int3x1", + "min12int3x2", + "min12int3x3", + "min12int3x4", + "min12int4", + "min12int4x1", + "min12int4x2", + "min12int4x3", + "min12int4x4", + "min16float", + "min16float1", + "min16float1x1", + "min16float1x2", + "min16float1x3", + "min16float1x4", + "min16float2", + "min16float2x1", + "min16float2x2", + "min16float2x3", + "min16float2x4", + "min16float3", + "min16float3x1", + "min16float3x2", + "min16float3x3", + "min16float3x4", + "min16float4", + "min16float4x1", + "min16float4x2", + "min16float4x3", + "min16float4x4", + "min16int", + "min16int1", + "min16int1x1", + "min16int1x2", + "min16int1x3", + "min16int1x4", + "min16int2", + "min16int2x1", + "min16int2x2", + "min16int2x3", + "min16int2x4", + "min16int3", + "min16int3x1", + "min16int3x2", + "min16int3x3", + "min16int3x4", + "min16int4", + "min16int4x1", + "min16int4x2", + "min16int4x3", + "min16int4x4", + "min16uint", + "min16uint1", + "min16uint1x1", + "min16uint1x2", + "min16uint1x3", + "min16uint1x4", + "min16uint2", + "min16uint2x1", + "min16uint2x2", + "min16uint2x3", + "min16uint2x4", + "min16uint3", + "min16uint3x1", + "min16uint3x2", + "min16uint3x3", + "min16uint3x4", + "min16uint4", + "min16uint4x1", + "min16uint4x2", + "min16uint4x3", + "min16uint4x4", + "modf", + "msad4", + "mul", + "mutable", + "namespace", + "new", + "nointerpolation", + "noise", + "noperspective", + "normalize", + "numthreads", + "operator", + "out", + "packoffset", + "pass", + "pixelfragment", + "pixelshader", + "point", + "pow", + "precise", + "printf", + "private", + "protected", + "public", + "radians", + "rcp", + "reflect", + "refract", + "register", + "reinterpret_cast", + "return", + "reversebits", + "round", + "row_major", + "rsqrt", + "sample", + "sampler1D", + "sampler2D", + "sampler3D", + "samplerCUBE", + "sampler_state", + "saturate", + "shared", + "short", + "sign", + "signed", + "sin", + "sincos", + "sinh", + "sizeof", + "smoothstep", + "snorm", + "sqrt", + "stateblock", + "stateblock_state", + "static", + "static_cast", + "step", + "string", + "struct", + "switch", + "tan", + "tanh", + "tbuffer", + "technique", + "technique10", + "technique11", + "template", + "tex1D", + "tex1Dbias", + "tex1Dgrad", + "tex1Dlod", + "tex1Dproj", + "tex2D", + "tex2Dbias", + "tex2Dgrad", + "tex2Dlod", + "tex2Dproj", + "tex3D", + "tex3Dbias", + "tex3Dgrad", + "tex3Dlod", + "tex3Dproj", + "texCUBE", + "texCUBEbias", + "texCUBEgrad", + "texCUBElod", + "texCUBEproj", + "texture", + "texture1D", + "texture1DArray", + "texture2D", + "texture2DArray", + "texture2DMS", + "texture2DMSArray", + "texture3D", + "textureCube", + "textureCubeArray", + "this", + "throw", + "transpose", + "triangle", + "triangleadj", + "true", + "trunc", + "try", + "typedef", + "typename", + "uint", + "uint1", + "uint1x1", + "uint1x2", + "uint1x3", + "uint1x4", + "uint2", + "uint2x1", + "uint2x2", + "uint2x3", + "uint2x4", + "uint3", + "uint3x1", + "uint3x2", + "uint3x3", + "uint3x4", + "uint4", + "uint4x1", + "uint4x2", + "uint4x3", + "uint4x4", + "uniform", + "union", + "unorm", + "unroll", + "unsigned", + "using", + "vector", + "vertexfragment", + "vertexshader", + "virtual", + "void", + "volatile", + "while")); + +} // namespace +} // namespace hlsl +} // namespace writer +} // namespace tint