spvIR.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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.hpp11"
  48. #include <algorithm>
  49. #include <cassert>
  50. #include <functional>
  51. #include <iostream>
  52. #include <memory>
  53. #include <vector>
  54. #include <set>
  55. #include <optional>
  56. namespace spv {
  57. class Block;
  58. class Function;
  59. class Module;
  60. const Id NoResult = 0;
  61. const Id NoType = 0;
  62. const Decoration NoPrecision = Decoration::Max;
  63. #ifdef __GNUC__
  64. # define POTENTIALLY_UNUSED __attribute__((unused))
  65. #else
  66. # define POTENTIALLY_UNUSED
  67. #endif
  68. POTENTIALLY_UNUSED
  69. const MemorySemanticsMask MemorySemanticsAllMemory =
  70. (MemorySemanticsMask)(MemorySemanticsMask::UniformMemory |
  71. MemorySemanticsMask::WorkgroupMemory |
  72. MemorySemanticsMask::AtomicCounterMemory |
  73. MemorySemanticsMask::ImageMemory);
  74. struct IdImmediate {
  75. bool isId; // true if word is an Id, false if word is an immediate
  76. unsigned word;
  77. IdImmediate(bool i, unsigned w) : isId(i), word(w) {}
  78. IdImmediate(bool i, spv::MemoryAccessMask w) : isId(i), word((unsigned)w) {}
  79. IdImmediate(bool i, spv::TensorAddressingOperandsMask w) : isId(i), word((unsigned)w) {}
  80. IdImmediate(bool i, spv::ImageOperandsMask w) : isId(i), word((unsigned)w) {}
  81. IdImmediate(bool i, spv::CooperativeMatrixOperandsMask w) : isId(i), word((unsigned)w) {}
  82. };
  83. //
  84. // SPIR-V IR instruction.
  85. //
  86. class Instruction {
  87. public:
  88. Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { }
  89. explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { }
  90. virtual ~Instruction() {}
  91. void reserveOperands(size_t count) {
  92. operands.reserve(count);
  93. idOperand.reserve(count);
  94. }
  95. void addIdOperand(Id id) {
  96. // ids can't be 0
  97. assert(id);
  98. operands.push_back(id);
  99. idOperand.push_back(true);
  100. }
  101. // This method is potentially dangerous as it can break assumptions
  102. // about SSA and lack of forward references.
  103. void setIdOperand(unsigned idx, Id id) {
  104. assert(id);
  105. assert(idOperand[idx]);
  106. operands[idx] = id;
  107. }
  108. void addImmediateOperand(unsigned int immediate) {
  109. operands.push_back(immediate);
  110. idOperand.push_back(false);
  111. }
  112. void addImmediateOperand(spv::StorageClass immediate) {
  113. addImmediateOperand((unsigned)immediate);
  114. }
  115. void addImmediateOperand(spv::ExecutionMode immediate) {
  116. addImmediateOperand((unsigned)immediate);
  117. }
  118. void addImmediateOperand(spv::ExecutionModel immediate) {
  119. addImmediateOperand((unsigned)immediate);
  120. }
  121. void addImmediateOperand(spv::Decoration immediate) {
  122. addImmediateOperand((unsigned)immediate);
  123. }
  124. void addImmediateOperand(spv::LinkageType immediate) {
  125. addImmediateOperand((unsigned)immediate);
  126. }
  127. void addImmediateOperand(spv::MemoryAccessMask immediate) {
  128. addImmediateOperand((unsigned)immediate);
  129. }
  130. void addImmediateOperand(spv::Capability immediate) {
  131. addImmediateOperand((unsigned)immediate);
  132. }
  133. void addImmediateOperand(spv::AddressingModel immediate) {
  134. addImmediateOperand((unsigned)immediate);
  135. }
  136. void addImmediateOperand(spv::MemoryModel immediate) {
  137. addImmediateOperand((unsigned)immediate);
  138. }
  139. void addImmediateOperand(spv::FPEncoding immediate) {
  140. addImmediateOperand((unsigned)immediate);
  141. }
  142. void addImmediateOperand(spv::SourceLanguage immediate) {
  143. addImmediateOperand((unsigned)immediate);
  144. }
  145. void addImmediateOperand(spv::Dim immediate) {
  146. addImmediateOperand((unsigned)immediate);
  147. }
  148. void addImmediateOperand(spv::FunctionControlMask immediate){
  149. addImmediateOperand((unsigned)immediate);
  150. }
  151. void addImmediateOperand(spv::SelectionControlMask immediate) {
  152. addImmediateOperand((unsigned)immediate);
  153. }
  154. void addImmediateOperand(spv::LoopControlMask immediate) {
  155. addImmediateOperand((unsigned)immediate);
  156. }
  157. void setImmediateOperand(unsigned idx, unsigned int immediate) {
  158. assert(!idOperand[idx]);
  159. operands[idx] = immediate;
  160. }
  161. void addStringOperand(const char* str)
  162. {
  163. unsigned int word = 0;
  164. unsigned int shiftAmount = 0;
  165. unsigned char c;
  166. do {
  167. c = *(str++);
  168. word |= ((unsigned int)c) << shiftAmount;
  169. shiftAmount += 8;
  170. if (shiftAmount == 32) {
  171. addImmediateOperand(word);
  172. word = 0;
  173. shiftAmount = 0;
  174. }
  175. } while (c != 0);
  176. // deal with partial last word
  177. if (shiftAmount > 0) {
  178. addImmediateOperand(word);
  179. }
  180. }
  181. bool isIdOperand(int op) const { return idOperand[op]; }
  182. void setBlock(Block* b) { block = b; }
  183. Block* getBlock() const { return block; }
  184. Op getOpCode() const { return opCode; }
  185. int getNumOperands() const
  186. {
  187. assert(operands.size() == idOperand.size());
  188. return (int)operands.size();
  189. }
  190. Id getResultId() const { return resultId; }
  191. Id getTypeId() const { return typeId; }
  192. void setTypeId(Id tId) { typeId = tId; }
  193. Id getIdOperand(int op) const {
  194. assert(idOperand[op]);
  195. return operands[op];
  196. }
  197. unsigned int getImmediateOperand(int op) const {
  198. assert(!idOperand[op]);
  199. return operands[op];
  200. }
  201. // Write out the binary form.
  202. void dump(std::vector<unsigned int>& out) const
  203. {
  204. // Compute the wordCount
  205. unsigned int wordCount = 1;
  206. if (typeId)
  207. ++wordCount;
  208. if (resultId)
  209. ++wordCount;
  210. wordCount += (unsigned int)operands.size();
  211. // Write out the beginning of the instruction
  212. out.push_back(((wordCount) << WordCountShift) | (unsigned)opCode);
  213. if (typeId)
  214. out.push_back(typeId);
  215. if (resultId)
  216. out.push_back(resultId);
  217. // Write out the operands
  218. for (int op = 0; op < (int)operands.size(); ++op)
  219. out.push_back(operands[op]);
  220. }
  221. const char *getNameString() const {
  222. if (opCode == Op::OpString) {
  223. return (const char *)&operands[0];
  224. } else {
  225. assert(opCode == Op::OpName);
  226. return (const char *)&operands[1];
  227. }
  228. }
  229. protected:
  230. Instruction(const Instruction&);
  231. Id resultId;
  232. Id typeId;
  233. Op opCode;
  234. std::vector<Id> operands; // operands, both <id> and immediates (both are unsigned int)
  235. std::vector<bool> idOperand; // true for operands that are <id>, false for immediates
  236. Block* block;
  237. };
  238. //
  239. // SPIR-V IR block.
  240. //
  241. struct DebugSourceLocation {
  242. int line;
  243. int column;
  244. spv::Id fileId;
  245. };
  246. class Block {
  247. public:
  248. Block(Id id, Function& parent);
  249. virtual ~Block()
  250. {
  251. }
  252. Id getId() { return instructions.front()->getResultId(); }
  253. Function& getParent() const { return parent; }
  254. // Returns true if the source location is actually updated.
  255. // Note we still need the builder to insert the line marker instruction. This is just a tracker.
  256. bool updateDebugSourceLocation(int line, int column, spv::Id fileId) {
  257. if (currentSourceLoc && currentSourceLoc->line == line && currentSourceLoc->column == column &&
  258. currentSourceLoc->fileId == fileId) {
  259. return false;
  260. }
  261. currentSourceLoc = DebugSourceLocation{line, column, fileId};
  262. return true;
  263. }
  264. // Returns true if the scope is actually updated.
  265. // Note we still need the builder to insert the debug scope instruction. This is just a tracker.
  266. bool updateDebugScope(spv::Id scopeId) {
  267. assert(scopeId);
  268. if (currentDebugScope && *currentDebugScope == scopeId) {
  269. return false;
  270. }
  271. currentDebugScope = scopeId;
  272. return true;
  273. }
  274. void addInstruction(std::unique_ptr<Instruction> inst);
  275. void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);}
  276. void addLocalVariable(std::unique_ptr<Instruction> inst) { localVariables.push_back(std::move(inst)); }
  277. const std::vector<Block*>& getPredecessors() const { return predecessors; }
  278. const std::vector<Block*>& getSuccessors() const { return successors; }
  279. std::vector<std::unique_ptr<Instruction> >& getInstructions() {
  280. return instructions;
  281. }
  282. const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
  283. void setUnreachable() { unreachable = true; }
  284. bool isUnreachable() const { return unreachable; }
  285. // Returns the block's merge instruction, if one exists (otherwise null).
  286. const Instruction* getMergeInstruction() const {
  287. if (instructions.size() < 2) return nullptr;
  288. const Instruction* nextToLast = (instructions.cend() - 2)->get();
  289. switch (nextToLast->getOpCode()) {
  290. case Op::OpSelectionMerge:
  291. case Op::OpLoopMerge:
  292. return nextToLast;
  293. default:
  294. return nullptr;
  295. }
  296. return nullptr;
  297. }
  298. // Change this block into a canonical dead merge block. Delete instructions
  299. // as necessary. A canonical dead merge block has only an OpLabel and an
  300. // OpUnreachable.
  301. void rewriteAsCanonicalUnreachableMerge() {
  302. assert(localVariables.empty());
  303. // Delete all instructions except for the label.
  304. assert(instructions.size() > 0);
  305. instructions.resize(1);
  306. successors.clear();
  307. addInstruction(std::unique_ptr<Instruction>(new Instruction(Op::OpUnreachable)));
  308. }
  309. // Change this block into a canonical dead continue target branching to the
  310. // given header ID. Delete instructions as necessary. A canonical dead continue
  311. // target has only an OpLabel and an unconditional branch back to the corresponding
  312. // header.
  313. void rewriteAsCanonicalUnreachableContinue(Block* header) {
  314. assert(localVariables.empty());
  315. // Delete all instructions except for the label.
  316. assert(instructions.size() > 0);
  317. instructions.resize(1);
  318. successors.clear();
  319. // Add OpBranch back to the header.
  320. assert(header != nullptr);
  321. Instruction* branch = new Instruction(Op::OpBranch);
  322. branch->addIdOperand(header->getId());
  323. addInstruction(std::unique_ptr<Instruction>(branch));
  324. successors.push_back(header);
  325. }
  326. bool isTerminated() const
  327. {
  328. switch (instructions.back()->getOpCode()) {
  329. case Op::OpBranch:
  330. case Op::OpBranchConditional:
  331. case Op::OpSwitch:
  332. case Op::OpKill:
  333. case Op::OpTerminateInvocation:
  334. case Op::OpReturn:
  335. case Op::OpReturnValue:
  336. case Op::OpUnreachable:
  337. return true;
  338. default:
  339. return false;
  340. }
  341. }
  342. void dump(std::vector<unsigned int>& out) const
  343. {
  344. instructions[0]->dump(out);
  345. for (int i = 0; i < (int)localVariables.size(); ++i)
  346. localVariables[i]->dump(out);
  347. for (int i = 1; i < (int)instructions.size(); ++i)
  348. instructions[i]->dump(out);
  349. }
  350. protected:
  351. Block(const Block&);
  352. Block& operator=(Block&);
  353. // To enforce keeping parent and ownership in sync:
  354. friend Function;
  355. std::vector<std::unique_ptr<Instruction> > instructions;
  356. std::vector<Block*> predecessors, successors;
  357. std::vector<std::unique_ptr<Instruction> > localVariables;
  358. Function& parent;
  359. // Track source location of the last source location marker instruction.
  360. std::optional<DebugSourceLocation> currentSourceLoc;
  361. // Track scope of the last debug scope instruction.
  362. std::optional<spv::Id> currentDebugScope;
  363. // track whether this block is known to be uncreachable (not necessarily
  364. // true for all unreachable blocks, but should be set at least
  365. // for the extraneous ones introduced by the builder).
  366. bool unreachable;
  367. };
  368. // The different reasons for reaching a block in the inReadableOrder traversal.
  369. enum ReachReason {
  370. // Reachable from the entry block via transfers of control, i.e. branches.
  371. ReachViaControlFlow = 0,
  372. // A continue target that is not reachable via control flow.
  373. ReachDeadContinue,
  374. // A merge block that is not reachable via control flow.
  375. ReachDeadMerge
  376. };
  377. // Traverses the control-flow graph rooted at root in an order suited for
  378. // readable code generation. Invokes callback at every node in the traversal
  379. // order. The callback arguments are:
  380. // - the block,
  381. // - the reason we reached the block,
  382. // - if the reason was that block is an unreachable continue or unreachable merge block
  383. // then the last parameter is the corresponding header block.
  384. void inReadableOrder(Block* root, std::function<void(Block*, ReachReason, Block* header)> callback);
  385. //
  386. // SPIR-V IR Function.
  387. //
  388. class Function {
  389. public:
  390. Function(Id id, Id resultType, Id functionType, Id firstParam, LinkageType linkage, const std::string& name, Module& parent);
  391. virtual ~Function()
  392. {
  393. for (int i = 0; i < (int)parameterInstructions.size(); ++i)
  394. delete parameterInstructions[i];
  395. for (int i = 0; i < (int)blocks.size(); ++i)
  396. delete blocks[i];
  397. }
  398. Id getId() const { return functionInstruction.getResultId(); }
  399. Id getParamId(int p) const { return parameterInstructions[p]->getResultId(); }
  400. Id getParamType(int p) const { return parameterInstructions[p]->getTypeId(); }
  401. void addBlock(Block* block) { blocks.push_back(block); }
  402. void removeBlock(Block* block)
  403. {
  404. auto found = find(blocks.begin(), blocks.end(), block);
  405. assert(found != blocks.end());
  406. blocks.erase(found);
  407. delete block;
  408. }
  409. Module& getParent() const { return parent; }
  410. Block* getEntryBlock() const { return blocks.front(); }
  411. Block* getLastBlock() const { return blocks.back(); }
  412. const std::vector<Block*>& getBlocks() const { return blocks; }
  413. void addLocalVariable(std::unique_ptr<Instruction> inst);
  414. Id getReturnType() const { return functionInstruction.getTypeId(); }
  415. Id getFuncId() const { return functionInstruction.getResultId(); }
  416. Id getFuncTypeId() const { return functionInstruction.getIdOperand(1); }
  417. void setReturnPrecision(Decoration precision)
  418. {
  419. if (precision == Decoration::RelaxedPrecision)
  420. reducedPrecisionReturn = true;
  421. }
  422. Decoration getReturnPrecision() const
  423. { return reducedPrecisionReturn ? Decoration::RelaxedPrecision : NoPrecision; }
  424. void setDebugLineInfo(Id fileName, int line, int column) {
  425. lineInstruction = std::unique_ptr<Instruction>{new Instruction(Op::OpLine)};
  426. lineInstruction->reserveOperands(3);
  427. lineInstruction->addIdOperand(fileName);
  428. lineInstruction->addImmediateOperand(line);
  429. lineInstruction->addImmediateOperand(column);
  430. }
  431. bool hasDebugLineInfo() const { return lineInstruction != nullptr; }
  432. void setImplicitThis() { implicitThis = true; }
  433. bool hasImplicitThis() const { return implicitThis; }
  434. void addParamPrecision(unsigned param, Decoration precision)
  435. {
  436. if (precision == Decoration::RelaxedPrecision)
  437. reducedPrecisionParams.insert(param);
  438. }
  439. Decoration getParamPrecision(unsigned param) const
  440. {
  441. return reducedPrecisionParams.find(param) != reducedPrecisionParams.end() ?
  442. Decoration::RelaxedPrecision : NoPrecision;
  443. }
  444. void dump(std::vector<unsigned int>& out) const
  445. {
  446. // OpLine
  447. if (lineInstruction != nullptr) {
  448. lineInstruction->dump(out);
  449. }
  450. // OpFunction
  451. functionInstruction.dump(out);
  452. // OpFunctionParameter
  453. for (int p = 0; p < (int)parameterInstructions.size(); ++p)
  454. parameterInstructions[p]->dump(out);
  455. // Blocks
  456. inReadableOrder(blocks[0], [&out](const Block* b, ReachReason, Block*) { b->dump(out); });
  457. Instruction end(0, 0, Op::OpFunctionEnd);
  458. end.dump(out);
  459. }
  460. LinkageType getLinkType() const { return linkType; }
  461. const char* getExportName() const { return exportName.c_str(); }
  462. protected:
  463. Function(const Function&);
  464. Function& operator=(Function&);
  465. Module& parent;
  466. std::unique_ptr<Instruction> lineInstruction;
  467. Instruction functionInstruction;
  468. std::vector<Instruction*> parameterInstructions;
  469. std::vector<Block*> blocks;
  470. bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument
  471. bool reducedPrecisionReturn;
  472. std::set<int> reducedPrecisionParams; // list of parameter indexes that need a relaxed precision arg
  473. LinkageType linkType;
  474. std::string exportName;
  475. };
  476. //
  477. // SPIR-V IR Module.
  478. //
  479. class Module {
  480. public:
  481. Module() {}
  482. virtual ~Module()
  483. {
  484. // TODO delete things
  485. }
  486. void addFunction(Function *fun) { functions.push_back(fun); }
  487. void mapInstruction(Instruction *instruction)
  488. {
  489. spv::Id resultId = instruction->getResultId();
  490. // map the instruction's result id
  491. if (resultId >= idToInstruction.size())
  492. idToInstruction.resize(resultId + 16);
  493. idToInstruction[resultId] = instruction;
  494. }
  495. Instruction* getInstruction(Id id) const { return idToInstruction[id]; }
  496. const std::vector<Function*>& getFunctions() const { return functions; }
  497. spv::Id getTypeId(Id resultId) const {
  498. return idToInstruction[resultId] == nullptr ? NoType : idToInstruction[resultId]->getTypeId();
  499. }
  500. StorageClass getStorageClass(Id typeId) const
  501. {
  502. assert(idToInstruction[typeId]->getOpCode() == spv::Op::OpTypePointer ||
  503. idToInstruction[typeId]->getOpCode() == spv::Op::OpTypeUntypedPointerKHR);
  504. return (StorageClass)idToInstruction[typeId]->getImmediateOperand(0);
  505. }
  506. void dump(std::vector<unsigned int>& out) const
  507. {
  508. for (int f = 0; f < (int)functions.size(); ++f)
  509. functions[f]->dump(out);
  510. }
  511. protected:
  512. Module(const Module&);
  513. std::vector<Function*> functions;
  514. // map from result id to instruction having that result id
  515. std::vector<Instruction*> idToInstruction;
  516. // map from a result id to its type id
  517. };
  518. //
  519. // Implementation (it's here due to circular type definitions).
  520. //
  521. // Add both
  522. // - the OpFunction instruction
  523. // - all the OpFunctionParameter instructions
  524. __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, LinkageType linkage, const std::string& name, Module& parent)
  525. : parent(parent), lineInstruction(nullptr),
  526. functionInstruction(id, resultType, Op::OpFunction), implicitThis(false),
  527. reducedPrecisionReturn(false),
  528. linkType(linkage)
  529. {
  530. // OpFunction
  531. functionInstruction.reserveOperands(2);
  532. functionInstruction.addImmediateOperand(FunctionControlMask::MaskNone);
  533. functionInstruction.addIdOperand(functionType);
  534. parent.mapInstruction(&functionInstruction);
  535. parent.addFunction(this);
  536. // OpFunctionParameter
  537. Instruction* typeInst = parent.getInstruction(functionType);
  538. int numParams = typeInst->getNumOperands() - 1;
  539. for (int p = 0; p < numParams; ++p) {
  540. Instruction* param = new Instruction(firstParamId + p, typeInst->getIdOperand(p + 1), Op::OpFunctionParameter);
  541. parent.mapInstruction(param);
  542. parameterInstructions.push_back(param);
  543. }
  544. // If importing/exporting, save the function name (without the mangled parameters) for the linkage decoration
  545. if (linkType != LinkageType::Max) {
  546. exportName = name.substr(0, name.find_first_of('('));
  547. }
  548. }
  549. __inline void Function::addLocalVariable(std::unique_ptr<Instruction> inst)
  550. {
  551. Instruction* raw_instruction = inst.get();
  552. blocks[0]->addLocalVariable(std::move(inst));
  553. parent.mapInstruction(raw_instruction);
  554. }
  555. __inline Block::Block(Id id, Function& parent) : parent(parent), unreachable(false)
  556. {
  557. instructions.push_back(std::unique_ptr<Instruction>(new Instruction(id, NoType, Op::OpLabel)));
  558. instructions.back()->setBlock(this);
  559. parent.getParent().mapInstruction(instructions.back().get());
  560. }
  561. __inline void Block::addInstruction(std::unique_ptr<Instruction> inst)
  562. {
  563. Instruction* raw_instruction = inst.get();
  564. instructions.push_back(std::move(inst));
  565. raw_instruction->setBlock(this);
  566. if (raw_instruction->getResultId())
  567. parent.getParent().mapInstruction(raw_instruction);
  568. }
  569. } // end spv namespace
  570. #endif // spvIR_H