Coverage Report

Created: 2026-11-12 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/opt/ir_context.cpp
Line
Count
Source
1
// Copyright (c) 2017 Google Inc.
2
// Modifications Copyright (C) 2024 Advanced Micro Devices, Inc. All rights
3
// reserved.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
//     http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
17
#include "source/opt/ir_context.h"
18
19
#include <cstring>
20
21
#include "OpenCLDebugInfo100.h"
22
#include "source/latest_version_glsl_std_450_header.h"
23
#include "source/opt/log.h"
24
#include "source/opt/reflect.h"
25
26
namespace spvtools {
27
namespace opt {
28
namespace {
29
constexpr int kSpvDecorateTargetIdInIdx = 0;
30
constexpr int kSpvDecorateDecorationInIdx = 1;
31
constexpr int kSpvDecorateBuiltinInIdx = 2;
32
constexpr int kEntryPointInterfaceInIdx = 3;
33
constexpr int kEntryPointFunctionIdInIdx = 1;
34
constexpr int kEntryPointExecutionModelInIdx = 0;
35
36
// Constants for OpenCL.DebugInfo.100 / NonSemantic.Shader.DebugInfo extension
37
// instructions.
38
constexpr uint32_t kDebugFunctionOperandFunctionIndex = 13;
39
constexpr uint32_t kDebugGlobalVariableOperandVariableIndex = 11;
40
}  // namespace
41
42
9.80k
void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
43
9.80k
  set = Analysis(set & ~valid_analyses_);
44
45
9.80k
  if (set & kAnalysisDefUse) {
46
0
    BuildDefUseManager();
47
0
  }
48
9.80k
  if (set & kAnalysisInstrToBlockMapping) {
49
0
    BuildInstrToBlockMapping();
50
0
  }
51
9.80k
  if (set & kAnalysisDecorations) {
52
0
    BuildDecorationManager();
53
0
  }
54
9.80k
  if (set & kAnalysisCFG) {
55
9.80k
    BuildCFG();
56
9.80k
  }
57
9.80k
  if (set & kAnalysisDominatorAnalysis) {
58
6.22k
    ResetDominatorAnalysis();
59
6.22k
  }
60
9.80k
  if (set & kAnalysisLoopAnalysis) {
61
0
    ResetLoopAnalysis();
62
0
  }
63
9.80k
  if (set & kAnalysisBuiltinVarId) {
64
0
    ResetBuiltinAnalysis();
65
0
  }
66
9.80k
  if (set & kAnalysisNameMap) {
67
0
    BuildIdToNameMap();
68
0
  }
69
9.80k
  if (set & kAnalysisScalarEvolution) {
70
0
    BuildScalarEvolutionAnalysis();
71
0
  }
72
9.80k
  if (set & kAnalysisRegisterPressure) {
73
0
    BuildRegPressureAnalysis();
74
0
  }
75
9.80k
  if (set & kAnalysisValueNumberTable) {
76
0
    BuildValueNumberTable();
77
0
  }
78
9.80k
  if (set & kAnalysisStructuredCFG) {
79
0
    BuildStructuredCFGAnalysis();
80
0
  }
81
9.80k
  if (set & kAnalysisIdToFuncMapping) {
82
0
    BuildIdToFuncMapping();
83
0
  }
84
9.80k
  if (set & kAnalysisConstants) {
85
0
    BuildConstantManager();
86
0
  }
87
9.80k
  if (set & kAnalysisTypes) {
88
0
    BuildTypeManager();
89
0
  }
90
9.80k
  if (set & kAnalysisDebugInfo) {
91
0
    BuildDebugInfoManager();
92
0
  }
93
9.80k
  if (set & kAnalysisLiveness) {
94
0
    BuildLivenessManager();
95
0
  }
96
9.80k
  if (set & kAnalysisIdToGraphMapping) {
97
0
    BuildIdToGraphMapping();
98
0
  }
99
9.80k
}
100
101
void IRContext::InvalidateAnalysesExceptFor(
102
66.3k
    IRContext::Analysis preserved_analyses) {
103
66.3k
  uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
104
66.3k
  InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate));
105
66.3k
}
106
107
143k
void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
108
  // The ConstantManager and DebugInfoManager contain Type pointers. If the
109
  // TypeManager goes away, the ConstantManager and DebugInfoManager have to
110
  // go away.
111
143k
  if (analyses_to_invalidate & kAnalysisTypes) {
112
7.81k
    analyses_to_invalidate |= kAnalysisConstants;
113
7.81k
    analyses_to_invalidate |= kAnalysisDebugInfo;
114
7.81k
  }
115
116
  // The dominator analysis hold the pseudo entry and exit nodes from the CFG.
117
  // Also if the CFG change the dominators many changed as well, so the
118
  // dominator analysis should be invalidated as well.
119
143k
  if (analyses_to_invalidate & kAnalysisCFG) {
120
48.0k
    analyses_to_invalidate |= kAnalysisDominatorAnalysis;
121
48.0k
    analyses_to_invalidate |= kAnalysisStructuredCFG;
122
48.0k
  }
123
124
143k
  if (analyses_to_invalidate & kAnalysisLoopAnalysis) {
125
4.61k
    analyses_to_invalidate |= kAnalysisScalarEvolution;
126
4.61k
    analyses_to_invalidate |= kAnalysisLiveness;
127
4.61k
  }
128
129
143k
  if (analyses_to_invalidate & kAnalysisDefUse) {
130
47.1k
    def_use_mgr_.reset(nullptr);
131
47.1k
  }
132
143k
  if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
133
9.37k
    instr_to_block_.clear();
134
9.37k
  }
135
143k
  if (analyses_to_invalidate & kAnalysisDecorations) {
136
68.8k
    decoration_mgr_.reset(nullptr);
137
68.8k
  }
138
143k
  if (analyses_to_invalidate & kAnalysisCombinators) {
139
19.8k
    combinator_ops_.clear();
140
19.8k
  }
141
143k
  if (analyses_to_invalidate & kAnalysisBuiltinVarId) {
142
0
    builtin_var_id_map_.clear();
143
0
  }
144
143k
  if (analyses_to_invalidate & kAnalysisCFG) {
145
48.0k
    cfg_.reset(nullptr);
146
48.0k
  }
147
143k
  if (analyses_to_invalidate & kAnalysisDominatorAnalysis) {
148
48.3k
    dominator_trees_.clear();
149
48.3k
    post_dominator_trees_.clear();
150
48.3k
  }
151
143k
  if (analyses_to_invalidate & kAnalysisLoopAnalysis) {
152
4.61k
    loop_descriptors_.clear();
153
4.61k
  }
154
143k
  if (analyses_to_invalidate & kAnalysisNameMap) {
155
38.5k
    id_to_name_.reset(nullptr);
156
38.5k
  }
157
143k
  if (analyses_to_invalidate & kAnalysisValueNumberTable) {
158
3.66k
    vn_table_.reset(nullptr);
159
3.66k
  }
160
143k
  if (analyses_to_invalidate & kAnalysisStructuredCFG) {
161
54.0k
    struct_cfg_analysis_.reset(nullptr);
162
54.0k
  }
163
143k
  if (analyses_to_invalidate & kAnalysisIdToFuncMapping) {
164
49.1k
    id_to_func_.clear();
165
49.1k
  }
166
143k
  if (analyses_to_invalidate & kAnalysisConstants) {
167
7.81k
    constant_mgr_.reset(nullptr);
168
7.81k
  }
169
143k
  if (analyses_to_invalidate & kAnalysisLiveness) {
170
4.61k
    liveness_mgr_.reset(nullptr);
171
4.61k
  }
172
143k
  if (analyses_to_invalidate & kAnalysisScalarEvolution) {
173
4.61k
    scalar_evolution_analysis_.reset(nullptr);
174
4.61k
  }
175
143k
  if (analyses_to_invalidate & kAnalysisRegisterPressure) {
176
0
    reg_pressure_.reset(nullptr);
177
0
  }
178
143k
  if (analyses_to_invalidate & kAnalysisTypes) {
179
7.81k
    type_mgr_.reset(nullptr);
180
7.81k
  }
181
182
143k
  if (analyses_to_invalidate & kAnalysisDebugInfo) {
183
14.1k
    debug_info_mgr_.reset(nullptr);
184
14.1k
  }
