instruction.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  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 "source/disassemble.h"
  17. #include "source/opt/fold.h"
  18. #include "source/opt/ir_context.h"
  19. #include "source/opt/reflect.h"
  20. namespace spvtools {
  21. namespace opt {
  22. namespace {
  23. // Indices used to get particular operands out of instructions using InOperand.
  24. const uint32_t kTypeImageDimIndex = 1;
  25. const uint32_t kLoadBaseIndex = 0;
  26. const uint32_t kVariableStorageClassIndex = 0;
  27. const uint32_t kTypeImageSampledIndex = 5;
  28. } // namespace
  29. Instruction::Instruction(IRContext* c)
  30. : utils::IntrusiveNodeBase<Instruction>(),
  31. context_(c),
  32. opcode_(SpvOpNop),
  33. has_type_id_(false),
  34. has_result_id_(false),
  35. unique_id_(c->TakeNextUniqueId()) {}
  36. Instruction::Instruction(IRContext* c, SpvOp op)
  37. : utils::IntrusiveNodeBase<Instruction>(),
  38. context_(c),
  39. opcode_(op),
  40. has_type_id_(false),
  41. has_result_id_(false),
  42. unique_id_(c->TakeNextUniqueId()) {}
  43. Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
  44. std::vector<Instruction>&& dbg_line)
  45. : context_(c),
  46. opcode_(static_cast<SpvOp>(inst.opcode)),
  47. has_type_id_(inst.type_id != 0),
  48. has_result_id_(inst.result_id != 0),
  49. unique_id_(c->TakeNextUniqueId()),
  50. dbg_line_insts_(std::move(dbg_line)) {
  51. assert((!IsDebugLineInst(opcode_) || dbg_line.empty()) &&
  52. "Op(No)Line attaching to Op(No)Line found");
  53. for (uint32_t i = 0; i < inst.num_operands; ++i) {
  54. const auto& current_payload = inst.operands[i];
  55. std::vector<uint32_t> words(
  56. inst.words + current_payload.offset,
  57. inst.words + current_payload.offset + current_payload.num_words);
  58. operands_.emplace_back(current_payload.type, std::move(words));
  59. }
  60. }
  61. Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
  62. uint32_t res_id, const OperandList& in_operands)
  63. : utils::IntrusiveNodeBase<Instruction>(),
  64. context_(c),
  65. opcode_(op),
  66. has_type_id_(ty_id != 0),
  67. has_result_id_(res_id != 0),
  68. unique_id_(c->TakeNextUniqueId()),
  69. operands_() {
  70. if (has_type_id_) {
  71. operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
  72. std::initializer_list<uint32_t>{ty_id});
  73. }
  74. if (has_result_id_) {
  75. operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
  76. std::initializer_list<uint32_t>{res_id});
  77. }
  78. operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
  79. }
  80. Instruction::Instruction(Instruction&& that)
  81. : utils::IntrusiveNodeBase<Instruction>(),
  82. opcode_(that.opcode_),
  83. has_type_id_(that.has_type_id_),
  84. has_result_id_(that.has_result_id_),
  85. unique_id_(that.unique_id_),
  86. operands_(std::move(that.operands_)),
  87. dbg_line_insts_(std::move(that.dbg_line_insts_)) {}
  88. Instruction& Instruction::operator=(Instruction&& that) {
  89. opcode_ = that.opcode_;
  90. has_type_id_ = that.has_type_id_;
  91. has_result_id_ = that.has_result_id_;
  92. unique_id_ = that.unique_id_;
  93. operands_ = std::move(that.operands_);
  94. dbg_line_insts_ = std::move(that.dbg_line_insts_);
  95. return *this;
  96. }
  97. Instruction* Instruction::Clone(IRContext* c) const {
  98. Instruction* clone = new Instruction(c);
  99. clone->opcode_ = opcode_;
  100. clone->has_type_id_ = has_type_id_;
  101. clone->has_result_id_ = has_result_id_;
  102. clone->unique_id_ = c->TakeNextUniqueId();
  103. clone->operands_ = operands_;
  104. clone->dbg_line_insts_ = dbg_line_insts_;
  105. return clone;
  106. }
  107. uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
  108. const auto& words = GetOperand(index).words;
  109. assert(words.size() == 1 && "expected the operand only taking one word");
  110. return words.front();
  111. }
  112. uint32_t Instruction::NumInOperandWords() const {
  113. uint32_t size = 0;
  114. for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
  115. size += static_cast<uint32_t>(operands_[i].words.size());
  116. return size;
  117. }
  118. void Instruction::ToBinaryWithoutAttachedDebugInsts(
  119. std::vector<uint32_t>* binary) const {
  120. const uint32_t num_words = 1 + NumOperandWords();
  121. binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
  122. for (const auto& operand : operands_)
  123. binary->insert(binary->end(), operand.words.begin(), operand.words.end());
  124. }
  125. void Instruction::ReplaceOperands(const OperandList& new_operands) {
  126. operands_.clear();
  127. operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
  128. }
  129. bool Instruction::IsReadOnlyLoad() const {
  130. if (IsLoad()) {
  131. Instruction* address_def = GetBaseAddress();
  132. if (!address_def || address_def->opcode() != SpvOpVariable) {
  133. return false;
  134. }
  135. return address_def->IsReadOnlyVariable();
  136. }
  137. return false;
  138. }
  139. Instruction* Instruction::GetBaseAddress() const {
  140. assert((IsLoad() || opcode() == SpvOpStore || opcode() == SpvOpAccessChain ||
  141. opcode() == SpvOpPtrAccessChain ||
  142. opcode() == SpvOpInBoundsAccessChain || opcode() == SpvOpCopyObject ||
  143. opcode() == SpvOpImageTexelPointer) &&
  144. "GetBaseAddress should only be called on instructions that take a "
  145. "pointer or image.");
  146. uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
  147. Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
  148. bool done = false;
  149. while (!done) {
  150. switch (base_inst->opcode()) {
  151. case SpvOpAccessChain:
  152. case SpvOpInBoundsAccessChain:
  153. case SpvOpPtrAccessChain:
  154. case SpvOpInBoundsPtrAccessChain:
  155. case SpvOpImageTexelPointer:
  156. case SpvOpCopyObject:
  157. // All of these instructions have the base pointer use a base pointer
  158. // in in-operand 0.
  159. base = base_inst->GetSingleWordInOperand(0);
  160. base_inst = context()->get_def_use_mgr()->GetDef(base);
  161. break;
  162. default:
  163. done = true;
  164. break;
  165. }
  166. }
  167. switch (opcode()) {
  168. case SpvOpLoad:
  169. case SpvOpStore:
  170. case SpvOpAccessChain:
  171. case SpvOpInBoundsAccessChain:
  172. case SpvOpPtrAccessChain:
  173. case SpvOpImageTexelPointer:
  174. case SpvOpCopyObject:
  175. // A load or store through a pointer.
  176. assert(base_inst->IsValidBasePointer() &&
  177. "We cannot have a base pointer come from this load");
  178. break;
  179. default:
  180. // A load or store of an image.
  181. assert(base_inst->IsValidBaseImage() && "We are expecting an image.");
  182. break;
  183. }
  184. return base_inst;
  185. }
  186. bool Instruction::IsReadOnlyVariable() const {
  187. if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  188. return IsReadOnlyVariableShaders();
  189. else
  190. return IsReadOnlyVariableKernel();
  191. }
  192. bool Instruction::IsVulkanStorageImage() const {
  193. if (opcode() != SpvOpTypePointer) {
  194. return false;
  195. }
  196. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  197. if (storage_class != SpvStorageClassUniformConstant) {
  198. return false;
  199. }
  200. Instruction* base_type =
  201. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  202. if (base_type->opcode() != SpvOpTypeImage) {
  203. return false;
  204. }
  205. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  206. return false;
  207. }
  208. // Check if the image is sampled. If we do not know for sure that it is,
  209. // then assume it is a storage image.
  210. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  211. return s != 1;
  212. }
  213. bool Instruction::IsVulkanSampledImage() const {
  214. if (opcode() != SpvOpTypePointer) {
  215. return false;
  216. }
  217. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  218. if (storage_class != SpvStorageClassUniformConstant) {
  219. return false;
  220. }
  221. Instruction* base_type =
  222. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  223. if (base_type->opcode() != SpvOpTypeImage) {
  224. return false;
  225. }
  226. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  227. return false;
  228. }
  229. // Check if the image is sampled. If we know for sure that it is,
  230. // then return true.
  231. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  232. return s == 1;
  233. }
  234. bool Instruction::IsVulkanStorageTexelBuffer() const {
  235. if (opcode() != SpvOpTypePointer) {
  236. return false;
  237. }
  238. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  239. if (storage_class != SpvStorageClassUniformConstant) {
  240. return false;
  241. }
  242. Instruction* base_type =
  243. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  244. if (base_type->opcode() != SpvOpTypeImage) {
  245. return false;
  246. }
  247. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
  248. return false;
  249. }
  250. // Check if the image is sampled. If we do not know for sure that it is,
  251. // then assume it is a storage texel buffer.
  252. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
  253. }
  254. bool Instruction::IsVulkanStorageBuffer() const {
  255. // Is there a difference between a "Storage buffer" and a "dynamic storage
  256. // buffer" in SPIR-V and do we care about the difference?
  257. if (opcode() != SpvOpTypePointer) {
  258. return false;
  259. }
  260. Instruction* base_type =
  261. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  262. if (base_type->opcode() != SpvOpTypeStruct) {
  263. return false;
  264. }
  265. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  266. if (storage_class == SpvStorageClassUniform) {
  267. bool is_buffer_block = false;
  268. context()->get_decoration_mgr()->ForEachDecoration(
  269. base_type->result_id(), SpvDecorationBufferBlock,
  270. [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
  271. return is_buffer_block;
  272. } else if (storage_class == SpvStorageClassStorageBuffer) {
  273. bool is_block = false;
  274. context()->get_decoration_mgr()->ForEachDecoration(
  275. base_type->result_id(), SpvDecorationBlock,
  276. [&is_block](const Instruction&) { is_block = true; });
  277. return is_block;
  278. }
  279. return false;
  280. }
  281. bool Instruction::IsVulkanUniformBuffer() const {
  282. if (opcode() != SpvOpTypePointer) {
  283. return false;
  284. }
  285. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  286. if (storage_class != SpvStorageClassUniform) {
  287. return false;
  288. }
  289. Instruction* base_type =
  290. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  291. if (base_type->opcode() != SpvOpTypeStruct) {
  292. return false;
  293. }
  294. bool is_block = false;
  295. context()->get_decoration_mgr()->ForEachDecoration(
  296. base_type->result_id(), SpvDecorationBlock,
  297. [&is_block](const Instruction&) { is_block = true; });
  298. return is_block;
  299. }
  300. bool Instruction::IsReadOnlyVariableShaders() const {
  301. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  302. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  303. switch (storage_class) {
  304. case SpvStorageClassUniformConstant:
  305. if (!type_def->IsVulkanStorageImage() &&
  306. !type_def->IsVulkanStorageTexelBuffer()) {
  307. return true;
  308. }
  309. break;
  310. case SpvStorageClassUniform:
  311. if (!type_def->IsVulkanStorageBuffer()) {
  312. return true;
  313. }
  314. break;
  315. case SpvStorageClassPushConstant:
  316. case SpvStorageClassInput:
  317. return true;
  318. default:
  319. break;
  320. }
  321. bool is_nonwritable = false;
  322. context()->get_decoration_mgr()->ForEachDecoration(
  323. result_id(), SpvDecorationNonWritable,
  324. [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
  325. return is_nonwritable;
  326. }
  327. bool Instruction::IsReadOnlyVariableKernel() const {
  328. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  329. return storage_class == SpvStorageClassUniformConstant;
  330. }
  331. uint32_t Instruction::GetTypeComponent(uint32_t element) const {
  332. uint32_t subtype = 0;
  333. switch (opcode()) {
  334. case SpvOpTypeStruct:
  335. subtype = GetSingleWordInOperand(element);
  336. break;
  337. case SpvOpTypeArray:
  338. case SpvOpTypeRuntimeArray:
  339. case SpvOpTypeVector:
  340. case SpvOpTypeMatrix:
  341. // These types all have uniform subtypes.
  342. subtype = GetSingleWordInOperand(0u);
  343. break;
  344. default:
  345. break;
  346. }
  347. return subtype;
  348. }
  349. Instruction* Instruction::InsertBefore(
  350. std::vector<std::unique_ptr<Instruction>>&& list) {
  351. Instruction* first_node = list.front().get();
  352. for (auto& i : list) {
  353. i.release()->InsertBefore(this);
  354. }
  355. list.clear();
  356. return first_node;
  357. }
  358. Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& i) {
  359. i.get()->InsertBefore(this);
  360. return i.release();
  361. }
  362. bool Instruction::IsValidBasePointer() const {
  363. uint32_t tid = type_id();
  364. if (tid == 0) {
  365. return false;
  366. }
  367. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  368. if (type->opcode() != SpvOpTypePointer) {
  369. return false;
  370. }
  371. auto feature_mgr = context()->get_feature_mgr();
  372. if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
  373. // TODO: The rules here could be more restrictive.
  374. return true;
  375. }
  376. if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
  377. return true;
  378. }
  379. // With variable pointers, there are more valid base pointer objects.
  380. // Variable pointers implicitly declares Variable pointers storage buffer.
  381. SpvStorageClass storage_class =
  382. static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
  383. if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
  384. storage_class == SpvStorageClassStorageBuffer) ||
  385. (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
  386. storage_class == SpvStorageClassWorkgroup)) {
  387. switch (opcode()) {
  388. case SpvOpPhi:
  389. case SpvOpSelect:
  390. case SpvOpFunctionCall:
  391. case SpvOpConstantNull:
  392. return true;
  393. default:
  394. break;
  395. }
  396. }
  397. uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
  398. Instruction* pointee_type_inst =
  399. context()->get_def_use_mgr()->GetDef(pointee_type_id);
  400. if (pointee_type_inst->IsOpaqueType()) {
  401. return true;
  402. }
  403. return false;
  404. }
  405. bool Instruction::IsValidBaseImage() const {
  406. uint32_t tid = type_id();
  407. if (tid == 0) {
  408. return false;
  409. }
  410. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  411. return (type->opcode() == SpvOpTypeImage ||
  412. type->opcode() == SpvOpTypeSampledImage);
  413. }
  414. bool Instruction::IsOpaqueType() const {
  415. if (opcode() == SpvOpTypeStruct) {
  416. bool is_opaque = false;
  417. ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
  418. Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  419. is_opaque |= type_inst->IsOpaqueType();
  420. });
  421. return is_opaque;
  422. } else if (opcode() == SpvOpTypeArray) {
  423. uint32_t sub_type_id = GetSingleWordInOperand(0);
  424. Instruction* sub_type_inst =
  425. context()->get_def_use_mgr()->GetDef(sub_type_id);
  426. return sub_type_inst->IsOpaqueType();
  427. } else {
  428. return opcode() == SpvOpTypeRuntimeArray ||
  429. spvOpcodeIsBaseOpaqueType(opcode());
  430. }
  431. }
  432. bool Instruction::IsFoldable() const {
  433. return IsFoldableByFoldScalar() ||
  434. context()->get_instruction_folder().HasConstFoldingRule(opcode());
  435. }
  436. bool Instruction::IsFoldableByFoldScalar() const {
  437. const InstructionFolder& folder = context()->get_instruction_folder();
  438. if (!folder.IsFoldableOpcode(opcode())) {
  439. return false;
  440. }
  441. Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
  442. return folder.IsFoldableType(type);
  443. }
  444. bool Instruction::IsFloatingPointFoldingAllowed() const {
  445. // TODO: Add the rules for kernels. For now it will be pessimistic.
  446. if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader)) {
  447. return false;
  448. }
  449. bool is_nocontract = false;
  450. context_->get_decoration_mgr()->WhileEachDecoration(
  451. result_id(), SpvDecorationNoContraction,
  452. [&is_nocontract](const Instruction&) {
  453. is_nocontract = true;
  454. return false;
  455. });
  456. return !is_nocontract;
  457. }
  458. std::string Instruction::PrettyPrint(uint32_t options) const {
  459. // Convert the module to binary.
  460. std::vector<uint32_t> module_binary;
  461. context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
  462. // Convert the instruction to binary. This is used to identify the correct
  463. // stream of words to output from the module.
  464. std::vector<uint32_t> inst_binary;
  465. ToBinaryWithoutAttachedDebugInsts(&inst_binary);
  466. // Do not generate a header.
  467. return spvInstructionBinaryToText(
  468. context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
  469. module_binary.data(), module_binary.size(),
  470. options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  471. }
  472. std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
  473. str << inst.PrettyPrint();
  474. return str;
  475. }
  476. void Instruction::Dump() const {
  477. std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
  478. }
  479. bool Instruction::IsOpcodeCodeMotionSafe() const {
  480. switch (opcode_) {
  481. case SpvOpNop:
  482. case SpvOpUndef:
  483. case SpvOpLoad:
  484. case SpvOpAccessChain:
  485. case SpvOpInBoundsAccessChain:
  486. case SpvOpArrayLength:
  487. case SpvOpVectorExtractDynamic:
  488. case SpvOpVectorInsertDynamic:
  489. case SpvOpVectorShuffle:
  490. case SpvOpCompositeConstruct:
  491. case SpvOpCompositeExtract:
  492. case SpvOpCompositeInsert:
  493. case SpvOpCopyObject:
  494. case SpvOpTranspose:
  495. case SpvOpConvertFToU:
  496. case SpvOpConvertFToS:
  497. case SpvOpConvertSToF:
  498. case SpvOpConvertUToF:
  499. case SpvOpUConvert:
  500. case SpvOpSConvert:
  501. case SpvOpFConvert:
  502. case SpvOpQuantizeToF16:
  503. case SpvOpBitcast:
  504. case SpvOpSNegate:
  505. case SpvOpFNegate:
  506. case SpvOpIAdd:
  507. case SpvOpFAdd:
  508. case SpvOpISub:
  509. case SpvOpFSub:
  510. case SpvOpIMul:
  511. case SpvOpFMul:
  512. case SpvOpUDiv:
  513. case SpvOpSDiv:
  514. case SpvOpFDiv:
  515. case SpvOpUMod:
  516. case SpvOpSRem:
  517. case SpvOpSMod:
  518. case SpvOpFRem:
  519. case SpvOpFMod:
  520. case SpvOpVectorTimesScalar:
  521. case SpvOpMatrixTimesScalar:
  522. case SpvOpVectorTimesMatrix:
  523. case SpvOpMatrixTimesVector:
  524. case SpvOpMatrixTimesMatrix:
  525. case SpvOpOuterProduct:
  526. case SpvOpDot:
  527. case SpvOpIAddCarry:
  528. case SpvOpISubBorrow:
  529. case SpvOpUMulExtended:
  530. case SpvOpSMulExtended:
  531. case SpvOpAny:
  532. case SpvOpAll:
  533. case SpvOpIsNan:
  534. case SpvOpIsInf:
  535. case SpvOpLogicalEqual:
  536. case SpvOpLogicalNotEqual:
  537. case SpvOpLogicalOr:
  538. case SpvOpLogicalAnd:
  539. case SpvOpLogicalNot:
  540. case SpvOpSelect:
  541. case SpvOpIEqual:
  542. case SpvOpINotEqual:
  543. case SpvOpUGreaterThan:
  544. case SpvOpSGreaterThan:
  545. case SpvOpUGreaterThanEqual:
  546. case SpvOpSGreaterThanEqual:
  547. case SpvOpULessThan:
  548. case SpvOpSLessThan:
  549. case SpvOpULessThanEqual:
  550. case SpvOpSLessThanEqual:
  551. case SpvOpFOrdEqual:
  552. case SpvOpFUnordEqual:
  553. case SpvOpFOrdNotEqual:
  554. case SpvOpFUnordNotEqual:
  555. case SpvOpFOrdLessThan:
  556. case SpvOpFUnordLessThan:
  557. case SpvOpFOrdGreaterThan:
  558. case SpvOpFUnordGreaterThan:
  559. case SpvOpFOrdLessThanEqual:
  560. case SpvOpFUnordLessThanEqual:
  561. case SpvOpFOrdGreaterThanEqual:
  562. case SpvOpFUnordGreaterThanEqual:
  563. case SpvOpShiftRightLogical:
  564. case SpvOpShiftRightArithmetic:
  565. case SpvOpShiftLeftLogical:
  566. case SpvOpBitwiseOr:
  567. case SpvOpBitwiseXor:
  568. case SpvOpBitwiseAnd:
  569. case SpvOpNot:
  570. case SpvOpBitFieldInsert:
  571. case SpvOpBitFieldSExtract:
  572. case SpvOpBitFieldUExtract:
  573. case SpvOpBitReverse:
  574. case SpvOpBitCount:
  575. case SpvOpSizeOf:
  576. return true;
  577. default:
  578. return false;
  579. }
  580. }
  581. bool Instruction::IsScalarizable() const {
  582. if (spvOpcodeIsScalarizable(opcode())) {
  583. return true;
  584. }
  585. const uint32_t kExtInstSetIdInIdx = 0;
  586. const uint32_t kExtInstInstructionInIdx = 1;
  587. if (opcode() == SpvOpExtInst) {
  588. uint32_t instSetId =
  589. context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
  590. if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
  591. switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
  592. case GLSLstd450Round:
  593. case GLSLstd450RoundEven:
  594. case GLSLstd450Trunc:
  595. case GLSLstd450FAbs:
  596. case GLSLstd450SAbs:
  597. case GLSLstd450FSign:
  598. case GLSLstd450SSign:
  599. case GLSLstd450Floor:
  600. case GLSLstd450Ceil:
  601. case GLSLstd450Fract:
  602. case GLSLstd450Radians:
  603. case GLSLstd450Degrees:
  604. case GLSLstd450Sin:
  605. case GLSLstd450Cos:
  606. case GLSLstd450Tan:
  607. case GLSLstd450Asin:
  608. case GLSLstd450Acos:
  609. case GLSLstd450Atan:
  610. case GLSLstd450Sinh:
  611. case GLSLstd450Cosh:
  612. case GLSLstd450Tanh:
  613. case GLSLstd450Asinh:
  614. case GLSLstd450Acosh:
  615. case GLSLstd450Atanh:
  616. case GLSLstd450Atan2:
  617. case GLSLstd450Pow:
  618. case GLSLstd450Exp:
  619. case GLSLstd450Log:
  620. case GLSLstd450Exp2:
  621. case GLSLstd450Log2:
  622. case GLSLstd450Sqrt:
  623. case GLSLstd450InverseSqrt:
  624. case GLSLstd450Modf:
  625. case GLSLstd450FMin:
  626. case GLSLstd450UMin:
  627. case GLSLstd450SMin:
  628. case GLSLstd450FMax:
  629. case GLSLstd450UMax:
  630. case GLSLstd450SMax:
  631. case GLSLstd450FClamp:
  632. case GLSLstd450UClamp:
  633. case GLSLstd450SClamp:
  634. case GLSLstd450FMix:
  635. case GLSLstd450Step:
  636. case GLSLstd450SmoothStep:
  637. case GLSLstd450Fma:
  638. case GLSLstd450Frexp:
  639. case GLSLstd450Ldexp:
  640. case GLSLstd450FindILsb:
  641. case GLSLstd450FindSMsb:
  642. case GLSLstd450FindUMsb:
  643. case GLSLstd450NMin:
  644. case GLSLstd450NMax:
  645. case GLSLstd450NClamp:
  646. return true;
  647. default:
  648. return false;
  649. }
  650. }
  651. }
  652. return false;
  653. }
  654. bool Instruction::IsOpcodeSafeToDelete() const {
  655. if (context()->IsCombinatorInstruction(this)) {
  656. return true;
  657. }
  658. switch (opcode()) {
  659. case SpvOpDPdx:
  660. case SpvOpDPdy:
  661. case SpvOpFwidth:
  662. case SpvOpDPdxFine:
  663. case SpvOpDPdyFine:
  664. case SpvOpFwidthFine:
  665. case SpvOpDPdxCoarse:
  666. case SpvOpDPdyCoarse:
  667. case SpvOpFwidthCoarse:
  668. case SpvOpImageQueryLod:
  669. return true;
  670. default:
  671. return false;
  672. }
  673. }
  674. } // namespace opt
  675. } // namespace spvtools