Coverage Report

Created: 2025-07-04 07:23

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