185
143k
  if (analyses_to_invalidate & kAnalysisIdToGraphMapping) {
186
0
    id_to_graph_.clear();
187
0
  }
188
189
143k
  valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
190
143k
}
191
192
13.4M
Instruction* IRContext::KillInst(Instruction* inst) {
193
13.4M
  if (!inst) {
194
0
    return nullptr;
195
0
  }
196
197
13.4M
  KillNamesAndDecorates(inst);
198
199
13.4M
  KillOperandFromDebugInstructions(inst);
200
201
13.4M
  KillRelatedDebugScopes(inst);
202
203
13.4M
  if (AreAnalysesValid(kAnalysisDefUse)) {
204
4.30M
    analysis::DefUseManager* def_use_mgr = get_def_use_mgr();
205
4.30M
    def_use_mgr->ClearInst(inst);
206
4.30M
    for (auto& l_inst : inst->dbg_line_insts()) def_use_mgr->ClearInst(&l_inst);
207
4.30M
  }
208
13.4M
  if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
209
3.72M
    instr_to_block_.erase(inst);
210
3.72M
  }
211
13.4M
  if (AreAnalysesValid(kAnalysisDecorations)) {
212
4.18M
    if (inst->IsDecoration()) {
213
124k
      decoration_mgr_->RemoveDecoration(inst);
214
124k
    }
215
4.18M
  }
216
13.4M
  if (AreAnalysesValid(kAnalysisDebugInfo)) {
217
763k
    get_debug_info_mgr()->ClearDebugScopeAndInlinedAtUses(inst);
218
763k
    get_debug_info_mgr()->ClearDebugInfo(inst);
219
763k
  }
220
13.4M
  if (type_mgr_ && IsTypeInst(inst->opcode())) {
221
27.6k
    type_mgr_->RemoveId(inst->result_id());
222
27.6k
  }
223
13.4M
  if (constant_mgr_ && IsConstantInst(inst->opcode())) {
224
78.9k
    constant_mgr_->RemoveId(inst->result_id());
225
78.9k
  }
226
13.4M
  if (inst->opcode() == spv::Op::OpCapability ||
227
13.4M
      inst->opcode() == spv::Op::OpConditionalCapabilityINTEL ||
228
13.4M
      inst->opcode() == spv::Op::OpExtension ||
229
13.4M
      inst->opcode() == spv::Op::OpConditionalExtensionINTEL ||
230
13.4M
      inst->opcode() == spv::Op::OpExtInstImport) {
231
    // We reset the feature manager, instead of updating it, because it is just
232
    // as much work.  We would have to remove all capabilities implied by this
233
    // capability that are not also implied by the remaining OpCapability
234
    // instructions. We could update extensions, but we will see if it is
235
    // needed.
236
0
    ResetFeatureManager();
237
0
  }
238
239
13.4M
  RemoveFromIdToName(inst);
240
241
13.4M
  Instruction* next_instruction = nullptr;
242
13.4M
  if (inst->IsInAList()) {
243
12.9M
    next_instruction = inst->NextNode();
244
12.9M
    inst->RemoveFromList();
245
12.9M
    delete inst;
246
12.9M
  } else {
247
    // Needed for instructions that are not part of a list like OpLabels,
248
    // OpFunction, OpFunctionEnd, etc..
249
501k
    inst->ToNop();
250
501k
  }
251
13.4M
  return next_instruction;
252
13.4M
}
253
254
bool IRContext::KillInstructionIf(Module::inst_iterator begin,
255
                                  Module::inst_iterator end,
256
0
                                  std::function<bool(Instruction*)> condition) {
257
0
  bool removed = false;
258
0
  for (auto it = begin; it != end;) {
259
0
    if (!condition(&*it)) {
260
0
      ++it;
261
0
      continue;
262
0
    }
263
264
0
    removed = true;
265
    // `it` is an iterator on an intrusive list. Next is invalidated on the
266
    // current node when an instruction is killed. The iterator must be moved
267
    // forward before deleting the node.
268
0
    auto instruction = &*it;
269
0
    ++it;
270
0
    KillInst(instruction);
271
0
  }
272
273
0
  return removed;
274
0
}
275
276
void IRContext::CollectNonSemanticTree(
277
498k
    Instruction* inst, std::unordered_set<Instruction*>* to_kill) {
278
498k
  if (!inst->HasResultId()) return;
279
  // Debug[No]Line result id is not used, so we are done
280
344k
  if (inst->IsDebugLineInst()) return;
281
344k
  std::vector<Instruction*> work_list;
282
344k
  std::unordered_set<Instruction*> seen;
283
344k
  work_list.push_back(inst);
284
285
689k
  while (!work_list.empty()) {
286
344k
    auto* i = work_list.back();
287
344k
    work_list.pop_back();
288
344k
    get_def_use_mgr()->ForEachUser(
289
434k
        i, [&work_list, to_kill, &seen](Instruction* user) {
290
434k
          if (user->IsNonSemanticInstruction() && !user->IsDebugLineInst() &&
291
0
              seen.insert(user).second) {
292
0
            work_list.push_back(user);
293
0
            to_kill->insert(user);
294
0
          }
295
434k
        });
296
344k
  }
297
344k
}
298
299
0
bool IRContext::KillDef(uint32_t id) {
300
0
  Instruction* def = get_def_use_mgr()->GetDef(id);
301
0
  if (def != nullptr) {
302
0
    KillInst(def);
303
0
    return true;
304
0
  }
305
0
  return false;
306
0
}
307
308
0
bool IRContext::RemoveCapability(spv::Capability capability) {
309
0
  const bool removed = KillInstructionIf(
310
0
      module()->capability_begin(), module()->capability_end(),
311
0
      [capability](Instruction* inst) {
312
0
        return static_cast<spv::Capability>(inst->GetSingleWordOperand(0)) ==
313
0
               capability;
314
0
      });
315
316
0
  if (removed && feature_mgr_ != nullptr) {
317
0
    feature_mgr_->RemoveCapability(capability);
318
0
  }
319
320
0
  return removed;
321
0
}
322
323
0
bool IRContext::RemoveExtension(Extension extension) {
324
0
  const std::string_view extensionName = ExtensionToString(extension);
325
0
  const bool removed = KillInstructionIf(
326
0
      module()->extension_begin(), module()->extension_end(),
327
0
      [&extensionName](Instruction* inst) {
328
0
        return inst->GetOperand(0).AsString() == extensionName;
329
0
      });
330
331
0
  if (removed && feature_mgr_ != nullptr) {
332
0
    feature_mgr_->RemoveExtension(extension);
333
0
  }
334
335
0
  return removed;
336
0
}
337
338
935k
bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
339
935k
  return ReplaceAllUsesWithPredicate(before, after,
340
935k
                                     [](Instruction*) { return true; });
