Coverage Report

Created: 2026-03-31 06:42

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