Coverage Report

Created: 2026-05-16 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/opt/ir_context.h
Line
Count
Source
1
// Copyright (c) 2017 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef SOURCE_OPT_IR_CONTEXT_H_
16
#define SOURCE_OPT_IR_CONTEXT_H_
17
18
#include <algorithm>
19
#include <iostream>
20
#include <limits>
21
#include <map>
22
#include <memory>
23
#include <queue>
24
#include <unordered_map>
25
#include <unordered_set>
26
#include <utility>
27
#include <vector>
28
29
#include "source/assembly_grammar.h"
30
#include "source/opt/cfg.h"
31
#include "source/opt/constants.h"
32
#include "source/opt/debug_info_manager.h"
33
#include "source/opt/decoration_manager.h"
34
#include "source/opt/def_use_manager.h"
35
#include "source/opt/dominator_analysis.h"
36
#include "source/opt/feature_manager.h"
37
#include "source/opt/fold.h"
38
#include "source/opt/liveness.h"
39
#include "source/opt/loop_descriptor.h"
40
#include "source/opt/module.h"
41
#include "source/opt/register_pressure.h"
42
#include "source/opt/scalar_analysis.h"
43
#include "source/opt/struct_cfg_analysis.h"
44
#include "source/opt/type_manager.h"
45
#include "source/opt/value_number_table.h"
46
#include "source/table2.h"
47
#include "source/util/make_unique.h"
48
#include "source/util/string_utils.h"
49
50
namespace spvtools {
51
namespace opt {
52
53
class IRContext {
54
 public:
55
  // Available analyses.
56
  //
57
  // When adding a new analysis:
58
  //
59
  // 1. Enum values should be powers of 2. These are cast into uint32_t
60
  //    bitmasks, so we can have at most 31 analyses represented.
61
  //
62
  // 2. Make sure it gets invalidated or preserved by IRContext methods that add
63
  //    or remove IR elements (e.g., KillDef, KillInst, ReplaceAllUsesWith).
64
  //
65
  // 3. Add handling code in BuildInvalidAnalyses and InvalidateAnalyses
66
  enum Analysis {
67
    kAnalysisNone = 0 << 0,
68
    kAnalysisBegin = 1 << 0,
69
    kAnalysisDefUse = kAnalysisBegin,
70
    kAnalysisInstrToBlockMapping = 1 << 1,
71
    kAnalysisDecorations = 1 << 2,
72
    kAnalysisCombinators = 1 << 3,
73
    kAnalysisCFG = 1 << 4,
74
    kAnalysisDominatorAnalysis = 1 << 5,
75
    kAnalysisLoopAnalysis = 1 << 6,
76
    kAnalysisNameMap = 1 << 7,
77
    kAnalysisScalarEvolution = 1 << 8,
78
    kAnalysisRegisterPressure = 1 << 9,
79
    kAnalysisValueNumberTable = 1 << 10,
80
    kAnalysisStructuredCFG = 1 << 11,
81
    kAnalysisBuiltinVarId = 1 << 12,
82
    kAnalysisIdToFuncMapping = 1 << 13,
83
    kAnalysisConstants = 1 << 14,
84
    kAnalysisTypes = 1 << 15,
85
    kAnalysisDebugInfo = 1 << 16,
86
    kAnalysisLiveness = 1 << 17,
87
    kAnalysisIdToGraphMapping = 1 << 18,
88
    kAnalysisEnd = 1 << 19
89
  };
90
91
  using ProcessFunction = std::function<bool(Function*)>;
92
93
  friend inline Analysis operator|(Analysis lhs, Analysis rhs);
94
  friend inline Analysis& operator|=(Analysis& lhs, Analysis rhs);
95
  friend inline Analysis operator<<(Analysis a, int shift);
96
  friend inline Analysis& operator<<=(Analysis& a, int shift);
97
98
  // Creates an |IRContext| that contains an owned |Module|
99
  IRContext(spv_target_env env, MessageConsumer c)
100
59.6k
      : syntax_context_(spvContextCreate(env)),
101
59.6k
        grammar_(syntax_context_),
102
59.6k
        unique_id_(0),
103
59.6k
        module_(new Module()),
104
59.6k
        consumer_(std::move(c)),
105
59.6k
        def_use_mgr_(nullptr),
106
59.6k
        feature_mgr_(nullptr),
107
59.6k
        valid_analyses_(kAnalysisNone),
108
59.6k
        constant_mgr_(nullptr),
109
59.6k
        type_mgr_(nullptr),
110
59.6k
        id_to_name_(nullptr),
111
59.6k
        max_id_bound_(kDefaultMaxIdBound),
112
59.6k
        preserve_bindings_(false),
113
59.6k
        preserve_spec_constants_(false),
114
59.6k
        id_overflow_(false) {
115
59.6k
    SetContextMessageConsumer(syntax_context_, consumer_);
116
59.6k
    module_->SetContext(this);
117
59.6k
  }
118
119
  IRContext(spv_target_env env, std::unique_ptr<Module>&& m, MessageConsumer c)
120
      : syntax_context_(spvContextCreate(env)),
121
        grammar_(syntax_context_),
122
        unique_id_(0),
123
        module_(std::move(m)),
124
        consumer_(std::move(c)),
125
        def_use_mgr_(nullptr),
126
        feature_mgr_(nullptr),
127
        valid_analyses_(kAnalysisNone),
128
        type_mgr_(nullptr),
129
        id_to_name_(nullptr),
130
        max_id_bound_(kDefaultMaxIdBound),
131
        preserve_bindings_(false),
132
        preserve_spec_constants_(false),
133
0
        id_overflow_(false) {
134
0
    SetContextMessageConsumer(syntax_context_, consumer_);
135
0
    module_->SetContext(this);
136
0
    InitializeCombinators();
137
0
  }
138
139
59.6k
  ~IRContext() { spvContextDestroy(syntax_context_); }
140
141
15.3M
  Module* module() const { return module_.get(); }
142
143
  // Returns a vector of pointers to constant-creation instructions in this
144
  // context.
145
  inline std::vector<Instruction*> GetConstants();
146
  inline std::vector<const Instruction*> GetConstants() const;
147
148
  // Iterators for annotation instructions contained in this context.
149
  inline Module::inst_iterator annotation_begin();
150
  inline Module::inst_iterator annotation_end();
151
  inline IteratorRange<Module::inst_iterator> annotations();
152
  inline IteratorRange<Module::const_inst_iterator> annotations() const;
153
154
  // Iterators for capabilities instructions contained in this module.
155
  inline Module::inst_iterator capability_begin();
156
  inline Module::inst_iterator capability_end();
157
  inline IteratorRange<Module::inst_iterator> capabilities();
158
  inline IteratorRange<Module::const_inst_iterator> capabilities() const;
159
160
  // Iterators for extensions instructions contained in this module.
161
  inline Module::inst_iterator extension_begin();
162
  inline Module::inst_iterator extension_end();
163
  inline IteratorRange<Module::inst_iterator> extensions();
164
  inline IteratorRange<Module::const_inst_iterator> extensions() const;
165
166
  // Iterators for types, constants and global variables instructions.
167
  inline Module::inst_iterator types_values_begin();
168
  inline Module::inst_iterator types_values_end();
169
  inline IteratorRange<Module::inst_iterator> types_values();
170
  inline IteratorRange<Module::const_inst_iterator> types_values() const;
171
172
  // Iterators for ext_inst import instructions contained in this module.
173
  inline Module::inst_iterator ext_inst_import_begin();
174
  inline Module::inst_iterator ext_inst_import_end();
175
  inline IteratorRange<Module::inst_iterator> ext_inst_imports();
176
  inline IteratorRange<Module::const_inst_iterator> ext_inst_imports() const;
177
178
  // There are several kinds of debug instructions, according to where they can
179
  // appear in the logical layout of a module:
180
  //  - Section 7a:  OpString, OpSourceExtension, OpSource, OpSourceContinued
181
  //  - Section 7b:  OpName, OpMemberName
182
  //  - Section 7c:  OpModuleProcessed
183
  //  - Mostly anywhere: OpLine and OpNoLine
184
  //
185
186
  // Iterators for debug 1 instructions (excluding OpLine & OpNoLine) contained
187
  // in this module.  These are for layout section 7a.
188
  inline Module::inst_iterator debug1_begin();
189
  inline Module::inst_iterator debug1_end();
190
  inline IteratorRange<Module::inst_iterator> debugs1();
191
  inline IteratorRange<Module::const_inst_iterator> debugs1() const;
192
193
  // Iterators for debug 2 instructions (excluding OpLine & OpNoLine) contained
194
  // in this module.  These are for layout section 7b.
195
  inline Module::inst_iterator debug2_begin();
196
  inline Module::inst_iterator debug2_end();
197
  inline IteratorRange<Module::inst_iterator> debugs2();
198
  inline IteratorRange<Module::const_inst_iterator> debugs2() const;
199
200
  // Iterators for debug 3 instructions (excluding OpLine & OpNoLine) contained
201
  // in this module.  These are for layout section 7c.
202
  inline Module::inst_iterator debug3_begin();
203
  inline Module::inst_iterator debug3_end();
204
  inline IteratorRange<Module::inst_iterator> debugs3();
205
  inline IteratorRange<Module::const_inst_iterator> debugs3() const;
206
207
  // Iterators for debug info instructions (excluding OpLine & OpNoLine)
208
  // contained in this module.  These are OpExtInst &
209
  // OpExtInstWithForwardRefsKHR for DebugInfo extension placed between section
210
  // 9 and 10.
211
  inline Module::inst_iterator ext_inst_debuginfo_begin();
212
  inline Module::inst_iterator ext_inst_debuginfo_end();
213
  inline IteratorRange<Module::inst_iterator> ext_inst_debuginfo();
214
  inline IteratorRange<Module::const_inst_iterator> ext_inst_debuginfo() const;
215
216
  // Add |capability| to the module, if it is not already enabled.
217
  inline void AddCapability(spv::Capability capability);
218
  // Appends a capability instruction to this module.
219
  inline void AddCapability(std::unique_ptr<Instruction>&& c);
220
  // Removes instruction declaring `capability` from this module.
221
  // Returns true if the capability was removed, false otherwise.
222
  bool RemoveCapability(spv::Capability capability);
223
224
  // Appends an extension instruction to this module.
225
  inline void AddExtension(const std::string& ext_name);
226
  inline void AddExtension(std::unique_ptr<Instruction>&& e);
227
  // Removes instruction declaring `extension` from this module.
228
  // Returns true if the extension was removed, false otherwise.
229
  bool RemoveExtension(Extension extension);
230
231
  // Appends an extended instruction set instruction to this module.
232
  inline void AddExtInstImport(const std::string& name);
233
  inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
234
  // Set the memory model for this module.
235
  inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
236
  // Get the memory model for this module.
237
  inline const Instruction* GetMemoryModel() const;
238
  // Appends an entry point instruction to this module.
239
  inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
240
  // Appends an execution mode instruction to this module.
241
  inline void AddExecutionMode(std::unique_ptr<Instruction>&& e);
242
  // Appends a debug 1 instruction (excluding OpLine & OpNoLine) to this module.
243
  // "debug 1" instructions are the ones in layout section 7.a), see section
244
  // 2.4 Logical Layout of a Module from the SPIR-V specification.
245
  inline void AddDebug1Inst(std::unique_ptr<Instruction>&& d);
246
  // Appends a debug 2 instruction (excluding OpLine & OpNoLine) to this module.
247
  // "debug 2" instructions are the ones in layout section 7.b), see section
248
  // 2.4 Logical Layout of a Module from the SPIR-V specification.
249
  inline void AddDebug2Inst(std::unique_ptr<Instruction>&& d);
250
  // Appends a debug 3 instruction (OpModuleProcessed) to this module.
251
  // This is due to decision by the SPIR Working Group, pending publication.
252
  inline void AddDebug3Inst(std::unique_ptr<Instruction>&& d);
253
  // Appends a OpExtInst for DebugInfo to this module.
254
  inline void AddExtInstDebugInfo(std::unique_ptr<Instruction>&& d);
255
  // Appends an annotation instruction to this module.
256
  inline void AddAnnotationInst(std::unique_ptr<Instruction>&& a);
257
  // Appends a type-declaration instruction to this module.
258
  inline void AddType(std::unique_ptr<Instruction>&& t);
259
  // Appends a constant, global variable, or OpUndef instruction to this module.
260
  inline void AddGlobalValue(std::unique_ptr<Instruction>&& v);
261
  // Prepends a function declaration to this module.
262
  inline void AddFunctionDeclaration(std::unique_ptr<Function>&& f);
263
  // Appends a function to this module.
264
  inline void AddFunction(std::unique_ptr<Function>&& f);
265
266
  // Returns a pointer to a def-use manager.  If the def-use manager is
267
  // invalid, it is rebuilt first.
268
216M
  analysis::DefUseManager* get_def_use_mgr() {
269
216M
    if (!AreAnalysesValid(kAnalysisDefUse)) {
270
36.1k
      BuildDefUseManager();
271
36.1k
    }
272
216M
    return def_use_mgr_.get();
273
216M
  }
274
275
  // Returns a pointer to a liveness manager.  If the liveness manager is
276
  // invalid, it is rebuilt first.
277
0
  analysis::LivenessManager* get_liveness_mgr() {
278
0
    if (!AreAnalysesValid(kAnalysisLiveness)) {
279
0
      BuildLivenessManager();
280
0
    }
281
0
    return liveness_mgr_.get();
282
0
  }
283
284
  // Returns a pointer to a value number table.  If the liveness analysis is
285
  // invalid, it is rebuilt first.
286
11.0k
  ValueNumberTable* GetValueNumberTable() {
287
11.0k
    if (!AreAnalysesValid(kAnalysisValueNumberTable)) {
288
11.0k
      BuildValueNumberTable();
289
11.0k
    }
290
11.0k
    return vn_table_.get();
291
11.0k
  }
292
293
  // Returns a pointer to a StructuredCFGAnalysis.  If the analysis is invalid,
294
  // it is rebuilt first.
295
16.8M
  StructuredCFGAnalysis* GetStructuredCFGAnalysis() {
296
16.8M
    if (!AreAnalysesValid(kAnalysisStructuredCFG)) {
297
80.9k
      BuildStructuredCFGAnalysis();
298
80.9k
    }
299
16.8M
    return struct_cfg_analysis_.get();
300
16.8M
  }
301
302
  // Returns a pointer to a liveness analysis.  If the liveness analysis is
303
  // invalid, it is rebuilt first.
304
0
  LivenessAnalysis* GetLivenessAnalysis() {
305
0
    if (!AreAnalysesValid(kAnalysisRegisterPressure)) {
306
0
      BuildRegPressureAnalysis();
307
0
    }
308
0
    return reg_pressure_.get();
309
0
  }
310
311
  // Returns the basic block for instruction |instr|. Re-builds the instruction
312
  // block map, if needed.
313
69.8M
  BasicBlock* get_instr_block(Instruction* instr) {
314
69.8M
    if (!AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
315
34.1k
      BuildInstrToBlockMapping();
316
34.1k
    }
317
69.8M
    auto entry = instr_to_block_.find(instr);
318
69.8M
    return (entry != instr_to_block_.end()) ? entry->second : nullptr;
319
69.8M
  }
320
321
  // Returns the basic block for |id|. Re-builds the instruction block map, if
322
  // needed.
323
  //
324
  // |id| must be a registered definition.
325
24.7M
  BasicBlock* get_instr_block(uint32_t id) {
326
24.7M
    Instruction* def = get_def_use_mgr()->GetDef(id);
327
24.7M
    return get_instr_block(def);
328
24.7M
  }
329
330
  // Sets the basic block for |inst|. Re-builds the mapping if it has become
331
  // invalid.
332
4.67M
  void set_instr_block(Instruction* inst, BasicBlock* block) {
333
4.67M
    if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
334
4.67M
      instr_to_block_[inst] = block;
335
4.67M
    }
336
4.67M
  }
337
338
  // Returns a pointer the decoration manager.  If the decoration manager is
339
  // invalid, it is rebuilt first.
340
42.5M
  analysis::DecorationManager* get_decoration_mgr() {
341
42.5M
    if (!AreAnalysesValid(kAnalysisDecorations)) {
342
153k
      BuildDecorationManager();
343
153k
    }
344
42.5M
    return decoration_mgr_.get();
345
42.5M
  }
346
347
  // Returns a pointer to the constant manager.  If no constant manager has been
348
  // created yet, it creates one.  NOTE: Once created, the constant manager
349
  // remains active and it is never re-built.
350
32.3M
  analysis::ConstantManager* get_constant_mgr() {
351
32.3M
    if (!AreAnalysesValid(kAnalysisConstants)) {
352
33.8k
      BuildConstantManager();
353
33.8k
    }
354
32.3M
    return constant_mgr_.get();
355
32.3M
  }
356
357
  // Returns a pointer to the type manager.  If no type manager has been created
358
  // yet, it creates one. NOTE: Once created, the type manager remains active it
359
  // is never re-built.
360
27.4M
  analysis::TypeManager* get_type_mgr() {
361
27.4M
    if (!AreAnalysesValid(kAnalysisTypes)) {
362
34.0k
      BuildTypeManager();
363
34.0k
    }
364
27.4M
    return type_mgr_.get();
365
27.4M
  }
366
367
  // Returns a pointer to the debug information manager.  If no debug
368
  // information manager has been created yet, it creates one.
369
  // NOTE: Once created, the debug information manager remains active
370
  // it is never re-built.
371
24.7M
  analysis::DebugInfoManager* get_debug_info_mgr() {
372
24.7M
    if (!AreAnalysesValid(kAnalysisDebugInfo)) {
373
25.6k
      BuildDebugInfoManager();
374
25.6k
    }
375
24.7M
    return debug_info_mgr_.get();
376
24.7M
  }
377
378
  // Returns a pointer to the scalar evolution analysis. If it is invalid it
379
  // will be rebuilt first.
380
0
  ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() {
381
0
    if (!AreAnalysesValid(kAnalysisScalarEvolution)) {
382
0
      BuildScalarEvolutionAnalysis();
383
0
    }
384
0
    return scalar_evolution_analysis_.get();
385
0
  }
386
387
  // Build the map from the ids to the OpName and OpMemberName instruction
388
  // associated with it.
389
  inline void BuildIdToNameMap();
390
391
  // Returns a range of instrucions that contain all of the OpName and
392
  // OpMemberNames associated with the given id.
393
  inline IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
394
  GetNames(uint32_t id);
395
396
  // Returns an OpMemberName instruction that targets |struct_type_id| at
397
  // index |index|. Returns nullptr if no such instruction exists.
398
  // While the SPIR-V spec does not prohibit having multiple OpMemberName
399
  // instructions for the same structure member, it is hard to imagine a member
400
  // having more than one name. This method returns the first one it finds.
401
  inline Instruction* GetMemberName(uint32_t struct_type_id, uint32_t index);
402
403
  // Copy names from |old_id| to |new_id|. Only copy member name if index is
404
  // less than |max_member_index|.
405
  inline void CloneNames(const uint32_t old_id, const uint32_t new_id,
406
                         const uint32_t max_member_index = UINT32_MAX);
407
408
  // Sets the message consumer to the given |consumer|. |consumer| which will be
409
  // invoked every time there is a message to be communicated to the outside.
410
0
  void SetMessageConsumer(MessageConsumer c) { consumer_ = std::move(c); }
411
412
  // Returns the reference to the message consumer for this pass.
413
34.0k
  const MessageConsumer& consumer() const { return consumer_; }
414
415
  // Rebuilds the analyses in |set| that are invalid.
416
  void BuildInvalidAnalyses(Analysis set);
417
418
  // Invalidates all of the analyses except for those in |preserved_analyses|.
419
  void InvalidateAnalysesExceptFor(Analysis preserved_analyses);
420
421
  // Invalidates the analyses marked in |analyses_to_invalidate|.
422
  void InvalidateAnalyses(Analysis analyses_to_invalidate);
423
424
  // Deletes the instruction defining the given |id|. Returns true on
425
  // success, false if the given |id| is not defined at all. This method also
426
  // erases the name, decorations, and definition of |id|.
427
  //
428
  // Pointers and iterators pointing to the deleted instructions become invalid.
429
  // However other pointers and iterators are still valid.
430
  bool KillDef(uint32_t id);
431
432
  // Deletes the given instruction |inst|. This method erases the
433
  // information of the given instruction's uses of its operands. If |inst|
434
  // defines a result id, its name and decorations will also be deleted.
435
  //
436
  // Pointer and iterator pointing to the deleted instructions become invalid.
437
  // However other pointers and iterators are still valid.
438
  //
439
  // Note that if an instruction is not in an instruction list, the memory may
440
  // not be safe to delete, so the instruction is turned into a OpNop instead.
441
  // This can happen with OpLabel.
442
  //
443
  // Returns a pointer to the instruction after |inst| or |nullptr| if no such
444
  // instruction exists.
445
  Instruction* KillInst(Instruction* inst);
446
447
  // Deletes all the instruction in the range [`begin`; `end`[, for which the
448
  // unary predicate `condition` returned true.
449
  // Returns true if at least one instruction was removed, false otherwise.
450
  //
451
  // Pointer and iterator pointing to the deleted instructions become invalid.
452
  // However other pointers and iterators are still valid.
453
  bool KillInstructionIf(Module::inst_iterator begin, Module::inst_iterator end,
454
                         std::function<bool(Instruction*)> condition);
455
456
  // Collects the non-semantic instruction tree that uses |inst|'s result id
457
  // to be killed later.
458
  void CollectNonSemanticTree(Instruction* inst,
459
                              std::unordered_set<Instruction*>* to_kill);
460
461
  // Collect function reachable from |entryId|, returns |funcs|
462
  void CollectCallTreeFromRoots(unsigned entryId,
463
                                std::unordered_set<uint32_t>* funcs);
464
465
  // Returns true if all of the given analyses are valid.
466
646M
  bool AreAnalysesValid(Analysis set) { return (set & valid_analyses_) == set; }
467
468
  // Replaces all uses of |before| id with |after| id. Returns true if any
469
  // replacement happens. This method does not kill the definition of the
470
  // |before| id. If |after| is the same as |before|, does nothing and returns
471
  // false.
472
  //
473
  // |before| and |after| must be registered definitions in the DefUseManager.
474
  bool ReplaceAllUsesWith(uint32_t before, uint32_t after);
475
476
  // Replace all uses of |before| id with |after| id if those uses
477
  // (instruction) return true for |predicate|. Returns true if
478
  // any replacement happens. This method does not kill the definition of the
479
  // |before| id. If |after| is the same as |before|, does nothing and return
480
  // false.
481
  bool ReplaceAllUsesWithPredicate(
482
      uint32_t before, uint32_t after,
483
      const std::function<bool(Instruction*)>& predicate);
484
485
  // Returns true if all of the analyses that are suppose to be valid are
486
  // actually valid.
487
  bool IsConsistent();
488
489
  // The IRContext will look at the def and uses of |inst| and update any valid
490
  // analyses will be updated accordingly.
491
  inline void AnalyzeDefUse(Instruction* inst);
492
493
  // Informs the IRContext that the uses of |inst| are going to change, and that
494
  // is should forget everything it know about the current uses.  Any valid
495
  // analyses will be updated accordingly.
496
  void ForgetUses(Instruction* inst);
497
498
  // The IRContext will look at the uses of |inst| and update any valid analyses
499
  // will be updated accordingly.
500
  void AnalyzeUses(Instruction* inst);
501
502
  // Kill all name and decorate ops targeting |id|.
503
  void KillNamesAndDecorates(uint32_t id);
504
505
  // Kill all name and decorate ops targeting the result id of |inst|.
506
  void KillNamesAndDecorates(Instruction* inst);
507
508
  // Change operands of debug instruction to DebugInfoNone.
509
  void KillOperandFromDebugInstructions(Instruction* inst);
510
511
  // Remove the debug scope from any instruction related to |inst|.
512
  void KillRelatedDebugScopes(Instruction* inst);
513
514
  // Returns the next unique id for use by an instruction.
515
46.4M
  inline uint32_t TakeNextUniqueId() {
516
46.4M
    assert(unique_id_ != std::numeric_limits<uint32_t>::max());
517
518
    // Skip zero.
519
46.4M
    return ++unique_id_;
520
46.4M
  }
521
522
  // Returns true if |inst| is a combinator in the current context.
523
  // |combinator_ops_| is built if it has not been already.
524
16.4M
  inline bool IsCombinatorInstruction(const Instruction* inst) {
525
16.4M
    if (!AreAnalysesValid(kAnalysisCombinators)) {
526
53.1k
      InitializeCombinators();
527
53.1k
    }
528
16.4M
    constexpr uint32_t kExtInstSetIdInIndx = 0;
529
16.4M
    constexpr uint32_t kExtInstInstructionInIndx = 1;
530
531
16.4M
    if (inst->opcode() != spv::Op::OpExtInst) {
532
16.0M
      return combinator_ops_[0].count(uint32_t(inst->opcode())) != 0;
533
16.0M
    } else {
534
388k
      uint32_t set = inst->GetSingleWordInOperand(kExtInstSetIdInIndx);
535
388k
      auto op = inst->GetSingleWordInOperand(kExtInstInstructionInIndx);
536
388k
      return combinator_ops_[set].count(op) != 0;
537
388k
    }
538
16.4M
  }
539
540
  // Returns a pointer to the CFG for all the functions in |module_|.
541
36.3M
  CFG* cfg() {
542
36.3M
    if (!AreAnalysesValid(kAnalysisCFG)) {
543
90.3k
      BuildCFG();
544
90.3k
    }
545
36.3M
    return cfg_.get();
546
36.3M
  }
547
548
  // Gets the loop descriptor for function |f|.
549
  LoopDescriptor* GetLoopDescriptor(const Function* f);
550
551
  // Gets the dominator analysis for function |f|.
552
  DominatorAnalysis* GetDominatorAnalysis(const Function* f);
553
554
  // Gets the postdominator analysis for function |f|.
555
  PostDominatorAnalysis* GetPostDominatorAnalysis(const Function* f);
556
557
  // Remove the dominator tree of |f| from the cache.
558
6.68k
  inline void RemoveDominatorAnalysis(const Function* f) {
559
6.68k
    dominator_trees_.erase(f);
560
6.68k
  }
561
562
  // Remove the postdominator tree of |f| from the cache.
563
0
  inline void RemovePostDominatorAnalysis(const Function* f) {
564
0
    post_dominator_trees_.erase(f);
565
0
  }
566
567
  // Return the next available SSA id and increment it.  Returns 0 if the
568
  // maximum SSA id has been reached.
569
8.14M
  inline uint32_t TakeNextId() {
570
8.14M
    uint32_t next_id = module()->TakeNextIdBound();
571
8.14M
    if (next_id == 0) {
572
0
      id_overflow_ = true;
573
0
      if (consumer()) {
574
0
        std::string message = "ID overflow. Try running compact-ids.";
575
0
        consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str());
576
0
      }
577
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
578
      // If TakeNextId returns 0, it is very likely that execution will
579
      // subsequently fail. Such failures are false alarms from a fuzzing point
580
      // of view: they are due to the fact that too many ids were used, rather
581
      // than being due to an actual bug. Thus, during a fuzzing build, it is
582
      // preferable to bail out when ID overflow occurs.
583
      //
584
      // A zero exit code is returned here because a non-zero code would cause
585
      // ClusterFuzz/OSS-Fuzz to regard the termination as a crash, and spurious
586
      // crash reports is what this guard aims to avoid.
587
0
      exit(0);
588
0
#endif
589
0
    }
590
8.14M
    return next_id;
591
8.14M
  }
592
593
  // Returns true if an ID overflow has occurred since the last time the flag
594
  // was cleared.
595
3.10M
  bool id_overflow() const { return id_overflow_; }
596
597
  // Clears the ID overflow flag.
598
0
  void clear_id_overflow() { id_overflow_ = false; }
599
600
52.0M
  FeatureManager* get_feature_mgr() {
601
52.0M
    if (!feature_mgr_.get()) {
602
25.4k
      AnalyzeFeatures();
603
25.4k
    }
604
52.0M
    return feature_mgr_.get();
605
52.0M
  }
606
607
0
  void ResetFeatureManager() { feature_mgr_.reset(nullptr); }
608
609
  // Returns the grammar for this context.
610
0
  const AssemblyGrammar& grammar() const { return grammar_; }
611
612
  // If |inst| has not yet been analysed by the def-use manager, then analyse
613
  // its definitions and uses.
614
  inline void UpdateDefUse(Instruction* inst);
615
616
34.8M
  const InstructionFolder& get_instruction_folder() {
617
34.8M
    if (!inst_folder_) {
618
15.7k
      inst_folder_ = MakeUnique<InstructionFolder>(this);
619
15.7k
    }
620
34.8M
    return *inst_folder_;
621
34.8M
  }
622
623
8.14M
  uint32_t max_id_bound() const { return max_id_bound_; }
624
20.1k
  void set_max_id_bound(uint32_t new_bound) { max_id_bound_ = new_bound; }
625
626
469k
  bool preserve_bindings() const { return preserve_bindings_; }
627
20.1k
  void set_preserve_bindings(bool should_preserve_bindings) {
628
20.1k
    preserve_bindings_ = should_preserve_bindings;
629
20.1k
  }
630
631
469k
  bool preserve_spec_constants() const { return preserve_spec_constants_; }
632
20.1k
  void set_preserve_spec_constants(bool should_preserve_spec_constants) {
633
20.1k
    preserve_spec_constants_ = should_preserve_spec_constants;
634
20.1k
  }
635
636
  // Return id of input variable only decorated with |builtin|, if in module.
637
  // Create variable and return its id otherwise. If builtin not currently
638
  // supported, return 0.
639
  uint32_t GetBuiltinInputVarId(uint32_t builtin);
640
641
  // Returns the function whose id is |id|, if one exists.  Returns |nullptr|
642
  // otherwise.
643
371k
  Function* GetFunction(uint32_t id) {
644
371k
    if (!AreAnalysesValid(kAnalysisIdToFuncMapping)) {
645
111k
      BuildIdToFuncMapping();
646
111k
    }
647
371k
    auto entry = id_to_func_.find(id);
648
371k
    return (entry != id_to_func_.end()) ? entry->second : nullptr;
649
371k
  }
650
651
0
  Function* GetFunction(Instruction* inst) {
652
0
    if (inst->opcode() != spv::Op::OpFunction) {
653
0
      return nullptr;
654
0
    }
655
0
    return GetFunction(inst->result_id());
656
0
  }
657
658
  // Returns the graph whose id is |id|, if one exists.  Returns |nullptr|
659
  // otherwise.
660
0
  Graph* GetGraph(uint32_t id) {
661
0
    if (!AreAnalysesValid(kAnalysisIdToGraphMapping)) {
662
0
      BuildIdToGraphMapping();
663
0
    }
664
0
    auto entry = id_to_graph_.find(id);
665
0
    return (entry != id_to_graph_.end()) ? entry->second : nullptr;
666
0
  }
667
668
0
  Graph* GetGraph(Instruction* inst) {
669
0
    if (inst->opcode() != spv::Op::OpGraphARM) {
670
0
      return nullptr;
671
0
    }
672
0
    return GetGraph(inst->result_id());
673
0
  }
674
675
  // Add to |todo| all ids of functions called directly from |func|.
676
  void AddCalls(const Function* func, std::queue<uint32_t>* todo);
677
678
  // Applies |pfn| to every function in the call trees that are rooted at the
679
  // entry points.  Returns true if any call |pfn| returns true.  By convention
680
  // |pfn| should return true if it modified the module.
681
  bool ProcessEntryPointCallTree(ProcessFunction& pfn);
682
683
  // Applies |pfn| to every function in the call trees rooted at the entry
684
  // points and exported functions.  Returns true if any call |pfn| returns
685
  // true.  By convention |pfn| should return true if it modified the module.
686
  bool ProcessReachableCallTree(ProcessFunction& pfn);
687
688
  // Applies |pfn| to every function in the call trees rooted at the elements of
689
  // |roots|.  Returns true if any call to |pfn| returns true.  By convention
690
  // |pfn| should return true if it modified the module.  After returning
691
  // |roots| will be empty.
692
  bool ProcessCallTreeFromRoots(ProcessFunction& pfn,
693
                                std::queue<uint32_t>* roots);
694
695
  // Emits a error message to the message consumer indicating the error
696
  // described by |message| occurred in |inst|.
697
  void EmitErrorMessage(std::string message, Instruction* inst);
698
699
  // Returns true if and only if there is a path to |bb| from the entry block of
700
  // the function that contains |bb|.
701
  bool IsReachable(const opt::BasicBlock& bb);
702
703
  // Return the stage of the module. Will generate error if entry points don't
704
  // all have the same stage.
705
  spv::ExecutionModel GetStage();
706
707
  // Returns true of the current target environment is at least that of the
708
  // given environment.
709
0
  bool IsTargetEnvAtLeast(spv_target_env env) {
710
    // A bit of a hack. We assume that the target environments are appended to
711
    // the enum, so that there is an appropriate order.
712
0
    return syntax_context_->target_env >= env;
713
0
  }
714
715
  // Return the target environment for the current context.
716
0
  spv_target_env GetTargetEnv() const { return syntax_context_->target_env; }
717
718
 private:
719
  // Builds the def-use manager from scratch, even if it was already valid.
720
36.1k
  void BuildDefUseManager() {
721
36.1k
    def_use_mgr_ = MakeUnique<analysis::DefUseManager>(module());
722
36.1k
    valid_analyses_ = valid_analyses_ | kAnalysisDefUse;
723
36.1k
  }
724
725
  // Builds the liveness manager from scratch, even if it was already valid.
726
0
  void BuildLivenessManager() {
727
0
    liveness_mgr_ = MakeUnique<analysis::LivenessManager>(this);
728
0
    valid_analyses_ = valid_analyses_ | kAnalysisLiveness;
729
0
  }
730
731
  // Builds the instruction-block map for the whole module.
732
34.1k
  void BuildInstrToBlockMapping() {
733
34.1k
    instr_to_block_.clear();
734
50.2k
    for (auto& fn : *module_) {
735
2.42M
      for (auto& block : fn) {
736
14.4M
        block.ForEachInst([this, &block](Instruction* inst) {
737
14.4M
          instr_to_block_[inst] = &block;
738
14.4M
        });
739
2.42M
      }
740
50.2k
    }
741
34.1k
    valid_analyses_ = valid_analyses_ | kAnalysisInstrToBlockMapping;
742
34.1k
  }
743
744
  // Builds the instruction-function map for the whole module.
745
111k
  void BuildIdToFuncMapping() {
746
111k
    id_to_func_.clear();
747
171k
    for (auto& fn : *module_) {
748
171k
      id_to_func_[fn.result_id()] = &fn;
749
171k
    }
750
111k
    valid_analyses_ = valid_analyses_ | kAnalysisIdToFuncMapping;
751
111k
  }
752
753
  // Builds the instruction-graph map for the whole module.
754
0
  void BuildIdToGraphMapping() {
755
0
    id_to_graph_.clear();
756
0
    for (auto& g : module_->graphs()) {
757
0
      id_to_graph_[g->DefInst().result_id()] = g.get();
758
0
    }
759
0
    valid_analyses_ = valid_analyses_ | kAnalysisIdToGraphMapping;
760
0
  }
761
762
153k
  void BuildDecorationManager() {
763
153k
    decoration_mgr_ = MakeUnique<analysis::DecorationManager>(module());
764
153k
    valid_analyses_ = valid_analyses_ | kAnalysisDecorations;
765
153k
  }
766
767
95.7k
  void BuildCFG() {
768
95.7k
    cfg_ = MakeUnique<CFG>(module());
769
95.7k
    valid_analyses_ = valid_analyses_ | kAnalysisCFG;
770
95.7k
  }
771
772
0
  void BuildScalarEvolutionAnalysis() {
773
0
    scalar_evolution_analysis_ = MakeUnique<ScalarEvolutionAnalysis>(this);
774
0
    valid_analyses_ = valid_analyses_ | kAnalysisScalarEvolution;
775
0
  }
776
777
  // Builds the liveness analysis from scratch, even if it was already valid.
778
0
  void BuildRegPressureAnalysis() {
779
0
    reg_pressure_ = MakeUnique<LivenessAnalysis>(this);
780
0
    valid_analyses_ = valid_analyses_ | kAnalysisRegisterPressure;
781
0
  }
782
783
  // Builds the value number table analysis from scratch, even if it was already
784
  // valid.
785
11.0k
  void BuildValueNumberTable() {
786
11.0k
    vn_table_ = MakeUnique<ValueNumberTable>(this);
787
11.0k
    valid_analyses_ = valid_analyses_ | kAnalysisValueNumberTable;
788
11.0k
  }
789
790
  // Builds the structured CFG analysis from scratch, even if it was already
791
  // valid.
792
80.9k
  void BuildStructuredCFGAnalysis() {
793
80.9k
    struct_cfg_analysis_ = MakeUnique<StructuredCFGAnalysis>(this);
794
80.9k
    valid_analyses_ = valid_analyses_ | kAnalysisStructuredCFG;
795
80.9k
  }
796
797
  // Builds the constant manager from scratch, even if it was already
798
  // valid.
799
33.8k
  void BuildConstantManager() {
800
33.8k
    constant_mgr_ = MakeUnique<analysis::ConstantManager>(this);
801
33.8k
    valid_analyses_ = valid_analyses_ | kAnalysisConstants;
802
33.8k
  }
803
804
  // Builds the type manager from scratch, even if it was already
805
  // valid.
806
34.0k
  void BuildTypeManager() {
807
34.0k
    type_mgr_ = MakeUnique<analysis::TypeManager>(consumer(), this);
808
34.0k
    valid_analyses_ = valid_analyses_ | kAnalysisTypes;
809
34.0k
  }
810
811
  // Builds the debug information manager from scratch, even if it was
812
  // already valid.
813
25.6k
  void BuildDebugInfoManager() {
814
25.6k
    debug_info_mgr_ = MakeUnique<analysis::DebugInfoManager>(this);
815
25.6k
    valid_analyses_ = valid_analyses_ | kAnalysisDebugInfo;
816
25.6k
  }
817
818
  // Removes all computed dominator and post-dominator trees. This will force
819
  // the context to rebuild the trees on demand.
820
62.4k
  void ResetDominatorAnalysis() {
821
    // Clear the cache.
822
62.4k
    dominator_trees_.clear();
823
62.4k
    post_dominator_trees_.clear();
824
62.4k
    valid_analyses_ = valid_analyses_ | kAnalysisDominatorAnalysis;
825
62.4k
  }
826
827
  // Removes all computed loop descriptors.
828
15.7k
  void ResetLoopAnalysis() {
829
    // Clear the cache.
830
15.7k
    loop_descriptors_.clear();
831
15.7k
    valid_analyses_ = valid_analyses_ | kAnalysisLoopAnalysis;
832
15.7k
  }
833
834
  // Removes all computed loop descriptors.
835
0
  void ResetBuiltinAnalysis() {
836
    // Clear the cache.
837
0
    builtin_var_id_map_.clear();
838
0
    valid_analyses_ = valid_analyses_ | kAnalysisBuiltinVarId;
839
0
  }
840
841
  // Analyzes the features in the owned module. Builds the manager if required.
842
25.4k
  void AnalyzeFeatures() {
843
25.4k
    feature_mgr_ =
844
25.4k
        std::unique_ptr<FeatureManager>(new FeatureManager(grammar_));
845
25.4k
    feature_mgr_->Analyze(module());
846
25.4k
  }
847
848
  // Scans a module looking for it capabilities, and initializes combinator_ops_
849
  // accordingly.
850
  void InitializeCombinators();
851
852
  // Add the combinator opcode for the given capability to combinator_ops_.
853
  void AddCombinatorsForCapability(uint32_t capability);
854
855
  // Add the combinator opcode for the given extension to combinator_ops_.
856
  void AddCombinatorsForExtension(Instruction* extension);
857
858
  // Remove |inst| from |id_to_name_| if it is in map.
859
  void RemoveFromIdToName(const Instruction* inst);
860
861
  // Returns true if it is suppose to be valid but it is incorrect.  Returns
862
  // true if the cfg is invalidated.
863
  bool CheckCFG();
864
865
  // Return id of input variable only decorated with |builtin|, if in module.
866
  // Return 0 otherwise.
867
  uint32_t FindBuiltinInputVar(uint32_t builtin);
868
869
  // Add |var_id| to all entry points in module.
870
  void AddVarToEntryPoints(uint32_t var_id);
871
872
  // The SPIR-V syntax context containing grammar tables for opcodes and
873
  // operands.
874
  spv_context syntax_context_;
875
876
  // Auxiliary object for querying SPIR-V grammar facts.
877
  AssemblyGrammar grammar_;
878
879
  // An unique identifier for instructions in |module_|. Can be used to order
880
  // instructions in a container.
881
  //
882
  // This member is initialized to 0, but always issues this value plus one.
883
  // Therefore, 0 is not a valid unique id for an instruction.
884
  uint32_t unique_id_;
885
886
  // The module being processed within this IR context.
887
  std::unique_ptr<Module> module_;
888
889
  // A message consumer for diagnostics.
890
  MessageConsumer consumer_;
891
892
  // The def-use manager for |module_|.
893
  std::unique_ptr<analysis::DefUseManager> def_use_mgr_;
894
895
  // The instruction decoration manager for |module_|.
896
  std::unique_ptr<analysis::DecorationManager> decoration_mgr_;
897
898
  // The feature manager for |module_|.
899
  std::unique_ptr<FeatureManager> feature_mgr_;
900
901
  // A map from instructions to the basic block they belong to. This mapping is
902
  // built on-demand when get_instr_block() is called.
903
  //
904
  // NOTE: Do not traverse this map. Ever. Use the function and basic block
905
  // iterators to traverse instructions.
906
  std::unordered_map<Instruction*, BasicBlock*> instr_to_block_;
907
908
  // A map from ids to the function they define. This mapping is
909
  // built on-demand when GetFunction() is called.
910
  //
911
  // NOTE: Do not traverse this map. Ever. Use the function and basic block
912
  // iterators to traverse instructions.
913
  std::unordered_map<uint32_t, Function*> id_to_func_;
914
915
  // A map from ids to the graph they define. This mapping is
916
  // built on-demand when GetGraph() is called.
917
  //
918
  // NOTE: Do not traverse this map. Ever. Use the graph iterators to
919
  // traverse instructions.
920
  std::unordered_map<uint32_t, Graph*> id_to_graph_;
921
922
  // A bitset indicating which analyzes are currently valid.
923
  Analysis valid_analyses_;
924
925
  // Opcodes of shader capability core executable instructions
926
  // without side-effect.
927
  std::unordered_map<uint32_t, std::unordered_set<uint32_t>> combinator_ops_;
928
929
  // Opcodes of shader capability core executable instructions
930
  // without side-effect.
931
  std::unordered_map<uint32_t, uint32_t> builtin_var_id_map_;
932
933
  // The CFG for all the functions in |module_|.
934
  std::unique_ptr<CFG> cfg_;
935
936
  // Each function in the module will create its own dominator tree. We cache
937
  // the result so it doesn't need to be rebuilt each time.
938
  std::map<const Function*, DominatorAnalysis> dominator_trees_;
939
  std::map<const Function*, PostDominatorAnalysis> post_dominator_trees_;
940
941
  // Cache of loop descriptors for each function.
942
  std::unordered_map<const Function*, LoopDescriptor> loop_descriptors_;
943
944
  // Constant manager for |module_|.
945
  std::unique_ptr<analysis::ConstantManager> constant_mgr_;
946
947
  // Type manager for |module_|.
948
  std::unique_ptr<analysis::TypeManager> type_mgr_;
949
950
  // Debug information manager for |module_|.
951
  std::unique_ptr<analysis::DebugInfoManager> debug_info_mgr_;
952
953
  // A map from an id to its corresponding OpName and OpMemberName instructions.
954
  std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
955
956
  // The cache scalar evolution analysis node.
957
  std::unique_ptr<ScalarEvolutionAnalysis> scalar_evolution_analysis_;
958
959
  // The liveness analysis |module_|.
960
  std::unique_ptr<LivenessAnalysis> reg_pressure_;
961
962
  std::unique_ptr<ValueNumberTable> vn_table_;
963
964
  std::unique_ptr<InstructionFolder> inst_folder_;
965
966
  std::unique_ptr<StructuredCFGAnalysis> struct_cfg_analysis_;
967
968
  // The liveness manager for |module_|.
969
  std::unique_ptr<analysis::LivenessManager> liveness_mgr_;
970
971
  // The maximum legal value for the id bound.
972
  uint32_t max_id_bound_;
973
974
  // Whether all bindings within |module_| should be preserved.
975
  bool preserve_bindings_;
976
977
  // Whether all specialization constants within |module_|
978
  // should be preserved.
979
  bool preserve_spec_constants_;
980
981
  // Set to true if TakeNextId() fails.
982
  bool id_overflow_;
983
};
984
985
inline IRContext::Analysis operator|(IRContext::Analysis lhs,
986
1.91M
                                     IRContext::Analysis rhs) {
987
1.91M
  return static_cast<IRContext::Analysis>(static_cast<int>(lhs) |
988
1.91M
                                          static_cast<int>(rhs));
989
1.91M
}
990
991
inline IRContext::Analysis& operator|=(IRContext::Analysis& lhs,
992
170k
                                       IRContext::Analysis rhs) {
993
170k
  lhs = lhs | rhs;
994
170k
  return lhs;
995
170k
}
996
997
0
inline IRContext::Analysis operator<<(IRContext::Analysis a, int shift) {
998
0
  return static_cast<IRContext::Analysis>(static_cast<int>(a) << shift);
999
0
}
1000
1001
0
inline IRContext::Analysis& operator<<=(IRContext::Analysis& a, int shift) {
1002
0
  a = static_cast<IRContext::Analysis>(static_cast<int>(a) << shift);
1003
0
  return a;
1004
0
}
1005
1006
0
std::vector<Instruction*> IRContext::GetConstants() {
1007
0
  return module()->GetConstants();
1008
0
}
1009
1010
0
std::vector<const Instruction*> IRContext::GetConstants() const {
1011
0
  return ((const Module*)module())->GetConstants();
1012
0
}
1013
1014
0
Module::inst_iterator IRContext::annotation_begin() {
1015
0
  return module()->annotation_begin();
1016
0
}
1017
1018
585
Module::inst_iterator IRContext::annotation_end() {
1019
585
  return module()->annotation_end();
1020
585
}
1021
1022
359k
IteratorRange<Module::inst_iterator> IRContext::annotations() {
1023
359k
  return module_->annotations();
1024
359k
}
1025
1026
0
IteratorRange<Module::const_inst_iterator> IRContext::annotations() const {
1027
0
  return ((const Module*)module_.get())->annotations();
1028
0
}
1029
1030
0
Module::inst_iterator IRContext::capability_begin() {
1031
0
  return module()->capability_begin();
1032
0
}
1033
1034
0
Module::inst_iterator IRContext::capability_end() {
1035
0
  return module()->capability_end();
1036
0
}
1037
1038
25.0k
IteratorRange<Module::inst_iterator> IRContext::capabilities() {
1039
25.0k
  return module()->capabilities();
1040
25.0k
}
1041
1042
0
IteratorRange<Module::const_inst_iterator> IRContext::capabilities() const {
1043
0
  return ((const Module*)module())->capabilities();
1044
0
}
1045
1046
0
Module::inst_iterator IRContext::extension_begin() {
1047
0
  return module()->extension_begin();
1048
0
}
1049
1050
0
Module::inst_iterator IRContext::extension_end() {
1051
0
  return module()->extension_end();
1052
0
}
1053
1054
0
IteratorRange<Module::inst_iterator> IRContext::extensions() {
1055
0
  return module()->extensions();
1056
0
}
1057
1058
0
IteratorRange<Module::const_inst_iterator> IRContext::extensions() const {
1059
0
  return ((const Module*)module())->extensions();
1060
0
}
1061
1062
0
Module::inst_iterator IRContext::types_values_begin() {
1063
0
  return module()->types_values_begin();
1064
0
}
1065
1066
420k
Module::inst_iterator IRContext::types_values_end() {
1067
420k
  return module()->types_values_end();
1068
420k
}
1069
1070
53.6k
IteratorRange<Module::inst_iterator> IRContext::types_values() {
1071
53.6k
  return module()->types_values();
1072
53.6k
}
1073
1074
0
IteratorRange<Module::const_inst_iterator> IRContext::types_values() const {
1075
0
  return ((const Module*)module_.get())->types_values();
1076
0
}
1077
1078
0
Module::inst_iterator IRContext::ext_inst_import_begin() {
1079
0
  return module()->ext_inst_import_begin();
1080
0
}
1081
1082
0
Module::inst_iterator IRContext::ext_inst_import_end() {
1083
0
  return module()->ext_inst_import_end();
1084
0
}
1085
1086
0
IteratorRange<Module::inst_iterator> IRContext::ext_inst_imports() {
1087
0
  return module()->ext_inst_imports();
1088
0
}
1089
1090
0
IteratorRange<Module::const_inst_iterator> IRContext::ext_inst_imports() const {
1091
0
  return ((const Module*)module_.get())->ext_inst_imports();
1092
0
}
1093
1094
0
Module::inst_iterator IRContext::debug1_begin() {
1095
0
  return module()->debug1_begin();
1096
0
}
1097
1098
0
Module::inst_iterator IRContext::debug1_end() { return module()->debug1_end(); }
1099
1100
0
IteratorRange<Module::inst_iterator> IRContext::debugs1() {
1101
0
  return module()->debugs1();
1102
0
}
1103
1104
0
IteratorRange<Module::const_inst_iterator> IRContext::debugs1() const {
1105
0
  return ((const Module*)module_.get())->debugs1();
1106
0
}
1107
1108
0
Module::inst_iterator IRContext::debug2_begin() {
1109
0
  return module()->debug2_begin();
1110
0
}
1111
0
Module::inst_iterator IRContext::debug2_end() { return module()->debug2_end(); }
1112
1113
82.5k
IteratorRange<Module::inst_iterator> IRContext::debugs2() {
1114
82.5k
  return module()->debugs2();
1115
82.5k
}
1116
1117
0
IteratorRange<Module::const_inst_iterator> IRContext::debugs2() const {
1118
0
  return ((const Module*)module_.get())->debugs2();
1119
0
}
1120
1121
0
Module::inst_iterator IRContext::debug3_begin() {
1122
0
  return module()->debug3_begin();
1123
0
}
1124
1125
0
Module::inst_iterator IRContext::debug3_end() { return module()->debug3_end(); }
1126
1127
0
IteratorRange<Module::inst_iterator> IRContext::debugs3() {
1128
0
  return module()->debugs3();
1129
0
}
1130
1131
0
IteratorRange<Module::const_inst_iterator> IRContext::debugs3() const {
1132
0
  return ((const Module*)module_.get())->debugs3();
1133
0
}
1134
1135
0
Module::inst_iterator IRContext::ext_inst_debuginfo_begin() {
1136
0
  return module()->ext_inst_debuginfo_begin();
1137
0
}
1138
1139
0
Module::inst_iterator IRContext::ext_inst_debuginfo_end() {
1140
0
  return module()->ext_inst_debuginfo_end();
1141
0
}
1142
1143
0
IteratorRange<Module::inst_iterator> IRContext::ext_inst_debuginfo() {
1144
0
  return module()->ext_inst_debuginfo();
1145
0
}
1146
1147
IteratorRange<Module::const_inst_iterator> IRContext::ext_inst_debuginfo()
1148
0
    const {
1149
0
  return ((const Module*)module_.get())->ext_inst_debuginfo();
1150
0
}
1151
1152
0
void IRContext::AddCapability(spv::Capability capability) {
1153
0
  if (!get_feature_mgr()->HasCapability(capability)) {
1154
0
    std::unique_ptr<Instruction> capability_inst(new Instruction(
1155
0
        this, spv::Op::OpCapability, 0, 0,
1156
0
        {{SPV_OPERAND_TYPE_CAPABILITY, {static_cast<uint32_t>(capability)}}}));
1157
0
    AddCapability(std::move(capability_inst));
1158
0
  }
1159
0
}
1160
1161
0
void IRContext::AddCapability(std::unique_ptr<Instruction>&& c) {
1162
0
  AddCombinatorsForCapability(c->GetSingleWordInOperand(0));
1163
0
  if (feature_mgr_ != nullptr) {
1164
0
    feature_mgr_->AddCapability(
1165
0
        static_cast<spv::Capability>(c->GetSingleWordInOperand(0)));
1166
0
  }
1167
0
  if (AreAnalysesValid(kAnalysisDefUse)) {
1168
0
    get_def_use_mgr()->AnalyzeInstDefUse(c.get());
1169
0
  }
1170
0
  module()->AddCapability(std::move(c));
1171
0
}
1172
1173
0
void IRContext::AddExtension(const std::string& ext_name) {
1174
0
  std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(ext_name);
1175
0
  AddExtension(std::unique_ptr<Instruction>(
1176
0
      new Instruction(this, spv::Op::OpExtension, 0u, 0u,
1177
0
                      {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
1178
0
}
1179
1180
0
void IRContext::AddExtension(std::unique_ptr<Instruction>&& e) {
1181
0
  if (AreAnalysesValid(kAnalysisDefUse)) {
1182
0
    get_def_use_mgr()->AnalyzeInstDefUse(e.get());
1183
0
  }
1184
0
  if (feature_mgr_ != nullptr) {
1185
0
    feature_mgr_->AddExtension(&*e);
1186
0
  }
1187
0
  module()->AddExtension(std::move(e));
1188
0
}
1189
1190
0
void IRContext::AddExtInstImport(const std::string& name) {
1191
0
  std::vector<uint32_t> ext_words = spvtools::utils::MakeVector(name);
1192
0
  AddExtInstImport(std::unique_ptr<Instruction>(
1193
0
      new Instruction(this, spv::Op::OpExtInstImport, 0u, TakeNextId(),
1194
0
                      {{SPV_OPERAND_TYPE_LITERAL_STRING, ext_words}})));
1195
0
}
1196
1197
0
void IRContext::AddExtInstImport(std::unique_ptr<Instruction>&& e) {
1198
0
  AddCombinatorsForExtension(e.get());
1199
0
  if (AreAnalysesValid(kAnalysisDefUse)) {
1200
0
    get_def_use_mgr()->AnalyzeInstDefUse(e.get());
1201
0
  }
1202
0
  module()->AddExtInstImport(std::move(e));
1203
0
  if (feature_mgr_ != nullptr) {
1204
0
    feature_mgr_->AddExtInstImportIds(module());
1205
0
  }
1206
0
}
1207
1208
0
void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
1209
0
  module()->SetMemoryModel(std::move(m));
1210
0
}
1211
1212
0
const Instruction* IRContext::GetMemoryModel() const {
1213
0
  return module()->GetMemoryModel();
1214
0
}
1215
1216
0
void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
1217
0
  module()->AddEntryPoint(std::move(e));
1218
0
}
1219
1220
0
void IRContext::AddExecutionMode(std::unique_ptr<Instruction>&& e) {
1221
0
  module()->AddExecutionMode(std::move(e));
1222
0
}
1223
1224
0
void IRContext::AddDebug1Inst(std::unique_ptr<Instruction>&& d) {
1225
0
  module()->AddDebug1Inst(std::move(d));
1226
0
}
1227
1228
0
void IRContext::AddDebug2Inst(std::unique_ptr<Instruction>&& d) {
1229
0
  if (AreAnalysesValid(kAnalysisNameMap)) {
1230
0
    if (d->opcode() == spv::Op::OpName ||
1231
0
        d->opcode() == spv::Op::OpMemberName) {
1232
      // OpName and OpMemberName do not have result-ids. The target of the
1233
      // instruction is at InOperand index 0.
1234
0
      id_to_name_->insert({d->GetSingleWordInOperand(0), d.get()});
1235
0
    }
1236
0
  }
1237
0
  if (AreAnalysesValid(kAnalysisDefUse)) {
1238
0
    get_def_use_mgr()->AnalyzeInstDefUse(d.get());
1239
0
  }
1240
0
  module()->AddDebug2Inst(std::move(d));
1241
0
}
1242
1243
0
void IRContext::AddDebug3Inst(std::unique_ptr<Instruction>&& d) {
1244
0
  module()->AddDebug3Inst(std::move(d));
1245
0
}
1246
1247
0
void IRContext::AddExtInstDebugInfo(std::unique_ptr<Instruction>&& d) {
1248
0
  module()->AddExtInstDebugInfo(std::move(d));
1249
0
}
1250
1251
7.88k
void IRContext::AddAnnotationInst(std::unique_ptr<Instruction>&& a) {
1252
7.88k
  if (AreAnalysesValid(kAnalysisDecorations)) {
1253
7.88k
    get_decoration_mgr()->AddDecoration(a.get());
1254
7.88k
  }
1255
7.88k
  if (AreAnalysesValid(kAnalysisDefUse)) {
1256
7.88k
    get_def_use_mgr()->AnalyzeInstDefUse(a.get());
1257
7.88k
  }
1258
7.88k
  module()->AddAnnotationInst(std::move(a));
1259
7.88k
}
1260
1261
8.09k
void IRContext::AddType(std::unique_ptr<Instruction>&& t) {
1262
8.09k
  module()->AddType(std::move(t));
1263
8.09k
  if (AreAnalysesValid(kAnalysisDefUse)) {
1264
7.96k
    get_def_use_mgr()->AnalyzeInstDefUse(&*(--types_values_end()));
1265
7.96k
  }
1266
8.09k
}
1267
1268
0
void IRContext::AddGlobalValue(std::unique_ptr<Instruction>&& v) {
1269
0
  if (AreAnalysesValid(kAnalysisDefUse)) {
1270
0
    get_def_use_mgr()->AnalyzeInstDefUse(&*v);
1271
0
  }
1272
0
  module()->AddGlobalValue(std::move(v));
1273
0
}
1274
1275
0
void IRContext::AddFunctionDeclaration(std::unique_ptr<Function>&& f) {
1276
0
  module()->AddFunctionDeclaration(std::move(f));
1277
0
}
1278
1279
15
void IRContext::AddFunction(std::unique_ptr<Function>&& f) {
1280
15
  module()->AddFunction(std::move(f));
1281
15
}
1282
1283
156k
void IRContext::AnalyzeDefUse(Instruction* inst) {
1284
156k
  if (AreAnalysesValid(kAnalysisDefUse)) {
1285
156k
    get_def_use_mgr()->AnalyzeInstDefUse(inst);
1286
156k
  }
1287
156k
}
1288
1289
1.93M
void IRContext::UpdateDefUse(Instruction* inst) {
1290
1.93M
  if (AreAnalysesValid(kAnalysisDefUse)) {
1291
1.93M
    get_def_use_mgr()->UpdateDefUse(inst);
1292
1.93M
  }
1293
1.93M
}
1294
1295
82.5k
void IRContext::BuildIdToNameMap() {
1296
82.5k
  id_to_name_ = MakeUnique<std::multimap<uint32_t, Instruction*>>();
1297
563k
  for (Instruction& debug_inst : debugs2()) {
1298
563k
    if (debug_inst.opcode() == spv::Op::OpMemberName ||
1299
563k
        debug_inst.opcode() == spv::Op::OpName) {
1300
563k
      id_to_name_->insert({debug_inst.GetSingleWordInOperand(0), &debug_inst});
1301
563k
    }
1302
563k
  }
1303
82.5k
  valid_analyses_ = valid_analyses_ | kAnalysisNameMap;
1304
82.5k
}
1305
1306
IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
1307
7.48M
IRContext::GetNames(uint32_t id) {
1308
7.48M
  if (!AreAnalysesValid(kAnalysisNameMap)) {
1309
82.5k
    BuildIdToNameMap();
1310
82.5k
  }
1311
7.48M
  auto result = id_to_name_->equal_range(id);
1312
7.48M
  return make_range(std::move(result.first), std::move(result.second));
1313
7.48M
}
1314
1315
0
Instruction* IRContext::GetMemberName(uint32_t struct_type_id, uint32_t index) {
1316
0
  if (!AreAnalysesValid(kAnalysisNameMap)) {
1317
0
    BuildIdToNameMap();
1318
0
  }
1319
0
  auto result = id_to_name_->equal_range(struct_type_id);
1320
0
  for (auto i = result.first; i != result.second; ++i) {
1321
0
    auto* name_instr = i->second;
1322
0
    if (name_instr->opcode() == spv::Op::OpMemberName &&
1323
0
        name_instr->GetSingleWordInOperand(1) == index) {
1324
0
      return name_instr;
1325
0
    }
1326
0
  }
1327
0
  return nullptr;
1328
0
}
1329
1330
void IRContext::CloneNames(const uint32_t old_id, const uint32_t new_id,
1331
0
                           const uint32_t max_member_index) {
1332
0
  std::vector<std::unique_ptr<Instruction>> names_to_add;
1333
0
  auto names = GetNames(old_id);
1334
0
  for (auto n : names) {
1335
0
    Instruction* old_name_inst = n.second;
1336
0
    if (old_name_inst->opcode() == spv::Op::OpMemberName) {
1337
0
      auto midx = old_name_inst->GetSingleWordInOperand(1);
1338
0
      if (midx >= max_member_index) continue;
1339
0
    }
1340
0
    std::unique_ptr<Instruction> new_name_inst(old_name_inst->Clone(this));
1341
0
    new_name_inst->SetInOperand(0, {new_id});
1342
0
    names_to_add.push_back(std::move(new_name_inst));
1343
0
  }
1344
  // We can't add the new names when we are iterating over name range above.
1345
  // We can add all the new names now.
1346
0
  for (auto& new_name : names_to_add) AddDebug2Inst(std::move(new_name));
1347
0
}
1348
1349
}  // namespace opt
1350
}  // namespace spvtools
1351
1352
#endif  // SOURCE_OPT_IR_CONTEXT_H_