341
935k
}
342
343
bool IRContext::ReplaceAllUsesWithPredicate(
344
    uint32_t before, uint32_t after,
345
1.25M
    const std::function<bool(Instruction*)>& predicate) {
346
1.25M
  if (before == after) return false;
347
348
1.25M
  if (AreAnalysesValid(kAnalysisDebugInfo)) {
349
398k
    get_debug_info_mgr()->ReplaceAllUsesInDebugScopeWithPredicate(before, after,
350
398k
                                                                  predicate);
351
398k
  }
352
353
  // Ensure that |after| has been registered as def.
354
1.25M
  assert(get_def_use_mgr()->GetDef(after) &&
355
1.25M
         "'after' is not a registered def.");
356
357
1.25M
  std::vector<std::pair<Instruction*, uint32_t>> uses_to_update;
358
1.25M
  get_def_use_mgr()->ForEachUse(
359
1.35M
      before, [&predicate, &uses_to_update](Instruction* user, uint32_t index) {
360
1.35M
        if (predicate(user)) {
361
1.34M
          uses_to_update.emplace_back(user, index);
362
1.34M
        }
363
1.35M
      });
364
365
1.25M
  Instruction* prev = nullptr;
366
1.34M
  for (auto p : uses_to_update) {
367
1.34M
    Instruction* user = p.first;
368
1.34M
    uint32_t index = p.second;
369
1.34M
    if (prev == nullptr || prev != user) {
370
1.29M
      ForgetUses(user);
371
1.29M
      prev = user;
372
1.29M
    }
373
1.34M
    const uint32_t type_result_id_count =
374
1.34M
        (user->result_id() != 0) + (user->type_id() != 0);
375
376
1.34M
    if (index < type_result_id_count) {
377
      // Update the type_id. Note that result id is immutable so it should
378
      // never be updated.
379
0
      if (user->type_id() != 0 && index == 0) {
380
0
        user->SetResultType(after);
381
0
      } else if (user->type_id() == 0) {
382
0
        SPIRV_ASSERT(consumer_, false,
383
0
                     "Result type id considered as use while the instruction "
384
0
                     "doesn't have a result type id.");
385
0
        (void)consumer_;  // Makes the compiler happy for release build.
386
0
      } else {
387
0
        SPIRV_ASSERT(consumer_, false,
388
0
                     "Trying setting the immutable result id.");
389
0
      }
390
1.34M
    } else {
391
      // Update an in-operand.
392
1.34M
      uint32_t in_operand_pos = index - type_result_id_count;
393
      // Make the modification in the instruction.
394
1.34M
      user->SetInOperand(in_operand_pos, {after});
395
1.34M
    }
396
1.34M
    AnalyzeUses(user);
397
1.34M
  }
398
1.25M
  return true;
399
1.25M
}
400
401
189k
bool IRContext::IsConsistent() {
402
#ifndef SPIRV_CHECK_CONTEXT
403
  return true;
404
#else
405
189k
  if (AreAnalysesValid(kAnalysisDefUse)) {
406
166k
    analysis::DefUseManager new_def_use(module());
407
166k
    if (!CompareAndPrintDifferences(*get_def_use_mgr(), new_def_use)) {
408
0
      return false;
409
0
    }
410
166k
  }
411
412
189k
  if (AreAnalysesValid(kAnalysisIdToFuncMapping)) {
413
95.7k
    for (auto& fn : *module_) {
414
95.7k
      if (id_to_func_[fn.result_id()] != &fn) {
415
0
        return false;
416
0
      }
417
95.7k
    }
418
74.8k
  }
419
420
189k
  if (AreAnalysesValid(kAnalysisIdToGraphMapping)) {
421
0
    for (auto& g : module_->graphs()) {
422
0
      if (id_to_graph_[g->DefInst().result_id()] != g.get()) {
423
0
        return false;
424
0
      }
425
0
    }
426
0
  }
427
428
189k
  if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
429
199k
    for (auto& func : *module()) {
430
11.4M
      for (auto& block : func) {
431
62.3M
        if (!block.WhileEachInst([this, &block](Instruction* inst) {
432
62.3M
              if (get_instr_block(inst) != &block) {
433
0
                return false;
434
0
              }
435
62.3M
              return true;
436
62.3M
            })) {
437
0
          return false;
438
0
        }
439
11.4M
      }
440
199k
    }
441
147k
  }
442
443
189k
  if (!CheckCFG()) {
444
0
    return false;
445
0
  }
446
447
189k
  if (AreAnalysesValid(kAnalysisDecorations)) {
448
71.8k
    analysis::DecorationManager* dec_mgr = get_decoration_mgr();
449
71.8k
    analysis::DecorationManager current(module());
450
451
71.8k
    if (*dec_mgr != current) {
452
0
      return false;
453
0
    }
454
71.8k
  }
455
456
189k
  if (AreAnalysesValid(kAnalysisDominatorAnalysis)) {
457
77.6k
    for (const auto& it : dominator_trees_) {
458
77.6k
      const Function* f = it.first;
459
77.6k
      const DominatorAnalysis& cached_dom = it.second;
460
77.6k
      DominatorAnalysis new_dom;
461
77.6k
      new_dom.InitializeTree(*cfg(), f);
462
463
77.6k
      if (!(cached_dom == new_dom)) {
464
0
        return false;
465
0
      }
466
77.6k
    }
467
63.5k
    for (const auto& it : post_dominator_trees_) {
468
0
      const Function* f = it.first;
469
0
      const PostDominatorAnalysis& cached_post_dom = it.second;
470
0
      PostDominatorAnalysis new_post_dom;
471
0
      new_post_dom.InitializeTree(*cfg(), f);
472
473
0
      if (!(cached_post_dom == new_post_dom)) {
474
0
        return false;
475
0
      }
476
0
    }
477
63.5k
  }
478
479
189k
  if (AreAnalysesValid(kAnalysisStructuredCFG)) {
480
59.6k
    StructuredCFGAnalysis new_struct_cfg(this);
481
59.6k
    StructuredCFGAnalysis* cached_struct_cfg = struct_cfg_analysis_.get();
482
59.6k
    if (!(*cached_struct_cfg == new_struct_cfg)) {
483
0
      return false;
484
0
    }
485
59.6k
  }
486
487
189k
  if (feature_mgr_ != nullptr) {
488
189k
    FeatureManager current(grammar_);
489
189k
    current.Analyze(module());
490
491
189k
    if (current != *feature_mgr_) {
492
0
      return false;
493
0
    }
494
189k
  }
495
189k
  return true;
496
189k
#endif
497
189k
}
498
499
1.73M
void IRContext::ForgetUses(Instruction* inst) {
500
1.73M
  if (AreAnalysesValid(kAnalysisDefUse)) {
501
1.73M
    get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
502
1.73M
  }
503
1.73M
  if (AreAnalysesValid(kAnalysisDecorations)) {
504
1.59M
    if (inst->IsDecoration()) {
505
532
      get_decoration_mgr()->RemoveDecoration(inst);
506
532
    }
507
1.59M
  }
508
1.73M
  if (AreAnalysesValid(kAnalysisDebugInfo)) {
509
456k
    get_debug_info_mgr()->ClearDebugInfo(inst);
510
456k
  }
511
1.73M
  RemoveFromIdToName(inst);
512
1.73M
}
513
514
3.94M
void IRContext::AnalyzeUses(Instruction* inst) {
515
3.94M
  if (AreAnalysesValid(kAnalysisDefUse)) {
516
3.85M
    get_def_use_mgr()->AnalyzeInstUse(inst);
517
3.85M
  }
518
3.94M
  if (AreAnalysesValid(kAnalysisDecorations)) {
519
3.76M
    if (inst->IsDecoration()) {
520
125k
      get_decoration_mgr()->AddDecoration(inst);
521
125k
    }
522
3.76M
  }
523
3.94M
  if (AreAnalysesValid(kAnalysisDebugInfo)) {
524
2.23M
    get_debug_info_mgr()->AnalyzeDebugInst(inst);
525
2.23M
  }
526
3.94M
  if (id_to_name_ && (inst->opcode() == spv::Op::OpName ||
527
2.28M
                      inst->opcode() == spv::Op::OpMemberName)) {
528
103
    id_to_name_->insert({inst->GetSingleWordInOperand(0), inst});
529
103
  }
530
3.94M
}
531
532
3.53M
void IRContext::KillNamesAndDecorates(uint32_t id) {
533
3.53M
  analysis::DecorationManager* dec_mgr = get_decoration_mgr();
534
3.53M
  dec_mgr->RemoveDecorationsFrom(id);
535
536
3.53M
  std::vector<Instruction*> name_to_kill;
537
3.53M
  for (auto name : GetNames(id)) {
538
31.5k
    name_to_kill.push_back(name.second);
539
31.5k
  }
540
3.53M
  for (Instruction* name_inst : name_to_kill) {
541
31.5k
    KillInst(name_inst);
542
31.5k
  }
543
3.53M
}
544
545
13.7M
void IRContext::KillNamesAndDecorates(Instruction* inst) {
546
13.7M
  const uint32_t rId = inst->result_id();
547
13.7M
  if (rId == 0) return;
548
3.06M
  KillNamesAndDecorates(rId);
549
3.06M
}
550
551
13.4M
void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
552
13.4M
  const auto opcode = inst->opcode();
553
13.4M
  const uint32_t id = inst->result_id();
554
  // Kill id of OpFunction from DebugFunction.
