[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 <dneto@google.com>
This commit is contained in:
dan sinclair 2020-07-21 14:51:33 +00:00
parent b44fe3c034
commit e5228407f4
10 changed files with 1603 additions and 12 deletions

View File

@ -527,6 +527,8 @@ source_set("libtint_hlsl_writer_src") {
"src/writer/hlsl/generator.h", "src/writer/hlsl/generator.h",
"src/writer/hlsl/generator_impl.cc", "src/writer/hlsl/generator_impl.cc",
"src/writer/hlsl/generator_impl.h", "src/writer/hlsl/generator_impl.h",
"src/writer/hlsl/namer.cc",
"src/writer/hlsl/namer.h",
] ]
configs += [ ":tint_common_config" ] configs += [ ":tint_common_config" ]
@ -1014,7 +1016,11 @@ source_set("tint_unittests_msl_writer_src") {
} }
source_set("tint_unittests_hlsl_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 += [ configs += [
":tint_common_config", ":tint_common_config",

View File

@ -268,6 +268,8 @@ if(${TINT_BUILD_HLSL_WRITER})
writer/hlsl/generator.h writer/hlsl/generator.h
writer/hlsl/generator_impl.cc writer/hlsl/generator_impl.cc
writer/hlsl/generator_impl.h writer/hlsl/generator_impl.h
writer/hlsl/namer.cc
writer/hlsl/namer.h
) )
endif() endif()
@ -539,7 +541,9 @@ endif()
if (${TINT_BUILD_HLSL_WRITER}) if (${TINT_BUILD_HLSL_WRITER})
list(APPEND TINT_TEST_SRCS list(APPEND TINT_TEST_SRCS
writer/hlsl/generator_impl_identifier_test.cc
writer/hlsl/generator_impl_test.cc writer/hlsl/generator_impl_test.cc
writer/hlsl/namer_test.cc
) )
endif() endif()

View File

@ -20,12 +20,13 @@ namespace tint {
namespace writer { namespace writer {
namespace hlsl { 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; Generator::~Generator() = default;
bool Generator::Generate() { bool Generator::Generate() {
auto ret = impl_.Generate(module_); auto ret = impl_.Generate();
if (!ret) { if (!ret) {
error_ = impl_.error(); error_ = impl_.error();
} }

View File

@ -14,15 +14,81 @@
#include "src/writer/hlsl/generator_impl.h" #include "src/writer/hlsl/generator_impl.h"
#include "src/ast/identifier_expression.h"
namespace tint { namespace tint {
namespace writer { namespace writer {
namespace hlsl { namespace hlsl {
GeneratorImpl::GeneratorImpl() = default; GeneratorImpl::GeneratorImpl(ast::Module* module) : module_(module) {}
GeneratorImpl::~GeneratorImpl() = default; 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; return true;
} }

View File

@ -16,6 +16,8 @@
#define SRC_WRITER_HLSL_GENERATOR_IMPL_H_ #define SRC_WRITER_HLSL_GENERATOR_IMPL_H_
#include "src/ast/module.h" #include "src/ast/module.h"
#include "src/scope_stack.h"
#include "src/writer/hlsl/namer.h"
#include "src/writer/text_generator.h" #include "src/writer/text_generator.h"
namespace tint { namespace tint {
@ -26,13 +28,43 @@ namespace hlsl {
class GeneratorImpl : public TextGenerator { class GeneratorImpl : public TextGenerator {
public: public:
/// Constructor /// Constructor
GeneratorImpl(); /// @param module the module to generate
explicit GeneratorImpl(ast::Module* module);
~GeneratorImpl(); ~GeneratorImpl();
/// Generates the result data
/// @param module the module to generate
/// @returns true on successful generation; false otherwise /// @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<ast::Variable*> global_variables_;
std::unordered_map<std::string, EntryPointData> ep_name_to_in_data_;
std::unordered_map<std::string, EntryPointData> ep_name_to_out_data_;
}; };
} // namespace hlsl } // namespace hlsl

View File

@ -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::string>{"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

View File

@ -37,9 +37,8 @@ TEST_F(HlslGeneratorImplTest, DISABLED_Generate) {
m.AddEntryPoint(std::make_unique<ast::EntryPoint>( m.AddEntryPoint(std::make_unique<ast::EntryPoint>(
ast::PipelineStage::kFragment, "my_func", "")); ast::PipelineStage::kFragment, "my_func", ""));
GeneratorImpl g; GeneratorImpl g(&m);
ASSERT_TRUE(g.Generate()) << g.error();
ASSERT_TRUE(g.Generate(m)) << g.error();
EXPECT_EQ(g.result(), R"(#import <metal_lib> EXPECT_EQ(g.result(), R"(#import <metal_lib>
void my_func() { void my_func() {

692
src/writer/hlsl/namer.cc Normal file
View File

@ -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 <algorithm>
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

58
src/writer/hlsl/namer.h Normal file
View File

@ -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 <string>
#include <unordered_map>
#include <unordered_set>
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<std::string, std::string> name_map_;
// The list of names taken by the remapper
std::unordered_set<std::string> remapped_names_;
};
} // namespace hlsl
} // namespace writer
} // namespace tint
#endif // SRC_WRITER_HLSL_NAMER_H_

View File

@ -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<std::string>;
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