spvIR.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. //
  2. // Copyright (C) 2014 LunarG, Inc.
  3. // Copyright (C) 2015-2018 Google, Inc.
  4. //
  5. // All rights reserved.
  6. //
  7. // Redistribution and use in source and binary forms, with or without
  8. // modification, are permitted provided that the following conditions
  9. // are met:
  10. //
  11. // Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. //
  14. // Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following
  16. // disclaimer in the documentation and/or other materials provided
  17. // with the distribution.
  18. //
  19. // Neither the name of 3Dlabs Inc. Ltd. nor the names of its
  20. // contributors may be used to endorse or promote products derived
  21. // from this software without specific prior written permission.
  22. //
  23. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  26. // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  27. // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  28. // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  29. // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  30. // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  31. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  33. // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. // POSSIBILITY OF SUCH DAMAGE.
  35. // SPIRV-IR
  36. //
  37. // Simple in-memory representation (IR) of SPIRV. Just for holding
  38. // Each function's CFG of blocks. Has this hierarchy:
  39. // - Module, which is a list of
  40. // - Function, which is a list of
  41. // - Block, which is a list of
  42. // - Instruction
  43. //
  44. #pragma once
  45. #ifndef spvIR_H
  46. #define spvIR_H
  47. #include "spirv.hpp"
  48. #include <algorithm>
  49. #include <cassert>
  50. #include <functional>
  51. #include <iostream>
  52. #include <memory>
  53. #include <vector>
  54. namespace spv {
  55. class Block;
  56. class Function;
  57. class Module;
  58. const Id NoResult = 0;
  59. const Id NoType = 0;
  60. const Decoration NoPrecision = DecorationMax;
  61. #ifdef __GNUC__
  62. # define POTENTIALLY_UNUSED __attribute__((unused))
  63. #else
  64. # define POTENTIALLY_UNUSED
  65. #endif
  66. POTENTIALLY_UNUSED
  67. const MemorySemanticsMask MemorySemanticsAllMemory =
  68. (MemorySemanticsMask)(MemorySemanticsUniformMemoryMask |
  69. MemorySemanticsWorkgroupMemoryMask |
  70. MemorySemanticsAtomicCounterMemoryMask |
  71. MemorySemanticsImageMemoryMask);
  72. struct IdImmediate {
  73. bool isId; // true if word is an Id, false if word is an immediate
  74. unsigned word;
  75. IdImmediate(bool i, unsigned w) : isId(i), word(w) {}
  76. };
  77. //
  78. // SPIR-V IR instruction.
  79. //
  80. class Instruction {
  81. public:
  82. Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
  83. explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
  84. virtual ~Instruction() {}
  85. void addIdOperand(Id id) {
  86. operands.push_back(id);
  87. idOperand.push_back(true);
  88. }
  89. void addImmediateOperand(unsigned int immediate) {
  90. operands.push_back(immediate);
  91. idOperand.push_back(false);
  92. }
  93. void setImmediateOperand(unsigned idx, unsigned int immediate) {
  94. assert(!idOperand[idx]);
  95. operands[idx] = immediate;
  96. }
  97. void addStringOperand(const char* str)
  98. {
  99. unsigned int word;
  100. char* wordString = (char*)&word;
  101. char* wordPtr = wordString;
  102. int charCount = 0;
  103. char c;
  104. do {
  105. c = *(str++);
  106. *(wordPtr++) = c;
  107. ++charCount;
  108. if (charCount == 4) {
  109. addImmediateOperand(word);
  110. wordPtr = wordString;
  111. charCount = 0;
  112. }
  113. } while (c != 0);
  114. // deal with partial last word
  115. if (charCount > 0) {
  116. // pad with 0s
  117. for (; charCount < 4; ++charCount)
  118. *(wordPtr++) = 0;
  119. addImmediateOperand(word);
  120. }
  121. }
  122. bool isIdOperand(int op) const { return idOperand[op]; }
  123. void setBlock(Block* b) { block = b; }
  124. Block* getBlock() const { return block; }
  125. Op getOpCode() const { return opCode; }
  126. int getNumOperands() const
  127. {
  128. assert(operands.size() == idOperand.size());
  129. return (int)operands.size();
  130. }
  131. Id getResultId() const { return resultId; }
  132. Id getTypeId() const { return typeId; }
  133. Id getIdOperand(int op) const {
  134. assert(idOperand[op]);
  135. return operands[op];
  136. }
  137. unsigned int getImmediateOperand(int op) const {
  138. assert(!idOperand[op]);
  139. return operands[op];
  140. }
  141. // Write out the binary form.
  142. void dump(std::vector<unsigned int>& out) const
  143. {
  144. // Compute the wordCount
  145. unsigned int wordCount = 1;
  146. if (typeId)
  147. ++wordCount;
  148. if (resultId)
  149. ++wordCount;
  150. wordCount += (unsigned int)operands.size();
  151. // Write out the beginning of the instruction
  152. out.push_back(((wordCount) << WordCountShift) | opCode);
  153. if (typeId)
  154. out.push_back(typeId);
  155. if (resultId)
  156. out.push_back(resultId);
  157. // Write out the operands
  158. for (int op = 0; op < (int)operands.size(); ++op)
  159. out.push_back(operands[op]);
  160. }
  161. protected:
  162. Instruction(const Instruction&);
  163. Id resultId;
  164. Id typeId;
  165. Op opCode;
  166. std::vector<Id> operands; // operands, both <id> and immediates (both are unsigned int)
  167. std::vector<bool> idOperand; // true for operands that are <id>, false for immediates
  168. Block* block;
  169. };
  170. //
  171. // SPIR-V IR block.
  172. //
  173. class Block {
  174. public:
  175. Block(Id id, Function& parent);
  176. virtual ~Block()
  177. {
  178. }
  179. Id getId() { return instructions.front()->getResultId(); }
  180. Function& getParent() const { return parent; }
  181. void addInstruction(std::unique_ptr<Instruction> inst);
  182. void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
  183. void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
  184. const std::vector<Block*>& getPredecessors() const { return predecessors; }
  185. const std::vector<Block*>& getSuccessors() const { return successors; }
  186. const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
  187. return instructions;
  188. }
  189. const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
  190. void setUnreachable() { unreachable = true; }
  191. bool isUnreachable() const { return unreachable; }
  192. // Returns the block's merge instruction, if one exists (otherwise null).
  193. const Instruction* getMergeInstruction() const {
  194. if (instructions.size() < 2) return nullptr;
  195. const Instruction* nextToLast = (instructions.cend() - 2)->get();
  196. switch (nextToLast->getOpCode()) {
  197. case OpSelectionMerge:
  198. case OpLoopMerge:
  199. return nextToLast;
  200. default:
  201. return nullptr;
  202. }
  203. return nullptr;
  204. }
  205. bool isTerminated() const
  206. {
  207. switch (instructions.back()->getOpCode()) {
  208. case OpBranch:
  209. case OpBranchConditional:
  210. case OpSwitch:
  211. case OpKill:
  212. case OpReturn:
  213. case OpReturnValue:
  214. return true;
  215. default:
  216. return false;
  217. }
  218. }
  219. void dump(std::vector<unsigned int>& out) const
  220. {
  221. instructions[0]->dump(out);
  222. for (int i = 0; i < (int)localVariables.size(); ++i)
  223. localVariables[i]->dump(out);
  224. for (int i = 1; i < (int)instructions.size(); ++i)
  225. instructions[i]->dump(out);
  226. }
  227. protected:
  228. Block(const Block&);
  229. Block& operator=(Block&);
  230. // To enforce keeping parent and ownership in sync:
  231. friend Function;
  232. std::vector<std::unique_ptr<Instruction> > instructions;
  233. std::vector<Block*> predecessors, successors;
  234. std::vector<std::unique_ptr<Instruction> > localVariables;
  235. Function& parent;
  236. // track whether this block is known to be uncreachable (not necessarily
  237. // true for all unreachable blocks, but should be set at least
  238. // for the extraneous ones introduced by the builder).
  239. bool unreachable;
  240. };
  241. // Traverses the control-flow graph rooted at root in an order suited for
  242. // readable code generation. Invokes callback at every node in the traversal
  243. // order.
  244. void inReadableOrder(Block* root, std::function<void(Block*)> callback);
  245. //
  246. // SPIR-V IR Function.
  247. //
  248. class Function {
  249. public:
  250. Function(Id id, Id resultType, Id functionType, Id firstParam, Module& parent);
  251. virtual ~Function()
  252. {
  253. for (int i = 0; i < (int)parameterInstructions.size(); ++i)
  254. delete parameterInstructions[i];
  255. for (int i = 0; i < (int)blocks.size(); ++i)
  256. delete blocks[i];
  257. }
  258. Id getId() const { return functionInstruction.getResultId(); }
  259. Id getParamId(int p) const { return parameterInstructions[p]->getResultId(); }
  260. Id getParamType(int p) const { return parameterInstructions[p]->getTypeId(); }
  261. void addBlock(Block* block) { blocks.push_back(block); }
  262. void removeBlock(Block* block)
  263. {
  264. auto found = find(blocks.begin(), blocks.end(), block);
  265. assert(found != blocks.end());
  266. blocks.erase(found);
  267. delete block;
  268. }
  269. Module& getParent() const { return parent; }
  270. Block* getEntryBlock() const { return blocks.front(); }
  271. Block* getLastBlock() const { return blocks.back(); }
  272. const std::vector<Block*>& getBlocks() const { return blocks; }
  273. void addLocalVariable(std::unique_ptr<Instruction> inst);
  274. Id getReturnType() const { return functionInstruction.getTypeId(); }
  275. void setImplicitThis() { implicitThis = true; }
  276. bool hasImplicitThis() const { return implicitThis; }
  277. void dump(std::vector<unsigned int>& out) const
  278. {
  279. // OpFunction
  280. functionInstruction.dump(out);
  281. // OpFunctionParameter
  282. for (int p = 0; p < (int)parameterInstructions.size(); ++p)
  283. parameterInstructions[p]->dump(out);
  284. // Blocks
  285. inReadableOrder(blocks[0], [&out](const Block* b) { b->dump(out); });
  286. Instruction end(0, 0, OpFunctionEnd);
  287. end.dump(out);
  288. }
  289. protected:
  290. Function(const Function&);
  291. Function& operator=(Function&);
  292. Module& parent;
  293. Instruction functionInstruction;
  294. std::vector<Instruction*> parameterInstructions;
  295. std::vector<Block*> blocks;
  296. bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument
  297. };
  298. //
  299. // SPIR-V IR Module.
  300. //
  301. class Module {
  302. public:
  303. Module() {}
  304. virtual ~Module()
  305. {
  306. // TODO delete things
  307. }
  308. void addFunction(Function *fun) { functions.push_back(fun); }
  309. void mapInstruction(Instruction *instruction)
  310. {
  311. spv::Id resultId = instruction->getResultId();
  312. // map the instruction's result id
  313. if (resultId >= idToInstruction.size())
  314. idToInstruction.resize(resultId + 16);
  315. idToInstruction[resultId] = instruction;
  316. }
  317. Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
  318. const std::vector<Function*>& getFunctions() const { return functions; }
  319. spv::Id getTypeId(Id resultId) const {
  320. return idToInstruction[resultId] == nullptr ? NoType : idToInstruction[resultId]->getTypeId();
  321. }
  322. StorageClass getStorageClass(Id typeId) const
  323. {
  324. assert(idToInstruction[typeId]->getOpCode() == spv::OpTypePointer);
  325. return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
  326. }
  327. void dump(std::vector<unsigned int>& out) const
  328. {
  329. for (int f = 0; f < (int)functions.size(); ++f)
  330. functions[f]->dump(out);
  331. }
  332. protected:
  333. Module(const Module&);
  334. std::vector<Function*> functions;
  335. // map from result id to instruction having that result id
  336. std::vector<Instruction*> idToInstruction;
  337. // map from a result id to its type id
  338. };
  339. //
  340. // Implementation (it's here due to circular type definitions).
  341. //
  342. // Add both
  343. // - the OpFunction instruction
  344. // - all the OpFunctionParameter instructions
  345. __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, Module& parent)
  346. : parent(parent), functionInstruction(id, resultType, OpFunction), implicitThis(false)
  347. {
  348. // OpFunction
  349. functionInstruction.addImmediateOperand(FunctionControlMaskNone);
  350. functionInstruction.addIdOperand(functionType);
  351. parent.mapInstruction(&functionInstruction);
  352. parent.addFunction(this);
  353. // OpFunctionParameter
  354. Instruction* typeInst = parent.getInstruction(functionType);
  355. int numParams = typeInst->getNumOperands() - 1;
  356. for (int p = 0; p < numParams; ++p) {
  357. Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), OpFunctionParameter);
  358. parent.mapInstruction(param);
  359. parameterInstructions.push_back(param);
  360. }
  361. }
  362. __inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
  363. {
  364. Instruction* raw_instruction = inst.get();
  365. blocks[0]->addLocalVariable(std::move(inst));
  366. parent.mapInstruction(raw_instruction);
  367. }
  368. __inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
  369. {
  370. instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, OpLabel)));
  371. instructions.back()->setBlock(this);
  372. parent.getParent().mapInstruction(instructions.back().get());
  373. }
  374. __inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
  375. {
  376. Instruction* raw_instruction = inst.get();
  377. instructions.push_back(std::move(inst));
  378. raw_instruction->setBlock(this);
  379. if (raw_instruction->getResultId())
  380. parent.getParent().mapInstruction(raw_instruction);
  381. }
  382. } // end spv namespace
  383. #endif // spvIR_H