555
13.4M
  if (opcode == spv::Op::OpFunction) {
556
7.76k
    for (auto it = module()->ext_inst_debuginfo_begin();
557
7.76k
         it != module()->ext_inst_debuginfo_end(); ++it) {
558
0
      if (it->GetOpenCL100DebugOpcode() != OpenCLDebugInfo100DebugFunction)
559
0
        continue;
560
0
      auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
561
0
      if (operand.words[0] == id) {
562
0
        Instruction* dbg_none = get_debug_info_mgr()->GetDebugInfoNone();
563
0
        if (dbg_none) {
564
0
          operand.words[0] = dbg_none->result_id();
565
0
          get_def_use_mgr()->AnalyzeInstUse(&*it);
566
0
        }
567
0
      }
568
0
    }
569
7.76k
  }
570
  // Kill id of OpVariable for global variable from DebugGlobalVariable.
571
13.4M
  if (opcode == spv::Op::OpVariable || IsConstantInst(opcode)) {
572
380k
    for (auto it = module()->ext_inst_debuginfo_begin();
573
380k
         it != module()->ext_inst_debuginfo_end(); ++it) {
574
0
      if (it->GetCommonDebugOpcode() != CommonDebugInfoDebugGlobalVariable)
575
0
        continue;
576
0
      auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
577
0
      if (operand.words[0] == id) {
578
0
        Instruction* dbg_none = get_debug_info_mgr()->GetDebugInfoNone();
579
0
        if (dbg_none) {
580
0
          operand.words[0] = dbg_none->result_id();
581
0
          get_def_use_mgr()->AnalyzeInstUse(&*it);
582
0
        }
583
0
      }
584
0
    }
585
380k
  }
