Coverage Report

Created: 2026-07-16 07:02

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