instruction.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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. uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
  141. Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
  142. bool done = false;
  143. while (!done) {
  144. switch (base_inst->opcode()) {
  145. case SpvOpAccessChain:
  146. case SpvOpInBoundsAccessChain:
  147. case SpvOpPtrAccessChain:
  148. case SpvOpInBoundsPtrAccessChain:
  149. case SpvOpImageTexelPointer:
  150. case SpvOpCopyObject:
  151. // All of these instructions have the base pointer use a base pointer
  152. // in in-operand 0.
  153. base = base_inst->GetSingleWordInOperand(0);
  154. base_inst = context()->get_def_use_mgr()->GetDef(base);
  155. break;
  156. default:
  157. done = true;
  158. break;
  159. }
  160. }
  161. return base_inst;
  162. }
  163. bool Instruction::IsReadOnlyVariable() const {
  164. if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
  165. return IsReadOnlyVariableShaders();
  166. else
  167. return IsReadOnlyVariableKernel();
  168. }
  169. bool Instruction::IsVulkanStorageImage() const {
  170. if (opcode() != SpvOpTypePointer) {
  171. return false;
  172. }
  173. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  174. if (storage_class != SpvStorageClassUniformConstant) {
  175. return false;
  176. }
  177. Instruction* base_type =
  178. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  179. if (base_type->opcode() != SpvOpTypeImage) {
  180. return false;
  181. }
  182. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  183. return false;
  184. }
  185. // Check if the image is sampled. If we do not know for sure that it is,
  186. // then assume it is a storage image.
  187. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  188. return s != 1;
  189. }
  190. bool Instruction::IsVulkanSampledImage() const {
  191. if (opcode() != SpvOpTypePointer) {
  192. return false;
  193. }
  194. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  195. if (storage_class != SpvStorageClassUniformConstant) {
  196. return false;
  197. }
  198. Instruction* base_type =
  199. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  200. if (base_type->opcode() != SpvOpTypeImage) {
  201. return false;
  202. }
  203. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
  204. return false;
  205. }
  206. // Check if the image is sampled. If we know for sure that it is,
  207. // then return true.
  208. auto s = base_type->GetSingleWordInOperand(kTypeImageSampledIndex);
  209. return s == 1;
  210. }
  211. bool Instruction::IsVulkanStorageTexelBuffer() const {
  212. if (opcode() != SpvOpTypePointer) {
  213. return false;
  214. }
  215. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  216. if (storage_class != SpvStorageClassUniformConstant) {
  217. return false;
  218. }
  219. Instruction* base_type =
  220. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  221. if (base_type->opcode() != SpvOpTypeImage) {
  222. return false;
  223. }
  224. if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
  225. return false;
  226. }
  227. // Check if the image is sampled. If we do not know for sure that it is,
  228. // then assume it is a storage texel buffer.
  229. return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
  230. }
  231. bool Instruction::IsVulkanStorageBuffer() const {
  232. // Is there a difference between a "Storage buffer" and a "dynamic storage
  233. // buffer" in SPIR-V and do we care about the difference?
  234. if (opcode() != SpvOpTypePointer) {
  235. return false;
  236. }
  237. Instruction* base_type =
  238. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  239. if (base_type->opcode() != SpvOpTypeStruct) {
  240. return false;
  241. }
  242. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  243. if (storage_class == SpvStorageClassUniform) {
  244. bool is_buffer_block = false;
  245. context()->get_decoration_mgr()->ForEachDecoration(
  246. base_type->result_id(), SpvDecorationBufferBlock,
  247. [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
  248. return is_buffer_block;
  249. } else if (storage_class == SpvStorageClassStorageBuffer) {
  250. bool is_block = false;
  251. context()->get_decoration_mgr()->ForEachDecoration(
  252. base_type->result_id(), SpvDecorationBlock,
  253. [&is_block](const Instruction&) { is_block = true; });
  254. return is_block;
  255. }
  256. return false;
  257. }
  258. bool Instruction::IsVulkanUniformBuffer() const {
  259. if (opcode() != SpvOpTypePointer) {
  260. return false;
  261. }
  262. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  263. if (storage_class != SpvStorageClassUniform) {
  264. return false;
  265. }
  266. Instruction* base_type =
  267. context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
  268. if (base_type->opcode() != SpvOpTypeStruct) {
  269. return false;
  270. }
  271. bool is_block = false;
  272. context()->get_decoration_mgr()->ForEachDecoration(
  273. base_type->result_id(), SpvDecorationBlock,
  274. [&is_block](const Instruction&) { is_block = true; });
  275. return is_block;
  276. }
  277. bool Instruction::IsReadOnlyVariableShaders() const {
  278. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  279. Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
  280. switch (storage_class) {
  281. case SpvStorageClassUniformConstant:
  282. if (!type_def->IsVulkanStorageImage() &&
  283. !type_def->IsVulkanStorageTexelBuffer()) {
  284. return true;
  285. }
  286. break;
  287. case SpvStorageClassUniform:
  288. if (!type_def->IsVulkanStorageBuffer()) {
  289. return true;
  290. }
  291. break;
  292. case SpvStorageClassPushConstant:
  293. case SpvStorageClassInput:
  294. return true;
  295. default:
  296. break;
  297. }
  298. bool is_nonwritable = false;
  299. context()->get_decoration_mgr()->ForEachDecoration(
  300. result_id(), SpvDecorationNonWritable,
  301. [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
  302. return is_nonwritable;
  303. }
  304. bool Instruction::IsReadOnlyVariableKernel() const {
  305. uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
  306. return storage_class == SpvStorageClassUniformConstant;
  307. }
  308. uint32_t Instruction::GetTypeComponent(uint32_t element) const {
  309. uint32_t subtype = 0;
  310. switch (opcode()) {
  311. case SpvOpTypeStruct:
  312. subtype = GetSingleWordInOperand(element);
  313. break;
  314. case SpvOpTypeArray:
  315. case SpvOpTypeRuntimeArray:
  316. case SpvOpTypeVector:
  317. case SpvOpTypeMatrix:
  318. // These types all have uniform subtypes.
  319. subtype = GetSingleWordInOperand(0u);
  320. break;
  321. default:
  322. break;
  323. }
  324. return subtype;
  325. }
  326. Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& i) {
  327. i.get()->InsertBefore(this);
  328. return i.release();
  329. }
  330. Instruction* Instruction::InsertBefore(
  331. std::vector<std::unique_ptr<Instruction>>&& list) {
  332. Instruction* first_node = list.front().get();
  333. for (auto& i : list) {
  334. i.release()->InsertBefore(this);
  335. }
  336. list.clear();
  337. return first_node;
  338. }
  339. bool Instruction::IsValidBasePointer() const {
  340. uint32_t tid = type_id();
  341. if (tid == 0) {
  342. return false;
  343. }
  344. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  345. if (type->opcode() != SpvOpTypePointer) {
  346. return false;
  347. }
  348. auto feature_mgr = context()->get_feature_mgr();
  349. if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
  350. // TODO: The rules here could be more restrictive.
  351. return true;
  352. }
  353. if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
  354. return true;
  355. }
  356. // With variable pointers, there are more valid base pointer objects.
  357. // Variable pointers implicitly declares Variable pointers storage buffer.
  358. SpvStorageClass storage_class =
  359. static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
  360. if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
  361. storage_class == SpvStorageClassStorageBuffer) ||
  362. (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
  363. storage_class == SpvStorageClassWorkgroup)) {
  364. switch (opcode()) {
  365. case SpvOpPhi:
  366. case SpvOpSelect:
  367. case SpvOpFunctionCall:
  368. case SpvOpConstantNull:
  369. return true;
  370. default:
  371. break;
  372. }
  373. }
  374. uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
  375. Instruction* pointee_type_inst =
  376. context()->get_def_use_mgr()->GetDef(pointee_type_id);
  377. if (pointee_type_inst->IsOpaqueType()) {
  378. return true;
  379. }
  380. return false;
  381. }
  382. bool Instruction::IsValidBaseImage() const {
  383. uint32_t tid = type_id();
  384. if (tid == 0) {
  385. return false;
  386. }
  387. Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
  388. return (type->opcode() == SpvOpTypeImage ||
  389. type->opcode() == SpvOpTypeSampledImage);
  390. }
  391. bool Instruction::IsOpaqueType() const {
  392. if (opcode() == SpvOpTypeStruct) {
  393. bool is_opaque = false;
  394. ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
  395. Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
  396. is_opaque |= type_inst->IsOpaqueType();
  397. });
  398. return is_opaque;
  399. } else if (opcode() == SpvOpTypeArray) {
  400. uint32_t sub_type_id = GetSingleWordInOperand(0);
  401. Instruction* sub_type_inst =
  402. context()->get_def_use_mgr()->GetDef(sub_type_id);
  403. return sub_type_inst->IsOpaqueType();
  404. } else {
  405. return opcode() == SpvOpTypeRuntimeArray ||
  406. spvOpcodeIsBaseOpaqueType(opcode());
  407. }
  408. }
  409. bool Instruction::IsFoldable() const {
  410. return IsFoldableByFoldScalar() ||
  411. context()->get_instruction_folder().HasConstFoldingRule(this);
  412. }
  413. bool Instruction::IsFoldableByFoldScalar() const {
  414. const InstructionFolder& folder = context()->get_instruction_folder();
  415. if (!folder.IsFoldableOpcode(opcode())) {
  416. return false;
  417. }
  418. Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
  419. return folder.IsFoldableType(type);
  420. }
  421. bool Instruction::IsFloatingPointFoldingAllowed() const {
  422. // TODO: Add the rules for kernels. For now it will be pessimistic.
  423. // For now, do not support capabilities introduced by SPV_KHR_float_controls.
  424. if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
  425. context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
  426. context_->get_feature_mgr()->HasCapability(
  427. SpvCapabilityDenormFlushToZero) ||
  428. context_->get_feature_mgr()->HasCapability(
  429. SpvCapabilitySignedZeroInfNanPreserve) ||
  430. context_->get_feature_mgr()->HasCapability(
  431. SpvCapabilityRoundingModeRTZ) ||
  432. context_->get_feature_mgr()->HasCapability(
  433. SpvCapabilityRoundingModeRTE)) {
  434. return false;
  435. }
  436. bool is_nocontract = false;
  437. context_->get_decoration_mgr()->WhileEachDecoration(
  438. result_id(), SpvDecorationNoContraction,
  439. [&is_nocontract](const Instruction&) {
  440. is_nocontract = true;
  441. return false;
  442. });
  443. return !is_nocontract;
  444. }
  445. std::string Instruction::PrettyPrint(uint32_t options) const {
  446. // Convert the module to binary.
  447. std::vector<uint32_t> module_binary;
  448. context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
  449. // Convert the instruction to binary. This is used to identify the correct
  450. // stream of words to output from the module.
  451. std::vector<uint32_t> inst_binary;
  452. ToBinaryWithoutAttachedDebugInsts(&inst_binary);
  453. // Do not generate a header.
  454. return spvInstructionBinaryToText(
  455. context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
  456. module_binary.data(), module_binary.size(),
  457. options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
  458. }
  459. std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
  460. str << inst.PrettyPrint();
  461. return str;
  462. }
  463. void Instruction::Dump() const {
  464. std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
  465. }
  466. bool Instruction::IsOpcodeCodeMotionSafe() const {
  467. switch (opcode_) {
  468. case SpvOpNop:
  469. case SpvOpUndef:
  470. case SpvOpLoad:
  471. case SpvOpAccessChain:
  472. case SpvOpInBoundsAccessChain:
  473. case SpvOpArrayLength:
  474. case SpvOpVectorExtractDynamic:
  475. case SpvOpVectorInsertDynamic:
  476. case SpvOpVectorShuffle:
  477. case SpvOpCompositeConstruct:
  478. case SpvOpCompositeExtract:
  479. case SpvOpCompositeInsert:
  480. case SpvOpCopyObject:
  481. case SpvOpTranspose:
  482. case SpvOpConvertFToU:
  483. case SpvOpConvertFToS:
  484. case SpvOpConvertSToF:
  485. case SpvOpConvertUToF:
  486. case SpvOpUConvert:
  487. case SpvOpSConvert:
  488. case SpvOpFConvert:
  489. case SpvOpQuantizeToF16:
  490. case SpvOpBitcast:
  491. case SpvOpSNegate:
  492. case SpvOpFNegate:
  493. case SpvOpIAdd:
  494. case SpvOpFAdd:
  495. case SpvOpISub:
  496. case SpvOpFSub:
  497. case SpvOpIMul:
  498. case SpvOpFMul:
  499. case SpvOpUDiv:
  500. case SpvOpSDiv:
  501. case SpvOpFDiv:
  502. case SpvOpUMod:
  503. case SpvOpSRem:
  504. case SpvOpSMod:
  505. case SpvOpFRem:
  506. case SpvOpFMod:
  507. case SpvOpVectorTimesScalar:
  508. case SpvOpMatrixTimesScalar:
  509. case SpvOpVectorTimesMatrix:
  510. case SpvOpMatrixTimesVector:
  511. case SpvOpMatrixTimesMatrix:
  512. case SpvOpOuterProduct:
  513. case SpvOpDot:
  514. case SpvOpIAddCarry:
  515. case SpvOpISubBorrow:
  516. case SpvOpUMulExtended:
  517. case SpvOpSMulExtended:
  518. case SpvOpAny:
  519. case SpvOpAll:
  520. case SpvOpIsNan:
  521. case SpvOpIsInf:
  522. case SpvOpLogicalEqual:
  523. case SpvOpLogicalNotEqual:
  524. case SpvOpLogicalOr:
  525. case SpvOpLogicalAnd:
  526. case SpvOpLogicalNot:
  527. case SpvOpSelect:
  528. case SpvOpIEqual:
  529. case SpvOpINotEqual:
  530. case SpvOpUGreaterThan:
  531. case SpvOpSGreaterThan:
  532. case SpvOpUGreaterThanEqual:
  533. case SpvOpSGreaterThanEqual:
  534. case SpvOpULessThan:
  535. case SpvOpSLessThan:
  536. case SpvOpULessThanEqual:
  537. case SpvOpSLessThanEqual:
  538. case SpvOpFOrdEqual:
  539. case SpvOpFUnordEqual:
  540. case SpvOpFOrdNotEqual:
  541. case SpvOpFUnordNotEqual:
  542. case SpvOpFOrdLessThan:
  543. case SpvOpFUnordLessThan:
  544. case SpvOpFOrdGreaterThan:
  545. case SpvOpFUnordGreaterThan:
  546. case SpvOpFOrdLessThanEqual:
  547. case SpvOpFUnordLessThanEqual:
  548. case SpvOpFOrdGreaterThanEqual:
  549. case SpvOpFUnordGreaterThanEqual:
  550. case SpvOpShiftRightLogical:
  551. case SpvOpShiftRightArithmetic:
  552. case SpvOpShiftLeftLogical:
  553. case SpvOpBitwiseOr:
  554. case SpvOpBitwiseXor:
  555. case SpvOpBitwiseAnd:
  556. case SpvOpNot:
  557. case SpvOpBitFieldInsert:
  558. case SpvOpBitFieldSExtract:
  559. case SpvOpBitFieldUExtract:
  560. case SpvOpBitReverse:
  561. case SpvOpBitCount:
  562. case SpvOpSizeOf:
  563. return true;
  564. default:
  565. return false;
  566. }
  567. }
  568. bool Instruction::IsScalarizable() const {
  569. if (spvOpcodeIsScalarizable(opcode())) {
  570. return true;
  571. }
  572. const uint32_t kExtInstSetIdInIdx = 0;
  573. const uint32_t kExtInstInstructionInIdx = 1;
  574. if (opcode() == SpvOpExtInst) {
  575. uint32_t instSetId =
  576. context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
  577. if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
  578. switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
  579. case GLSLstd450Round:
  580. case GLSLstd450RoundEven:
  581. case GLSLstd450Trunc:
  582. case GLSLstd450FAbs:
  583. case GLSLstd450SAbs:
  584. case GLSLstd450FSign:
  585. case GLSLstd450SSign:
  586. case GLSLstd450Floor:
  587. case GLSLstd450Ceil:
  588. case GLSLstd450Fract:
  589. case GLSLstd450Radians:
  590. case GLSLstd450Degrees:
  591. case GLSLstd450Sin:
  592. case GLSLstd450Cos:
  593. case GLSLstd450Tan:
  594. case GLSLstd450Asin:
  595. case GLSLstd450Acos:
  596. case GLSLstd450Atan:
  597. case GLSLstd450Sinh:
  598. case GLSLstd450Cosh:
  599. case GLSLstd450Tanh:
  600. case GLSLstd450Asinh:
  601. case GLSLstd450Acosh:
  602. case GLSLstd450Atanh:
  603. case GLSLstd450Atan2:
  604. case GLSLstd450Pow:
  605. case GLSLstd450Exp:
  606. case GLSLstd450Log:
  607. case GLSLstd450Exp2:
  608. case GLSLstd450Log2:
  609. case GLSLstd450Sqrt:
  610. case GLSLstd450InverseSqrt:
  611. case GLSLstd450Modf:
  612. case GLSLstd450FMin:
  613. case GLSLstd450UMin:
  614. case GLSLstd450SMin:
  615. case GLSLstd450FMax:
  616. case GLSLstd450UMax:
  617. case GLSLstd450SMax:
  618. case GLSLstd450FClamp:
  619. case GLSLstd450UClamp:
  620. case GLSLstd450SClamp:
  621. case GLSLstd450FMix:
  622. case GLSLstd450Step:
  623. case GLSLstd450SmoothStep:
  624. case GLSLstd450Fma:
  625. case GLSLstd450Frexp:
  626. case GLSLstd450Ldexp:
  627. case GLSLstd450FindILsb:
  628. case GLSLstd450FindSMsb:
  629. case GLSLstd450FindUMsb:
  630. case GLSLstd450NMin:
  631. case GLSLstd450NMax:
  632. case GLSLstd450NClamp:
  633. return true;
  634. default:
  635. return false;
  636. }
  637. }
  638. }
  639. return false;
  640. }
  641. bool Instruction::IsOpcodeSafeToDelete() const {
  642. if (context()->IsCombinatorInstruction(this)) {
  643. return true;
  644. }
  645. switch (opcode()) {
  646. case SpvOpDPdx:
  647. case SpvOpDPdy:
  648. case SpvOpFwidth:
  649. case SpvOpDPdxFine:
  650. case SpvOpDPdyFine:
  651. case SpvOpFwidthFine:
  652. case SpvOpDPdxCoarse:
  653. case SpvOpDPdyCoarse:
  654. case SpvOpFwidthCoarse:
  655. case SpvOpImageQueryLod:
  656. return true;
  657. default:
  658. return false;
  659. }
  660. }
  661. } // namespace opt
  662. } // namespace spvtools