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 namespace {
28 // Indices used to get particular operands out of instructions using InOperand.
29 constexpr uint32_t kTypeImageDimIndex = 1;
30 constexpr uint32_t kLoadBaseIndex = 0;
31 constexpr uint32_t kPointerTypeStorageClassIndex = 0;
32 constexpr uint32_t kVariableStorageClassIndex = 0;
33 constexpr uint32_t kTypeImageSampledIndex = 5;
34
35 // Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo.100
36 // extension instructions.
37 constexpr uint32_t kExtInstSetIdInIdx = 0;
38 constexpr uint32_t kExtInstInstructionInIdx = 1;
39 constexpr uint32_t kDebugScopeNumWords = 7;
40 constexpr uint32_t kDebugScopeNumWordsWithoutInlinedAt = 6;
41 constexpr uint32_t kDebugNoScopeNumWords = 5;
42
43 // Number of operands of an OpBranchConditional instruction
44 // with weights.
45 constexpr uint32_t kOpBranchConditionalWithWeightsNumOperands = 5;
46 } // namespace
47
Instruction(IRContext * c)48 Instruction::Instruction(IRContext* c)
49 : utils::IntrusiveNodeBase<Instruction>(),
50 context_(c),
51 opcode_(spv::Op::OpNop),
52 has_type_id_(false),
53 has_result_id_(false),
54 unique_id_(c->TakeNextUniqueId()),
55 dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
56
Instruction(IRContext * c,spv::Op op)57 Instruction::Instruction(IRContext* c, spv::Op op)
58 : utils::IntrusiveNodeBase<Instruction>(),
59 context_(c),
60 opcode_(op),
61 has_type_id_(false),
62 has_result_id_(false),
63 unique_id_(c->TakeNextUniqueId()),
64 dbg_scope_(kNoDebugScope, kNoInlinedAt) {}
65
Instruction(IRContext * c,const spv_parsed_instruction_t & inst,std::vector<Instruction> && dbg_line)66 Instruction::Instruction(IRContext* c, const spv_parsed_instruction_t& inst,
67 std::vector<Instruction>&& dbg_line)
68 : utils::IntrusiveNodeBase<Instruction>(),
69 context_(c),
70 opcode_(static_cast<spv::Op>(inst.opcode)),
71 has_type_id_(inst.type_id != 0),
72 has_result_id_(inst.result_id != 0),
73 unique_id_(c->TakeNextUniqueId()),
74 dbg_line_insts_(std::move(dbg_line)),
75 dbg_scope_(kNoDebugScope, kNoInlinedAt) {
76 operands_.reserve(inst.num_operands);
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<spv::Op>(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 operands_.reserve(inst.num_operands);
97 for (uint32_t i = 0; i < inst.num_operands; ++i) {
98 const auto& current_payload = inst.operands[i];
99 operands_.emplace_back(
100 current_payload.type, inst.words + current_payload.offset,
101 inst.words + current_payload.offset + current_payload.num_words);
102 }
103 }
104
Instruction(IRContext * c,spv::Op op,uint32_t ty_id,uint32_t res_id,const OperandList & in_operands)105 Instruction::Instruction(IRContext* c, spv::Op op, uint32_t ty_id,
106 uint32_t res_id, const OperandList& in_operands)
107 : utils::IntrusiveNodeBase<Instruction>(),
108 context_(c),
109 opcode_(op),
110 has_type_id_(ty_id != 0),
111 has_result_id_(res_id != 0),
112 unique_id_(c->TakeNextUniqueId()),
113 operands_(),
114 dbg_scope_(kNoDebugScope, kNoInlinedAt) {
115 size_t operands_size = in_operands.size();
116 if (has_type_id_) {
117 operands_size++;
118 }
119 if (has_result_id_) {
120 operands_size++;
121 }
122 operands_.reserve(operands_size);
123 if (has_type_id_) {
124 operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_TYPE_ID,
125 std::initializer_list<uint32_t>{ty_id});
126 }
127 if (has_result_id_) {
128 operands_.emplace_back(spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
129 std::initializer_list<uint32_t>{res_id});
130 }
131 operands_.insert(operands_.end(), in_operands.begin(), in_operands.end());
132 }
133
Instruction(Instruction && that)134 Instruction::Instruction(Instruction&& that)
135 : utils::IntrusiveNodeBase<Instruction>(),
136 context_(that.context_),
137 opcode_(that.opcode_),
138 has_type_id_(that.has_type_id_),
139 has_result_id_(that.has_result_id_),
140 unique_id_(that.unique_id_),
141 operands_(std::move(that.operands_)),
142 dbg_line_insts_(std::move(that.dbg_line_insts_)),
143 dbg_scope_(that.dbg_scope_) {
144 for (auto& i : dbg_line_insts_) {
145 i.dbg_scope_ = that.dbg_scope_;
146 }
147 }
148
operator =(Instruction && that)149 Instruction& Instruction::operator=(Instruction&& that) {
150 context_ = that.context_;
151 opcode_ = that.opcode_;
152 has_type_id_ = that.has_type_id_;
153 has_result_id_ = that.has_result_id_;
154 unique_id_ = that.unique_id_;
155 operands_ = std::move(that.operands_);
156 dbg_line_insts_ = std::move(that.dbg_line_insts_);
157 dbg_scope_ = that.dbg_scope_;
158 return *this;
159 }
160
Clone(IRContext * c) const161 Instruction* Instruction::Clone(IRContext* c) const {
162 Instruction* clone = new Instruction(c);
163 clone->opcode_ = opcode_;
164 clone->has_type_id_ = has_type_id_;
165 clone->has_result_id_ = has_result_id_;
166 clone->unique_id_ = c->TakeNextUniqueId();
167 clone->operands_ = operands_;
168 clone->dbg_line_insts_ = dbg_line_insts_;
169 for (auto& i : clone->dbg_line_insts_) {
170 i.unique_id_ = c->TakeNextUniqueId();
171 if (i.IsDebugLineInst()) i.SetResultId(c->TakeNextId());
172 }
173 clone->dbg_scope_ = dbg_scope_;
174 return clone;
175 }
176
GetSingleWordOperand(uint32_t index) const177 uint32_t Instruction::GetSingleWordOperand(uint32_t index) const {
178 const auto& words = GetOperand(index).words;
179 assert(words.size() == 1 && "expected the operand only taking one word");
180 return words.front();
181 }
182
NumInOperandWords() const183 uint32_t Instruction::NumInOperandWords() const {
184 uint32_t size = 0;
185 for (uint32_t i = TypeResultIdCount(); i < operands_.size(); ++i)
186 size += static_cast<uint32_t>(operands_[i].words.size());
187 return size;
188 }
189
HasBranchWeights() const190 bool Instruction::HasBranchWeights() const {
191 if (opcode_ == spv::Op::OpBranchConditional &&
192 NumOperands() == kOpBranchConditionalWithWeightsNumOperands) {
193 return true;
194 }
195
196 return false;
197 }
198
ToBinaryWithoutAttachedDebugInsts(std::vector<uint32_t> * binary) const199 void Instruction::ToBinaryWithoutAttachedDebugInsts(
200 std::vector<uint32_t>* binary) const {
201 const uint32_t num_words = 1 + NumOperandWords();
202 binary->push_back((num_words << 16) | static_cast<uint16_t>(opcode_));
203 for (const auto& operand : operands_) {
204 binary->insert(binary->end(), operand.words.begin(), operand.words.end());
205 }
206 }
207
ReplaceOperands(const OperandList & new_operands)208 void Instruction::ReplaceOperands(const OperandList& new_operands) {
209 operands_.clear();
210 operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
211 }
212
IsReadOnlyLoad() const213 bool Instruction::IsReadOnlyLoad() const {
214 if (IsLoad()) {
215 Instruction* address_def = GetBaseAddress();
216 if (!address_def) {
217 return false;
218 }
219
220 if (address_def->opcode() == spv::Op::OpVariable) {
221 if (address_def->IsReadOnlyPointer()) {
222 return true;
223 }
224 }
225
226 if (address_def->opcode() == spv::Op::OpLoad) {
227 const analysis::Type* address_type =
228 context()->get_type_mgr()->GetType(address_def->type_id());
229 if (address_type->AsSampledImage() != nullptr) {
230 const auto* image_type =
231 address_type->AsSampledImage()->image_type()->AsImage();
232 if (image_type->sampled() == 1) {
233 return true;
234 }
235 }
236 }
237 }
238 return false;
239 }
240
GetBaseAddress() const241 Instruction* Instruction::GetBaseAddress() const {
242 uint32_t base = GetSingleWordInOperand(kLoadBaseIndex);
243 Instruction* base_inst = context()->get_def_use_mgr()->GetDef(base);
244 bool done = false;
245 while (!done) {
246 switch (base_inst->opcode()) {
247 case spv::Op::OpAccessChain:
248 case spv::Op::OpInBoundsAccessChain:
249 case spv::Op::OpPtrAccessChain:
250 case spv::Op::OpInBoundsPtrAccessChain:
251 case spv::Op::OpImageTexelPointer:
252 case spv::Op::OpCopyObject:
253 // All of these instructions have the base pointer use a base pointer
254 // in in-operand 0.
255 base = base_inst->GetSingleWordInOperand(0);
256 base_inst = context()->get_def_use_mgr()->GetDef(base);
257 break;
258 default:
259 done = true;
260 break;
261 }
262 }
263 return base_inst;
264 }
265
IsReadOnlyPointer() const266 bool Instruction::IsReadOnlyPointer() const {
267 if (context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
268 return IsReadOnlyPointerShaders();
269 else
270 return IsReadOnlyPointerKernel();
271 }
272
IsVulkanStorageImage() const273 bool Instruction::IsVulkanStorageImage() const {
274 if (opcode() != spv::Op::OpTypePointer) {
275 return false;
276 }
277
278 spv::StorageClass storage_class =
279 spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
280 if (storage_class != spv::StorageClass::UniformConstant) {
281 return false;
282 }
283
284 Instruction* base_type =
285 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
286
287 // Unpack the optional layer of arraying.
288 if (base_type->opcode() == spv::Op::OpTypeArray ||
289 base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
290 base_type = context()->get_def_use_mgr()->GetDef(
291 base_type->GetSingleWordInOperand(0));
292 }
293
294 if (base_type->opcode() != spv::Op::OpTypeImage) {
295 return false;
296 }
297
298 if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
299 spv::Dim::Buffer) {
300 return false;
301 }
302
303 // Check if the image is sampled. If we do not know for sure that it is,
304 // then assume it is a storage image.
305 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
306 }
307
IsVulkanSampledImage() const308 bool Instruction::IsVulkanSampledImage() const {
309 if (opcode() != spv::Op::OpTypePointer) {
310 return false;
311 }
312
313 spv::StorageClass storage_class =
314 spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
315 if (storage_class != spv::StorageClass::UniformConstant) {
316 return false;
317 }
318
319 Instruction* base_type =
320 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
321
322 // Unpack the optional layer of arraying.
323 if (base_type->opcode() == spv::Op::OpTypeArray ||
324 base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
325 base_type = context()->get_def_use_mgr()->GetDef(
326 base_type->GetSingleWordInOperand(0));
327 }
328
329 if (base_type->opcode() != spv::Op::OpTypeImage) {
330 return false;
331 }
332
333 if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) ==
334 spv::Dim::Buffer) {
335 return false;
336 }
337
338 // Check if the image is sampled. If we know for sure that it is,
339 // then return true.
340 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) == 1;
341 }
342
IsVulkanStorageTexelBuffer() const343 bool Instruction::IsVulkanStorageTexelBuffer() const {
344 if (opcode() != spv::Op::OpTypePointer) {
345 return false;
346 }
347
348 spv::StorageClass storage_class =
349 spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
350 if (storage_class != spv::StorageClass::UniformConstant) {
351 return false;
352 }
353
354 Instruction* base_type =
355 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
356
357 // Unpack the optional layer of arraying.
358 if (base_type->opcode() == spv::Op::OpTypeArray ||
359 base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
360 base_type = context()->get_def_use_mgr()->GetDef(
361 base_type->GetSingleWordInOperand(0));
362 }
363
364 if (base_type->opcode() != spv::Op::OpTypeImage) {
365 return false;
366 }
367
368 if (spv::Dim(base_type->GetSingleWordInOperand(kTypeImageDimIndex)) !=
369 spv::Dim::Buffer) {
370 return false;
371 }
372
373 // Check if the image is sampled. If we do not know for sure that it is,
374 // then assume it is a storage texel buffer.
375 return base_type->GetSingleWordInOperand(kTypeImageSampledIndex) != 1;
376 }
377
IsVulkanStorageBuffer() const378 bool Instruction::IsVulkanStorageBuffer() const {
379 // Is there a difference between a "Storage buffer" and a "dynamic storage
380 // buffer" in SPIR-V and do we care about the difference?
381 if (opcode() != spv::Op::OpTypePointer) {
382 return false;
383 }
384
385 Instruction* base_type =
386 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
387
388 // Unpack the optional layer of arraying.
389 if (base_type->opcode() == spv::Op::OpTypeArray ||
390 base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
391 base_type = context()->get_def_use_mgr()->GetDef(
392 base_type->GetSingleWordInOperand(0));
393 }
394
395 if (base_type->opcode() != spv::Op::OpTypeStruct) {
396 return false;
397 }
398
399 spv::StorageClass storage_class =
400 spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
401 if (storage_class == spv::StorageClass::Uniform) {
402 bool is_buffer_block = false;
403 context()->get_decoration_mgr()->ForEachDecoration(
404 base_type->result_id(), uint32_t(spv::Decoration::BufferBlock),
405 [&is_buffer_block](const Instruction&) { is_buffer_block = true; });
406 return is_buffer_block;
407 } else if (storage_class == spv::StorageClass::StorageBuffer) {
408 bool is_block = false;
409 context()->get_decoration_mgr()->ForEachDecoration(
410 base_type->result_id(), uint32_t(spv::Decoration::Block),
411 [&is_block](const Instruction&) { is_block = true; });
412 return is_block;
413 }
414 return false;
415 }
416
IsVulkanStorageBufferVariable() const417 bool Instruction::IsVulkanStorageBufferVariable() const {
418 if (opcode() != spv::Op::OpVariable) {
419 return false;
420 }
421
422 spv::StorageClass storage_class =
423 spv::StorageClass(GetSingleWordInOperand(kVariableStorageClassIndex));
424 if (storage_class == spv::StorageClass::StorageBuffer ||
425 storage_class == spv::StorageClass::Uniform) {
426 Instruction* var_type = context()->get_def_use_mgr()->GetDef(type_id());
427 return var_type != nullptr && var_type->IsVulkanStorageBuffer();
428 }
429
430 return false;
431 }
432
IsVulkanUniformBuffer() const433 bool Instruction::IsVulkanUniformBuffer() const {
434 if (opcode() != spv::Op::OpTypePointer) {
435 return false;
436 }
437
438 spv::StorageClass storage_class =
439 spv::StorageClass(GetSingleWordInOperand(kPointerTypeStorageClassIndex));
440 if (storage_class != spv::StorageClass::Uniform) {
441 return false;
442 }
443
444 Instruction* base_type =
445 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(1));
446
447 // Unpack the optional layer of arraying.
448 if (base_type->opcode() == spv::Op::OpTypeArray ||
449 base_type->opcode() == spv::Op::OpTypeRuntimeArray) {
450 base_type = context()->get_def_use_mgr()->GetDef(
451 base_type->GetSingleWordInOperand(0));
452 }
453
454 if (base_type->opcode() != spv::Op::OpTypeStruct) {
455 return false;
456 }
457
458 bool is_block = false;
459 context()->get_decoration_mgr()->ForEachDecoration(
460 base_type->result_id(), uint32_t(spv::Decoration::Block),
461 [&is_block](const Instruction&) { is_block = true; });
462 return is_block;
463 }
464
IsReadOnlyPointerShaders() const465 bool Instruction::IsReadOnlyPointerShaders() const {
466 if (type_id() == 0) {
467 return false;
468 }
469
470 Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
471 if (type_def->opcode() != spv::Op::OpTypePointer) {
472 return false;
473 }
474
475 spv::StorageClass storage_class = spv::StorageClass(
476 type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
477
478 switch (storage_class) {
479 case spv::StorageClass::UniformConstant:
480 if (!type_def->IsVulkanStorageImage() &&
481 !type_def->IsVulkanStorageTexelBuffer()) {
482 return true;
483 }
484 break;
485 case spv::StorageClass::Uniform:
486 if (!type_def->IsVulkanStorageBuffer()) {
487 return true;
488 }
489 break;
490 case spv::StorageClass::PushConstant:
491 case spv::StorageClass::Input:
492 return true;
493 default:
494 break;
495 }
496
497 bool is_nonwritable = false;
498 context()->get_decoration_mgr()->ForEachDecoration(
499 result_id(), uint32_t(spv::Decoration::NonWritable),
500 [&is_nonwritable](const Instruction&) { is_nonwritable = true; });
501 return is_nonwritable;
502 }
503
IsReadOnlyPointerKernel() const504 bool Instruction::IsReadOnlyPointerKernel() const {
505 if (type_id() == 0) {
506 return false;
507 }
508
509 Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
510 if (type_def->opcode() != spv::Op::OpTypePointer) {
511 return false;
512 }
513
514 spv::StorageClass storage_class = spv::StorageClass(
515 type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex));
516
517 return storage_class == spv::StorageClass::UniformConstant;
518 }
519
UpdateLexicalScope(uint32_t scope)520 void Instruction::UpdateLexicalScope(uint32_t scope) {
521 dbg_scope_.SetLexicalScope(scope);
522 for (auto& i : dbg_line_insts_) {
523 i.dbg_scope_.SetLexicalScope(scope);
524 }
525 if (!IsLineInst() &&
526 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
527 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
528 }
529 }
530
UpdateDebugInlinedAt(uint32_t new_inlined_at)531 void Instruction::UpdateDebugInlinedAt(uint32_t new_inlined_at) {
532 dbg_scope_.SetInlinedAt(new_inlined_at);
533 for (auto& i : dbg_line_insts_) {
534 i.dbg_scope_.SetInlinedAt(new_inlined_at);
535 }
536 if (!IsLineInst() &&
537 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
538 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
539 }
540 }
541
ClearDbgLineInsts()542 void Instruction::ClearDbgLineInsts() {
543 if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse)) {
544 auto def_use_mgr = context()->get_def_use_mgr();
545 for (auto& l_inst : dbg_line_insts_) def_use_mgr->ClearInst(&l_inst);
546 }
547 clear_dbg_line_insts();
548 }
549
UpdateDebugInfoFrom(const Instruction * from)550 void Instruction::UpdateDebugInfoFrom(const Instruction* from) {
551 if (from == nullptr) return;
552 ClearDbgLineInsts();
553 if (!from->dbg_line_insts().empty())
554 AddDebugLine(&from->dbg_line_insts().back());
555 SetDebugScope(from->GetDebugScope());
556 if (!IsLineInst() &&
557 context()->AreAnalysesValid(IRContext::kAnalysisDebugInfo)) {
558 context()->get_debug_info_mgr()->AnalyzeDebugInst(this);
559 }
560 }
561
AddDebugLine(const Instruction * inst)562 void Instruction::AddDebugLine(const Instruction* inst) {
563 dbg_line_insts_.push_back(*inst);
564 dbg_line_insts_.back().unique_id_ = context()->TakeNextUniqueId();
565 if (inst->IsDebugLineInst())
566 dbg_line_insts_.back().SetResultId(context_->TakeNextId());
567 if (context()->AreAnalysesValid(IRContext::kAnalysisDefUse))
568 context()->get_def_use_mgr()->AnalyzeInstDefUse(&dbg_line_insts_.back());
569 }
570
IsDebugLineInst() const571 bool Instruction::IsDebugLineInst() const {
572 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
573 return ((ext_opt == NonSemanticShaderDebugInfo100DebugLine) ||
574 (ext_opt == NonSemanticShaderDebugInfo100DebugNoLine));
575 }
576
IsLineInst() const577 bool Instruction::IsLineInst() const { return IsLine() || IsNoLine(); }
578
IsLine() const579 bool Instruction::IsLine() const {
580 if (opcode() == spv::Op::OpLine) return true;
581 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
582 return ext_opt == NonSemanticShaderDebugInfo100DebugLine;
583 }
584
IsNoLine() const585 bool Instruction::IsNoLine() const {
586 if (opcode() == spv::Op::OpNoLine) return true;
587 NonSemanticShaderDebugInfo100Instructions ext_opt = GetShader100DebugOpcode();
588 return ext_opt == NonSemanticShaderDebugInfo100DebugNoLine;
589 }
590
InsertBefore(std::unique_ptr<Instruction> && inst)591 Instruction* Instruction::InsertBefore(std::unique_ptr<Instruction>&& inst) {
592 inst.get()->InsertBefore(this);
593 return inst.release();
594 }
595
InsertBefore(std::vector<std::unique_ptr<Instruction>> && list)596 Instruction* Instruction::InsertBefore(
597 std::vector<std::unique_ptr<Instruction>>&& list) {
598 Instruction* first_node = list.front().get();
599 for (auto& inst : list) {
600 inst.release()->InsertBefore(this);
601 }
602 list.clear();
603 return first_node;
604 }
605
IsValidBasePointer() const606 bool Instruction::IsValidBasePointer() const {
607 uint32_t tid = type_id();
608 if (tid == 0) {
609 return false;
610 }
611
612 Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
613 if (type->opcode() != spv::Op::OpTypePointer) {
614 return false;
615 }
616
617 auto feature_mgr = context()->get_feature_mgr();
618 if (feature_mgr->HasCapability(spv::Capability::Addresses)) {
619 // TODO: The rules here could be more restrictive.
620 return true;
621 }
622
623 if (opcode() == spv::Op::OpVariable ||
624 opcode() == spv::Op::OpFunctionParameter) {
625 return true;
626 }
627
628 // With variable pointers, there are more valid base pointer objects.
629 // Variable pointers implicitly declares Variable pointers storage buffer.
630 spv::StorageClass storage_class =
631 static_cast<spv::StorageClass>(type->GetSingleWordInOperand(0));
632 if ((feature_mgr->HasCapability(
633 spv::Capability::VariablePointersStorageBuffer) &&
634 storage_class == spv::StorageClass::StorageBuffer) ||
635 (feature_mgr->HasCapability(spv::Capability::VariablePointers) &&
636 storage_class == spv::StorageClass::Workgroup)) {
637 switch (opcode()) {
638 case spv::Op::OpPhi:
639 case spv::Op::OpSelect:
640 case spv::Op::OpFunctionCall:
641 case spv::Op::OpConstantNull:
642 return true;
643 default:
644 break;
645 }
646 }
647
648 uint32_t pointee_type_id = type->GetSingleWordInOperand(1);
649 Instruction* pointee_type_inst =
650 context()->get_def_use_mgr()->GetDef(pointee_type_id);
651
652 if (pointee_type_inst->IsOpaqueType()) {
653 return true;
654 }
655 return false;
656 }
657
GetOpenCL100DebugOpcode() const658 OpenCLDebugInfo100Instructions Instruction::GetOpenCL100DebugOpcode() const {
659 if (opcode() != spv::Op::OpExtInst) {
660 return OpenCLDebugInfo100InstructionsMax;
661 }
662
663 if (!context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
664 return OpenCLDebugInfo100InstructionsMax;
665 }
666
667 if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
668 context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()) {
669 return OpenCLDebugInfo100InstructionsMax;
670 }
671
672 return OpenCLDebugInfo100Instructions(
673 GetSingleWordInOperand(kExtInstInstructionInIdx));
674 }
675
GetShader100DebugOpcode() const676 NonSemanticShaderDebugInfo100Instructions Instruction::GetShader100DebugOpcode()
677 const {
678 if (opcode() != spv::Op::OpExtInst) {
679 return NonSemanticShaderDebugInfo100InstructionsMax;
680 }
681
682 if (!context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
683 return NonSemanticShaderDebugInfo100InstructionsMax;
684 }
685
686 if (GetSingleWordInOperand(kExtInstSetIdInIdx) !=
687 context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo()) {
688 return NonSemanticShaderDebugInfo100InstructionsMax;
689 }
690
691 uint32_t opcode = GetSingleWordInOperand(kExtInstInstructionInIdx);
692 if (opcode >= NonSemanticShaderDebugInfo100InstructionsMax) {
693 return NonSemanticShaderDebugInfo100InstructionsMax;
694 }
695
696 return NonSemanticShaderDebugInfo100Instructions(opcode);
697 }
698
GetCommonDebugOpcode() const699 CommonDebugInfoInstructions Instruction::GetCommonDebugOpcode() const {
700 if (opcode() != spv::Op::OpExtInst) {
701 return CommonDebugInfoInstructionsMax;
702 }
703
704 const uint32_t opencl_set_id =
705 context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo();
706 const uint32_t shader_set_id =
707 context()->get_feature_mgr()->GetExtInstImportId_Shader100DebugInfo();
708
709 if (!opencl_set_id && !shader_set_id) {
710 return CommonDebugInfoInstructionsMax;
711 }
712
713 const uint32_t used_set_id = GetSingleWordInOperand(kExtInstSetIdInIdx);
714
715 if (used_set_id != opencl_set_id && used_set_id != shader_set_id) {
716 return CommonDebugInfoInstructionsMax;
717 }
718
719 return CommonDebugInfoInstructions(
720 GetSingleWordInOperand(kExtInstInstructionInIdx));
721 }
722
IsValidBaseImage() const723 bool Instruction::IsValidBaseImage() const {
724 uint32_t tid = type_id();
725 if (tid == 0) {
726 return false;
727 }
728
729 Instruction* type = context()->get_def_use_mgr()->GetDef(tid);
730 return (type->opcode() == spv::Op::OpTypeImage ||
731 type->opcode() == spv::Op::OpTypeSampledImage);
732 }
733
IsOpaqueType() const734 bool Instruction::IsOpaqueType() const {
735 if (opcode() == spv::Op::OpTypeStruct) {
736 bool is_opaque = false;
737 ForEachInOperand([&is_opaque, this](const uint32_t* op_id) {
738 Instruction* type_inst = context()->get_def_use_mgr()->GetDef(*op_id);
739 is_opaque |= type_inst->IsOpaqueType();
740 });
741 return is_opaque;
742 } else if (opcode() == spv::Op::OpTypeArray) {
743 uint32_t sub_type_id = GetSingleWordInOperand(0);
744 Instruction* sub_type_inst =
745 context()->get_def_use_mgr()->GetDef(sub_type_id);
746 return sub_type_inst->IsOpaqueType();
747 } else {
748 return opcode() == spv::Op::OpTypeRuntimeArray ||
749 spvOpcodeIsBaseOpaqueType(opcode());
750 }
751 }
752
IsFoldable() const753 bool Instruction::IsFoldable() const {
754 return IsFoldableByFoldScalar() || IsFoldableByFoldVector() ||
755 context()->get_instruction_folder().HasConstFoldingRule(this);
756 }
757
IsFoldableByFoldScalar() const758 bool Instruction::IsFoldableByFoldScalar() const {
759 const InstructionFolder& folder = context()->get_instruction_folder();
760 if (!folder.IsFoldableOpcode(opcode())) {
761 return false;
762 }
763
764 Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
765 if (!folder.IsFoldableScalarType(type)) {
766 return false;
767 }
768
769 // Even if the type of the instruction is foldable, its operands may not be
770 // foldable (e.g., comparisons of 64bit types). Check that all operand types
771 // are foldable before accepting the instruction.
772 return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
773 Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
774 Instruction* def_inst_type =
775 context()->get_def_use_mgr()->GetDef(def_inst->type_id());
776 return folder.IsFoldableScalarType(def_inst_type);
777 });
778 }
779
IsFoldableByFoldVector() const780 bool Instruction::IsFoldableByFoldVector() const {
781 const InstructionFolder& folder = context()->get_instruction_folder();
782 if (!folder.IsFoldableOpcode(opcode())) {
783 return false;
784 }
785
786 Instruction* type = context()->get_def_use_mgr()->GetDef(type_id());
787 if (!folder.IsFoldableVectorType(type)) {
788 return false;
789 }
790
791 // Even if the type of the instruction is foldable, its operands may not be
792 // foldable (e.g., comparisons of 64bit types). Check that all operand types
793 // are foldable before accepting the instruction.
794 return WhileEachInOperand([&folder, this](const uint32_t* op_id) {
795 Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id);
796 Instruction* def_inst_type =
797 context()->get_def_use_mgr()->GetDef(def_inst->type_id());
798 return folder.IsFoldableVectorType(def_inst_type);
799 });
800 }
801
IsFloatingPointFoldingAllowed() const802 bool Instruction::IsFloatingPointFoldingAllowed() const {
803 // TODO: Add the rules for kernels. For now it will be pessimistic.
804 // For now, do not support capabilities introduced by SPV_KHR_float_controls.
805 if (!context_->get_feature_mgr()->HasCapability(spv::Capability::Shader) ||
806 context_->get_feature_mgr()->HasCapability(
807 spv::Capability::DenormPreserve) ||
808 context_->get_feature_mgr()->HasCapability(
809 spv::Capability::DenormFlushToZero) ||
810 context_->get_feature_mgr()->HasCapability(
811 spv::Capability::SignedZeroInfNanPreserve) ||
812 context_->get_feature_mgr()->HasCapability(
813 spv::Capability::RoundingModeRTZ) ||
814 context_->get_feature_mgr()->HasCapability(
815 spv::Capability::RoundingModeRTE)) {
816 return false;
817 }
818
819 bool is_nocontract = false;
820 context_->get_decoration_mgr()->WhileEachDecoration(
821 result_id(), uint32_t(spv::Decoration::NoContraction),
822 [&is_nocontract](const Instruction&) {
823 is_nocontract = true;
824 return false;
825 });
826 return !is_nocontract;
827 }
828
PrettyPrint(uint32_t options) const829 std::string Instruction::PrettyPrint(uint32_t options) const {
830 // Convert the module to binary.
831 std::vector<uint32_t> module_binary;
832 context()->module()->ToBinary(&module_binary, /* skip_nop = */ false);
833
834 // Convert the instruction to binary. This is used to identify the correct
835 // stream of words to output from the module.
836 std::vector<uint32_t> inst_binary;
837 ToBinaryWithoutAttachedDebugInsts(&inst_binary);
838
839 // Do not generate a header.
840 return spvInstructionBinaryToText(
841 context()->grammar().target_env(), inst_binary.data(), inst_binary.size(),
842 module_binary.data(), module_binary.size(),
843 options | SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
844 }
845
operator <<(std::ostream & str,const Instruction & inst)846 std::ostream& operator<<(std::ostream& str, const Instruction& inst) {
847 str << inst.PrettyPrint();
848 return str;
849 }
850
Dump() const851 void Instruction::Dump() const {
852 std::cerr << "Instruction #" << unique_id() << "\n" << *this << "\n";
853 }
854
IsOpcodeCodeMotionSafe() const855 bool Instruction::IsOpcodeCodeMotionSafe() const {
856 switch (opcode_) {
857 case spv::Op::OpNop:
858 case spv::Op::OpUndef:
859 case spv::Op::OpLoad:
860 case spv::Op::OpAccessChain:
861 case spv::Op::OpInBoundsAccessChain:
862 case spv::Op::OpArrayLength:
863 case spv::Op::OpVectorExtractDynamic:
864 case spv::Op::OpVectorInsertDynamic:
865 case spv::Op::OpVectorShuffle:
866 case spv::Op::OpCompositeConstruct:
867 case spv::Op::OpCompositeExtract:
868 case spv::Op::OpCompositeInsert:
869 case spv::Op::OpCopyObject:
870 case spv::Op::OpTranspose:
871 case spv::Op::OpConvertFToU:
872 case spv::Op::OpConvertFToS:
873 case spv::Op::OpConvertSToF:
874 case spv::Op::OpConvertUToF:
875 case spv::Op::OpUConvert:
876 case spv::Op::OpSConvert:
877 case spv::Op::OpFConvert:
878 case spv::Op::OpQuantizeToF16:
879 case spv::Op::OpBitcast:
880 case spv::Op::OpSNegate:
881 case spv::Op::OpFNegate:
882 case spv::Op::OpIAdd:
883 case spv::Op::OpFAdd:
884 case spv::Op::OpISub:
885 case spv::Op::OpFSub:
886 case spv::Op::OpIMul:
887 case spv::Op::OpFMul:
888 case spv::Op::OpUDiv:
889 case spv::Op::OpSDiv:
890 case spv::Op::OpFDiv:
891 case spv::Op::OpUMod:
892 case spv::Op::OpSRem:
893 case spv::Op::OpSMod:
894 case spv::Op::OpFRem:
895 case spv::Op::OpFMod:
896 case spv::Op::OpVectorTimesScalar:
897 case spv::Op::OpMatrixTimesScalar:
898 case spv::Op::OpVectorTimesMatrix:
899 case spv::Op::OpMatrixTimesVector:
900 case spv::Op::OpMatrixTimesMatrix:
901 case spv::Op::OpOuterProduct:
902 case spv::Op::OpDot:
903 case spv::Op::OpIAddCarry:
904 case spv::Op::OpISubBorrow:
905 case spv::Op::OpUMulExtended:
906 case spv::Op::OpSMulExtended:
907 case spv::Op::OpAny:
908 case spv::Op::OpAll:
909 case spv::Op::OpIsNan:
910 case spv::Op::OpIsInf:
911 case spv::Op::OpLogicalEqual:
912 case spv::Op::OpLogicalNotEqual:
913 case spv::Op::OpLogicalOr:
914 case spv::Op::OpLogicalAnd:
915 case spv::Op::OpLogicalNot:
916 case spv::Op::OpSelect:
917 case spv::Op::OpIEqual:
918 case spv::Op::OpINotEqual:
919 case spv::Op::OpUGreaterThan:
920 case spv::Op::OpSGreaterThan:
921 case spv::Op::OpUGreaterThanEqual:
922 case spv::Op::OpSGreaterThanEqual:
923 case spv::Op::OpULessThan:
924 case spv::Op::OpSLessThan:
925 case spv::Op::OpULessThanEqual:
926 case spv::Op::OpSLessThanEqual:
927 case spv::Op::OpFOrdEqual:
928 case spv::Op::OpFUnordEqual:
929 case spv::Op::OpFOrdNotEqual:
930 case spv::Op::OpFUnordNotEqual:
931 case spv::Op::OpFOrdLessThan:
932 case spv::Op::OpFUnordLessThan:
933 case spv::Op::OpFOrdGreaterThan:
934 case spv::Op::OpFUnordGreaterThan:
935 case spv::Op::OpFOrdLessThanEqual:
936 case spv::Op::OpFUnordLessThanEqual:
937 case spv::Op::OpFOrdGreaterThanEqual:
938 case spv::Op::OpFUnordGreaterThanEqual:
939 case spv::Op::OpShiftRightLogical:
940 case spv::Op::OpShiftRightArithmetic:
941 case spv::Op::OpShiftLeftLogical:
942 case spv::Op::OpBitwiseOr:
943 case spv::Op::OpBitwiseXor:
944 case spv::Op::OpBitwiseAnd:
945 case spv::Op::OpNot:
946 case spv::Op::OpBitFieldInsert:
947 case spv::Op::OpBitFieldSExtract:
948 case spv::Op::OpBitFieldUExtract:
949 case spv::Op::OpBitReverse:
950 case spv::Op::OpBitCount:
951 case spv::Op::OpSizeOf:
952 return true;
953 default:
954 return false;
955 }
956 }
957
IsScalarizable() const958 bool Instruction::IsScalarizable() const {
959 if (spvOpcodeIsScalarizable(opcode())) {
960 return true;
961 }
962
963 if (opcode() == spv::Op::OpExtInst) {
964 uint32_t instSetId =
965 context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450();
966
967 if (GetSingleWordInOperand(kExtInstSetIdInIdx) == instSetId) {
968 switch (GetSingleWordInOperand(kExtInstInstructionInIdx)) {
969 case GLSLstd450Round:
970 case GLSLstd450RoundEven:
971 case GLSLstd450Trunc:
972 case GLSLstd450FAbs:
973 case GLSLstd450SAbs:
974 case GLSLstd450FSign:
975 case GLSLstd450SSign:
976 case GLSLstd450Floor:
977 case GLSLstd450Ceil:
978 case GLSLstd450Fract:
979 case GLSLstd450Radians:
980 case GLSLstd450Degrees:
981 case GLSLstd450Sin:
982 case GLSLstd450Cos:
983 case GLSLstd450Tan:
984 case GLSLstd450Asin:
985 case GLSLstd450Acos:
986 case GLSLstd450Atan:
987 case GLSLstd450Sinh:
988 case GLSLstd450Cosh:
989 case GLSLstd450Tanh:
990 case GLSLstd450Asinh:
991 case GLSLstd450Acosh:
992 case GLSLstd450Atanh:
993 case GLSLstd450Atan2:
994 case GLSLstd450Pow:
995 case GLSLstd450Exp:
996 case GLSLstd450Log:
997 case GLSLstd450Exp2:
998 case GLSLstd450Log2:
999 case GLSLstd450Sqrt:
1000 case GLSLstd450InverseSqrt:
1001 case GLSLstd450Modf:
1002 case GLSLstd450FMin:
1003 case GLSLstd450UMin:
1004 case GLSLstd450SMin:
1005 case GLSLstd450FMax:
1006 case GLSLstd450UMax:
1007 case GLSLstd450SMax:
1008 case GLSLstd450FClamp:
1009 case GLSLstd450UClamp:
1010 case GLSLstd450SClamp:
1011 case GLSLstd450FMix:
1012 case GLSLstd450Step:
1013 case GLSLstd450SmoothStep:
1014 case GLSLstd450Fma:
1015 case GLSLstd450Frexp:
1016 case GLSLstd450Ldexp:
1017 case GLSLstd450FindILsb:
1018 case GLSLstd450FindSMsb:
1019 case GLSLstd450FindUMsb:
1020 case GLSLstd450NMin:
1021 case GLSLstd450NMax:
1022 case GLSLstd450NClamp:
1023 return true;
1024 default:
1025 return false;
1026 }
1027 }
1028 }
1029 return false;
1030 }
1031
IsOpcodeSafeToDelete() const1032 bool Instruction::IsOpcodeSafeToDelete() const {
1033 if (context()->IsCombinatorInstruction(this)) {
1034 return true;
1035 }
1036
1037 switch (opcode()) {
1038 case spv::Op::OpDPdx:
1039 case spv::Op::OpDPdy:
1040 case spv::Op::OpFwidth:
1041 case spv::Op::OpDPdxFine:
1042 case spv::Op::OpDPdyFine:
1043 case spv::Op::OpFwidthFine:
1044 case spv::Op::OpDPdxCoarse:
1045 case spv::Op::OpDPdyCoarse:
1046 case spv::Op::OpFwidthCoarse:
1047 case spv::Op::OpImageQueryLod:
1048 return true;
1049 default:
1050 return false;
1051 }
1052 }
1053
IsNonSemanticInstruction() const1054 bool Instruction::IsNonSemanticInstruction() const {
1055 if (!HasResultId()) return false;
1056 if (opcode() != spv::Op::OpExtInst) return false;
1057
1058 auto import_inst =
1059 context()->get_def_use_mgr()->GetDef(GetSingleWordInOperand(0));
1060 std::string import_name = import_inst->GetInOperand(0).AsString();
1061 return import_name.find("NonSemantic.") == 0;
1062 }
1063
ToBinary(uint32_t type_id,uint32_t result_id,uint32_t ext_set,std::vector<uint32_t> * binary) const1064 void DebugScope::ToBinary(uint32_t type_id, uint32_t result_id,
1065 uint32_t ext_set,
1066 std::vector<uint32_t>* binary) const {
1067 uint32_t num_words = kDebugScopeNumWords;
1068 CommonDebugInfoInstructions dbg_opcode = CommonDebugInfoDebugScope;
1069 if (GetLexicalScope() == kNoDebugScope) {
1070 num_words = kDebugNoScopeNumWords;
1071 dbg_opcode = CommonDebugInfoDebugNoScope;
1072 } else if (GetInlinedAt() == kNoInlinedAt) {
1073 num_words = kDebugScopeNumWordsWithoutInlinedAt;
1074 }
1075 std::vector<uint32_t> operands = {
1076 (num_words << 16) | static_cast<uint16_t>(spv::Op::OpExtInst),
1077 type_id,
1078 result_id,
1079 ext_set,
1080 static_cast<uint32_t>(dbg_opcode),
1081 };
1082 binary->insert(binary->end(), operands.begin(), operands.end());
1083 if (GetLexicalScope() != kNoDebugScope) {
1084 binary->push_back(GetLexicalScope());
1085 if (GetInlinedAt() != kNoInlinedAt) binary->push_back(GetInlinedAt());
1086 }
1087 }
1088
1089 } // namespace opt
1090 } // namespace spvtools
1091