instruction.cpp 22 KB

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