spirv_cross_parsed_ir.cpp 24 KB

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