Coverage Report

Created: 2026-06-08 06:54

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