instruction.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  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. void Instruction::ReplaceOperands(const OperandList& new_operands) {
  170. operands_.clear();
  171. operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
  172. }
  173. bool Instruction::IsReadOnlyLoad() const {
  174. if (IsLoad()) {
  175. Instruction* address_def = GetBaseAddress();
  176. if (!address_def) {
  177. return false;
  178. }
  179. if (address_def->opcode() == SpvOpVariable) {
  180. if (address_def->IsReadOnlyPointer()) {
  181. return true;
  182. }
  183. }
  184. if (address_def->opcode() == SpvOpLoad) {
  185. const analysis::Type* address_type =
  186. context()->get_type_mgr()->GetType(address_def->type_id());
  187. if (address_type->AsSampledImage() != nullptr) {
  188. const auto* image_type =
  189. address_type->AsSampledImage()->image_type()->AsImage();
  190. if (image_type->sampled() == 1) {
  191. return true;
  192. }
  193. }
  194. }
  195. }
  196. return false;
  197. }
  198. Instruction* Instruction::GetBaseAddress() const {
  199. uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
  200. Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
  201. bool done = false;
  202. while (!done) {
  203. switch (base_inst->opcode()) {
  204. case SpvOpAccessChain:
  205. case SpvOpInBoundsAccessChain:
  206. case SpvOpPtrAccessChain:
  207. case SpvOpInBoundsPtrAccessChain:
  208. case SpvOpImageTexelPointer:
  209. case SpvOpCopyObject:
  210. // All of these instructions have the base pointer use a base pointer
  211. // in in-operand 0.
  212. base = base_inst->GetSingleWordInOperand(0);
  213. base_inst = context()->get_def_use_mgr()->GetDef(base);
  214. break;
  215. default:
  216. done = true;
  217. break;
  218. }
  219. }
  220. return base_inst;
  221. }
  222. bool Instruction::IsReadOnlyPointer() const {
  223. if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  224. return IsReadOnlyPointerShaders();
  225. else
  226. return IsReadOnlyPointerKernel();
  227. }
  228. bool Instruction::IsVulkanStorageImage() const {
  229. if (opcode() != SpvOpTypePointer) {
  230. return false;
  231. }
  232. uint32_t storage_class =
  233. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  234. if (storage_class != SpvStorageClassUniformConstant) {
  235. return false;
  236. }
  237. Instruction* base_type =
  238. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  239. // Unpack the optional layer of arraying.
  240. if (base_type->opcode() == SpvOpTypeArray ||
  241. base_type->opcode() == SpvOpTypeRuntimeArray) {
  242. base_type = context()->get_def_use_mgr()->GetDef(
  243. base_type->GetSingleWordInOperand(0));
  244. }
  245. if (base_type->opcode() != SpvOpTypeImage) {
  246. return false;
  247. }
  248. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  249. return false;
  250. }
  251. // Check if the image is sampled. If we do not know for sure that it is,
  252. // then assume it is a storage image.
  253. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  254. return s != 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. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  282. return s == 1;
  283. }
  284. bool Instruction::IsVulkanStorageTexelBuffer() const {
  285. if (opcode() != SpvOpTypePointer) {
  286. return false;
  287. }
  288. uint32_t storage_class =
  289. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  290. if (storage_class != SpvStorageClassUniformConstant) {
  291. return false;
  292. }
  293. Instruction* base_type =
  294. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  295. // Unpack the optional layer of arraying.
  296. if (base_type->opcode() == SpvOpTypeArray ||
  297. base_type->opcode() == SpvOpTypeRuntimeArray) {
  298. base_type = context()->get_def_use_mgr()->GetDef(
  299. base_type->GetSingleWordInOperand(0));
  300. }
  301. if (base_type->opcode() != SpvOpTypeImage) {
  302. return false;
  303. }
  304. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
  305. return false;
  306. }
  307. // Check if the image is sampled. If we do not know for sure that it is,
  308. // then assume it is a storage texel buffer.
  309. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
  310. }
  311. bool Instruction::IsVulkanStorageBuffer() const {
  312. // Is there a difference between a "Storage buffer" and a "dynamic storage
  313. // buffer" in SPIR-V and do we care about the difference?
  314. if (opcode() != SpvOpTypePointer) {
  315. return false;
  316. }
  317. Instruction* base_type =
  318. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  319. // Unpack the optional layer of arraying.
  320. if (base_type->opcode() == SpvOpTypeArray ||
  321. base_type->opcode() == SpvOpTypeRuntimeArray) {
  322. base_type = context()->get_def_use_mgr()->GetDef(
  323. base_type->GetSingleWordInOperand(0));
  324. }
  325. if (base_type->opcode() != SpvOpTypeStruct) {
  326. return false;
  327. }
  328. uint32_t storage_class =
  329. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  330. if (storage_class == SpvStorageClassUniform) {
  331. bool is_buffer_block = false;
  332. context()->get_decoration_mgr()->ForEachDecoration(
  333. base_type->result_id(), SpvDecorationBufferBlock,
  334. [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
  335. return is_buffer_block;
  336. } else if (storage_class == SpvStorageClassStorageBuffer) {
  337. bool is_block = false;
  338. context()->get_decoration_mgr()->ForEachDecoration(
  339. base_type->result_id(), SpvDecorationBlock,
  340. [&is_block](const Instruction&) { is_block = true; });
  341. return is_block;
  342. }
  343. return false;
  344. }
  345. bool Instruction::IsVulkanUniformBuffer() const {
  346. if (opcode() != SpvOpTypePointer) {
  347. return false;
  348. }
  349. uint32_t storage_class =
  350. GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  351. if (storage_class != SpvStorageClassUniform) {
  352. return false;
  353. }
  354. Instruction* base_type =
  355. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  356. // Unpack the optional layer of arraying.
  357. if (base_type->opcode() == SpvOpTypeArray ||
  358. base_type->opcode() == SpvOpTypeRuntimeArray) {
  359. base_type = context()->get_def_use_mgr()->GetDef(
  360. base_type->GetSingleWordInOperand(0));
  361. }
  362. if (base_type->opcode() != SpvOpTypeStruct) {
  363. return false;
  364. }
  365. bool is_block = false;
  366. context()->get_decoration_mgr()->ForEachDecoration(
  367. base_type->result_id(), SpvDecorationBlock,
  368. [&is_block](const Instruction&) { is_block = true; });
  369. return is_block;
  370. }
  371. bool Instruction::IsReadOnlyPointerShaders() const {
  372. if (type_id() == 0) {
  373. return false;
  374. }
  375. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  376. if (type_def->opcode() != SpvOpTypePointer) {
  377. return false;
  378. }
  379. uint32_t storage_class =
  380. type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  381. switch (storage_class) {
  382. case SpvStorageClassUniformConstant:
  383. if (!type_def->IsVulkanStorageImage() &&
  384. !type_def->IsVulkanStorageTexelBuffer()) {
  385. return true;
  386. }
  387. break;
  388. case SpvStorageClassUniform:
  389. if (!type_def->IsVulkanStorageBuffer()) {
  390. return true;
  391. }
  392. break;
  393. case SpvStorageClassPushConstant:
  394. case SpvStorageClassInput:
  395. return true;
  396. default:
  397. break;
  398. }
  399. bool is_nonwritable = false;
  400. context()->get_decoration_mgr()->ForEachDecoration(
  401. result_id(), SpvDecorationNonWritable,
  402. [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
  403. return is_nonwritable;
  404. }
  405. bool Instruction::IsReadOnlyPointerKernel() const {
  406. if (type_id() == 0) {
  407. return false;
  408. }
  409. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  410. if (type_def->opcode() != SpvOpTypePointer) {
  411. return false;
  412. }
  413. uint32_t storage_class =
  414. type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
  415. return storage_class == SpvStorageClassUniformConstant;
  416. }
  417. uint32_t Instruction::GetTypeComponent(uint32_t element) const {
  418. uint32_t subtype = 0;
  419. switch (opcode()) {
  420. case SpvOpTypeStruct:
  421. subtype = GetSingleWordInOperand(element);
  422. break;
  423. case SpvOpTypeArray:
  424. case SpvOpTypeRuntimeArray:
  425. case SpvOpTypeVector:
  426. case SpvOpTypeMatrix:
  427. // These types all have uniform subtypes.
  428. subtype = GetSingleWordInOperand(0u);
  429. break;
  430. default:
  431. break;
  432. }
  433. return subtype;
  434. }
  435. Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& i) {
  436. i.get()->InsertBefore(this);
  437. return i.release();
  438. }
  439. Instruction* Instruction::InsertBefore(
  440. std::vector<std::unique_ptr<Instruction>>&& list) {
  441. Instruction* first_node = list.front().get();
  442. for (auto& i : list) {
  443. i.release()->InsertBefore(this);
  444. }
  445. list.clear();
  446. return first_node;
  447. }
  448. bool Instruction::IsValidBasePointer() const {
  449. uint32_t tid = type_id();
  450. if (tid == 0) {
  451. return false;
  452. }
  453. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  454. if (type->opcode() != SpvOpTypePointer) {
  455. return false;
  456. }
  457. auto feature_mgr = context()->get_feature_mgr();
  458. if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
  459. // TODO: The rules here could be more restrictive.
  460. return true;
  461. }
  462. if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
  463. return true;
  464. }
  465. // With variable pointers, there are more valid base pointer objects.
  466. // Variable pointers implicitly declares Variable pointers storage buffer.
  467. SpvStorageClass storage_class =
  468. static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
  469. if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
  470. storage_class == SpvStorageClassStorageBuffer) ||
  471. (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
  472. storage_class == SpvStorageClassWorkgroup)) {
  473. switch (opcode()) {
  474. case SpvOpPhi:
  475. case SpvOpSelect:
  476. case SpvOpFunctionCall:
  477. case SpvOpConstantNull:
  478. return true;
  479. default:
  480. break;
  481. }
  482. }
  483. uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
  484. Instruction* pointee_type_inst =
  485. context()->get_def_use_mgr()->GetDef(pointee_type_id);
  486. if (pointee_type_inst->IsOpaqueType()) {
  487. return true;
  488. }
  489. return false;
  490. }
  491. OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
  492. if (opcode() != SpvOpExtInst) return OpenCLDebugInfo100InstructionsMax;
  493. if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo())
  494. return OpenCLDebugInfo100InstructionsMax;
  495. if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
  496. context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
  497. return OpenCLDebugInfo100InstructionsMax;
  498. }
  499. return OpenCLDebugInfo100Instructions(
  500. GetSingleWordInOperand(kExtInstInstructionInIdx));
  501. }
  502. bool Instruction::IsValidBaseImage() const {
  503. uint32_t tid = type_id();
  504. if (tid == 0) {
  505. return false;
  506. }
  507. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  508. return (type->opcode() == SpvOpTypeImage ||
  509. type->opcode() == SpvOpTypeSampledImage);
  510. }
  511. bool Instruction::IsOpaqueType() const {
  512. if (opcode() == SpvOpTypeStruct) {
  513. bool is_opaque = false;
  514. ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
  515. Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  516. is_opaque |= type_inst->IsOpaqueType();
  517. });
  518. return is_opaque;
  519. } else if (opcode() == SpvOpTypeArray) {
  520. uint32_t sub_type_id = GetSingleWordInOperand(0);
  521. Instruction* sub_type_inst =
  522. context()->get_def_use_mgr()->GetDef(sub_type_id);
  523. return sub_type_inst->IsOpaqueType();
  524. } else {
  525. return opcode() == SpvOpTypeRuntimeArray ||
  526. spvOpcodeIsBaseOpaqueType(opcode());
  527. }
  528. }
  529. bool Instruction::IsFoldable() const {
  530. return IsFoldableByFoldScalar() ||
  531. context()->get_instruction_folder().HasConstFoldingRule(this);
  532. }
  533. bool Instruction::IsFoldableByFoldScalar() const {
  534. const InstructionFolder& folder = context()->get_instruction_folder();
  535. if (!folder.IsFoldableOpcode(opcode())) {
  536. return false;
  537. }
  538. Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
  539. if (!folder.IsFoldableType(type)) {
  540. return false;
  541. }
  542. // Even if the type of the instruction is foldable, its operands may not be
  543. // foldable (e.g., comparisons of 64bit types). Check that all operand types
  544. // are foldable before accepting the instruction.
  545. return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
  546. Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  547. Instruction* def_inst_type =
  548. context()->get_def_use_mgr()->GetDef(def_inst->type_id());
  549. return folder.IsFoldableType(def_inst_type);
  550. });
  551. }
  552. bool Instruction::IsFloatingPointFoldingAllowed() const {
  553. // TODO: Add the rules for kernels. For now it will be pessimistic.
  554. // For now, do not support capabilities introduced by SPV_KHR_float_controls.
  555. if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
  556. context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
  557. context_->get_feature_mgr()->HasCapability(
  558. SpvCapabilityDenormFlushToZero) ||
  559. context_->get_feature_mgr()->HasCapability(
  560. SpvCapabilitySignedZeroInfNanPreserve) ||
  561. context_->get_feature_mgr()->HasCapability(
  562. SpvCapabilityRoundingModeRTZ) ||
  563. context_->get_feature_mgr()->HasCapability(
  564. SpvCapabilityRoundingModeRTE)) {
  565. return false;
  566. }
  567. bool is_nocontract = false;
  568. context_->get_decoration_mgr()->WhileEachDecoration(
  569. result_id(), SpvDecorationNoContraction,
  570. [&is_nocontract](const Instruction&) {
  571. is_nocontract = true;
  572. return false;
  573. });
  574. return !is_nocontract;
  575. }
  576. std::string Instruction::PrettyPrint(uint32_t options) const {
  577. // Convert the module to binary.
  578. std::vector<uint32_t> module_binary;
  579. context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
  580. // Convert the instruction to binary. This is used to identify the correct
  581. // stream of words to output from the module.
  582. std::vector<uint32_t> inst_binary;
  583. ToBinaryWithoutAttachedDebugInsts(&inst_binary);
  584. // Do not generate a header.
  585. return spvInstructionBinaryToText(
  586. context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
  587. module_binary.data(), module_binary.size(),
  588. options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  589. }
  590. std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
  591. str << inst.PrettyPrint();
  592. return str;
  593. }
  594. void Instruction::Dump() const {
  595. std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
  596. }
  597. bool Instruction::IsOpcodeCodeMotionSafe() const {
  598. switch (opcode_) {
  599. case SpvOpNop:
  600. case SpvOpUndef:
  601. case SpvOpLoad:
  602. case SpvOpAccessChain:
  603. case SpvOpInBoundsAccessChain:
  604. case SpvOpArrayLength:
  605. case SpvOpVectorExtractDynamic:
  606. case SpvOpVectorInsertDynamic:
  607. case SpvOpVectorShuffle:
  608. case SpvOpCompositeConstruct:
  609. case SpvOpCompositeExtract:
  610. case SpvOpCompositeInsert:
  611. case SpvOpCopyObject:
  612. case SpvOpTranspose:
  613. case SpvOpConvertFToU:
  614. case SpvOpConvertFToS:
  615. case SpvOpConvertSToF:
  616. case SpvOpConvertUToF:
  617. case SpvOpUConvert:
  618. case SpvOpSConvert:
  619. case SpvOpFConvert:
  620. case SpvOpQuantizeToF16:
  621. case SpvOpBitcast:
  622. case SpvOpSNegate:
  623. case SpvOpFNegate:
  624. case SpvOpIAdd:
  625. case SpvOpFAdd:
  626. case SpvOpISub:
  627. case SpvOpFSub:
  628. case SpvOpIMul:
  629. case SpvOpFMul:
  630. case SpvOpUDiv:
  631. case SpvOpSDiv:
  632. case SpvOpFDiv:
  633. case SpvOpUMod:
  634. case SpvOpSRem:
  635. case SpvOpSMod:
  636. case SpvOpFRem:
  637. case SpvOpFMod:
  638. case SpvOpVectorTimesScalar:
  639. case SpvOpMatrixTimesScalar:
  640. case SpvOpVectorTimesMatrix:
  641. case SpvOpMatrixTimesVector:
  642. case SpvOpMatrixTimesMatrix:
  643. case SpvOpOuterProduct:
  644. case SpvOpDot:
  645. case SpvOpIAddCarry:
  646. case SpvOpISubBorrow:
  647. case SpvOpUMulExtended:
  648. case SpvOpSMulExtended:
  649. case SpvOpAny:
  650. case SpvOpAll:
  651. case SpvOpIsNan:
  652. case SpvOpIsInf:
  653. case SpvOpLogicalEqual:
  654. case SpvOpLogicalNotEqual:
  655. case SpvOpLogicalOr:
  656. case SpvOpLogicalAnd:
  657. case SpvOpLogicalNot:
  658. case SpvOpSelect:
  659. case SpvOpIEqual:
  660. case SpvOpINotEqual:
  661. case SpvOpUGreaterThan:
  662. case SpvOpSGreaterThan:
  663. case SpvOpUGreaterThanEqual:
  664. case SpvOpSGreaterThanEqual:
  665. case SpvOpULessThan:
  666. case SpvOpSLessThan:
  667. case SpvOpULessThanEqual:
  668. case SpvOpSLessThanEqual:
  669. case SpvOpFOrdEqual:
  670. case SpvOpFUnordEqual:
  671. case SpvOpFOrdNotEqual:
  672. case SpvOpFUnordNotEqual:
  673. case SpvOpFOrdLessThan:
  674. case SpvOpFUnordLessThan:
  675. case SpvOpFOrdGreaterThan:
  676. case SpvOpFUnordGreaterThan:
  677. case SpvOpFOrdLessThanEqual:
  678. case SpvOpFUnordLessThanEqual:
  679. case SpvOpFOrdGreaterThanEqual:
  680. case SpvOpFUnordGreaterThanEqual:
  681. case SpvOpShiftRightLogical:
  682. case SpvOpShiftRightArithmetic:
  683. case SpvOpShiftLeftLogical:
  684. case SpvOpBitwiseOr:
  685. case SpvOpBitwiseXor:
  686. case SpvOpBitwiseAnd:
  687. case SpvOpNot:
  688. case SpvOpBitFieldInsert:
  689. case SpvOpBitFieldSExtract:
  690. case SpvOpBitFieldUExtract:
  691. case SpvOpBitReverse:
  692. case SpvOpBitCount:
  693. case SpvOpSizeOf:
  694. return true;
  695. default:
  696. return false;
  697. }
  698. }
  699. bool Instruction::IsScalarizable() const {
  700. if (spvOpcodeIsScalarizable(opcode())) {
  701. return true;
  702. }
  703. if (opcode() == SpvOpExtInst) {
  704. uint32_t instSetId =
  705. context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
  706. if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
  707. switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
  708. case GLSLstd450Round:
  709. case GLSLstd450RoundEven:
  710. case GLSLstd450Trunc:
  711. case GLSLstd450FAbs:
  712. case GLSLstd450SAbs:
  713. case GLSLstd450FSign:
  714. case GLSLstd450SSign:
  715. case GLSLstd450Floor:
  716. case GLSLstd450Ceil:
  717. case GLSLstd450Fract:
  718. case GLSLstd450Radians:
  719. case GLSLstd450Degrees:
  720. case GLSLstd450Sin:
  721. case GLSLstd450Cos:
  722. case GLSLstd450Tan:
  723. case GLSLstd450Asin:
  724. case GLSLstd450Acos:
  725. case GLSLstd450Atan:
  726. case GLSLstd450Sinh:
  727. case GLSLstd450Cosh:
  728. case GLSLstd450Tanh:
  729. case GLSLstd450Asinh:
  730. case GLSLstd450Acosh:
  731. case GLSLstd450Atanh:
  732. case GLSLstd450Atan2:
  733. case GLSLstd450Pow:
  734. case GLSLstd450Exp:
  735. case GLSLstd450Log:
  736. case GLSLstd450Exp2:
  737. case GLSLstd450Log2:
  738. case GLSLstd450Sqrt:
  739. case GLSLstd450InverseSqrt:
  740. case GLSLstd450Modf:
  741. case GLSLstd450FMin:
  742. case GLSLstd450UMin:
  743. case GLSLstd450SMin:
  744. case GLSLstd450FMax:
  745. case GLSLstd450UMax:
  746. case GLSLstd450SMax:
  747. case GLSLstd450FClamp:
  748. case GLSLstd450UClamp:
  749. case GLSLstd450SClamp:
  750. case GLSLstd450FMix:
  751. case GLSLstd450Step:
  752. case GLSLstd450SmoothStep:
  753. case GLSLstd450Fma:
  754. case GLSLstd450Frexp:
  755. case GLSLstd450Ldexp:
  756. case GLSLstd450FindILsb:
  757. case GLSLstd450FindSMsb:
  758. case GLSLstd450FindUMsb:
  759. case GLSLstd450NMin:
  760. case GLSLstd450NMax:
  761. case GLSLstd450NClamp:
  762. return true;
  763. default:
  764. return false;
  765. }
  766. }
  767. }
  768. return false;
  769. }
  770. bool Instruction::IsOpcodeSafeToDelete() const {
  771. if (context()->IsCombinatorInstruction(this)) {
  772. return true;
  773. }
  774. switch (opcode()) {
  775. case SpvOpDPdx:
  776. case SpvOpDPdy:
  777. case SpvOpFwidth:
  778. case SpvOpDPdxFine:
  779. case SpvOpDPdyFine:
  780. case SpvOpFwidthFine:
  781. case SpvOpDPdxCoarse:
  782. case SpvOpDPdyCoarse:
  783. case SpvOpFwidthCoarse:
  784. case SpvOpImageQueryLod:
  785. return true;
  786. default:
  787. return false;
  788. }
  789. }
  790. void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
  791. uint32_t ext_set,
  792. std::vector<uint32_t>* binary) const {
  793. uint32_t num_words = kDebugScopeNumWords;
  794. OpenCLDebugInfo100Instructions dbg_opcode = OpenCLDebugInfo100DebugScope;
  795. if (GetLexicalScope() == kNoDebugScope) {
  796. num_words = kDebugNoScopeNumWords;
  797. dbg_opcode = OpenCLDebugInfo100DebugNoScope;
  798. } else if (GetInlinedAt() == kNoInlinedAt) {
  799. num_words = kDebugScopeNumWordsWithoutInlinedAt;
  800. }
  801. std::vector<uint32_t> operands = {
  802. (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
  803. type_id,
  804. result_id,
  805. ext_set,
  806. static_cast<uint32_t>(dbg_opcode),
  807. };
  808. binary->insert(binary->end(), operands.begin(), operands.end());
  809. if (GetLexicalScope() != kNoDebugScope) binary->push_back(GetLexicalScope());
  810. if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
  811. }
  812. } // namespace opt
  813. } // namespace spvtools