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