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
15 #include "source/opt/instruction.h"
16
17 #include <initializer_list>
18
19 #include "OpenCLDebugInfo100.h"
20 #include "source/disassemble.h"
21 #include "source/opt/fold.h"
22 #include "source/opt/ir_context.h"
23 #include "source/opt/reflect.h"
24
25 namespace spvtools {
26 namespace opt {
27
28 namespace {
29 // Indices used to get particular operands out of instructions using InOperand.
30 const uint32_t kTypeImageDimIndex = 1;
31 const uint32_t kLoadBaseIndex = 0;
32 const uint32_t kPointerTypeStorageClassIndex = 0;
33 const uint32_t kVariableStorageClassIndex = 0;
34 const uint32_t kTypeImageSampledIndex = 5;
35
36 // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
37 // extension instructions.
38 const uint32_t kExtInstSetIdInIdx = 0;
39 const uint32_t kExtInstInstructionInIdx = 1;
40 const uint32_t kDebugScopeNumWords = 7;
41 const uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
42 const uint32_t kDebugNoScopeNumWords = 5;
43
44 // Number of operands of an OpBranchConditional instruction
45 // with weights.
46 const uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
47 } // namespace
48
Instruction(IRContext * c)49 Instruction::Instruction(IRContext* c)
50 : utils::IntrusiveNodeBase<Instruction>(),
51 context_(c),
52 opcode_(SpvOpNop),
53 has_type_id_(false),
54 has_result_id_(false),
55 unique_id_(c->TakeNextUniqueId()),
56 dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
57
Instruction(IRContext * c,SpvOp op)58 Instruction::Instruction(IRContext* c, SpvOp op)
59 : utils::IntrusiveNodeBase<Instruction>(),
60 context_(c),
61 opcode_(op),
62 has_type_id_(false),
63 has_result_id_(false),
64 unique_id_(c->TakeNextUniqueId()),
65 dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
66
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,std::vector<Instruction> && dbg_line)67 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
68 std::vector<Instruction>&& dbg_line)
69 : utils::IntrusiveNodeBase<Instruction>(),
70 context_(c),
71 opcode_(static_cast<SpvOp>(inst.opcode)),
72 has_type_id_(inst.type_id != 0),
73 has_result_id_(inst.result_id != 0),
74 unique_id_(c->TakeNextUniqueId()),
75 dbg_line_insts_(std::move(dbg_line)),
76 dbg_scope_(kNoDebugScope, kNoInlinedAt) {
77 for (uint32_t i = 0; i < inst.num_operands; ++i) {
78 const auto& current_payload = inst.operands[i];
79 operands_.emplace_back(
80 current_payload.type, inst.words + current_payload.offset,
81 inst.words + current_payload.offset + current_payload.num_words);
82 }
83 assert((!IsLineInst() || dbg_line.empty()) &&
84 "Op(No)Line attaching to Op(No)Line found");
85 }
86
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,const DebugScope & dbg_scope)87 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
88 const DebugScope& dbg_scope)
89 : utils::IntrusiveNodeBase<Instruction>(),
90 context_(c),
91 opcode_(static_cast<SpvOp>(inst.opcode)),
92 has_type_id_(inst.type_id != 0),
93 has_result_id_(inst.result_id != 0),
94 unique_id_(c->TakeNextUniqueId()),
95 dbg_scope_(dbg_scope) {
96 for (uint32_t i = 0; i < inst.num_operands; ++i) {
97 const auto& current_payload = inst.operands[i];
98 operands_.emplace_back(
99 current_payload.type, inst.words + current_payload.offset,
100 inst.words + current_payload.offset + current_payload.num_words);
101 }
102 }
103
Instruction(IRContext * c,SpvOp op,uint32_t ty_id,uint32_t res_id,const OperandList & in_operands)104 Instruction::Instruction(IRContext* c, SpvOp op, uint32_t ty_id,
105 uint32_t res_id, const OperandList& in_operands)
106 : utils::IntrusiveNodeBase<Instruction>(),
107 context_(c),
108 opcode_(op),
109 has_type_id_(ty_id != 0),
110 has_result_id_(res_id != 0),
111 unique_id_(c->TakeNextUniqueId()),
112 operands_(),
113 dbg_scope_(kNoDebugScope, kNoInlinedAt) {
114 if (has_type_id_) {
115 operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
116 std::initializer_list<uint32_t>{ty_id});
117 }
118 if (has_result_id_) {
119 operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
120 std::initializer_list<uint32_t>{res_id});
121 }
122 operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
123 }
124
Instruction(Instruction && that)125 Instruction::Instruction(Instruction&& that)
126 : utils::IntrusiveNodeBase<Instruction>(),
127 context_(that.context_),
128 opcode_(that.opcode_),
129 has_type_id_(that.has_type_id_),
130 has_result_id_(that.has_result_id_),
131 unique_id_(that.unique_id_),
132 operands_(std::move(that.operands_)),
133 dbg_line_insts_(std::move(that.dbg_line_insts_)),
134 dbg_scope_(that.dbg_scope_) {
135 for (auto& i : dbg_line_insts_) {
136 i.dbg_scope_ = that.dbg_scope_;
137 }
138 }
139
operator =(Instruction && that)140 Instruction& Instruction::operator=(Instruction&& that) {
141 context_ = that.context_;
142 opcode_ = that.opcode_;
143 has_type_id_ = that.has_type_id_;
144 has_result_id_ = that.has_result_id_;
145 unique_id_ = that.unique_id_;
146 operands_ = std::move(that.operands_);
147 dbg_line_insts_ = std::move(that.dbg_line_insts_);
148 dbg_scope_ = that.dbg_scope_;
149 return *this;
150 }
151
Clone(IRContext * c) const152 Instruction* Instruction::Clone(IRContext* c) const {
153 Instruction* clone = new Instruction(c);
154 clone->opcode_ = opcode_;
155 clone->has_type_id_ = has_type_id_;
156 clone->has_result_id_ = has_result_id_;
157 clone->unique_id_ = c->TakeNextUniqueId();
158 clone->operands_ = operands_;
159 clone->dbg_line_insts_ = dbg_line_insts_;
160 for (auto& i : clone->dbg_line_insts_) {
161 i.unique_id_ = c->TakeNextUniqueId();
162 if (i.IsDebugLineInst()) i.SetResultId(c->TakeNextId());
163 }
164 clone->dbg_scope_ = dbg_scope_;
165 return clone;
166 }
167
GetSingleWordOperand(uint32_t index) const168 uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
169 const auto& words = GetOperand(index).words;
170 assert(words.size() == 1 && "expected the operand only taking one word");
171 return words.front();
172 }
173
NumInOperandWords() const174 uint32_t Instruction::NumInOperandWords() const {
175 uint32_t size = 0;
176 for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
177 size += static_cast<uint32_t>(operands_[i].words.size());
178 return size;
179 }
180
HasBranchWeights() const181 bool Instruction::HasBranchWeights() const {
182 if (opcode_ == SpvOpBranchConditional &&
183 NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
184 return true;
185 }
186
187 return false;
188 }
189
ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t> * binary) const190 void Instruction::ToBinaryWithoutAttachedDebugInsts(
191 std::vector<uint32_t>* binary) const {
192 const uint32_t num_words = 1 + NumOperandWords();
193 binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
194 for (const auto& operand : operands_) {
195 binary->insert(binary->end(), operand.words.begin(), operand.words.end());
196 }
197 }
198
ReplaceOperands(const OperandList & new_operands)199 void Instruction::ReplaceOperands(const OperandList& new_operands) {
200 operands_.clear();
201 operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
202 }
203
IsReadOnlyLoad() const204 bool Instruction::IsReadOnlyLoad() const {
205 if (IsLoad()) {
206 Instruction* address_def = GetBaseAddress();
207 if (!address_def) {
208 return false;
209 }
210
211 if (address_def->opcode() == SpvOpVariable) {
212 if (address_def->IsReadOnlyPointer()) {
213 return true;
214 }
215 }
216
217 if (address_def->opcode() == SpvOpLoad) {
218 const analysis::Type* address_type =
219 context()->get_type_mgr()->GetType(address_def->type_id());
220 if (address_type->AsSampledImage() != nullptr) {
221 const auto* image_type =
222 address_type->AsSampledImage()->image_type()->AsImage();
223 if (image_type->sampled() == 1) {
224 return true;
225 }
226 }
227 }
228 }
229 return false;
230 }
231
GetBaseAddress() const232 Instruction* Instruction::GetBaseAddress() const {
233 uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
234 Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
235 bool done = false;
236 while (!done) {
237 switch (base_inst->opcode()) {
238 case SpvOpAccessChain:
239 case SpvOpInBoundsAccessChain:
240 case SpvOpPtrAccessChain:
241 case SpvOpInBoundsPtrAccessChain:
242 case SpvOpImageTexelPointer:
243 case SpvOpCopyObject:
244 // All of these instructions have the base pointer use a base pointer
245 // in in-operand 0.
246 base = base_inst->GetSingleWordInOperand(0);
247 base_inst = context()->get_def_use_mgr()->GetDef(base);
248 break;
249 default:
250 done = true;
251 break;
252 }
253 }
254 return base_inst;
255 }
256
IsReadOnlyPointer() const257 bool Instruction::IsReadOnlyPointer() const {
258 if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
259 return IsReadOnlyPointerShaders();
260 else
261 return IsReadOnlyPointerKernel();
262 }
263
IsVulkanStorageImage() const264 bool Instruction::IsVulkanStorageImage() const {
265 if (opcode() != SpvOpTypePointer) {
266 return false;
267 }
268
269 uint32_t storage_class =
270 GetSingleWordInOperand(kPointerTypeStorageClassIndex);
271 if (storage_class != SpvStorageClassUniformConstant) {
272 return false;
273 }
274
275 Instruction* base_type =
276 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
277
278 // Unpack the optional layer of arraying.
279 if (base_type->opcode() == SpvOpTypeArray ||
280 base_type->opcode() == SpvOpTypeRuntimeArray) {
281 base_type = context()->get_def_use_mgr()->GetDef(
282 base_type->GetSingleWordInOperand(0));
283 }
284
285 if (base_type->opcode() != SpvOpTypeImage) {
286 return false;
287 }
288
289 if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
290 return false;
291 }
292
293 // Check if the image is sampled. If we do not know for sure that it is,
294 // then assume it is a storage image.
295 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
296 }
297
IsVulkanSampledImage() const298 bool Instruction::IsVulkanSampledImage() const {
299 if (opcode() != SpvOpTypePointer) {
300 return false;
301 }
302
303 uint32_t storage_class =
304 GetSingleWordInOperand(kPointerTypeStorageClassIndex);
305 if (storage_class != SpvStorageClassUniformConstant) {
306 return false;
307 }
308
309 Instruction* base_type =
310 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
311
312 // Unpack the optional layer of arraying.
313 if (base_type->opcode() == SpvOpTypeArray ||
314 base_type->opcode() == SpvOpTypeRuntimeArray) {
315 base_type = context()->get_def_use_mgr()->GetDef(
316 base_type->GetSingleWordInOperand(0));
317 }
318
319 if (base_type->opcode() != SpvOpTypeImage) {
320 return false;
321 }
322
323 if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) == SpvDimBuffer) {
324 return false;
325 }
326
327 // Check if the image is sampled. If we know for sure that it is,
328 // then return true.
329 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) == 1;
330 }
331
IsVulkanStorageTexelBuffer() const332 bool Instruction::IsVulkanStorageTexelBuffer() const {
333 if (opcode() != SpvOpTypePointer) {
334 return false;
335 }
336
337 uint32_t storage_class =
338 GetSingleWordInOperand(kPointerTypeStorageClassIndex);
339 if (storage_class != SpvStorageClassUniformConstant) {
340 return false;
341 }
342
343 Instruction* base_type =
344 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
345
346 // Unpack the optional layer of arraying.
347 if (base_type->opcode() == SpvOpTypeArray ||
348 base_type->opcode() == SpvOpTypeRuntimeArray) {
349 base_type = context()->get_def_use_mgr()->GetDef(
350 base_type->GetSingleWordInOperand(0));
351 }
352
353 if (base_type->opcode() != SpvOpTypeImage) {
354 return false;
355 }
356
357 if (base_type->GetSingleWordInOperand(kTypeImageDimIndex) != SpvDimBuffer) {
358 return false;
359 }
360
361 // Check if the image is sampled. If we do not know for sure that it is,
362 // then assume it is a storage texel buffer.
363 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
364 }
365
IsVulkanStorageBuffer() const366 bool Instruction::IsVulkanStorageBuffer() const {
367 // Is there a difference between a "Storage buffer" and a "dynamic storage
368 // buffer" in SPIR-V and do we care about the difference?
369 if (opcode() != SpvOpTypePointer) {
370 return false;
371 }
372
373 Instruction* base_type =
374 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
375
376 // Unpack the optional layer of arraying.
377 if (base_type->opcode() == SpvOpTypeArray ||
378 base_type->opcode() == SpvOpTypeRuntimeArray) {
379 base_type = context()->get_def_use_mgr()->GetDef(
380 base_type->GetSingleWordInOperand(0));
381 }
382
383 if (base_type->opcode() != SpvOpTypeStruct) {
384 return false;
385 }
386
387 uint32_t storage_class =
388 GetSingleWordInOperand(kPointerTypeStorageClassIndex);
389 if (storage_class == SpvStorageClassUniform) {
390 bool is_buffer_block = false;
391 context()->get_decoration_mgr()->ForEachDecoration(
392 base_type->result_id(), SpvDecorationBufferBlock,
393 [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
394 return is_buffer_block;
395 } else if (storage_class == SpvStorageClassStorageBuffer) {
396 bool is_block = false;
397 context()->get_decoration_mgr()->ForEachDecoration(
398 base_type->result_id(), SpvDecorationBlock,
399 [&is_block](const Instruction&) { is_block = true; });
400 return is_block;
401 }
402 return false;
403 }
404
IsVulkanStorageBufferVariable() const405 bool Instruction::IsVulkanStorageBufferVariable() const {
406 if (opcode() != SpvOpVariable) {
407 return false;
408 }
409
410 uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
411 if (storage_class == SpvStorageClassStorageBuffer ||
412 storage_class == SpvStorageClassUniform) {
413 Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id());
414 return var_type != nullptr && var_type->IsVulkanStorageBuffer();
415 }
416
417 return false;
418 }
419
IsVulkanUniformBuffer() const420 bool Instruction::IsVulkanUniformBuffer() const {
421 if (opcode() != SpvOpTypePointer) {
422 return false;
423 }
424
425 uint32_t storage_class =
426 GetSingleWordInOperand(kPointerTypeStorageClassIndex);
427 if (storage_class != SpvStorageClassUniform) {
428 return false;
429 }
430
431 Instruction* base_type =
432 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
433
434 // Unpack the optional layer of arraying.
435 if (base_type->opcode() == SpvOpTypeArray ||
436 base_type->opcode() == SpvOpTypeRuntimeArray) {
437 base_type = context()->get_def_use_mgr()->GetDef(
438 base_type->GetSingleWordInOperand(0));
439 }
440
441 if (base_type->opcode() != SpvOpTypeStruct) {
442 return false;
443 }
444
445 bool is_block = false;
446 context()->get_decoration_mgr()->ForEachDecoration(
447 base_type->result_id(), SpvDecorationBlock,
448 [&is_block](const Instruction&) { is_block = true; });
449 return is_block;
450 }
451
IsReadOnlyPointerShaders() const452 bool Instruction::IsReadOnlyPointerShaders() const {
453 if (type_id() == 0) {
454 return false;
455 }
456
457 Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
458 if (type_def->opcode() != SpvOpTypePointer) {
459 return false;
460 }
461
462 uint32_t storage_class =
463 type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
464
465 switch (storage_class) {
466 case SpvStorageClassUniformConstant:
467 if (!type_def->IsVulkanStorageImage() &&
468 !type_def->IsVulkanStorageTexelBuffer()) {
469 return true;
470 }
471 break;
472 case SpvStorageClassUniform:
473 if (!type_def->IsVulkanStorageBuffer()) {
474 return true;
475 }
476 break;
477 case SpvStorageClassPushConstant:
478 case SpvStorageClassInput:
479 return true;
480 default:
481 break;
482 }
483
484 bool is_nonwritable = false;
485 context()->get_decoration_mgr()->ForEachDecoration(
486 result_id(), SpvDecorationNonWritable,
487 [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
488 return is_nonwritable;
489 }
490
IsReadOnlyPointerKernel() const491 bool Instruction::IsReadOnlyPointerKernel() const {
492 if (type_id() == 0) {
493 return false;
494 }
495
496 Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
497 if (type_def->opcode() != SpvOpTypePointer) {
498 return false;
499 }
500
501 uint32_t storage_class =
502 type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
503
504 return storage_class == SpvStorageClassUniformConstant;
505 }
506
GetTypeComponent(uint32_t element) const507 uint32_t Instruction::GetTypeComponent(uint32_t element) const {
508 uint32_t subtype = 0;
509 switch (opcode()) {
510 case SpvOpTypeStruct:
511 subtype = GetSingleWordInOperand(element);
512 break;
513 case SpvOpTypeArray:
514 case SpvOpTypeRuntimeArray:
515 case SpvOpTypeVector:
516 case SpvOpTypeMatrix:
517 // These types all have uniform subtypes.
518 subtype = GetSingleWordInOperand(0u);
519 break;
520 default:
521 break;
522 }
523
524 return subtype;
525 }
526
UpdateLexicalScope(uint32_t scope)527 void Instruction::UpdateLexicalScope(uint32_t scope) {
528 dbg_scope_.SetLexicalScope(scope);
529 for (auto& i : dbg_line_insts_) {
530 i.dbg_scope_.SetLexicalScope(scope);
531 }
532 if (!IsLineInst() &&
533 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
534 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
535 }
536 }
537
UpdateDebugInlinedAt(uint32_t new_inlined_at)538 void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
539 dbg_scope_.SetInlinedAt(new_inlined_at);
540 for (auto& i : dbg_line_insts_) {
541 i.dbg_scope_.SetInlinedAt(new_inlined_at);
542 }
543 if (!IsLineInst() &&
544 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
545 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
546 }
547 }
548
ClearDbgLineInsts()549 void Instruction::ClearDbgLineInsts() {
550 if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) {
551 auto def_use_mgr = context()->get_def_use_mgr();
552 for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst);
553 }
554 clear_dbg_line_insts();
555 }
556
UpdateDebugInfoFrom(const Instruction * from)557 void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
558 if (from == nullptr) return;
559 ClearDbgLineInsts();
560 if (!from->dbg_line_insts().empty())
561 AddDebugLine(&from->dbg_line_insts().back());
562 SetDebugScope(from->GetDebugScope());
563 if (!IsLineInst() &&
564 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
565 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
566 }
567 }
568
AddDebugLine(const Instruction * inst)569 void Instruction::AddDebugLine(const Instruction* inst) {
570 dbg_line_insts_.push_back(*inst);
571 dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId();
572 if (inst->IsDebugLineInst())
573 dbg_line_insts_.back().SetResultId(context_->TakeNextId());
574 if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse))
575 context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back());
576 }
577
IsDebugLineInst() const578 bool Instruction::IsDebugLineInst() const {
579 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
580 return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) ||
581 (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine));
582 }
583
IsLineInst() const584 bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
585
IsLine() const586 bool Instruction::IsLine() const {
587 if (opcode() == SpvOpLine) return true;
588 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
589 return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
590 }
591
IsNoLine() const592 bool Instruction::IsNoLine() const {
593 if (opcode() == SpvOpNoLine) return true;
594 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
595 return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
596 }
597
InsertBefore(std::unique_ptr<Instruction> && inst)598 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
599 inst.get()->InsertBefore(this);
600 return inst.release();
601 }
602
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)603 Instruction* Instruction::InsertBefore(
604 std::vector<std::unique_ptr<Instruction>>&& list) {
605 Instruction* first_node = list.front().get();
606 for (auto& inst : list) {
607 inst.release()->InsertBefore(this);
608 }
609 list.clear();
610 return first_node;
611 }
612
IsValidBasePointer() const613 bool Instruction::IsValidBasePointer() const {
614 uint32_t tid = type_id();
615 if (tid == 0) {
616 return false;
617 }
618
619 Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
620 if (type->opcode() != SpvOpTypePointer) {
621 return false;
622 }
623
624 auto feature_mgr = context()->get_feature_mgr();
625 if (feature_mgr->HasCapability(SpvCapabilityAddresses)) {
626 // TODO: The rules here could be more restrictive.
627 return true;
628 }
629
630 if (opcode() == SpvOpVariable || opcode() == SpvOpFunctionParameter) {
631 return true;
632 }
633
634 // With variable pointers, there are more valid base pointer objects.
635 // Variable pointers implicitly declares Variable pointers storage buffer.
636 SpvStorageClass storage_class =
637 static_cast<SpvStorageClass>(type->GetSingleWordInOperand(0));
638 if ((feature_mgr->HasCapability(SpvCapabilityVariablePointersStorageBuffer) &&
639 storage_class == SpvStorageClassStorageBuffer) ||
640 (feature_mgr->HasCapability(SpvCapabilityVariablePointers) &&
641 storage_class == SpvStorageClassWorkgroup)) {
642 switch (opcode()) {
643 case SpvOpPhi:
644 case SpvOpSelect:
645 case SpvOpFunctionCall:
646 case SpvOpConstantNull:
647 return true;
648 default:
649 break;
650 }
651 }
652
653 uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
654 Instruction* pointee_type_inst =
655 context()->get_def_use_mgr()->GetDef(pointee_type_id);
656
657 if (pointee_type_inst->IsOpaqueType()) {
658 return true;
659 }
660 return false;
661 }
662
GetOpenCL100DebugOpcode() const663 OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
664 if (opcode() != SpvOpExtInst) {
665 return OpenCLDebugInfo100InstructionsMax;
666 }
667
668 if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
669 return OpenCLDebugInfo100InstructionsMax;
670 }
671
672 if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
673 context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
674 return OpenCLDebugInfo100InstructionsMax;
675 }
676
677 return OpenCLDebugInfo100Instructions(
678 GetSingleWordInOperand(kExtInstInstructionInIdx));
679 }
680
GetShader100DebugOpcode() const681 NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
682 const {
683 if (opcode() != SpvOpExtInst) {
684 return NonSemanticShaderDebugInfo100InstructionsMax;
685 }
686
687 if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
688 return NonSemanticShaderDebugInfo100InstructionsMax;
689 }
690
691 if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
692 context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
693 return NonSemanticShaderDebugInfo100InstructionsMax;
694 }
695
696 return NonSemanticShaderDebugInfo100Instructions(
697 GetSingleWordInOperand(kExtInstInstructionInIdx));
698 }
699
GetCommonDebugOpcode() const700 CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
701 if (opcode() != SpvOpExtInst) {
702 return CommonDebugInfoInstructionsMax;
703 }
704
705 const uint32_t opencl_set_id =
706 context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
707 const uint32_t shader_set_id =
708 context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
709
710 if (!opencl_set_id && !shader_set_id) {
711 return CommonDebugInfoInstructionsMax;
712 }
713
714 const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
715
716 if (used_set_id != opencl_set_id && used_set_id != shader_set_id) {
717 return CommonDebugInfoInstructionsMax;
718 }
719
720 return CommonDebugInfoInstructions(
721 GetSingleWordInOperand(kExtInstInstructionInIdx));
722 }
723
IsValidBaseImage() const724 bool Instruction::IsValidBaseImage() const {
725 uint32_t tid = type_id();
726 if (tid == 0) {
727 return false;
728 }
729
730 Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
731 return (type->opcode() == SpvOpTypeImage ||
732 type->opcode() == SpvOpTypeSampledImage);
733 }
734
IsOpaqueType() const735 bool Instruction::IsOpaqueType() const {
736 if (opcode() == SpvOpTypeStruct) {
737 bool is_opaque = false;
738 ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
739 Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
740 is_opaque |= type_inst->IsOpaqueType();
741 });
742 return is_opaque;
743 } else if (opcode() == SpvOpTypeArray) {
744 uint32_t sub_type_id = GetSingleWordInOperand(0);
745 Instruction* sub_type_inst =
746 context()->get_def_use_mgr()->GetDef(sub_type_id);
747 return sub_type_inst->IsOpaqueType();
748 } else {
749 return opcode() == SpvOpTypeRuntimeArray ||
750 spvOpcodeIsBaseOpaqueType(opcode());
751 }
752 }
753
IsFoldable() const754 bool Instruction::IsFoldable() const {
755 return IsFoldableByFoldScalar() ||
756 context()->get_instruction_folder().HasConstFoldingRule(this);
757 }
758
IsFoldableByFoldScalar() const759 bool Instruction::IsFoldableByFoldScalar() const {
760 const InstructionFolder& folder = context()->get_instruction_folder();
761 if (!folder.IsFoldableOpcode(opcode())) {
762 return false;
763 }
764
765 Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
766 if (!folder.IsFoldableType(type)) {
767 return false;
768 }
769
770 // Even if the type of the instruction is foldable, its operands may not be
771 // foldable (e.g., comparisons of 64bit types). Check that all operand types
772 // are foldable before accepting the instruction.
773 return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
774 Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
775 Instruction* def_inst_type =
776 context()->get_def_use_mgr()->GetDef(def_inst->type_id());
777 return folder.IsFoldableType(def_inst_type);
778 });
779 }
780
IsFloatingPointFoldingAllowed() const781 bool Instruction::IsFloatingPointFoldingAllowed() const {
782 // TODO: Add the rules for kernels. For now it will be pessimistic.
783 // For now, do not support capabilities introduced by SPV_KHR_float_controls.
784 if (!context_->get_feature_mgr()->HasCapability(SpvCapabilityShader) ||
785 context_->get_feature_mgr()->HasCapability(SpvCapabilityDenormPreserve) ||
786 context_->get_feature_mgr()->HasCapability(
787 SpvCapabilityDenormFlushToZero) ||
788 context_->get_feature_mgr()->HasCapability(
789 SpvCapabilitySignedZeroInfNanPreserve) ||
790 context_->get_feature_mgr()->HasCapability(
791 SpvCapabilityRoundingModeRTZ) ||
792 context_->get_feature_mgr()->HasCapability(
793 SpvCapabilityRoundingModeRTE)) {
794 return false;
795 }
796
797 bool is_nocontract = false;
798 context_->get_decoration_mgr()->WhileEachDecoration(
799 result_id(), SpvDecorationNoContraction,
800 [&is_nocontract](const Instruction&) {
801 is_nocontract = true;
802 return false;
803 });
804 return !is_nocontract;
805 }
806
PrettyPrint(uint32_t options) const807 std::string Instruction::PrettyPrint(uint32_t options) const {
808 // Convert the module to binary.
809 std::vector<uint32_t> module_binary;
810 context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
811
812 // Convert the instruction to binary. This is used to identify the correct
813 // stream of words to output from the module.
814 std::vector<uint32_t> inst_binary;
815 ToBinaryWithoutAttachedDebugInsts(&inst_binary);
816
817 // Do not generate a header.
818 return spvInstructionBinaryToText(
819 context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
820 module_binary.data(), module_binary.size(),
821 options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
822 }
823
operator <<(std::ostream & str,const Instruction & inst)824 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
825 str << inst.PrettyPrint();
826 return str;
827 }
828
Dump() const829 void Instruction::Dump() const {
830 std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
831 }
832
IsOpcodeCodeMotionSafe() const833 bool Instruction::IsOpcodeCodeMotionSafe() const {
834 switch (opcode_) {
835 case SpvOpNop:
836 case SpvOpUndef:
837 case SpvOpLoad:
838 case SpvOpAccessChain:
839 case SpvOpInBoundsAccessChain:
840 case SpvOpArrayLength:
841 case SpvOpVectorExtractDynamic:
842 case SpvOpVectorInsertDynamic:
843 case SpvOpVectorShuffle:
844 case SpvOpCompositeConstruct:
845 case SpvOpCompositeExtract:
846 case SpvOpCompositeInsert:
847 case SpvOpCopyObject:
848 case SpvOpTranspose:
849 case SpvOpConvertFToU:
850 case SpvOpConvertFToS:
851 case SpvOpConvertSToF:
852 case SpvOpConvertUToF:
853 case SpvOpUConvert:
854 case SpvOpSConvert:
855 case SpvOpFConvert:
856 case SpvOpQuantizeToF16:
857 case SpvOpBitcast:
858 case SpvOpSNegate:
859 case SpvOpFNegate:
860 case SpvOpIAdd:
861 case SpvOpFAdd:
862 case SpvOpISub:
863 case SpvOpFSub:
864 case SpvOpIMul:
865 case SpvOpFMul:
866 case SpvOpUDiv:
867 case SpvOpSDiv:
868 case SpvOpFDiv:
869 case SpvOpUMod:
870 case SpvOpSRem:
871 case SpvOpSMod:
872 case SpvOpFRem:
873 case SpvOpFMod:
874 case SpvOpVectorTimesScalar:
875 case SpvOpMatrixTimesScalar:
876 case SpvOpVectorTimesMatrix:
877 case SpvOpMatrixTimesVector:
878 case SpvOpMatrixTimesMatrix:
879 case SpvOpOuterProduct:
880 case SpvOpDot:
881 case SpvOpIAddCarry:
882 case SpvOpISubBorrow:
883 case SpvOpUMulExtended:
884 case SpvOpSMulExtended:
885 case SpvOpAny:
886 case SpvOpAll:
887 case SpvOpIsNan:
888 case SpvOpIsInf:
889 case SpvOpLogicalEqual:
890 case SpvOpLogicalNotEqual:
891 case SpvOpLogicalOr:
892 case SpvOpLogicalAnd:
893 case SpvOpLogicalNot:
894 case SpvOpSelect:
895 case SpvOpIEqual:
896 case SpvOpINotEqual:
897 case SpvOpUGreaterThan:
898 case SpvOpSGreaterThan:
899 case SpvOpUGreaterThanEqual:
900 case SpvOpSGreaterThanEqual:
901 case SpvOpULessThan:
902 case SpvOpSLessThan:
903 case SpvOpULessThanEqual:
904 case SpvOpSLessThanEqual:
905 case SpvOpFOrdEqual:
906 case SpvOpFUnordEqual:
907 case SpvOpFOrdNotEqual:
908 case SpvOpFUnordNotEqual:
909 case SpvOpFOrdLessThan:
910 case SpvOpFUnordLessThan:
911 case SpvOpFOrdGreaterThan:
912 case SpvOpFUnordGreaterThan:
913 case SpvOpFOrdLessThanEqual:
914 case SpvOpFUnordLessThanEqual:
915 case SpvOpFOrdGreaterThanEqual:
916 case SpvOpFUnordGreaterThanEqual:
917 case SpvOpShiftRightLogical:
918 case SpvOpShiftRightArithmetic:
919 case SpvOpShiftLeftLogical:
920 case SpvOpBitwiseOr:
921 case SpvOpBitwiseXor:
922 case SpvOpBitwiseAnd:
923 case SpvOpNot:
924 case SpvOpBitFieldInsert:
925 case SpvOpBitFieldSExtract:
926 case SpvOpBitFieldUExtract:
927 case SpvOpBitReverse:
928 case SpvOpBitCount:
929 case SpvOpSizeOf:
930 return true;
931 default:
932 return false;
933 }
934 }
935
IsScalarizable() const936 bool Instruction::IsScalarizable() const {
937 if (spvOpcodeIsScalarizable(opcode())) {
938 return true;
939 }
940
941 if (opcode() == SpvOpExtInst) {
942 uint32_t instSetId =
943 context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
944
945 if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
946 switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
947 case GLSLstd450Round:
948 case GLSLstd450RoundEven:
949 case GLSLstd450Trunc:
950 case GLSLstd450FAbs:
951 case GLSLstd450SAbs:
952 case GLSLstd450FSign:
953 case GLSLstd450SSign:
954 case GLSLstd450Floor:
955 case GLSLstd450Ceil:
956 case GLSLstd450Fract:
957 case GLSLstd450Radians:
958 case GLSLstd450Degrees:
959 case GLSLstd450Sin:
960 case GLSLstd450Cos:
961 case GLSLstd450Tan:
962 case GLSLstd450Asin:
963 case GLSLstd450Acos:
964 case GLSLstd450Atan:
965 case GLSLstd450Sinh:
966 case GLSLstd450Cosh:
967 case GLSLstd450Tanh:
968 case GLSLstd450Asinh:
969 case GLSLstd450Acosh:
970 case GLSLstd450Atanh:
971 case GLSLstd450Atan2:
972 case GLSLstd450Pow:
973 case GLSLstd450Exp:
974 case GLSLstd450Log:
975 case GLSLstd450Exp2:
976 case GLSLstd450Log2:
977 case GLSLstd450Sqrt:
978 case GLSLstd450InverseSqrt:
979 case GLSLstd450Modf:
980 case GLSLstd450FMin:
981 case GLSLstd450UMin:
982 case GLSLstd450SMin:
983 case GLSLstd450FMax:
984 case GLSLstd450UMax:
985 case GLSLstd450SMax:
986 case GLSLstd450FClamp:
987 case GLSLstd450UClamp:
988 case GLSLstd450SClamp:
989 case GLSLstd450FMix:
990 case GLSLstd450Step:
991 case GLSLstd450SmoothStep:
992 case GLSLstd450Fma:
993 case GLSLstd450Frexp:
994 case GLSLstd450Ldexp:
995 case GLSLstd450FindILsb:
996 case GLSLstd450FindSMsb:
997 case GLSLstd450FindUMsb:
998 case GLSLstd450NMin:
999 case GLSLstd450NMax:
1000 case GLSLstd450NClamp:
1001 return true;
1002 default:
1003 return false;
1004 }
1005 }
1006 }
1007 return false;
1008 }
1009
IsOpcodeSafeToDelete() const1010 bool Instruction::IsOpcodeSafeToDelete() const {
1011 if (context()->IsCombinatorInstruction(this)) {
1012 return true;
1013 }
1014
1015 switch (opcode()) {
1016 case SpvOpDPdx:
1017 case SpvOpDPdy:
1018 case SpvOpFwidth:
1019 case SpvOpDPdxFine:
1020 case SpvOpDPdyFine:
1021 case SpvOpFwidthFine:
1022 case SpvOpDPdxCoarse:
1023 case SpvOpDPdyCoarse:
1024 case SpvOpFwidthCoarse:
1025 case SpvOpImageQueryLod:
1026 return true;
1027 default:
1028 return false;
1029 }
1030 }
1031
IsNonSemanticInstruction() const1032 bool Instruction::IsNonSemanticInstruction() const {
1033 if (!HasResultId()) return false;
1034 if (opcode() != SpvOpExtInst) return false;
1035
1036 auto import_inst =
1037 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
1038 std::string import_name = import_inst->GetInOperand(0).AsString();
1039 return import_name.find("NonSemantic.") == 0;
1040 }
1041
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const1042 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
1043 uint32_t ext_set,
1044 std::vector<uint32_t>* binary) const {
1045 uint32_t num_words = kDebugScopeNumWords;
1046 CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope;
1047 if (GetLexicalScope() == kNoDebugScope) {
1048 num_words = kDebugNoScopeNumWords;
1049 dbg_opcode = CommonDebugInfoDebugNoScope;
1050 } else if (GetInlinedAt() == kNoInlinedAt) {
1051 num_words = kDebugScopeNumWordsWithoutInlinedAt;
1052 }
1053 std::vector<uint32_t> operands = {
1054 (num_words << 16) | static_cast<uint16_t>(SpvOpExtInst),
1055 type_id,
1056 result_id,
1057 ext_set,
1058 static_cast<uint32_t>(dbg_opcode),
1059 };
1060 binary->insert(binary->end(), operands.begin(), operands.end());
1061 if (GetLexicalScope() != kNoDebugScope) {
1062 binary->push_back(GetLexicalScope());
1063 if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
1064 }
1065 }
1066
1067 } // namespace opt
1068 } // namespace spvtools
1069