586
13.4M
}
587
588
13.4M
void IRContext::KillRelatedDebugScopes(Instruction* inst) {
589
  // Extension has been fully unloaded, remove debug scope from every
590
  // instruction.
591
13.4M
  if (inst->opcode() == spv::Op::OpExtInstImport) {
592
0
    const std::string extension_name = inst->GetInOperand(0).AsString();
593
0
    if (extension_name.compare(0, 29, "NonSemantic.Shader.DebugInfo.") == 0 ||
594
0
        extension_name == "OpenCL.DebugInfo.100") {
595
0
      module()->ForEachInst([](Instruction* child) {
596
0
        child->SetDebugScope(DebugScope(kNoDebugScope, kNoInlinedAt));
597
0
      });
598
0
    }
599
0
  }
600
13.4M
}
601
602
48.0k
void IRContext::AddCombinatorsForCapability(uint32_t capability) {
603
48.0k
  spv::Capability cap = spv::Capability(capability);
604
48.0k
  if (cap == spv::Capability::Shader) {
605
23.2k
    combinator_ops_[0].insert(
606
23.2k
        {(uint32_t)spv::Op::OpNop,
607
23.2k
         (uint32_t)spv::Op::OpUndef,
608
23.2k
         (uint32_t)spv::Op::OpConstant,
609
23.2k
         (uint32_t)spv::Op::OpConstantTrue,
610
23.2k
         (uint32_t)spv::Op::OpConstantFalse,
611
23.2k
         (uint32_t)spv::Op::OpConstantComposite,
612
23.2k
         (uint32_t)spv::Op::OpConstantSampler,
613
23.2k
         (uint32_t)spv::Op::OpConstantNull,
614
23.2k
         (uint32_t)spv::Op::OpTypeVoid,
615
23.2k
         (uint32_t)spv::Op::OpTypeBool,
616
23.2k
         (uint32_t)spv::Op::OpTypeInt,
617
23.2k
         (uint32_t)spv::Op::OpTypeFloat,
618
23.2k
         (uint32_t)spv::Op::OpTypeVector,
619
23.2k
         (uint32_t)spv::Op::OpTypeMatrix,
620
23.2k
         (uint32_t)spv::Op::OpTypeImage,
621
23.2k
         (uint32_t)spv::Op::OpTypeSampler,
622
23.2k
         (uint32_t)spv::Op::OpTypeSampledImage,
623
23.2k
         (uint32_t)spv::Op::OpTypeAccelerationStructureNV,
624
23.2k
         (uint32_t)spv::Op::OpTypeAccelerationStructureKHR,
625
23.2k
         (uint32_t)spv::Op::OpTypeRayQueryKHR,
626
23.2k
         (uint32_t)spv::Op::OpTypeHitObjectNV,
627
23.2k
         (uint32_t)spv::Op::OpTypeHitObjectEXT,
628
23.2k
         (uint32_t)spv::Op::OpTypeArray,
629
23.2k
         (uint32_t)spv::Op::OpTypeRuntimeArray,
630
23.2k
         (uint32_t)spv::Op::OpTypeNodePayloadArrayAMDX,
631
23.2k
         (uint32_t)spv::Op::OpTypeStruct,
632
23.2k
         (uint32_t)spv::Op::OpTypeOpaque,
633
23.2k
         (uint32_t)spv::Op::OpTypePointer,
634
23.2k
         (uint32_t)spv::Op::OpTypeUntypedPointerKHR,
635
23.2k
         (uint32_t)spv::Op::OpTypeFunction,
636
23.2k
         (uint32_t)spv::Op::OpTypeEvent,
637
23.2k
         (uint32_t)spv::Op::OpTypeDeviceEvent,
638
23.2k
         (uint32_t)spv::Op::OpTypeReserveId,
639
23.2k
         (uint32_t)spv::Op::OpTypeQueue,
640
23.2k
         (uint32_t)spv::Op::OpTypePipe,
641
23.2k
         (uint32_t)spv::Op::OpTypeForwardPointer,
642
23.2k
         (uint32_t)spv::Op::OpVariable,
643
23.2k
         (uint32_t)spv::Op::OpUntypedVariableKHR,
644
23.2k
         (uint32_t)spv::Op::OpImageTexelPointer,
645
23.2k
         (uint32_t)spv::Op::OpLoad,
646
23.2k
         (uint32_t)spv::Op::OpAccessChain,
647
23.2k
         (uint32_t)spv::Op::OpInBoundsAccessChain,
648
23.2k
         (uint32_t)spv::Op::OpUntypedAccessChainKHR,
649
23.2k
         (uint32_t)spv::Op::OpArrayLength,
650
23.2k
         (uint32_t)spv::Op::OpVectorExtractDynamic,
651
23.2k
         (uint32_t)spv::Op::OpVectorInsertDynamic,
652
23.2k
         (uint32_t)spv::Op::OpVectorShuffle,
653
23.2k
         (uint32_t)spv::Op::OpCompositeConstruct,
654
23.2k
         (uint32_t)spv::Op::OpCompositeExtract,
655
23.2k
         (uint32_t)spv::Op::OpCompositeInsert,
656
23.2k
         (uint32_t)spv::Op::OpCopyLogical,
657
23.2k
         (uint32_t)spv::Op::OpCopyObject,
658
23.2k
         (uint32_t)spv::Op::OpTranspose,
659
23.2k
         (uint32_t)spv::Op::OpSampledImage,
660
23.2k
         (uint32_t)spv::Op::OpImageSampleImplicitLod,
661
23.2k
         (uint32_t)spv::Op::OpImageSampleExplicitLod,
662
23.2k
         (uint32_t)spv::Op::OpImageSampleDrefImplicitLod,
663
23.2k
         (uint32_t)spv::Op::OpImageSampleDrefExplicitLod,
664
23.2k
         (uint32_t)spv::Op::OpImageSampleProjImplicitLod,
665
23.2k
         (uint32_t)spv::Op::OpImageSampleProjExplicitLod,
666
23.2k
         (uint32_t)spv::Op::OpImageSampleProjDrefImplicitLod,
667
23.2k
         (uint32_t)spv::Op::OpImageSampleProjDrefExplicitLod,
668
23.2k
         (uint32_t)spv::Op::OpImageFetch,
669
23.2k
         (uint32_t)spv::Op::OpImageGather,
670
23.2k
         (uint32_t)spv::Op::OpImageDrefGather,
671
23.2k
         (uint32_t)spv::Op::OpImageRead,
672
23.2k
         (uint32_t)spv::Op::OpImage,
673
23.2k
         (uint32_t)spv::Op::OpImageQueryFormat,
674
23.2k
         (uint32_t)spv::Op::OpImageQueryOrder,
675
23.2k
         (uint32_t)spv::Op::OpImageQuerySizeLod,
676
23.2k
         (uint32_t)spv::Op::OpImageQuerySize,
677
23.2k
         (uint32_t)spv::Op::OpImageQueryLevels,
678
23.2k
         (uint32_t)spv::Op::OpImageQuerySamples,
679
23.2k
         (uint32_t)spv::Op::OpConvertFToU,
680
23.2k
         (uint32_t)spv::Op::OpConvertFToS,
681
23.2k
         (uint32_t)spv::Op::OpConvertSToF,
682
23.2k
         (uint32_t)spv::Op::OpConvertUToF,
683
23.2k
         (uint32_t)spv::Op::OpUConvert,
684
23.2k
         (uint32_t)spv::Op::OpSConvert,
685
23.2k
         (uint32_t)spv::Op::OpFConvert,
686
23.2k
         (uint32_t)spv::Op::OpQuantizeToF16,
687
23.2k
         (uint32_t)spv::Op::OpBitcast,
688
23.2k
         (uint32_t)spv::Op::OpSNegate,
689
23.2k
         (uint32_t)spv::Op::OpFNegate,
690
23.2k
         (uint32_t)spv::Op::OpIAdd,
691
23.2k
         (uint32_t)spv::Op::OpFAdd,
692
23.2k
         (uint32_t)spv::Op::OpISub,
693
23.2k
         (uint32_t)spv::Op::OpFSub,
694
23.2k
         (uint32_t)spv::Op::OpIMul,
695
23.2k
         (uint32_t)spv::Op::OpFMul,
696
23.2k
         (uint32_t)spv::Op::OpUDiv,
697
23.2k
         (uint32_t)spv::Op::OpSDiv,
698
23.2k
         (uint32_t)spv::Op::OpFDiv,
699
23.2k
         (uint32_t)spv::Op::OpUMod,
700
23.2k
         (uint32_t)spv::Op::OpSRem,
701
23.2k
         (uint32_t)spv::Op::OpSMod,
702
23.2k
         (uint32_t)spv::Op::OpFRem,
703
23.2k
         (uint32_t)spv::Op::OpFMod,
704
23.2k
         (uint32_t)spv::Op::OpVectorTimesScalar,
705
23.2k
         (uint32_t)spv::Op::OpMatrixTimesScalar,
706
23.2k
         (uint32_t)spv::Op::OpVectorTimesMatrix,
707
23.2k
         (uint32_t)spv::Op::OpMatrixTimesVector,
708
23.2k
         (uint32_t)spv::Op::OpMatrixTimesMatrix,
709
23.2k
         (uint32_t)spv::Op::OpOuterProduct,
710
23.2k
         (uint32_t)spv::Op::OpDot,
711
23.2k
         (uint32_t)spv::Op::OpIAddCarry,
712
23.2k
         (uint32_t)spv::Op::OpISubBorrow,
713
23.2k
         (uint32_t)spv::Op::OpUMulExtended,
714
23.2k
         (uint32_t)spv::Op::OpSMulExtended,
715
23.2k
         (uint32_t)spv::Op::OpAny,
716
23.2k
         (uint32_t)spv::Op::OpAll,
717
23.2k
         (uint32_t)spv::Op::OpIsNan,
718
23.2k
         (uint32_t)spv::Op::OpIsInf,
719
23.2k
         (uint32_t)spv::Op::OpLogicalEqual,
720
23.2k
         (uint32_t)spv::Op::OpLogicalNotEqual,
721
23.2k
         (uint32_t)spv::Op::OpLogicalOr,
722
23.2k
         (uint32_t)spv::Op::OpLogicalAnd,
723
23.2k
         (uint32_t)spv::Op::OpLogicalNot,
724
23.2k
         (uint32_t)spv::Op::OpSelect,
725
23.2k
         (uint32_t)spv::Op::OpIEqual,
726
23.2k
         (uint32_t)spv::Op::OpINotEqual,
727
23.2k
         (uint32_t)spv::Op::OpUGreaterThan,
728
23.2k
         (uint32_t)spv::Op::OpSGreaterThan,
729
23.2k
         (uint32_t)spv::Op::OpUGreaterThanEqual,
730
23.2k
         (uint32_t)spv::Op::OpSGreaterThanEqual,
731
23.2k
         (uint32_t)spv::Op::OpULessThan,
732
23.2k
         (uint32_t)spv::Op::OpSLessThan,
733
23.2k
         (uint32_t)spv::Op::OpULessThanEqual,
734
23.2k
         (uint32_t)spv::Op::OpSLessThanEqual,
735
23.2k
         (uint32_t)spv::Op::OpFOrdEqual,
736
23.2k
         (uint32_t)spv::Op::OpFUnordEqual,
737
23.2k
         (uint32_t)spv::Op::OpFOrdNotEqual,
738
23.2k
         (uint32_t)spv::Op::OpFUnordNotEqual,
739
23.2k
         (uint32_t)spv::Op::OpFOrdLessThan,
740
23.2k
         (uint32_t)spv::Op::OpFUnordLessThan,
741
23.2k
         (uint32_t)spv::Op::OpFOrdGreaterThan,
742
23.2k
         (uint32_t)spv::Op::OpFUnordGreaterThan,
743
23.2k
         (uint32_t)spv::Op::OpFOrdLessThanEqual,
744
23.2k
         (uint32_t)spv::Op::OpFUnordLessThanEqual,
745
23.2k
         (uint32_t)spv::Op::OpFOrdGreaterThanEqual,
746
23.2k
         (uint32_t)spv::Op::OpFUnordGreaterThanEqual,
747
23.2k
         (uint32_t)spv::Op::OpShiftRightLogical,
748
23.2k
         (uint32_t)spv::Op::OpShiftRightArithmetic,
749
23.2k
         (uint32_t)spv::Op::OpShiftLeftLogical,
750
23.2k
         (uint32_t)spv::Op::OpBitwiseOr,
751
23.2k
         (uint32_t)spv::Op::OpBitwiseXor,
752
23.2k
         (uint32_t)spv::Op::OpBitwiseAnd,
753
23.2k
         (uint32_t)spv::Op::OpNot,
754
23.2k
         (uint32_t)spv::Op::OpBitFieldInsert,
755
23.2k
         (uint32_t)spv::Op::OpBitFieldSExtract,
756
23.2k
         (uint32_t)spv::Op::OpBitFieldUExtract,
757
23.2k
         (uint32_t)spv::Op::OpBitReverse,
758
23.2k
         (uint32_t)spv::Op::OpBitCount,
759
23.2k
         (uint32_t)spv::Op::OpPhi,
760
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleImplicitLod,
761
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleExplicitLod,
762
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleDrefImplicitLod,
763
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleDrefExplicitLod,
764
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleProjImplicitLod,
765
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleProjExplicitLod,
766
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleProjDrefImplicitLod,
767
23.2k
         (uint32_t)spv::Op::OpImageSparseSampleProjDrefExplicitLod,
768
23.2k
         (uint32_t)spv::Op::OpImageSparseFetch,
769
23.2k
         (uint32_t)spv::Op::OpImageSparseGather,
770
23.2k
         (uint32_t)spv::Op::OpImageSparseDrefGather,
771
23.2k
         (uint32_t)spv::Op::OpImageSparseTexelsResident,
772
23.2k
         (uint32_t)spv::Op::OpImageSparseRead,
773
23.2k
         (uint32_t)spv::Op::OpSizeOf});
774
23.2k
  }
775
48.0k
}
776
777
22.9k
void IRContext::AddCombinatorsForExtension(Instruction* extension) {
778
22.9k
  assert(extension->opcode() == spv::Op::OpExtInstImport &&
779
22.9k
         "Expecting an import of an extension's instruction set.");
780
22.9k
  const std::string extension_name = extension->GetInOperand(0).AsString();
781
22.9k
  if (extension_name == "GLSL.std.450") {
782
22.9k
    combinator_ops_[extension->result_id()] = {
783
22.9k
        (uint32_t)GLSLstd450Round,
784
22.9k
        (uint32_t)GLSLstd450RoundEven,
785
22.9k
        (uint32_t)GLSLstd450Trunc,
786
22.9k
        (uint32_t)GLSLstd450FAbs,
787
22.9k
        (uint32_t)GLSLstd450SAbs,
788
22.9k
        (uint32_t)GLSLstd450FSign,
789
22.9k
        (uint32_t)GLSLstd450SSign,
790
22.9k
        (uint32_t)GLSLstd450Floor,
791
22.9k
        (uint32_t)GLSLstd450Ceil,
792
22.9k
        (uint32_t)GLSLstd450Fract,
793
22.9k
        (uint32_t)GLSLstd450Radians,
794
22.9k
        (uint32_t)GLSLstd450Degrees,
795
22.9k
        (uint32_t)GLSLstd450Sin,
796
22.9k
        (uint32_t)GLSLstd450Cos,
797
22.9k
        (uint32_t)GLSLstd450Tan,
798
22.9k
        (uint32_t)GLSLstd450Asin,
799
22.9k
        (uint32_t)GLSLstd450Acos,
800
22.9k
        (uint32_t)GLSLstd450Atan,
801
22.9k
        (uint32_t)GLSLstd450Sinh,
802
22.9k
        (uint32_t)GLSLstd450Cosh,
803
22.9k
        (uint32_t)GLSLstd450Tanh,
804
22.9k
        (uint32_t)GLSLstd450Asinh,
805
22.9k
        (uint32_t)GLSLstd450Acosh,
806
22.9k
        (uint32_t)GLSLstd450Atanh,
807
22.9k
        (uint32_t)GLSLstd450Atan2,
808
22.9k
        (uint32_t)GLSLstd450Pow,
809
22.9k
        (uint32_t)GLSLstd450Exp,
810
22.9k
        (uint32_t)GLSLstd450Log,
811
22.9k
        (uint32_t)GLSLstd450Exp2,
812
22.9k
        (uint32_t)GLSLstd450Log2,
813
22.9k
        (uint32_t)GLSLstd450Sqrt,
814
22.9k
        (uint32_t)GLSLstd450InverseSqrt,
815
22.9k
        (uint32_t)GLSLstd450Determinant,
816
22.9k
        (uint32_t)GLSLstd450MatrixInverse,
817
22.9k
        (uint32_t)GLSLstd450ModfStruct,
818
22.9k
        (uint32_t)GLSLstd450FMin,
819
22.9k
        (uint32_t)GLSLstd450UMin,
820
22.9k
        (uint32_t)GLSLstd450SMin,
821
22.9k
        (uint32_t)GLSLstd450FMax,
822
22.9k
        (uint32_t)GLSLstd450UMax,
823
22.9k
        (uint32_t)GLSLstd450SMax,
824
22.9k
        (uint32_t)GLSLstd450FClamp,
825
22.9k
        (uint32_t)GLSLstd450UClamp,
826
22.9k
        (uint32_t)GLSLstd450SClamp,
827
22.9k
        (uint32_t)GLSLstd450FMix,
828
22.9k
        (uint32_t)GLSLstd450IMix,
829
22.9k
        (uint32_t)GLSLstd450Step,
830
22.9k
        (uint32_t)GLSLstd450SmoothStep,
831
22.9k
        (uint32_t)GLSLstd450Fma,
832
22.9k
        (uint32_t)GLSLstd450FrexpStruct,
833
22.9k
        (uint32_t)GLSLstd450Ldexp,
834
22.9k
        (uint32_t)GLSLstd450PackSnorm4x8,
835
22.9k
        (uint32_t)GLSLstd450PackUnorm4x8,
836
22.9k
        (uint32_t)GLSLstd450PackSnorm2x16,
837
22.9k
        (uint32_t)GLSLstd450PackUnorm2x16,
838
22.9k
        (uint32_t)GLSLstd450PackHalf2x16,
839
22.9k
        (uint32_t)GLSLstd450PackDouble2x32,
840
22.9k
        (uint32_t)GLSLstd450UnpackSnorm2x16,
841
22.9k
        (uint32_t)GLSLstd450UnpackUnorm2x16,
842
22.9k
        (uint32_t)GLSLstd450UnpackHalf2x16,
843
22.9k
        (uint32_t)GLSLstd450UnpackSnorm4x8,
844
22.9k
        (uint32_t)GLSLstd450UnpackUnorm4x8,
845
22.9k
        (uint32_t)GLSLstd450UnpackDouble2x32,
846
22.9k
        (uint32_t)GLSLstd450Length,
847
22.9k
        (uint32_t)GLSLstd450Distance,
848
22.9k
        (uint32_t)GLSLstd450Cross,
849
22.9k
        (uint32_t)GLSLstd450Normalize,
850
22.9k
        (uint32_t)GLSLstd450FaceForward,
851
22.9k
        (uint32_t)GLSLstd450Reflect,
852
22.9k
        (uint32_t)GLSLstd450Refract,
853
22.9k
        (uint32_t)GLSLstd450FindILsb,
854
22.9k
        (uint32_t)GLSLstd450FindSMsb,
855
22.9k
        (uint32_t)GLSLstd450FindUMsb,
856
22.9k
        (uint32_t)GLSLstd450InterpolateAtCentroid,
857
22.9k
        (uint32_t)GLSLstd450InterpolateAtSample,
858
22.9k
        (uint32_t)GLSLstd450InterpolateAtOffset,
859
22.9k
        (uint32_t)GLSLstd450NMin,
860
22.9k
        (uint32_t)GLSLstd450NMax,
861
22.9k
        (uint32_t)GLSLstd450NClamp};
862
22.9k
  } else {
863
    // Map the result id to the empty set.
864
62
    combinator_ops_[extension->result_id()];
865
62
  }
866
22.9k
}
867
868
23.2k
void IRContext::InitializeCombinators() {
869
48.0k
  for (auto capability : get_feature_mgr()->GetCapabilities()) {
870
48.0k
    AddCombinatorsForCapability(uint32_t(capability));
871
48.0k
  }
872
873
23.2k
  for (auto& extension : module()->ext_inst_imports()) {
874
22.9k
    AddCombinatorsForExtension(&extension);
875
22.9k
  }
876
877
23.2k
  valid_analyses_ |= kAnalysisCombinators;
878
23.2k
}
879
880
15.2M
void IRContext::RemoveFromIdToName(const Instruction* inst) {
881
15.2M
  if (id_to_name_ && (inst->opcode() == spv::Op::OpName ||
882
5.45M
                      inst->opcode() == spv::Op::OpMemberName)) {
883
40.8k
    auto range = id_to_name_->equal_range(inst->GetSingleWordInOperand(0));
884
55.9k
    for (auto it = range.first; it != range.second; ++it) {
885
55.9k
      if (it->second == inst) {
886
40.8k
        id_to_name_->erase(it);
887
40.8k
        break;
888
40.8k
      }
889
55.9k
    }
890
40.8k
  }
891
15.2M
}
892
893
29.1k
LoopDescriptor* IRContext::GetLoopDescriptor(const Function* f) {
894
29.1k
  if (!AreAnalysesValid(kAnalysisLoopAnalysis)) {
895
4.68k
    ResetLoopAnalysis();
896
4.68k
  }
897
898
29.1k
  std::unordered_map<const Function*, LoopDescriptor>::iterator it =
899
29.1k
      loop_descriptors_.find(f);
900
29.1k
  if (it == loop_descriptors_.end()) {
901
6.14k
    return &loop_descriptors_
902
6.14k
                .emplace(std::make_pair(f, LoopDescriptor(this, f)))
903
6.14k
                .first->second;
904
6.14k
  }
905
906
22.9k
  return &it->second;
907
29.1k
}
908
909
0
uint32_t IRContext::FindBuiltinInputVar(uint32_t builtin) {
910
0
  for (auto& a : module_->annotations()) {
911
0
    if (spv::Op(a.opcode()) != spv::Op::OpDecorate) continue;
912
0
    if (spv::Decoration(a.GetSingleWordInOperand(
913
0
            kSpvDecorateDecorationInIdx)) != spv::Decoration::BuiltIn)
914
0
      continue;
915
0
    if (a.GetSingleWordInOperand(kSpvDecorateBuiltinInIdx) != builtin) continue;
916
0
    uint32_t target_id = a.GetSingleWordInOperand(kSpvDecorateTargetIdInIdx);
917
0
    Instruction* b_var = get_def_use_mgr()->GetDef(target_id);
918
0
    if (b_var->opcode() != spv::Op::OpVariable) continue;
919
0
    if (spv::StorageClass(b_var->GetSingleWordInOperand(0)) !=
920
0
        spv::StorageClass::Input)
921
0
      continue;
922
0
    return target_id;
923
0
  }
924
0
  return 0;
925
0
}
926
927
0
void IRContext::AddVarToEntryPoints(uint32_t var_id) {
928
0
  uint32_t ocnt = 0;
929
0
  for (auto& e : module()->entry_points()) {
930
0
    bool found = false;
931
0
    e.ForEachInOperand([&ocnt, &found, &var_id](const uint32_t* idp) {
932
0
      if (ocnt >= kEntryPointInterfaceInIdx) {
933
0
        if (*idp == var_id) found = true;
934
0
      }
935
0
      ++ocnt;
936
0
    });
937
0
    if (!found) {
938
0
      e.AddOperand({SPV_OPERAND_TYPE_ID, {var_id}});
939
0
      get_def_use_mgr()->AnalyzeInstDefUse(&e);
940
0
    }
941
0
  }
942
0
}
943
944
0
uint32_t IRContext::GetBuiltinInputVarId(uint32_t builtin) {
945
0
  if (!AreAnalysesValid(kAnalysisBuiltinVarId)) ResetBuiltinAnalysis();
946
  // If cached, return it.
947
0
  std::unordered_map<uint32_t, uint32_t>::iterator it =
948
0
      builtin_var_id_map_.find(builtin);
949
0
  if (it != builtin_var_id_map_.end()) return it->second;
950
  // Look for one in shader
951
0
  uint32_t var_id = FindBuiltinInputVar(builtin);
952
0
  if (var_id == 0) {
953
    // If not found, create it
954
    // TODO(greg-lunarg): Add support for all builtins
955
0
    analysis::TypeManager* type_mgr = get_type_mgr();
956
0
    analysis::Type* reg_type;
957
0
    switch (spv::BuiltIn(builtin)) {
958
0
      case spv::BuiltIn::FragCoord: {
959
0
        analysis::Float float_ty(32);
960
0
        analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
961
0
        analysis::Vector v4float_ty(reg_float_ty, 4);
962
0
        reg_type = type_mgr->GetRegisteredType(&v4float_ty);
963
0
        break;
964
0
      }
965
0
      case spv::BuiltIn::VertexIndex:
966
0
      case spv::BuiltIn::InstanceIndex:
967
0
      case spv::BuiltIn::PrimitiveId:
968
0
      case spv::BuiltIn::InvocationId:
969
0
      case spv::BuiltIn::SubgroupLocalInvocationId: {
970
0
        analysis::Integer uint_ty(32, false);
971
0
        reg_type = type_mgr->GetRegisteredType(&uint_ty);
972
0
        break;
973
0
      }
974
0
      case spv::BuiltIn::GlobalInvocationId:
975
0
      case spv::BuiltIn::LaunchIdNV: {
976
0
        analysis::Integer uint_ty(32, false);
977
0
        analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
978
0
        analysis::Vector v3uint_ty(reg_uint_ty, 3);
979
0
        reg_type = type_mgr->GetRegisteredType(&v3uint_ty);
980
0
        break;
981
0
      }
982
0
      case spv::BuiltIn::TessCoord: {
983
0
        analysis::Float float_ty(32);
984
0
        analysis::Type* reg_float_ty = type_mgr->GetRegisteredType(&float_ty);
985
0
        analysis::Vector v3float_ty(reg_float_ty, 3);
986
0
        reg_type = type_mgr->GetRegisteredType(&v3float_ty);
987
0
        break;
988
0
      }
989
0
      case spv::BuiltIn::SubgroupLtMask: {
990
0
        analysis::Integer uint_ty(32, false);
991
0
        analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty);
992
0
        analysis::Vector v4uint_ty(reg_uint_ty, 4);
993
0
        reg_type = type_mgr->GetRegisteredType(&v4uint_ty);
994
0
        break;
995
0
      }
996
0
      default: {
997
0
        assert(false && "unhandled builtin");
998
0
        return 0;
999
0
      }
1000
0
    }
1001
0
    if (reg_type == nullptr) return 0;  // Error
1002
1003
0
    uint32_t type_id = type_mgr->GetTypeInstruction(reg_type);
1004
0
    uint32_t varTyPtrId =
1005
0
        type_mgr->FindPointerToType(type_id, spv::StorageClass::Input);
1006
0
    var_id = TakeNextId();
1007
0
    if (var_id == 0) return 0;  // Error
1008
0
    std::unique_ptr<Instruction> newVarOp(
1009
0
        new Instruction(this, spv::Op::OpVariable, varTyPtrId, var_id,
1010
0
                        {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER,
1011
0
                          {uint32_t(spv::StorageClass::Input)}}}));
