spirv_cross_parsed_ir.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. /*
  2. * Copyright 2018-2021 Arm Limited
  3. * SPDX-License-Identifier: Apache-2.0 OR MIT
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /*
  18. * At your option, you may choose to accept this material under either:
  19. * 1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or
  20. * 2. The MIT License, found at <http://opensource.org/licenses/MIT>.
  21. */
  22. #include "spirv_cross_parsed_ir.hpp"
  23. #include <algorithm>
  24. #include <assert.h>
  25. using namespace std;
  26. using namespace SPIRV_CROSS_SPV_HEADER_NAMESPACE;
  27. namespace SPIRV_CROSS_NAMESPACE
  28. {
  29. ParsedIR::ParsedIR()
  30. {
  31. // If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
  32. // so need an extra pointer here.
  33. pool_group.reset(new ObjectPoolGroup);
  34. pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
  35. pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
  36. pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
  37. pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
  38. pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
  39. pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
  40. pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
  41. pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
  42. pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
  43. pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
  44. pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
  45. pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
  46. pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
  47. }
  48. // Should have been default-implemented, but need this on MSVC 2013.
  49. ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
  50. {
  51. *this = std::move(other);
  52. }
  53. ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
  54. {
  55. if (this != &other)
  56. {
  57. pool_group = std::move(other.pool_group);
  58. spirv = std::move(other.spirv);
  59. meta = std::move(other.meta);
  60. for (int i = 0; i < TypeCount; i++)
  61. ids_for_type[i] = std::move(other.ids_for_type[i]);
  62. ids_for_constant_undef_or_type = std::move(other.ids_for_constant_undef_or_type);
  63. ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable);
  64. declared_capabilities = std::move(other.declared_capabilities);
  65. declared_extensions = std::move(other.declared_extensions);
  66. block_meta = std::move(other.block_meta);
  67. continue_block_to_loop_header = std::move(other.continue_block_to_loop_header);
  68. entry_points = std::move(other.entry_points);
  69. ids = std::move(other.ids);
  70. addressing_model = other.addressing_model;
  71. memory_model = other.memory_model;
  72. default_entry_point = other.default_entry_point;
  73. source = other.source;
  74. loop_iteration_depth_hard = other.loop_iteration_depth_hard;
  75. loop_iteration_depth_soft = other.loop_iteration_depth_soft;
  76. meta_needing_name_fixup = std::move(other.meta_needing_name_fixup);
  77. load_type_width = std::move(other.load_type_width);
  78. }
  79. return *this;
  80. }
  81. ParsedIR::ParsedIR(const ParsedIR &other)
  82. : ParsedIR()
  83. {
  84. *this = other;
  85. }
  86. ParsedIR &ParsedIR::operator=(const ParsedIR &other)
  87. {
  88. if (this != &other)
  89. {
  90. spirv = other.spirv;
  91. meta = other.meta;
  92. for (int i = 0; i < TypeCount; i++)
  93. ids_for_type[i] = other.ids_for_type[i];
  94. ids_for_constant_undef_or_type = other.ids_for_constant_undef_or_type;
  95. ids_for_constant_or_variable = other.ids_for_constant_or_variable;
  96. declared_capabilities = other.declared_capabilities;
  97. declared_extensions = other.declared_extensions;
  98. block_meta = other.block_meta;
  99. continue_block_to_loop_header = other.continue_block_to_loop_header;
  100. entry_points = other.entry_points;
  101. default_entry_point = other.default_entry_point;
  102. source = other.source;
  103. loop_iteration_depth_hard = other.loop_iteration_depth_hard;
  104. loop_iteration_depth_soft = other.loop_iteration_depth_soft;
  105. addressing_model = other.addressing_model;
  106. memory_model = other.memory_model;
  107. meta_needing_name_fixup = other.meta_needing_name_fixup;
  108. load_type_width = other.load_type_width;
  109. // Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
  110. // Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
  111. ids.clear();
  112. ids.reserve(other.ids.size());
  113. for (size_t i = 0; i < other.ids.size(); i++)
  114. {
  115. ids.emplace_back(pool_group.get());
  116. ids.back() = other.ids[i];
  117. }
  118. }
  119. return *this;
  120. }
  121. void ParsedIR::set_id_bounds(uint32_t bounds)
  122. {
  123. ids.reserve(bounds);
  124. while (ids.size() < bounds)
  125. ids.emplace_back(pool_group.get());
  126. block_meta.resize(bounds);
  127. }
  128. // Roll our own versions of these functions to avoid potential locale shenanigans.
  129. static bool is_alpha(char c)
  130. {
  131. return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
  132. }
  133. static bool is_numeric(char c)
  134. {
  135. return c >= '0' && c <= '9';
  136. }
  137. static bool is_alphanumeric(char c)
  138. {
  139. return is_alpha(c) || is_numeric(c);
  140. }
  141. static bool is_valid_identifier(const string &name)
  142. {
  143. if (name.empty())
  144. return true;
  145. if (is_numeric(name[0]))
  146. return false;
  147. for (auto c : name)
  148. if (!is_alphanumeric(c) && c != '_')
  149. return false;
  150. bool saw_underscore = false;
  151. // Two underscores in a row is not a valid identifier either.
  152. // Technically reserved, but it's easier to treat it as invalid.
  153. for (auto c : name)
  154. {
  155. bool is_underscore = c == '_';
  156. if (is_underscore && saw_underscore)
  157. return false;
  158. saw_underscore = is_underscore;
  159. }
  160. return true;
  161. }
  162. static bool is_reserved_prefix(const string &name)
  163. {
  164. // Generic reserved identifiers used by the implementation.
  165. return name.compare(0, 3, "gl_", 3) == 0 ||
  166. // Ignore this case for now, might rewrite internal code to always use spv prefix.
  167. //name.compare(0, 11, "SPIRV_Cross", 11) == 0 ||
  168. name.compare(0, 3, "spv", 3) == 0;
  169. }
  170. static bool is_reserved_identifier(const string &name, bool member, bool allow_reserved_prefixes)
  171. {
  172. if (!allow_reserved_prefixes && is_reserved_prefix(name))
  173. return true;
  174. if (member)
  175. {
  176. // Reserved member identifiers come in one form:
  177. // _m[0-9]+$.
  178. if (name.size() < 3)
  179. return false;
  180. if (name.compare(0, 2, "_m", 2) != 0)
  181. return false;
  182. size_t index = 2;
  183. while (index < name.size() && is_numeric(name[index]))
  184. index++;
  185. return index == name.size();
  186. }
  187. else
  188. {
  189. // Reserved non-member identifiers come in two forms:
  190. // _[0-9]+$, used for temporaries which map directly to a SPIR-V ID.
  191. // _[0-9]+_, used for auxillary temporaries which derived from a SPIR-V ID.
  192. if (name.size() < 2)
  193. return false;
  194. if (name[0] != '_' || !is_numeric(name[1]))
  195. return false;
  196. size_t index = 2;
  197. while (index < name.size() && is_numeric(name[index]))
  198. index++;
  199. return index == name.size() || (index < name.size() && name[index] == '_');
  200. }
  201. }
  202. bool ParsedIR::is_globally_reserved_identifier(std::string &str, bool allow_reserved_prefixes)
  203. {
  204. return is_reserved_identifier(str, false, allow_reserved_prefixes);
  205. }
  206. uint32_t ParsedIR::get_spirv_version() const
  207. {
  208. return spirv[1];
  209. }
  210. static string make_unreserved_identifier(const string &name)
  211. {
  212. if (is_reserved_prefix(name))
  213. return "_RESERVED_IDENTIFIER_FIXUP_" + name;
  214. else
  215. return "_RESERVED_IDENTIFIER_FIXUP" + name;
  216. }
  217. void ParsedIR::sanitize_underscores(std::string &str)
  218. {
  219. // Compact adjacent underscores to make it valid.
  220. auto dst = str.begin();
  221. auto src = dst;
  222. bool saw_underscore = false;
  223. while (src != str.end())
  224. {
  225. bool is_underscore = *src == '_';
  226. if (saw_underscore && is_underscore)
  227. {
  228. src++;
  229. }
  230. else
  231. {
  232. if (dst != src)
  233. *dst = *src;
  234. dst++;
  235. src++;
  236. saw_underscore = is_underscore;
  237. }
  238. }
  239. str.erase(dst, str.end());
  240. }
  241. static string ensure_valid_identifier(const string &name)
  242. {
  243. // Functions in glslangValidator are mangled with name(<mangled> stuff.
  244. // Normally, we would never see '(' in any legal identifiers, so just strip them out.
  245. auto str = name.substr(0, name.find('('));
  246. if (str.empty())
  247. return str;
  248. if (is_numeric(str[0]))
  249. str[0] = '_';
  250. for (auto &c : str)
  251. if (!is_alphanumeric(c) && c != '_')
  252. c = '_';
  253. ParsedIR::sanitize_underscores(str);
  254. return str;
  255. }
  256. const string &ParsedIR::get_name(ID id) const
  257. {
  258. auto *m = find_meta(id);
  259. if (m)
  260. return m->decoration.alias;
  261. else
  262. return empty_string;
  263. }
  264. const string &ParsedIR::get_member_name(TypeID id, uint32_t index) const
  265. {
  266. auto *m = find_meta(id);
  267. if (m)
  268. {
  269. if (index >= m->members.size())
  270. return empty_string;
  271. return m->members[index].alias;
  272. }
  273. else
  274. return empty_string;
  275. }
  276. void ParsedIR::sanitize_identifier(std::string &name, bool member, bool allow_reserved_prefixes)
  277. {
  278. if (!is_valid_identifier(name))
  279. name = ensure_valid_identifier(name);
  280. if (is_reserved_identifier(name, member, allow_reserved_prefixes))
  281. name = make_unreserved_identifier(name);
  282. }
  283. void ParsedIR::fixup_reserved_names()
  284. {
  285. for (uint32_t id : meta_needing_name_fixup)
  286. {
  287. // Don't rename remapped variables like 'gl_LastFragDepthARM'.
  288. if (ids[id].get_type() == TypeVariable && get<SPIRVariable>(id).remapped_variable)
  289. continue;
  290. auto &m = meta[id];
  291. sanitize_identifier(m.decoration.alias, false, false);
  292. for (auto &memb : m.members)
  293. sanitize_identifier(memb.alias, true, false);
  294. }
  295. meta_needing_name_fixup.clear();
  296. }
  297. void ParsedIR::set_name(ID id, const string &name)
  298. {
  299. auto &m = meta[id];
  300. m.decoration.alias = name;
  301. if (!is_valid_identifier(name) || is_reserved_identifier(name, false, false))
  302. meta_needing_name_fixup.insert(id);
  303. }
  304. void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name)
  305. {
  306. auto &m = meta[id];
  307. m.members.resize(max(m.members.size(), size_t(index) + 1));
  308. m.members[index].alias = name;
  309. if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false))
  310. meta_needing_name_fixup.insert(id);
  311. }
  312. void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string &argument)
  313. {
  314. auto &dec = meta[id].decoration;
  315. dec.decoration_flags.set(decoration);
  316. switch (decoration)
  317. {
  318. case DecorationUserSemantic:
  319. dec.user_semantic = argument;
  320. break;
  321. case DecorationUserTypeGOOGLE:
  322. dec.user_type = argument;
  323. break;
  324. default:
  325. break;
  326. }
  327. }
  328. void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
  329. {
  330. auto &dec = meta[id].decoration;
  331. dec.decoration_flags.set(decoration);
  332. switch (decoration)
  333. {
  334. case DecorationBuiltIn:
  335. dec.builtin = true;
  336. dec.builtin_type = static_cast<BuiltIn>(argument);
  337. break;
  338. case DecorationLocation:
  339. dec.location = argument;
  340. break;
  341. case DecorationComponent:
  342. dec.component = argument;
  343. break;
  344. case DecorationOffset:
  345. dec.offset = argument;
  346. break;
  347. case DecorationXfbBuffer:
  348. dec.xfb_buffer = argument;
  349. break;
  350. case DecorationXfbStride:
  351. dec.xfb_stride = argument;
  352. break;
  353. case DecorationStream:
  354. dec.stream = argument;
  355. break;
  356. case DecorationArrayStride:
  357. dec.array_stride = argument;
  358. break;
  359. case DecorationMatrixStride:
  360. dec.matrix_stride = argument;
  361. break;
  362. case DecorationBinding:
  363. dec.binding = argument;
  364. break;
  365. case DecorationDescriptorSet:
  366. dec.set = argument;
  367. break;
  368. case DecorationInputAttachmentIndex:
  369. dec.input_attachment = argument;
  370. break;
  371. case DecorationSpecId:
  372. dec.spec_id = argument;
  373. break;
  374. case DecorationIndex:
  375. dec.index = argument;
  376. break;
  377. case DecorationHlslCounterBufferGOOGLE:
  378. meta[id].hlsl_magic_counter_buffer = argument;
  379. meta[argument].hlsl_is_magic_counter_buffer = true;
  380. break;
  381. case DecorationFPRoundingMode:
  382. dec.fp_rounding_mode = static_cast<FPRoundingMode>(argument);
  383. break;
  384. case DecorationFPFastMathMode:
  385. dec.fp_fast_math_mode = static_cast<FPFastMathModeMask>(argument);
  386. break;
  387. default:
  388. break;
  389. }
  390. }
  391. void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument)
  392. {
  393. auto &m = meta[id];
  394. m.members.resize(max(m.members.size(), size_t(index) + 1));
  395. auto &dec = m.members[index];
  396. dec.decoration_flags.set(decoration);
  397. switch (decoration)
  398. {
  399. case DecorationBuiltIn:
  400. dec.builtin = true;
  401. dec.builtin_type = static_cast<BuiltIn>(argument);
  402. break;
  403. case DecorationLocation:
  404. dec.location = argument;
  405. break;
  406. case DecorationComponent:
  407. dec.component = argument;
  408. break;
  409. case DecorationBinding:
  410. dec.binding = argument;
  411. break;
  412. case DecorationOffset:
  413. dec.offset = argument;
  414. break;
  415. case DecorationXfbBuffer:
  416. dec.xfb_buffer = argument;
  417. break;
  418. case DecorationXfbStride:
  419. dec.xfb_stride = argument;
  420. break;
  421. case DecorationStream:
  422. dec.stream = argument;
  423. break;
  424. case DecorationSpecId:
  425. dec.spec_id = argument;
  426. break;
  427. case DecorationMatrixStride:
  428. dec.matrix_stride = argument;
  429. break;
  430. case DecorationIndex:
  431. dec.index = argument;
  432. break;
  433. default:
  434. break;
  435. }
  436. }
  437. // Recursively marks any constants referenced by the specified constant instruction as being used
  438. // as an array length. The id must be a constant instruction (SPIRConstant or SPIRConstantOp).
  439. void ParsedIR::mark_used_as_array_length(ID id)
  440. {
  441. switch (ids[id].get_type())
  442. {
  443. case TypeConstant:
  444. {
  445. auto &c = get<SPIRConstant>(id);
  446. c.is_used_as_array_length = true;
  447. // Mark composite dependencies as well.
  448. for (auto &sub_id: c.m.id)
  449. if (sub_id)
  450. mark_used_as_array_length(sub_id);
  451. for (uint32_t col = 0; col < c.m.columns; col++)
  452. {
  453. for (auto &sub_id : c.m.c[col].id)
  454. if (sub_id)
  455. mark_used_as_array_length(sub_id);
  456. }
  457. for (auto &sub_id : c.subconstants)
  458. if (sub_id)
  459. mark_used_as_array_length(sub_id);
  460. break;
  461. }
  462. case TypeConstantOp:
  463. {
  464. auto &cop = get<SPIRConstantOp>(id);
  465. if (cop.opcode == OpCompositeExtract)
  466. mark_used_as_array_length(cop.arguments[0]);
  467. else if (cop.opcode == OpCompositeInsert)
  468. {
  469. mark_used_as_array_length(cop.arguments[0]);
  470. mark_used_as_array_length(cop.arguments[1]);
  471. }
  472. else
  473. for (uint32_t arg_id : cop.arguments)
  474. mark_used_as_array_length(arg_id);
  475. break;
  476. }
  477. case TypeUndef:
  478. break;
  479. default:
  480. assert(0);
  481. }
  482. }
  483. Bitset ParsedIR::get_buffer_block_type_flags(const SPIRType &type) const
  484. {
  485. if (type.member_types.empty())
  486. return {};
  487. Bitset all_members_flags = get_member_decoration_bitset(type.self, 0);
  488. for (uint32_t i = 1; i < uint32_t(type.member_types.size()); i++)
  489. all_members_flags.merge_and(get_member_decoration_bitset(type.self, i));
  490. return all_members_flags;
  491. }
  492. Bitset ParsedIR::get_buffer_block_flags(const SPIRVariable &var) const
  493. {
  494. auto &type = get<SPIRType>(var.basetype);
  495. if (type.basetype != SPIRType::Struct)
  496. SPIRV_CROSS_THROW("Cannot get buffer block flags for non-buffer variable.");
  497. // Some flags like non-writable, non-readable are actually found
  498. // as member decorations. If all members have a decoration set, propagate
  499. // the decoration up as a regular variable decoration.
  500. Bitset base_flags;
  501. auto *m = find_meta(var.self);
  502. if (m)
  503. base_flags = m->decoration.decoration_flags;
  504. if (type.member_types.empty())
  505. return base_flags;
  506. auto all_members_flags = get_buffer_block_type_flags(type);
  507. base_flags.merge_or(all_members_flags);
  508. return base_flags;
  509. }
  510. const Bitset &ParsedIR::get_member_decoration_bitset(TypeID id, uint32_t index) const
  511. {
  512. auto *m = find_meta(id);
  513. if (m)
  514. {
  515. if (index >= m->members.size())
  516. return cleared_bitset;
  517. return m->members[index].decoration_flags;
  518. }
  519. else
  520. return cleared_bitset;
  521. }
  522. bool ParsedIR::has_decoration(ID id, Decoration decoration) const
  523. {
  524. return get_decoration_bitset(id).get(decoration);
  525. }
  526. uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
  527. {
  528. auto *m = find_meta(id);
  529. if (!m)
  530. return 0;
  531. auto &dec = m->decoration;
  532. if (!dec.decoration_flags.get(decoration))
  533. return 0;
  534. switch (decoration)
  535. {
  536. case DecorationBuiltIn:
  537. return dec.builtin_type;
  538. case DecorationLocation:
  539. return dec.location;
  540. case DecorationComponent:
  541. return dec.component;
  542. case DecorationOffset:
  543. return dec.offset;
  544. case DecorationXfbBuffer:
  545. return dec.xfb_buffer;
  546. case DecorationXfbStride:
  547. return dec.xfb_stride;
  548. case DecorationStream:
  549. return dec.stream;
  550. case DecorationBinding:
  551. return dec.binding;
  552. case DecorationDescriptorSet:
  553. return dec.set;
  554. case DecorationInputAttachmentIndex:
  555. return dec.input_attachment;
  556. case DecorationSpecId:
  557. return dec.spec_id;
  558. case DecorationArrayStride:
  559. return dec.array_stride;
  560. case DecorationMatrixStride:
  561. return dec.matrix_stride;
  562. case DecorationIndex:
  563. return dec.index;
  564. case DecorationFPRoundingMode:
  565. return dec.fp_rounding_mode;
  566. case DecorationFPFastMathMode:
  567. return dec.fp_fast_math_mode;
  568. default:
  569. return 1;
  570. }
  571. }
  572. const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) const
  573. {
  574. auto *m = find_meta(id);
  575. if (!m)
  576. return empty_string;
  577. auto &dec = m->decoration;
  578. if (!dec.decoration_flags.get(decoration))
  579. return empty_string;
  580. switch (decoration)
  581. {
  582. case DecorationUserSemantic:
  583. return dec.user_semantic;
  584. case DecorationUserTypeGOOGLE:
  585. return dec.user_type;
  586. default:
  587. return empty_string;
  588. }
  589. }
  590. void ParsedIR::unset_decoration(ID id, Decoration decoration)
  591. {
  592. auto &dec = meta[id].decoration;
  593. dec.decoration_flags.clear(decoration);
  594. switch (decoration)
  595. {
  596. case DecorationBuiltIn:
  597. dec.builtin = false;
  598. break;
  599. case DecorationLocation:
  600. dec.location = 0;
  601. break;
  602. case DecorationComponent:
  603. dec.component = 0;
  604. break;
  605. case DecorationOffset:
  606. dec.offset = 0;
  607. break;
  608. case DecorationXfbBuffer:
  609. dec.xfb_buffer = 0;
  610. break;
  611. case DecorationXfbStride:
  612. dec.xfb_stride = 0;
  613. break;
  614. case DecorationStream:
  615. dec.stream = 0;
  616. break;
  617. case DecorationBinding:
  618. dec.binding = 0;
  619. break;
  620. case DecorationDescriptorSet:
  621. dec.set = 0;
  622. break;
  623. case DecorationInputAttachmentIndex:
  624. dec.input_attachment = 0;
  625. break;
  626. case DecorationSpecId:
  627. dec.spec_id = 0;
  628. break;
  629. case DecorationUserSemantic:
  630. dec.user_semantic.clear();
  631. break;
  632. case DecorationFPRoundingMode:
  633. dec.fp_rounding_mode = FPRoundingModeMax;
  634. break;
  635. case DecorationFPFastMathMode:
  636. dec.fp_fast_math_mode = FPFastMathModeMaskNone;
  637. break;
  638. case DecorationHlslCounterBufferGOOGLE:
  639. {
  640. auto &counter = meta[id].hlsl_magic_counter_buffer;
  641. if (counter)
  642. {
  643. meta[counter].hlsl_is_magic_counter_buffer = false;
  644. counter = 0;
  645. }
  646. break;
  647. }
  648. default:
  649. break;
  650. }
  651. }
  652. bool ParsedIR::has_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
  653. {
  654. return get_member_decoration_bitset(id, index).get(decoration);
  655. }
  656. uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration decoration) const
  657. {
  658. auto *m = find_meta(id);
  659. if (!m)
  660. return 0;
  661. if (index >= m->members.size())
  662. return 0;
  663. auto &dec = m->members[index];
  664. if (!dec.decoration_flags.get(decoration))
  665. return 0;
  666. switch (decoration)
  667. {
  668. case DecorationBuiltIn:
  669. return dec.builtin_type;
  670. case DecorationLocation:
  671. return dec.location;
  672. case DecorationComponent:
  673. return dec.component;
  674. case DecorationBinding:
  675. return dec.binding;
  676. case DecorationOffset:
  677. return dec.offset;
  678. case DecorationXfbBuffer:
  679. return dec.xfb_buffer;
  680. case DecorationXfbStride:
  681. return dec.xfb_stride;
  682. case DecorationStream:
  683. return dec.stream;
  684. case DecorationSpecId:
  685. return dec.spec_id;
  686. case DecorationMatrixStride:
  687. return dec.matrix_stride;
  688. case DecorationIndex:
  689. return dec.index;
  690. default:
  691. return 1;
  692. }
  693. }
  694. const Bitset &ParsedIR::get_decoration_bitset(ID id) const
  695. {
  696. auto *m = find_meta(id);
  697. if (m)
  698. {
  699. auto &dec = m->decoration;
  700. return dec.decoration_flags;
  701. }
  702. else
  703. return cleared_bitset;
  704. }
  705. void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument)
  706. {
  707. auto &m = meta[id];
  708. m.members.resize(max(m.members.size(), size_t(index) + 1));
  709. auto &dec = meta[id].members[index];
  710. dec.decoration_flags.set(decoration);
  711. switch (decoration)
  712. {
  713. case DecorationUserSemantic:
  714. dec.user_semantic = argument;
  715. break;
  716. default:
  717. break;
  718. }
  719. }
  720. const string &ParsedIR::get_member_decoration_string(TypeID id, uint32_t index, Decoration decoration) const
  721. {
  722. auto *m = find_meta(id);
  723. if (m)
  724. {
  725. if (!has_member_decoration(id, index, decoration))
  726. return empty_string;
  727. auto &dec = m->members[index];
  728. switch (decoration)
  729. {
  730. case DecorationUserSemantic:
  731. return dec.user_semantic;
  732. default:
  733. return empty_string;
  734. }
  735. }
  736. else
  737. return empty_string;
  738. }
  739. void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration decoration)
  740. {
  741. auto &m = meta[id];
  742. if (index >= m.members.size())
  743. return;
  744. auto &dec = m.members[index];
  745. dec.decoration_flags.clear(decoration);
  746. switch (decoration)
  747. {
  748. case DecorationBuiltIn:
  749. dec.builtin = false;
  750. break;
  751. case DecorationLocation:
  752. dec.location = 0;
  753. break;
  754. case DecorationComponent:
  755. dec.component = 0;
  756. break;
  757. case DecorationOffset:
  758. dec.offset = 0;
  759. break;
  760. case DecorationXfbBuffer:
  761. dec.xfb_buffer = 0;
  762. break;
  763. case DecorationXfbStride:
  764. dec.xfb_stride = 0;
  765. break;
  766. case DecorationStream:
  767. dec.stream = 0;
  768. break;
  769. case DecorationSpecId:
  770. dec.spec_id = 0;
  771. break;
  772. case DecorationUserSemantic:
  773. dec.user_semantic.clear();
  774. break;
  775. default:
  776. break;
  777. }
  778. }
  779. uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
  780. {
  781. auto curr_bound = ids.size();
  782. auto new_bound = curr_bound + incr_amount;
  783. ids.reserve(ids.size() + incr_amount);
  784. for (uint32_t i = 0; i < incr_amount; i++)
  785. ids.emplace_back(pool_group.get());
  786. block_meta.resize(new_bound);
  787. return uint32_t(curr_bound);
  788. }
  789. void ParsedIR::remove_typed_id(Types type, ID id)
  790. {
  791. auto &type_ids = ids_for_type[type];
  792. type_ids.erase(remove(begin(type_ids), end(type_ids), id), end(type_ids));
  793. }
  794. void ParsedIR::reset_all_of_type(Types type)
  795. {
  796. for (auto &id : ids_for_type[type])
  797. if (ids[id].get_type() == type)
  798. ids[id].reset();
  799. ids_for_type[type].clear();
  800. }
  801. void ParsedIR::add_typed_id(Types type, ID id)
  802. {
  803. assert(id < ids.size());
  804. if (loop_iteration_depth_hard != 0)
  805. SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");
  806. if (loop_iteration_depth_soft != 0)
  807. {
  808. if (!ids[id].empty())
  809. SPIRV_CROSS_THROW("Cannot override IDs when loop is soft locked.");
  810. return;
  811. }
  812. if (ids[id].empty() || ids[id].get_type() != type)
  813. {
  814. switch (type)
  815. {
  816. case TypeConstant:
  817. ids_for_constant_or_variable.push_back(id);
  818. ids_for_constant_undef_or_type.push_back(id);
  819. break;
  820. case TypeVariable:
  821. ids_for_constant_or_variable.push_back(id);
  822. break;
  823. case TypeType:
  824. case TypeConstantOp:
  825. case TypeUndef:
  826. ids_for_constant_undef_or_type.push_back(id);
  827. break;
  828. default:
  829. break;
  830. }
  831. }
  832. if (ids[id].empty())
  833. {
  834. ids_for_type[type].push_back(id);
  835. }
  836. else if (ids[id].get_type() != type)
  837. {
  838. remove_typed_id(ids[id].get_type(), id);
  839. ids_for_type[type].push_back(id);
  840. }
  841. }
  842. const Meta *ParsedIR::find_meta(ID id) const
  843. {
  844. auto itr = meta.find(id);
  845. if (itr != end(meta))
  846. return &itr->second;
  847. else
  848. return nullptr;
  849. }
  850. Meta *ParsedIR::find_meta(ID id)
  851. {
  852. auto itr = meta.find(id);
  853. if (itr != end(meta))
  854. return &itr->second;
  855. else
  856. return nullptr;
  857. }
  858. ParsedIR::LoopLock ParsedIR::create_loop_hard_lock() const
  859. {
  860. return ParsedIR::LoopLock(&loop_iteration_depth_hard);
  861. }
  862. ParsedIR::LoopLock ParsedIR::create_loop_soft_lock() const
  863. {
  864. return ParsedIR::LoopLock(&loop_iteration_depth_soft);
  865. }
  866. ParsedIR::LoopLock::~LoopLock()
  867. {
  868. if (lock)
  869. (*lock)--;
  870. }
  871. ParsedIR::LoopLock::LoopLock(uint32_t *lock_)
  872. : lock(lock_)
  873. {
  874. if (lock)
  875. (*lock)++;
  876. }
  877. ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
  878. {
  879. *this = std::move(other);
  880. }
  881. ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT
  882. {
  883. if (lock)
  884. (*lock)--;
  885. lock = other.lock;
  886. other.lock = nullptr;
  887. return *this;
  888. }
  889. void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
  890. {
  891. assert(id < ids.size());
  892. auto &constant_type = get<SPIRType>(type);
  893. if (constant_type.pointer)
  894. {
  895. if (add_to_typed_id_set)
  896. add_typed_id(TypeConstant, id);
  897. auto &constant = variant_set<SPIRConstant>(ids[id], type);
  898. constant.self = id;
  899. constant.make_null(constant_type);
  900. }
  901. else if (!constant_type.array.empty())
  902. {
  903. assert(constant_type.parent_type);
  904. uint32_t parent_id = increase_bound_by(1);
  905. make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
  906. // The array size of OpConstantNull can be either literal or specialization constant.
  907. // In the latter case, we cannot take the value as-is, as it can be changed to anything.
  908. // Rather, we assume it to be *one* for the sake of initializer.
  909. bool is_literal_array_size = constant_type.array_size_literal.back();
  910. uint32_t count = is_literal_array_size ? constant_type.array.back() : 1;
  911. SmallVector<uint32_t> elements(count);
  912. for (uint32_t i = 0; i < count; i++)
  913. elements[i] = parent_id;
  914. if (add_to_typed_id_set)
  915. add_typed_id(TypeConstant, id);
  916. auto& constant = variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false);
  917. constant.self = id;
  918. constant.is_null_array_specialized_length = !is_literal_array_size;
  919. }
  920. else if (!constant_type.member_types.empty())
  921. {
  922. uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
  923. SmallVector<uint32_t> elements(constant_type.member_types.size());
  924. for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
  925. {
  926. make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
  927. elements[i] = member_ids + i;
  928. }
  929. if (add_to_typed_id_set)
  930. add_typed_id(TypeConstant, id);
  931. variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
  932. }
  933. else
  934. {
  935. if (add_to_typed_id_set)
  936. add_typed_id(TypeConstant, id);
  937. auto &constant = variant_set<SPIRConstant>(ids[id], type);
  938. constant.self = id;
  939. constant.make_null(constant_type);
  940. }
  941. }
  942. } // namespace SPIRV_CROSS_NAMESPACE