Coverage Report

Created: 2026-04-12 06:23

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