instruction.cpp 25 KB

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