1012
0
    get_def_use_mgr()->AnalyzeInstDefUse(&*newVarOp);
1013
0
    module()->AddGlobalValue(std::move(newVarOp));
1014
0
    get_decoration_mgr()->AddDecorationVal(
1015
0
        var_id, uint32_t(spv::Decoration::BuiltIn), builtin);
1016
0
    AddVarToEntryPoints(var_id);
1017
0
  }
1018
0
  builtin_var_id_map_[builtin] = var_id;
1019
0
  return var_id;
1020
0
}
1021
1022
172k
void IRContext::AddCalls(const Function* func, std::queue<uint32_t>* todo) {
1023
8.01M
  for (auto bi = func->begin(); bi != func->end(); ++bi)
1024
46.0M
    for (auto ii = bi->begin(); ii != bi->end(); ++ii) {
1025
38.1M
      if (ii->opcode() == spv::Op::OpFunctionCall)
1026
188k
        todo->push(ii->GetSingleWordInOperand(0));
1027
38.1M
      if (ii->opcode() == spv::Op::OpCooperativeMatrixPerElementOpEXT)
1028
0
        todo->push(ii->GetSingleWordInOperand(1));
1029
38.1M
      if (ii->opcode() == spv::Op::OpCooperativeMatrixReduceEXT)
1030
0
        todo->push(ii->GetSingleWordInOperand(2));
1031
38.1M
      if (ii->opcode() == spv::Op::OpCooperativeMatrixLoadTensorNV) {
1032
0
        const auto memory_operands_index = 3;
1033
0
        auto mask = ii->GetSingleWordInOperand(memory_operands_index);
1034
1035
0
        uint32_t count = 1;
1036
0
        if (mask & uint32_t(spv::MemoryAccessMask::Aligned)) ++count;
1037
0
        if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR))
1038
0
          ++count;
1039
0
        if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR))
