instruction.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. // Copyright (c) 2016 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "source/opt/instruction.h"
  15. #include <initializer_list>
  16. #include "OpenCLDebugInfo100.h"
  17. #include "source/disassemble.h"
  18. #include "source/opt/fold.h"
  19. #include "source/opt/ir_context.h"
  20. #include "source/opt/reflect.h"
  21. namespace spvtools {
  22. namespace opt {
  23. namespace {
  24. // Indices used to get particular operands out of instructions using InOperand.
  25. const uint32_t kTypeImageDimIndex = 1;
  26. const uint32_t kLoadBaseIndex = 0;
  27. const uint32_t kPointerTypeStorageClassIndex = 0;
  28. const uint32_t kTypeImageSampledIndex = 5;
  29. // Constants for OpenCL.DebugInfo.100 extension instructions.
  30. const uint32_t kExtInstSetIdInIdx = 0;
  31. const uint32_t kExtInstInstructionInIdx = 1;
  32. const uint32_t kDebugScopeNumWords = 7;
  33. const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
  34. const uint32_t kDebugNoScopeNumWords = 5;
  35. // Number of operands of an OpBranchConditional instruction
  36. // with weights.
  37. const uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
  38. } // namespace
  39. Instruction::Instruction(IRContext* c)
  40. : utils::IntrusiveNodeBase<Instruction>(),
  41. context_(c),
  42. opcode_(SpvOpNop),
  43. has_type_id_(false),
  44. has_result_id_(false),
  45. unique_id_(c->TakeNextUniqueId()),
  46. dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
  47. Instruction::Instruction(IRContext* c, SpvOp op)
  48. : utils::IntrusiveNodeBase<Instruction>(),
  49. context_(c),
  50. opcode_(op),
  51. has_type_id_(false),
  52. has_result_id_(false),
  53. unique_id_(c->TakeNextUniqueId()),
  54. dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
  55. Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
  56. std::vector<Instruction>&& dbg_line)
  57. : context_(c),
  58. opcode_(static_cast<SpvOp>(inst.opcode)),
  59. has_type_id_(inst.type_id != 0),
  60. has_result_id_(inst.result_id != 0),
  61. unique_id_(c->TakeNextUniqueId()),
  62. dbg_line_insts_(std::move(dbg_line)),
  63. dbg_scope_(kNoDebugScope, kNoInlinedAt) {
  64. assert((!IsDebugLineInst(opcode_) || dbg_line.empty()) &&
  65. "Op(No)Line attaching to Op(No)Line found");
  66. for (uint32_t i = 0; i < inst.num_operands; ++i) {
  67. const auto& current_payload = inst.operands[i];
  68. std::vector<uint32_t> words(
  69. inst.words + current_payload.offset,
  70. inst.words + current_payload.offset + current_payload.num_words);
  71. operands_.emplace_back(current_payload.type, std::move(words));
  72. }
  73. }
  74. Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
  75. const DebugScope& dbg_scope)
  76. : context_(c),
  77. opcode_(static_cast<SpvOp>(inst.opcode)),
  78. has_type_id_(inst.type_id != 0),
  79. has_result_id_(inst.result_id != 0),
  80. unique_id_(c->TakeNextUniqueId()),
  81. dbg_scope_(dbg_scope) {
  82. for (uint32_t i = 0; i < inst.num_operands; ++i) {
  83. const auto& current_payload = inst.operands[i];
  84. std::vector<uint32_t> words(
  85. inst.words + current_payload.offset,
  86. inst.words + current_payload.offset + current_payload.num_words);
  87. operands_.emplace_back(current_payload.type, std::move(words));
  88. }
  89. }
  90. Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
  91. uint32_t res_id, const OperandList& in_operands)
  92. : utils::IntrusiveNodeBase<Instruction>(),
  93. context_(c),
  94. opcode_(op),
  95. has_type_id_(ty_id != 0),
  96. has_result_id_(res_id != 0),
  97. unique_id_(c->TakeNextUniqueId()),
  98. operands_(),
  99. dbg_scope_(kNoDebugScope, kNoInlinedAt) {
  100. if (has_type_id_) {
  101. operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
  102. std::initializer_list<uint32_t>{ty_id});
  103. }
  104. if (has_result_id_) {
  105. operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
  106. std::initializer_list<uint32_t>{res_id});
  107. }
  108. operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
  109. }
  110. Instruction::Instruction(Instruction&& that)
  111. : utils::IntrusiveNodeBase<Instruction>(),
  112. opcode_(that.opcode_),
  113. has_type_id_(that.has_type_id_),
  114. has_result_id_(that.has_result_id_),
  115. unique_id_(that.unique_id_),
  116. operands_(std::move(that.operands_)),
  117. dbg_line_insts_(std::move(that.dbg_line_insts_)),
  118. dbg_scope_(that.dbg_scope_) {
  119. for (auto& i : dbg_line_insts_) {
  120. i.dbg_scope_ = that.dbg_scope_;
  121. }
  122. }
  123. Instruction& Instruction::operator=(Instruction&& that) {
  124. opcode_ = that.opcode_;
  125. has_type_id_ = that.has_type_id_;
  126. has_result_id_ = that.has_result_id_;
  127. unique_id_ = that.unique_id_;
  128. operands_ = std::move(that.operands_);
  129. dbg_line_insts_ = std::move(that.dbg_line_insts_);
  130. dbg_scope_ = that.dbg_scope_;
  131. return *this;
  132. }
  133. Instruction* Instruction::Clone(IRContext* c) const {
  134. Instruction* clone = new Instruction(c);
  135. clone->opcode_ = opcode_;
  136. clone->has_type_id_ = has_type_id_;
  137. clone->has_result_id_ = has_result_id_;
  138. clone->unique_id_ = c->TakeNextUniqueId();
  139. clone->operands_ = operands_;
  140. clone->dbg_line_insts_ = dbg_line_insts_;
  141. clone->dbg_scope_ = dbg_scope_;
  142. return clone;
  143. }
  144. uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
  145. const auto& words = GetOperand(index).words;
  146. assert(words.size() == 1 && "expected the operand only taking one word");
  147. return words.front();
  148. }
  149. uint32_t Instruction::NumInOperandWords() const {
  150. uint32_t size = 0;
  151. for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
  152. size += static_cast<uint32_t>(operands_[i].words.size());
  153. return size;
  154. }
  155. bool Instruction::HasBranchWeights() const {
  156. if (opcode_ == SpvOpBranchConditional &&
  157. NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
  158. return true;
  159. }
  160. return false;
  161. }
  162. void Instruction::ToBinaryWithoutAttachedDebugInsts(
  163. std::vector<uint32_t>* binary) const {
  164. const uint32_t num_words = 1 + NumOperandWords();
  165. binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
  166. for (const auto& operand : operands_) {
  167. binary->insert(binary->end(), operand.words.begin(), operand.words.end());
  168. }
  169. }
  170. void Instruction::ReplaceOperands(const OperandList& new_operands) {
  171. operands_.clear();
  172. operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
  173. }
  174. bool Instruction::IsReadOnlyLoad() const {
  175. if (IsLoad()) {
  176. Instruction* address_def = GetBaseAddress();
  177. if (!address_def) {
  178. return false;
  179. }
  180. if (address_def->opcode() == SpvOpVariable) {
  181. if (address_def->IsReadOnlyPointer()) {
  182. return true;
  183. }
  184. }
  185. if (address_def->opcode() == SpvOpLoad) {
  186. const analysis::Type* address_type =
  187. context()->get_type_mgr()->GetType(address_def->type_id());
  188. if (address_type->AsSampledImage() != nullptr) {
  189. const auto* image_type =
  190. address_type->AsSampledImage()->image_type()->AsImage();
  191. if (image_type->sampled() == 1) {
  192. return true;
  193. }
  194. }
  195. }
  196. }
  197. return false;
  198. }
  199. Instruction* Instruction::GetBaseAddress() const {
  200. uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
  201. Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
  202. bool done = false;
  203. while (!done) {
  204. switch (base_inst->opcode()) {
  205. case SpvOpAccessChain:
  206. case SpvOpInBoundsAccessChain:
  207. case SpvOpPtrAccessChain:
  208. case SpvOpInBoundsPtrAccessChain:
  209. case SpvOpImageTexelPointer:
  210. case SpvOpCopyObject:
  211. // All of these instructions have the base pointer use a base pointer
  212. // in in-operand 0.
  213. base = base_inst->GetSingleWordInOperand(0);
  214. base_inst = context()->get_def_use_mgr()->GetDef(base);
  215. break;
  216. default:
  217. done = true;
  218. break;
  219. }
  220. }
  221. return base_inst;
  222. }
  223. bool Instruction::IsReadOnlyPointer() const {
  224. if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  225. return IsReadOnlyPointerShaders();
  226. else
  227. return IsReadOnlyPointerKernel();
  228. }
  229. bool Instruction::IsVulkanStorageImage() const {
  230. if (opcode() != SpvOpTypePointer) {
  231. return false;
  232. }
  233. uint32_t storage_class =
  234. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  235. if (storage_class != SpvStorageClassUniformConstant) {
  236. return false;
  237. }
  238. Instruction* base_type =
  239. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  240. // Unpack the optional layer of arraying.
  241. if (base_type->opcode() == SpvOpTypeArray ||
  242. base_type->opcode() == SpvOpTypeRuntimeArray) {
  243. base_type = context()->get_def_use_mgr()->GetDef(
  244. base_type->GetSingleWordInOperand(0));
  245. }
  246. if (base_type->opcode() != SpvOpTypeImage) {
  247. return false;
  248. }
  249. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  250. return false;
  251. }
  252. // Check if the image is sampled. If we do not know for sure that it is,
  253. // then assume it is a storage image.
  254. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
  255. }
  256. bool Instruction::IsVulkanSampledImage() const {
  257. if (opcode() != SpvOpTypePointer) {
  258. return false;
  259. }
  260. uint32_t storage_class =
  261. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  262. if (storage_class != SpvStorageClassUniformConstant) {
  263. return false;
  264. }
  265. Instruction* base_type =
  266. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  267. // Unpack the optional layer of arraying.
  268. if (base_type->opcode() == SpvOpTypeArray ||
  269. base_type->opcode() == SpvOpTypeRuntimeArray) {
  270. base_type = context()->get_def_use_mgr()->GetDef(
  271. base_type->GetSingleWordInOperand(0));
  272. }
  273. if (base_type->opcode() != SpvOpTypeImage) {
  274. return false;
  275. }
  276. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  277. return false;
  278. }
  279. // Check if the image is sampled. If we know for sure that it is,
  280. // then return true.
  281. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) == 1;
  282. }
  283. bool Instruction::IsVulkanStorageTexelBuffer() const {
  284. if (opcode() != SpvOpTypePointer) {
  285. return false;
  286. }
  287. uint32_t storage_class =
  288. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  289. if (storage_class != SpvStorageClassUniformConstant) {
  290. return false;
  291. }
  292. Instruction* base_type =
  293. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  294. // Unpack the optional layer of arraying.
  295. if (base_type->opcode() == SpvOpTypeArray ||
  296. base_type->opcode() == SpvOpTypeRuntimeArray) {
  297. base_type = context()->get_def_use_mgr()->GetDef(
  298. base_type->GetSingleWordInOperand(0));
  299. }
  300. if (base_type->opcode() != SpvOpTypeImage) {
  301. return false;
  302. }
  303. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
  304. return false;
  305. }
  306. // Check if the image is sampled. If we do not know for sure that it is,
  307. // then assume it is a storage texel buffer.
  308. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
  309. }
  310. bool Instruction::IsVulkanStorageBuffer() const {
  311. // Is there a difference between a "Storage buffer" and a "dynamic storage
  312. // buffer" in SPIR-V and do we care about the difference?
  313. if (opcode() != SpvOpTypePointer) {
  314. return false;
  315. }
  316. Instruction* base_type =
  317. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  318. // Unpack the optional layer of arraying.
  319. if (base_type->opcode() == SpvOpTypeArray ||
  320. base_type->opcode() == SpvOpTypeRuntimeArray) {
  321. base_type = context()->get_def_use_mgr()->GetDef(
  322. base_type->GetSingleWordInOperand(0));
  323. }
  324. if (base_type->opcode() != SpvOpTypeStruct) {
  325. return false;
  326. }
  327. uint32_t storage_class =
  328. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  329. if (storage_class == SpvStorageClassUniform) {
  330. bool is_buffer_block = false;
  331. context()->get_decoration_mgr()->ForEachDecoration(
  332. base_type->result_id(), SpvDecorationBufferBlock,
  333. [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
  334. return is_buffer_block;
  335. } else if (storage_class == SpvStorageClassStorageBuffer) {
  336. bool is_block = false;
  337. context()->get_decoration_mgr()->ForEachDecoration(
  338. base_type->result_id(), SpvDecorationBlock,
  339. [&is_block](const Instruction&) { is_block = true; });
  340. return is_block;
  341. }
  342. return false;
  343. }
  344. bool Instruction::IsVulkanUniformBuffer() const {
  345. if (opcode() != SpvOpTypePointer) {
  346. return false;
  347. }
  348. uint32_t storage_class =
  349. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  350. if (storage_class != SpvStorageClassUniform) {
  351. return false;
  352. }
  353. Instruction* base_type =
  354. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  355. // Unpack the optional layer of arraying.
  356. if (base_type->opcode() == SpvOpTypeArray ||
  357. base_type->opcode() == SpvOpTypeRuntimeArray) {
  358. base_type = context()->get_def_use_mgr()->GetDef(
  359. base_type->GetSingleWordInOperand(0));
  360. }
  361. if (base_type->opcode() != SpvOpTypeStruct) {
  362. return false;
  363. }
  364. bool is_block = false;
  365. context()->get_decoration_mgr()->ForEachDecoration(
  366. base_type->result_id(), SpvDecorationBlock,
  367. [&is_block](const Instruction&) { is_block = true; });
  368. return is_block;
  369. }
  370. bool Instruction::IsReadOnlyPointerShaders() const {
  371. if (type_id() == 0) {
  372. return false;
  373. }
  374. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  375. if (type_def->opcode() != SpvOpTypePointer) {
  376. return false;
  377. }
  378. uint32_t storage_class =
  379. type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  380. switch (storage_class) {
  381. case SpvStorageClassUniformConstant:
  382. if (!type_def->IsVulkanStorageImage() &&
  383. !type_def->IsVulkanStorageTexelBuffer()) {
  384. return true;
  385. }
  386. break;
  387. case SpvStorageClassUniform:
  388. if (!type_def->IsVulkanStorageBuffer()) {
  389. return true;
  390. }
  391. break;
  392. case SpvStorageClassPushConstant:
  393. case SpvStorageClassInput:
  394. return true;
  395. default:
  396. break;
  397. }
  398. bool is_nonwritable = false;
  399. context()->get_decoration_mgr()->ForEachDecoration(
  400. result_id(), SpvDecorationNonWritable,
  401. [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
  402. return is_nonwritable;
  403. }
  404. bool Instruction::IsReadOnlyPointerKernel() const {
  405. if (type_id() == 0) {
  406. return false;
  407. }
  408. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  409. if (type_def->opcode() != SpvOpTypePointer) {
  410. return false;
  411. }
  412. uint32_t storage_class =
  413. type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  414. return storage_class == SpvStorageClassUniformConstant;
  415. }
  416. uint32_t Instruction::GetTypeComponent(uint32_t element) const {
  417. uint32_t subtype = 0;
  418. switch (opcode()) {
  419. case SpvOpTypeStruct:
  420. subtype = GetSingleWordInOperand(element);
  421. break;
  422. case SpvOpTypeArray:
  423. case SpvOpTypeRuntimeArray:
  424. case SpvOpTypeVector:
  425. case SpvOpTypeMatrix:
  426. // These types all have uniform subtypes.
  427. subtype = GetSingleWordInOperand(0u);
  428. break;
  429. default:
  430. break;
  431. }
  432. return subtype;
  433. }
  434. void Instruction::UpdateLexicalScope(uint32_t scope) {
  435. dbg_scope_.SetLexicalScope(scope);
  436. for (auto& i : dbg_line_insts_) {
  437. i.dbg_scope_.SetLexicalScope(scope);
  438. }
  439. if (!IsDebugLineInst(opcode()) &&
  440. context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
  441. context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
  442. }
  443. }
  444. void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
  445. dbg_scope_.SetInlinedAt(new_inlined_at);
  446. for (auto& i : dbg_line_insts_) {
  447. i.dbg_scope_.SetInlinedAt(new_inlined_at);
  448. }
  449. if (!IsDebugLineInst(opcode()) &&
  450. context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
  451. context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
  452. }
  453. }
  454. void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
  455. if (from == nullptr) return;
  456. clear_dbg_line_insts();
  457. if (!from->dbg_line_insts().empty())
  458. dbg_line_insts().push_back(from->dbg_line_insts().back());
  459. SetDebugScope(from->GetDebugScope());
  460. if (!IsDebugLineInst(opcode()) &&
  461. context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
  462. context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
  463. }
  464. }
  465. Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
  466. inst.get()->InsertBefore(this);
  467. return inst.release();
  468. }
  469. Instruction* Instruction::InsertBefore(
  470. std::vector<std::unique_ptr<Instruction>>&& list) {
  471. Instruction* first_node = list.front().get();
  472. for (auto& inst : list) {
  473. inst.release()->InsertBefore(this);
  474. }
  475. list.clear();
  476. return first_node;
  477. }
  478. bool Instruction::IsValidBasePointer() const {
  479. uint32_t tid = type_id();
  480. if (tid == 0) {
  481. return false;
  482. }
  483. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  484. if (type->opcode() != SpvOpTypePointer) {
  485. return false;
  486. }
  487. auto feature_mgr = context()->get_feature_mgr();
  488. if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
  489. // TODO: The rules here could be more restrictive.
  490. return true;
  491. }
  492. if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
  493. return true;
  494. }
  495. // With variable pointers, there are more valid base pointer objects.
  496. // Variable pointers implicitly declares Variable pointers storage buffer.
  497. SpvStorageClass storage_class =
  498. static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
  499. if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
  500. storage_class == SpvStorageClassStorageBuffer) ||
  501. (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
  502. storage_class == SpvStorageClassWorkgroup)) {
  503. switch (opcode()) {
  504. case SpvOpPhi:
  505. case SpvOpSelect:
  506. case SpvOpFunctionCall:
  507. case SpvOpConstantNull:
  508. return true;
  509. default:
  510. break;
  511. }
  512. }
  513. uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
  514. Instruction* pointee_type_inst =
  515. context()->get_def_use_mgr()->GetDef(pointee_type_id);
  516. if (pointee_type_inst->IsOpaqueType()) {
  517. return true;
  518. }
  519. return false;
  520. }
  521. OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
  522. if (opcode() != SpvOpExtInst) {
  523. return OpenCLDebugInfo100InstructionsMax;
  524. }
  525. if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
  526. return OpenCLDebugInfo100InstructionsMax;
  527. }
  528. if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
  529. context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
  530. return OpenCLDebugInfo100InstructionsMax;
  531. }
  532. return OpenCLDebugInfo100Instructions(
  533. GetSingleWordInOperand(kExtInstInstructionInIdx));
  534. }
  535. bool Instruction::IsValidBaseImage() const {
  536. uint32_t tid = type_id();
  537. if (tid == 0) {
  538. return false;
  539. }
  540. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  541. return (type->opcode() == SpvOpTypeImage ||
  542. type->opcode() == SpvOpTypeSampledImage);
  543. }
  544. bool Instruction::IsOpaqueType() const {
  545. if (opcode() == SpvOpTypeStruct) {
  546. bool is_opaque = false;
  547. ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
  548. Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  549. is_opaque |= type_inst->IsOpaqueType();
  550. });
  551. return is_opaque;
  552. } else if (opcode() == SpvOpTypeArray) {
  553. uint32_t sub_type_id = GetSingleWordInOperand(0);
  554. Instruction* sub_type_inst =
  555. context()->get_def_use_mgr()->GetDef(sub_type_id);
  556. return sub_type_inst->IsOpaqueType();
  557. } else {
  558. return opcode() == SpvOpTypeRuntimeArray ||
  559. spvOpcodeIsBaseOpaqueType(opcode());
  560. }
  561. }
  562. bool Instruction::IsFoldable() const {
  563. return IsFoldableByFoldScalar() ||
  564. context()->get_instruction_folder().HasConstFoldingRule(this);
  565. }
  566. bool Instruction::IsFoldableByFoldScalar() const {
  567. const InstructionFolder& folder = context()->get_instruction_folder();
  568. if (!folder.IsFoldableOpcode(opcode())) {
  569. return false;
  570. }
  571. Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
  572. if (!folder.IsFoldableType(type)) {
  573. return false;
  574. }
  575. // Even if the type of the instruction is foldable, its operands may not be
  576. // foldable (e.g., comparisons of 64bit types). Check that all operand types
  577. // are foldable before accepting the instruction.
  578. return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
  579. Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  580. Instruction* def_inst_type =
  581. context()->get_def_use_mgr()->GetDef(def_inst->type_id());
  582. return folder.IsFoldableType(def_inst_type);
  583. });
  584. }
  585. bool Instruction::IsFloatingPointFoldingAllowed() const {
  586. // TODO: Add the rules for kernels. For now it will be pessimistic.
  587. // For now, do not support capabilities introduced by SPV_KHR_float_controls.
  588. if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
  589. context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
  590. context_->get_feature_mgr()->HasCapability(
  591. SpvCapabilityDenormFlushToZero) ||
  592. context_->get_feature_mgr()->HasCapability(
  593. SpvCapabilitySignedZeroInfNanPreserve) ||
  594. context_->get_feature_mgr()->HasCapability(
  595. SpvCapabilityRoundingModeRTZ) ||
  596. context_->get_feature_mgr()->HasCapability(
  597. SpvCapabilityRoundingModeRTE)) {
  598. return false;
  599. }
  600. bool is_nocontract = false;
  601. context_->get_decoration_mgr()->WhileEachDecoration(
  602. result_id(), SpvDecorationNoContraction,
  603. [&is_nocontract](const Instruction&) {
  604. is_nocontract = true;
  605. return false;
  606. });
  607. return !is_nocontract;
  608. }
  609. std::string Instruction::PrettyPrint(uint32_t options) const {
  610. // Convert the module to binary.
  611. std::vector<uint32_t> module_binary;
  612. context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
  613. // Convert the instruction to binary. This is used to identify the correct
  614. // stream of words to output from the module.
  615. std::vector<uint32_t> inst_binary;
  616. ToBinaryWithoutAttachedDebugInsts(&inst_binary);
  617. // Do not generate a header.
  618. return spvInstructionBinaryToText(
  619. context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
  620. module_binary.data(), module_binary.size(),
  621. options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  622. }
  623. std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
  624. str << inst.PrettyPrint();
  625. return str;
  626. }
  627. void Instruction::Dump() const {
  628. std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
  629. }
  630. bool Instruction::IsOpcodeCodeMotionSafe() const {
  631. switch (opcode_) {
  632. case SpvOpNop:
  633. case SpvOpUndef:
  634. case SpvOpLoad:
  635. case SpvOpAccessChain:
  636. case SpvOpInBoundsAccessChain:
  637. case SpvOpArrayLength:
  638. case SpvOpVectorExtractDynamic:
  639. case SpvOpVectorInsertDynamic:
  640. case SpvOpVectorShuffle:
  641. case SpvOpCompositeConstruct:
  642. case SpvOpCompositeExtract:
  643. case SpvOpCompositeInsert:
  644. case SpvOpCopyObject:
  645. case SpvOpTranspose:
  646. case SpvOpConvertFToU:
  647. case SpvOpConvertFToS:
  648. case SpvOpConvertSToF:
  649. case SpvOpConvertUToF:
  650. case SpvOpUConvert:
  651. case SpvOpSConvert:
  652. case SpvOpFConvert:
  653. case SpvOpQuantizeToF16:
  654. case SpvOpBitcast:
  655. case SpvOpSNegate:
  656. case SpvOpFNegate:
  657. case SpvOpIAdd:
  658. case SpvOpFAdd:
  659. case SpvOpISub:
  660. case SpvOpFSub:
  661. case SpvOpIMul:
  662. case SpvOpFMul:
  663. case SpvOpUDiv:
  664. case SpvOpSDiv:
  665. case SpvOpFDiv:
  666. case SpvOpUMod:
  667. case SpvOpSRem:
  668. case SpvOpSMod:
  669. case SpvOpFRem:
  670. case SpvOpFMod:
  671. case SpvOpVectorTimesScalar:
  672. case SpvOpMatrixTimesScalar:
  673. case SpvOpVectorTimesMatrix:
  674. case SpvOpMatrixTimesVector:
  675. case SpvOpMatrixTimesMatrix:
  676. case SpvOpOuterProduct:
  677. case SpvOpDot:
  678. case SpvOpIAddCarry:
  679. case SpvOpISubBorrow:
  680. case SpvOpUMulExtended:
  681. case SpvOpSMulExtended:
  682. case SpvOpAny:
  683. case SpvOpAll:
  684. case SpvOpIsNan:
  685. case SpvOpIsInf:
  686. case SpvOpLogicalEqual:
  687. case SpvOpLogicalNotEqual:
  688. case SpvOpLogicalOr:
  689. case SpvOpLogicalAnd:
  690. case SpvOpLogicalNot:
  691. case SpvOpSelect:
  692. case SpvOpIEqual:
  693. case SpvOpINotEqual:
  694. case SpvOpUGreaterThan:
  695. case SpvOpSGreaterThan:
  696. case SpvOpUGreaterThanEqual:
  697. case SpvOpSGreaterThanEqual:
  698. case SpvOpULessThan:
  699. case SpvOpSLessThan:
  700. case SpvOpULessThanEqual:
  701. case SpvOpSLessThanEqual:
  702. case SpvOpFOrdEqual:
  703. case SpvOpFUnordEqual:
  704. case SpvOpFOrdNotEqual:
  705. case SpvOpFUnordNotEqual:
  706. case SpvOpFOrdLessThan:
  707. case SpvOpFUnordLessThan:
  708. case SpvOpFOrdGreaterThan:
  709. case SpvOpFUnordGreaterThan:
  710. case SpvOpFOrdLessThanEqual:
  711. case SpvOpFUnordLessThanEqual:
  712. case SpvOpFOrdGreaterThanEqual:
  713. case SpvOpFUnordGreaterThanEqual:
  714. case SpvOpShiftRightLogical:
  715. case SpvOpShiftRightArithmetic:
  716. case SpvOpShiftLeftLogical:
  717. case SpvOpBitwiseOr:
  718. case SpvOpBitwiseXor:
  719. case SpvOpBitwiseAnd:
  720. case SpvOpNot:
  721. case SpvOpBitFieldInsert:
  722. case SpvOpBitFieldSExtract:
  723. case SpvOpBitFieldUExtract:
  724. case SpvOpBitReverse:
  725. case SpvOpBitCount:
  726. case SpvOpSizeOf:
  727. return true;
  728. default:
  729. return false;
  730. }
  731. }
  732. bool Instruction::IsScalarizable() const {
  733. if (spvOpcodeIsScalarizable(opcode())) {
  734. return true;
  735. }
  736. if (opcode() == SpvOpExtInst) {
  737. uint32_t instSetId =
  738. context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
  739. if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
  740. switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
  741. case GLSLstd450Round:
  742. case GLSLstd450RoundEven:
  743. case GLSLstd450Trunc:
  744. case GLSLstd450FAbs:
  745. case GLSLstd450SAbs:
  746. case GLSLstd450FSign:
  747. case GLSLstd450SSign:
  748. case GLSLstd450Floor:
  749. case GLSLstd450Ceil:
  750. case GLSLstd450Fract:
  751. case GLSLstd450Radians:
  752. case GLSLstd450Degrees:
  753. case GLSLstd450Sin:
  754. case GLSLstd450Cos:
  755. case GLSLstd450Tan:
  756. case GLSLstd450Asin:
  757. case GLSLstd450Acos:
  758. case GLSLstd450Atan:
  759. case GLSLstd450Sinh:
  760. case GLSLstd450Cosh:
  761. case GLSLstd450Tanh:
  762. case GLSLstd450Asinh:
  763. case GLSLstd450Acosh:
  764. case GLSLstd450Atanh:
  765. case GLSLstd450Atan2:
  766. case GLSLstd450Pow:
  767. case GLSLstd450Exp:
  768. case GLSLstd450Log:
  769. case GLSLstd450Exp2:
  770. case GLSLstd450Log2:
  771. case GLSLstd450Sqrt:
  772. case GLSLstd450InverseSqrt:
  773. case GLSLstd450Modf:
  774. case GLSLstd450FMin:
  775. case GLSLstd450UMin:
  776. case GLSLstd450SMin:
  777. case GLSLstd450FMax:
  778. case GLSLstd450UMax:
  779. case GLSLstd450SMax:
  780. case GLSLstd450FClamp:
  781. case GLSLstd450UClamp:
  782. case GLSLstd450SClamp:
  783. case GLSLstd450FMix:
  784. case GLSLstd450Step:
  785. case GLSLstd450SmoothStep:
  786. case GLSLstd450Fma:
  787. case GLSLstd450Frexp:
  788. case GLSLstd450Ldexp:
  789. case GLSLstd450FindILsb:
  790. case GLSLstd450FindSMsb:
  791. case GLSLstd450FindUMsb:
  792. case GLSLstd450NMin:
  793. case GLSLstd450NMax:
  794. case GLSLstd450NClamp:
  795. return true;
  796. default:
  797. return false;
  798. }
  799. }
  800. }
  801. return false;
  802. }
  803. bool Instruction::IsOpcodeSafeToDelete() const {
  804. if (context()->IsCombinatorInstruction(this)) {
  805. return true;
  806. }
  807. switch (opcode()) {
  808. case SpvOpDPdx:
  809. case SpvOpDPdy:
  810. case SpvOpFwidth:
  811. case SpvOpDPdxFine:
  812. case SpvOpDPdyFine:
  813. case SpvOpFwidthFine:
  814. case SpvOpDPdxCoarse:
  815. case SpvOpDPdyCoarse:
  816. case SpvOpFwidthCoarse:
  817. case SpvOpImageQueryLod:
  818. return true;
  819. default:
  820. return false;
  821. }
  822. }
  823. bool Instruction::IsNonSemanticInstruction() const {
  824. if (!HasResultId()) return false;
  825. if (opcode() != SpvOpExtInst) return false;
  826. auto import_inst =
  827. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
  828. std::string import_name = import_inst->GetInOperand(0).AsString();
  829. return import_name.find("NonSemantic.") == 0;
  830. }
  831. void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
  832. uint32_t ext_set,
  833. std::vector<uint32_t>* binary) const {
  834. uint32_t num_words = kDebugScopeNumWords;
  835. OpenCLDebugInfo100Instructions dbg_opcode = OpenCLDebugInfo100DebugScope;
  836. if (GetLexicalScope() == kNoDebugScope) {
  837. num_words = kDebugNoScopeNumWords;
  838. dbg_opcode = OpenCLDebugInfo100DebugNoScope;
  839. } else if (GetInlinedAt() == kNoInlinedAt) {
  840. num_words = kDebugScopeNumWordsWithoutInlinedAt;
  841. }
  842. std::vector<uint32_t> operands = {
  843. (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
  844. type_id,
  845. result_id,
  846. ext_set,
  847. static_cast<uint32_t>(dbg_opcode),
  848. };
  849. binary->insert(binary->end(), operands.begin(), operands.end());
  850. if (GetLexicalScope() != kNoDebugScope) {
  851. binary->push_back(GetLexicalScope());
  852. if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
  853. }
  854. }
  855. } // namespace opt
  856. } // namespace spvtools