• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SRC_READER_SPIRV_NAMER_H_
16 #define SRC_READER_SPIRV_NAMER_H_
17 
18 #include <string>
19 #include <unordered_map>
20 #include <vector>
21 
22 #include "src/reader/spirv/fail_stream.h"
23 
24 namespace tint {
25 namespace reader {
26 namespace spirv {
27 
28 /// A Namer maps SPIR-V IDs to strings.
29 ///
30 /// Sanitization:
31 /// Some names are user-suggested, but "sanitized" in the sense that an
32 /// unusual character (e.g. invalid for use in WGSL identifiers) is remapped
33 /// to a safer character such as an underscore.  Also, sanitized names
34 /// never start with an underscore.
35 class Namer {
36  public:
37   /// Creates a new namer
38   /// @param fail_stream the error reporting stream
39   explicit Namer(const FailStream& fail_stream);
40   /// Destructor
41   ~Namer();
42 
43   /// Sanitizes the given string, to replace unusual characters with
44   /// obviously-valid idenfier characters. An empy string yields "empty".
45   /// A sanitized name never starts with an underscore.
46   /// @param suggested_name input string
47   /// @returns sanitized name, suitable for use as an identifier
48   static std::string Sanitize(const std::string& suggested_name);
49 
50   /// Registers a failure.
51   /// @returns a fail stream to accumulate diagnostics.
Fail()52   FailStream& Fail() { return fail_stream_.Fail(); }
53 
54   /// @param id the SPIR-V ID
55   /// @returns true if we the given ID already has a registered name.
HasName(uint32_t id)56   bool HasName(uint32_t id) {
57     return id_to_name_.find(id) != id_to_name_.end();
58   }
59 
60   /// @param name a string
61   /// @returns true if the string has been registered as a name.
IsRegistered(const std::string & name)62   bool IsRegistered(const std::string& name) const {
63     return name_to_id_.find(name) != name_to_id_.end();
64   }
65 
66   /// @param id the SPIR-V ID
67   /// @returns the name for the ID. It must have been registered.
GetName(uint32_t id)68   const std::string& GetName(uint32_t id) const {
69     return id_to_name_.find(id)->second;
70   }
71 
72   /// Gets a unique name for the ID. If one already exists, then return
73   /// that, otherwise synthesize a name and remember it for later.
74   /// @param id the SPIR-V ID
75   /// @returns a name for the given ID. Generates a name if non exists.
Name(uint32_t id)76   const std::string& Name(uint32_t id) {
77     if (!HasName(id)) {
78       SuggestSanitizedName(id, "x_" + std::to_string(id));
79     }
80     return GetName(id);
81   }
82 
83   /// Gets the registered name for a struct member. If no name has
84   /// been registered for this member, then returns the empty string.
85   /// member index is in bounds.
86   /// @param id the SPIR-V ID of the struct type
87   /// @param member_index the index of the member, counting from 0
88   /// @returns the registered name for the ID, or an empty string if
89   /// nothing has been registered.
90   std::string GetMemberName(uint32_t id, uint32_t member_index) const;
91 
92   /// Returns an unregistered name based on a given base name.
93   /// @param base_name the base name
94   /// @returns a new name
95   std::string FindUnusedDerivedName(const std::string& base_name) const;
96 
97   /// Returns a newly registered name based on a given base name.
98   /// In the internal table `name_to_id_`, it is mapped to the invalid
99   /// SPIR-V ID 0.  It does not have an entry in `id_to_name_`.
100   /// @param base_name the base name
101   /// @returns a new name
102   std::string MakeDerivedName(const std::string& base_name);
103 
104   /// Records a mapping from the given ID to a name. Emits a failure
105   /// if the ID already has a registered name.
106   /// @param id the SPIR-V ID
107   /// @param name the name to map to the ID
108   /// @returns true if the ID did not have a previously registered name.
109   bool Register(uint32_t id, const std::string& name);
110 
111   /// Registers a name, but not associated to any ID. Fails and emits
112   /// a diagnostic if the name was already registered.
113   /// @param name the name to register
114   /// @returns true if the name was not already reegistered.
115   bool RegisterWithoutId(const std::string& name);
116 
117   /// Saves a sanitized name for the given ID, if that ID does not yet
118   /// have a registered name, and if the sanitized name has not already
119   /// been registered to a different ID.
120   /// @param id the SPIR-V ID
121   /// @param suggested_name the suggested name
122   /// @returns true if a name was newly registered for the ID
123   bool SuggestSanitizedName(uint32_t id, const std::string& suggested_name);
124 
125   /// Saves a sanitized name for a member of a struct, if that member
126   /// does not yet have a registered name.
127   /// @param struct_id the SPIR-V ID for the struct
128   /// @param member_index the index of the member inside the struct
129   /// @param suggested_name the suggested name
130   /// @returns true if a name was newly registered
131   bool SuggestSanitizedMemberName(uint32_t struct_id,
132                                   uint32_t member_index,
133                                   const std::string& suggested_name);
134 
135   /// Ensure there are member names registered for members of the given struct
136   /// such that:
137   /// - Each member has a non-empty sanitized name.
138   /// - No two members in the struct have the same name.
139   /// @param struct_id the SPIR-V ID for the struct
140   /// @param num_members the number of members in the struct
141   void ResolveMemberNamesForStruct(uint32_t struct_id, uint32_t num_members);
142 
143  private:
144   FailStream fail_stream_;
145 
146   // Maps an ID to its registered name.
147   std::unordered_map<uint32_t, std::string> id_to_name_;
148   // Maps a name to a SPIR-V ID, or 0 (the case for derived names).
149   std::unordered_map<std::string, uint32_t> name_to_id_;
150 
151   // Maps a struct id and member index to a suggested sanitized name.
152   // If entry k in the vector is an empty string, then a suggestion
153   // was recorded for a higher-numbered index, but not for index k.
154   std::unordered_map<uint32_t, std::vector<std::string>> struct_member_names_;
155 };
156 
157 }  // namespace spirv
158 }  // namespace reader
159 }  // namespace tint
160 
161 #endif  // SRC_READER_SPIRV_NAMER_H_
162