1040
0
          ++count;
1041
1042
0
        const auto tensor_operands_index = memory_operands_index + count;
1043
0
        mask = ii->GetSingleWordInOperand(tensor_operands_index);
1044
0
        count = 1;
1045
0
        if (mask & uint32_t(spv::TensorAddressingOperandsMask::TensorView))
1046
0
          ++count;
1047
1048
0
        if (mask & uint32_t(spv::TensorAddressingOperandsMask::DecodeFunc)) {
1049
0
          todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count));
1050
0
          ++count;
1051
0
        }
1052
0
        if (mask &
1053
0
            uint32_t(spv::TensorAddressingOperandsMask::DecodeVectorFunc)) {
1054
0
          todo->push(ii->GetSingleWordInOperand(tensor_operands_index + count));
1055
0
        }
1056
0
      }
1057
38.1M
    }
1058
172k
}
1059
1060
0
bool IRContext::ProcessEntryPointCallTree(ProcessFunction& pfn) {
1061
  // Collect all of the entry points as the roots.
1062
0
  std::queue<uint32_t> roots;
1063
0
  for (auto& e : module()->entry_points()) {
1064
0
    roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
1065
0
  }
1066
0
  return ProcessCallTreeFromRoots(pfn, &roots);
1067
0
}
1068
1069
104k
bool IRContext::ProcessReachableCallTree(ProcessFunction& pfn) {
1070
104k
  std::queue<uint32_t> roots;
1071
1072
  // Add all entry points since they can be reached from outside the module.
1073
104k
  for (auto& e : module()->entry_points())
1074
96.7k
    roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx));
1075
1076
  // Add all exported functions since they can be reached from outside the
1077
  // module.
