Coverage Report

Created: 2025-11-16 06:14

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