1078
47.3M
  for (auto& a : annotations()) {
1079
    // TODO: Handle group decorations as well.  Currently not generate by any
1080
    // front-end, but could be coming.
1081
47.3M
    if (a.opcode() == spv::Op::OpDecorate) {
1082
1.55M
      if (spv::Decoration(a.GetSingleWordOperand(1)) ==
1083
1.55M
          spv::Decoration::LinkageAttributes) {
1084
0
        uint32_t lastOperand = a.NumOperands() - 1;
1085
0
        if (spv::LinkageType(a.GetSingleWordOperand(lastOperand)) ==
1086
0
            spv::LinkageType::Export) {
1087
0
          uint32_t id = a.GetSingleWordOperand(0);
1088
0
          if (GetFunction(id)) {
1089
0
            roots.push(id);
1090
0
          }
1091
0
        }
1092
0
      }
1093
1.55M
    }
1094
47.3M
  }
1095
1096
104k
  return ProcessCallTreeFromRoots(pfn, &roots);
1097
104k
}
1098
1099
bool IRContext::ProcessCallTreeFromRoots(ProcessFunction& pfn,
1100
117k
                                         std::queue<uint32_t>* roots) {
1101
  // Process call tree
1102
117k
  bool modified = false;
1103
117k
  std::unordered_set<uint32_t> done;
1104
1105
402k
  while (!roots->empty()) {
1106
285k
    const uint32_t fi = roots->front();
1107
285k
    roots->pop();
1108
285k
    if (done.insert(fi).second) {
1109
160k
      Function* fn = GetFunction(fi);
1110
160k
      assert(fn && "Trying to process a function that does not exist.");
1111
160k
      modified = pfn(fn) || modified;
1112
160k
      AddCalls(fn, roots);
1113
160k
    }
1114
285k
  }
1115
117k
  return modified;
1116
117k
}
1117
1118
void IRContext::CollectCallTreeFromRoots(unsigned entryId,
1119
0
                                         std::unordered_set<uint32_t>* funcs) {
1120
0
  std::queue<uint32_t> roots;
1121
0
  roots.push(entryId);
1122
0
  while (!roots.empty()) {
1123
0
    const uint32_t fi = roots.front();
1124
0
    roots.pop();
1125
0
    funcs->insert(fi);
1126
0
    Function* fn = GetFunction(fi);
1127
0
    AddCalls(fn, &roots);
1128
0
  }
1129
0
}
1130
1131
0
void IRContext::EmitErrorMessage(std::string message, Instruction* inst) {
1132
0
  if (!consumer()) {
1133
0
    return;
1134
0
  }
1135
1136
0
  Instruction* line_inst = inst;
1137
0
  while (line_inst != nullptr) {  // Stop at the beginning of the basic block.
1138
0
    if (!line_inst->dbg_line_insts().empty()) {
1139
0
      line_inst = &line_inst->dbg_line_insts().back();
1140
0
      if (line_inst->IsNoLine()) {
1141
0
        line_inst = nullptr;
1142
0
      }
1143
0
      break;
1144
0
    }
1145
0
    line_inst = line_inst->PreviousNode();
1146
0
  }
1147
1148
0
  uint32_t line_number = 0;
1149
0
  uint32_t col_number = 0;
1150
0
  std::string source;
1151
0
  if (line_inst != nullptr) {
1152
0
    Instruction* file_name =
1153
0
        get_def_use_mgr()->GetDef(line_inst->GetSingleWordInOperand(0));
1154
0
    source = file_name->GetInOperand(0).AsString();
1155
1156
    // Get the line number and column number.
1157
0
    line_number = line_inst->GetSingleWordInOperand(1);
1158
0
    col_number = line_inst->GetSingleWordInOperand(2);
1159
0
  }
1160
1161
0
  message +=
1162
0
      "\n  " + inst->PrettyPrint(SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
1163
0
  consumer()(SPV_MSG_ERROR, source.c_str(), {line_number, col_number, 0},
1164
0
             message.c_str());
1165
0
}
1166
1167
// Gets the dominator analysis for function |f|.
1168
837k
DominatorAnalysis* IRContext::GetDominatorAnalysis(const Function* f) {
1169
837k
  if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
1170
26.0k
    ResetDominatorAnalysis();
1171
26.0k
  }
1172
1173
837k
  if (dominator_trees_.find(f) == dominator_trees_.end()) {
1174
35.0k
    dominator_trees_[f].InitializeTree(*cfg(), f);
1175
35.0k
  }
1176
1177
837k
  return &dominator_trees_[f];
1178
837k
}
1179
1180
// Gets the postdominator analysis for function |f|.
1181
0
PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(const Function* f) {
1182
0
  if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
1183
0
    ResetDominatorAnalysis();
1184
0
  }
1185
1186
0
  if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) {
1187
0
    post_dominator_trees_[f].InitializeTree(*cfg(), f);
1188
0
  }
1189
1190
0
  return &post_dominator_trees_[f];
1191
0
}
1192
1193
189k
bool IRContext::CheckCFG() {
1194
189k
  std::unordered_map<uint32_t, std::vector<uint32_t>> real_preds;
1195
189k
  if (!AreAnalysesValid(kAnalysisCFG)) {
1196
79.7k
    return true;
1197
79.7k
  }
1198
1199
149k
  for (Function& function : *module()) {
1200
7.78M
    for (const auto& bb : function) {
1201
9.54M
      bb.ForEachSuccessorLabel([&bb, &real_preds](const uint32_t lab_id) {
1202
9.54M
        real_preds[lab_id].push_back(bb.id());
1203
9.54M
      });
1204
7.78M
    }
1205
1206
7.78M
    for (auto& bb : function) {
1207
7.78M
      std::vector<uint32_t> preds = cfg()->preds(bb.id());
1208
7.78M
      std::vector<uint32_t> real = real_preds[bb.id()];
1209
7.78M
      std::sort(preds.begin(), preds.end());
1210
7.78M
      std::sort(real.begin(), real.end());
1211
1212
7.78M
      bool same = true;
1213
7.78M
      if (preds.size() != real.size()) {
1214
0
        same = false;
1215
0
      }
1216
1217
17.3M
      for (size_t i = 0; i < real.size() && same; i++) {
1218
9.54M
        if (preds[i] != real[i]) {
1219
0
          same = false;
1220
0
        }
1221
9.54M
      }
1222
1223
7.78M
      if (!same) {
1224
0
        std::cerr << "Predecessors for " << bb.id() << " are different:\n";
1225
1226
0
        std::cerr << "Real:";
1227
0
        for (uint32_t i : real) {
1228
0
          std::cerr << ' ' << i;
1229
0
        }
1230
0
        std::cerr << std::endl;
1231
1232
0
        std::cerr << "Recorded:";
1233
0
        for (uint32_t i : preds) {
1234
0
          std::cerr << ' ' << i;
1235
0
        }
1236
0
        std::cerr << std::endl;
1237
0
      }
1238
7.78M
      if (!same) return false;
1239
7.78M
    }
1240
149k
  }
1241
1242
109k
  return true;
1243
109k
}
1244
1245
518k
bool IRContext::IsReachable(const opt::BasicBlock& bb) {
1246
518k
  auto enclosing_function = bb.GetParent();
1247
518k
  return GetDominatorAnalysis(enclosing_function)
1248
518k
      ->Dominates(enclosing_function->entry().get(), &bb);
1249
518k
}
1250
1251
0
spv::ExecutionModel IRContext::GetStage() {
1252
0
  const auto& entry_points = module()->entry_points();
1253
0
  if (entry_points.empty()) {
1254
0
    return spv::ExecutionModel::Max;
1255
0
  }
1256
1257
0
  uint32_t stage = entry_points.begin()->GetSingleWordInOperand(
1258
0
      kEntryPointExecutionModelInIdx);
1259
0
  auto it = std::find_if(
1260
0
      entry_points.begin(), entry_points.end(), [stage](const Instruction& x) {
1261
0
        return x.GetSingleWordInOperand(kEntryPointExecutionModelInIdx) !=
1262
0
               stage;
1263
0
      });
1264
0
  if (it != entry_points.end()) {
1265
0
    EmitErrorMessage("Mixed stage shader module not supported", &(*it));
1266
0
  }
1267
1268
0
  return static_cast<spv::ExecutionModel>(stage);
1269
0
}
1270
1271
}  // namespace opt
1272
}  // namespace spvtools