2017-10-30 15:13:24 +00:00
|
|
|
// Copyright (c) 2017 Google Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
#ifndef SPIRV_TOOLS_IR_CONTEXT_H
|
|
|
|
#define SPIRV_TOOLS_IR_CONTEXT_H
|
|
|
|
|
2017-12-19 19:18:13 +00:00
|
|
|
#include "assembly_grammar.h"
|
2017-11-27 19:20:32 +00:00
|
|
|
#include "cfg.h"
|
2017-12-07 21:42:27 +00:00
|
|
|
#include "constants.h"
|
2017-11-13 20:31:43 +00:00
|
|
|
#include "decoration_manager.h"
|
2017-11-02 18:25:48 +00:00
|
|
|
#include "def_use_manager.h"
|
2017-11-27 21:21:26 +00:00
|
|
|
#include "dominator_analysis.h"
|
2017-11-30 22:03:06 +00:00
|
|
|
#include "feature_manager.h"
|
2018-01-25 10:33:06 +00:00
|
|
|
#include "loop_descriptor.h"
|
2017-10-30 15:13:24 +00:00
|
|
|
#include "module.h"
|
2018-04-17 14:31:09 +00:00
|
|
|
#include "register_pressure.h"
|
2018-03-28 13:19:55 +00:00
|
|
|
#include "scalar_analysis.h"
|
2017-12-07 21:42:27 +00:00
|
|
|
#include "type_manager.h"
|
2018-04-26 19:07:48 +00:00
|
|
|
#include "value_number_table.h"
|
2017-10-30 15:13:24 +00:00
|
|
|
|
2017-11-13 20:31:43 +00:00
|
|
|
#include <algorithm>
|
2017-10-30 15:13:24 +00:00
|
|
|
#include <iostream>
|
2017-11-14 19:11:50 +00:00
|
|
|
#include <limits>
|
2017-11-11 01:26:55 +00:00
|
|
|
#include <unordered_set>
|
2017-10-30 15:13:24 +00:00
|
|
|
|
|
|
|
namespace spvtools {
|
|
|
|
namespace ir {
|
|
|
|
|
|
|
|
class IRContext {
|
|
|
|
public:
|
2017-11-10 14:39:00 +00:00
|
|
|
// Available analyses.
|
|
|
|
//
|
|
|
|
// When adding a new analysis:
|
|
|
|
//
|
|
|
|
// 1. Enum values should be powers of 2. These are cast into uint32_t
|
|
|
|
// bitmasks, so we can have at most 31 analyses represented.
|
|
|
|
//
|
|
|
|
// 2. Make sure it gets invalidated or preserved by IRContext methods that add
|
|
|
|
// or remove IR elements (e.g., KillDef, KillInst, ReplaceAllUsesWith).
|
|
|
|
//
|
2017-11-27 19:20:32 +00:00
|
|
|
// 3. Add handling code in BuildInvalidAnalyses and InvalidateAnalyses
|
2017-11-02 18:25:48 +00:00
|
|
|
enum Analysis {
|
2017-11-10 14:39:00 +00:00
|
|
|
kAnalysisNone = 0 << 0,
|
|
|
|
kAnalysisBegin = 1 << 0,
|
2017-11-02 18:25:48 +00:00
|
|
|
kAnalysisDefUse = kAnalysisBegin,
|
2017-11-10 14:39:00 +00:00
|
|
|
kAnalysisInstrToBlockMapping = 1 << 1,
|
2017-11-13 20:31:43 +00:00
|
|
|
kAnalysisDecorations = 1 << 2,
|
2017-11-11 01:26:55 +00:00
|
|
|
kAnalysisCombinators = 1 << 3,
|
2017-11-27 19:20:32 +00:00
|
|
|
kAnalysisCFG = 1 << 4,
|
2017-11-27 21:21:26 +00:00
|
|
|
kAnalysisDominatorAnalysis = 1 << 5,
|
2018-01-25 10:33:06 +00:00
|
|
|
kAnalysisLoopAnalysis = 1 << 6,
|
2018-02-13 04:28:38 +00:00
|
|
|
kAnalysisNameMap = 1 << 7,
|
2018-03-28 13:19:55 +00:00
|
|
|
kAnalysisScalarEvolution = 1 << 8,
|
2018-04-17 14:31:09 +00:00
|
|
|
kAnalysisRegisterPressure = 1 << 9,
|
2018-04-26 19:07:48 +00:00
|
|
|
kAnalysisValueNumberTable = 1 << 10,
|
|
|
|
kAnalysisEnd = 1 << 11
|
2017-11-02 18:25:48 +00:00
|
|
|
};
|
|
|
|
|
2018-01-30 21:43:55 +00:00
|
|
|
friend inline Analysis operator|(Analysis lhs, Analysis rhs);
|
2017-11-02 18:25:48 +00:00
|
|
|
friend inline Analysis& operator|=(Analysis& lhs, Analysis rhs);
|
2018-01-30 21:43:55 +00:00
|
|
|
friend inline Analysis operator<<(Analysis a, int shift);
|
2017-11-02 18:25:48 +00:00
|
|
|
friend inline Analysis& operator<<=(Analysis& a, int shift);
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// Creates an |IRContext| that contains an owned |Module|
|
2017-12-19 19:18:13 +00:00
|
|
|
IRContext(spv_target_env env, spvtools::MessageConsumer c)
|
|
|
|
: syntax_context_(spvContextCreate(env)),
|
|
|
|
grammar_(syntax_context_),
|
|
|
|
unique_id_(0),
|
2017-11-14 19:11:50 +00:00
|
|
|
module_(new Module()),
|
|
|
|
consumer_(std::move(c)),
|
|
|
|
def_use_mgr_(nullptr),
|
2017-12-07 21:42:27 +00:00
|
|
|
valid_analyses_(kAnalysisNone),
|
|
|
|
constant_mgr_(nullptr),
|
2018-02-13 04:28:38 +00:00
|
|
|
type_mgr_(nullptr),
|
|
|
|
id_to_name_(nullptr) {
|
2017-12-19 19:18:13 +00:00
|
|
|
libspirv::SetContextMessageConsumer(syntax_context_, consumer_);
|
2017-11-14 19:11:50 +00:00
|
|
|
module_->SetContext(this);
|
|
|
|
}
|
|
|
|
|
2017-12-19 19:18:13 +00:00
|
|
|
IRContext(spv_target_env env, std::unique_ptr<Module>&& m,
|
|
|
|
spvtools::MessageConsumer c)
|
|
|
|
: syntax_context_(spvContextCreate(env)),
|
|
|
|
grammar_(syntax_context_),
|
|
|
|
unique_id_(0),
|
2017-11-14 19:11:50 +00:00
|
|
|
module_(std::move(m)),
|
2017-11-02 18:25:48 +00:00
|
|
|
consumer_(std::move(c)),
|
|
|
|
def_use_mgr_(nullptr),
|
2017-12-07 21:42:27 +00:00
|
|
|
valid_analyses_(kAnalysisNone),
|
2018-02-13 04:28:38 +00:00
|
|
|
type_mgr_(nullptr),
|
|
|
|
id_to_name_(nullptr) {
|
2017-12-19 19:18:13 +00:00
|
|
|
libspirv::SetContextMessageConsumer(syntax_context_, consumer_);
|
2017-11-14 19:11:50 +00:00
|
|
|
module_->SetContext(this);
|
2017-11-11 01:26:55 +00:00
|
|
|
InitializeCombinators();
|
2017-11-14 19:11:50 +00:00
|
|
|
}
|
2017-12-19 19:18:13 +00:00
|
|
|
|
|
|
|
~IRContext() { spvContextDestroy(syntax_context_); }
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
Module* module() const { return module_.get(); }
|
|
|
|
|
|
|
|
// Returns a vector of pointers to constant-creation instructions in this
|
|
|
|
// context.
|
|
|
|
inline std::vector<Instruction*> GetConstants();
|
|
|
|
inline std::vector<const Instruction*> GetConstants() const;
|
|
|
|
|
|
|
|
// Iterators for annotation instructions contained in this context.
|
|
|
|
inline Module::inst_iterator annotation_begin();
|
|
|
|
inline Module::inst_iterator annotation_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> annotations();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> annotations() const;
|
|
|
|
|
|
|
|
// Iterators for capabilities instructions contained in this module.
|
|
|
|
inline Module::inst_iterator capability_begin();
|
|
|
|
inline Module::inst_iterator capability_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> capabilities();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> capabilities() const;
|
|
|
|
|
|
|
|
// Iterators for types, constants and global variables instructions.
|
|
|
|
inline ir::Module::inst_iterator types_values_begin();
|
|
|
|
inline ir::Module::inst_iterator types_values_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> types_values();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> types_values() const;
|
|
|
|
|
|
|
|
// Iterators for extension instructions contained in this module.
|
|
|
|
inline Module::inst_iterator ext_inst_import_begin();
|
|
|
|
inline Module::inst_iterator ext_inst_import_end();
|
2017-11-21 19:47:46 +00:00
|
|
|
inline IteratorRange<Module::inst_iterator> ext_inst_imports();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> ext_inst_imports() const;
|
2017-10-30 15:13:24 +00:00
|
|
|
|
|
|
|
// There are several kinds of debug instructions, according to where they can
|
|
|
|
// appear in the logical layout of a module:
|
|
|
|
// - Section 7a: OpString, OpSourceExtension, OpSource, OpSourceContinued
|
|
|
|
// - Section 7b: OpName, OpMemberName
|
|
|
|
// - Section 7c: OpModuleProcessed
|
|
|
|
// - Mostly anywhere: OpLine and OpNoLine
|
|
|
|
//
|
|
|
|
|
|
|
|
// Iterators for debug 1 instructions (excluding OpLine & OpNoLine) contained
|
|
|
|
// in this module. These are for layout section 7a.
|
|
|
|
inline Module::inst_iterator debug1_begin();
|
|
|
|
inline Module::inst_iterator debug1_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> debugs1();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> debugs1() const;
|
|
|
|
|
|
|
|
// Iterators for debug 2 instructions (excluding OpLine & OpNoLine) contained
|
|
|
|
// in this module. These are for layout section 7b.
|
|
|
|
inline Module::inst_iterator debug2_begin();
|
|
|
|
inline Module::inst_iterator debug2_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> debugs2();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> debugs2() const;
|
|
|
|
|
|
|
|
// Iterators for debug 3 instructions (excluding OpLine & OpNoLine) contained
|
|
|
|
// in this module. These are for layout section 7c.
|
|
|
|
inline Module::inst_iterator debug3_begin();
|
|
|
|
inline Module::inst_iterator debug3_end();
|
|
|
|
inline IteratorRange<Module::inst_iterator> debugs3();
|
|
|
|
inline IteratorRange<Module::const_inst_iterator> debugs3() const;
|
|
|
|
|
|
|
|
// Clears all debug instructions (excluding OpLine & OpNoLine).
|
|
|
|
inline void debug_clear();
|
|
|
|
|
|
|
|
// Appends a capability instruction to this module.
|
|
|
|
inline void AddCapability(std::unique_ptr<Instruction>&& c);
|
|
|
|
// Appends an extension instruction to this module.
|
|
|
|
inline void AddExtension(std::unique_ptr<Instruction>&& e);
|
|
|
|
// Appends an extended instruction set instruction to this module.
|
|
|
|
inline void AddExtInstImport(std::unique_ptr<Instruction>&& e);
|
|
|
|
// Set the memory model for this module.
|
|
|
|
inline void SetMemoryModel(std::unique_ptr<Instruction>&& m);
|
|
|
|
// Appends an entry point instruction to this module.
|
|
|
|
inline void AddEntryPoint(std::unique_ptr<Instruction>&& e);
|
|
|
|
// Appends an execution mode instruction to this module.
|
|
|
|
inline void AddExecutionMode(std::unique_ptr<Instruction>&& e);
|
|
|
|
// Appends a debug 1 instruction (excluding OpLine & OpNoLine) to this module.
|
|
|
|
// "debug 1" instructions are the ones in layout section 7.a), see section
|
|
|
|
// 2.4 Logical Layout of a Module from the SPIR-V specification.
|
|
|
|
inline void AddDebug1Inst(std::unique_ptr<Instruction>&& d);
|
|
|
|
// Appends a debug 2 instruction (excluding OpLine & OpNoLine) to this module.
|
|
|
|
// "debug 2" instructions are the ones in layout section 7.b), see section
|
|
|
|
// 2.4 Logical Layout of a Module from the SPIR-V specification.
|
|
|
|
inline void AddDebug2Inst(std::unique_ptr<Instruction>&& d);
|
|
|
|
// Appends a debug 3 instruction (OpModuleProcessed) to this module.
|
|
|
|
// This is due to decision by the SPIR Working Group, pending publication.
|
|
|
|
inline void AddDebug3Inst(std::unique_ptr<Instruction>&& d);
|
|
|
|
// Appends an annotation instruction to this module.
|
|
|
|
inline void AddAnnotationInst(std::unique_ptr<Instruction>&& a);
|
|
|
|
// Appends a type-declaration instruction to this module.
|
|
|
|
inline void AddType(std::unique_ptr<Instruction>&& t);
|
|
|
|
// Appends a constant, global variable, or OpUndef instruction to this module.
|
|
|
|
inline void AddGlobalValue(std::unique_ptr<Instruction>&& v);
|
|
|
|
// Appends a function to this module.
|
|
|
|
inline void AddFunction(std::unique_ptr<Function>&& f);
|
|
|
|
|
2017-11-02 18:25:48 +00:00
|
|
|
// Returns a pointer to a def-use manager. If the def-use manager is
|
|
|
|
// invalid, it is rebuilt first.
|
|
|
|
opt::analysis::DefUseManager* get_def_use_mgr() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisDefUse)) {
|
|
|
|
BuildDefUseManager();
|
|
|
|
}
|
|
|
|
return def_use_mgr_.get();
|
|
|
|
}
|
|
|
|
|
2018-04-26 19:07:48 +00:00
|
|
|
// Returns a pointer to a value number table. If the liveness analysis is
|
|
|
|
// invalid, it is rebuilt first.
|
|
|
|
opt::ValueNumberTable* GetValueNumberTable() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisValueNumberTable)) {
|
|
|
|
BuildValueNumberTable();
|
|
|
|
}
|
|
|
|
return vn_table_.get();
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:31:09 +00:00
|
|
|
// Returns a pointer to a liveness analysis. If the liveness analysis is
|
|
|
|
// invalid, it is rebuilt first.
|
|
|
|
opt::LivenessAnalysis* GetLivenessAnalysis() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisRegisterPressure)) {
|
|
|
|
BuildRegPressureAnalysis();
|
|
|
|
}
|
|
|
|
return reg_pressure_.get();
|
|
|
|
}
|
|
|
|
|
2017-11-10 14:39:00 +00:00
|
|
|
// Returns the basic block for instruction |instr|. Re-builds the instruction
|
|
|
|
// block map, if needed.
|
|
|
|
ir::BasicBlock* get_instr_block(ir::Instruction* instr) {
|
|
|
|
if (!AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
|
|
|
|
BuildInstrToBlockMapping();
|
|
|
|
}
|
|
|
|
auto entry = instr_to_block_.find(instr);
|
|
|
|
return (entry != instr_to_block_.end()) ? entry->second : nullptr;
|
2017-11-02 18:25:48 +00:00
|
|
|
}
|
|
|
|
|
2017-11-30 22:03:06 +00:00
|
|
|
// Returns the basic block for |id|. Re-builds the instruction block map, if
|
|
|
|
// needed.
|
|
|
|
//
|
|
|
|
// |id| must be a registered definition.
|
|
|
|
ir::BasicBlock* get_instr_block(uint32_t id) {
|
|
|
|
ir::Instruction* def = get_def_use_mgr()->GetDef(id);
|
|
|
|
return get_instr_block(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the basic block for |inst|. Re-builds the mapping if it has become
|
|
|
|
// invalid.
|
|
|
|
void set_instr_block(ir::Instruction* inst, ir::BasicBlock* block) {
|
|
|
|
if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
|
|
|
|
instr_to_block_[inst] = block;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-13 20:31:43 +00:00
|
|
|
// Returns a pointer the decoration manager. If the decoration manger is
|
|
|
|
// invalid, it is rebuilt first.
|
|
|
|
opt::analysis::DecorationManager* get_decoration_mgr() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisDecorations)) {
|
|
|
|
BuildDecorationManager();
|
|
|
|
}
|
|
|
|
return decoration_mgr_.get();
|
|
|
|
};
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// Returns a pointer to the constant manager. If no constant manager has been
|
|
|
|
// created yet, it creates one. NOTE: Once created, the constant manager
|
|
|
|
// remains active and it is never re-built.
|
|
|
|
opt::analysis::ConstantManager* get_constant_mgr() {
|
|
|
|
if (!constant_mgr_)
|
|
|
|
constant_mgr_.reset(new opt::analysis::ConstantManager(this));
|
|
|
|
return constant_mgr_.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the type manager. If no type manager has been created
|
|
|
|
// yet, it creates one. NOTE: Once created, the type manager remains active it
|
|
|
|
// is never re-built.
|
|
|
|
opt::analysis::TypeManager* get_type_mgr() {
|
|
|
|
if (!type_mgr_)
|
2017-12-08 20:33:19 +00:00
|
|
|
type_mgr_.reset(new opt::analysis::TypeManager(consumer(), this));
|
2017-12-07 21:42:27 +00:00
|
|
|
return type_mgr_.get();
|
|
|
|
}
|
|
|
|
|
2018-03-28 13:19:55 +00:00
|
|
|
// Returns a pointer to the scalar evolution analysis. If it is invalid it
|
|
|
|
// will be rebuilt first.
|
|
|
|
opt::ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisScalarEvolution)) {
|
|
|
|
BuildScalarEvolutionAnalysis();
|
|
|
|
}
|
|
|
|
return scalar_evolution_analysis_.get();
|
|
|
|
}
|
|
|
|
|
2018-02-13 04:28:38 +00:00
|
|
|
// Build the map from the ids to the OpName and OpMemberName instruction
|
|
|
|
// associated with it.
|
|
|
|
inline void BuildIdToNameMap();
|
|
|
|
|
|
|
|
// Returns a range of instrucions that contain all of the OpName and
|
|
|
|
// OpMemberNames associated with the given id.
|
|
|
|
inline IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
|
|
|
|
GetNames(uint32_t id);
|
|
|
|
|
2017-11-02 18:25:48 +00:00
|
|
|
// Sets the message consumer to the given |consumer|. |consumer| which will be
|
|
|
|
// invoked every time there is a message to be communicated to the outside.
|
|
|
|
void SetMessageConsumer(spvtools::MessageConsumer c) {
|
|
|
|
consumer_ = std::move(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the reference to the message consumer for this pass.
|
|
|
|
const spvtools::MessageConsumer& consumer() const { return consumer_; }
|
|
|
|
|
|
|
|
// Rebuilds the analyses in |set| that are invalid.
|
|
|
|
void BuildInvalidAnalyses(Analysis set);
|
|
|
|
|
|
|
|
// Invalidates all of the analyses except for those in |preserved_analyses|.
|
|
|
|
void InvalidateAnalysesExceptFor(Analysis preserved_analyses);
|
|
|
|
|
2017-11-10 14:39:00 +00:00
|
|
|
// Invalidates the analyses marked in |analyses_to_invalidate|.
|
|
|
|
void InvalidateAnalyses(Analysis analyses_to_invalidate);
|
|
|
|
|
2017-11-21 19:47:46 +00:00
|
|
|
// Deletes the instruction defining the given |id|. Returns true on
|
2017-11-02 18:25:48 +00:00
|
|
|
// success, false if the given |id| is not defined at all. This method also
|
2017-11-21 19:47:46 +00:00
|
|
|
// erases the name, decorations, and defintion of |id|.
|
|
|
|
//
|
|
|
|
// Pointers and iterators pointing to the deleted instructions become invalid.
|
|
|
|
// However other pointers and iterators are still valid.
|
2017-11-02 18:25:48 +00:00
|
|
|
bool KillDef(uint32_t id);
|
|
|
|
|
2017-11-21 19:47:46 +00:00
|
|
|
// Deletes the given instruction |inst|. This method erases the
|
2017-11-02 18:25:48 +00:00
|
|
|
// information of the given instruction's uses of its operands. If |inst|
|
2017-11-21 19:47:46 +00:00
|
|
|
// defines a result id, its name and decorations will also be deleted.
|
|
|
|
//
|
|
|
|
// Pointer and iterator pointing to the deleted instructions become invalid.
|
|
|
|
// However other pointers and iterators are still valid.
|
|
|
|
//
|
|
|
|
// Note that if an instruction is not in an instruction list, the memory may
|
|
|
|
// not be safe to delete, so the instruction is turned into a OpNop instead.
|
|
|
|
// This can happen with OpLabel.
|
|
|
|
//
|
|
|
|
// Returns a pointer to the instruction after |inst| or |nullptr| if no such
|
|
|
|
// instruction exists.
|
|
|
|
Instruction* KillInst(ir::Instruction* inst);
|
2017-11-02 18:25:48 +00:00
|
|
|
|
|
|
|
// Returns true if all of the given analyses are valid.
|
|
|
|
bool AreAnalysesValid(Analysis set) { return (set & valid_analyses_) == set; }
|
|
|
|
|
|
|
|
// Replaces all uses of |before| id with |after| id. Returns true if any
|
|
|
|
// replacement happens. This method does not kill the definition of the
|
|
|
|
// |before| id. If |after| is the same as |before|, does nothing and returns
|
|
|
|
// false.
|
2017-11-14 19:11:50 +00:00
|
|
|
//
|
|
|
|
// |before| and |after| must be registered definitions in the DefUseManager.
|
2017-11-02 18:25:48 +00:00
|
|
|
bool ReplaceAllUsesWith(uint32_t before, uint32_t after);
|
|
|
|
|
2017-11-09 16:24:41 +00:00
|
|
|
// Returns true if all of the analyses that are suppose to be valid are
|
|
|
|
// actually valid.
|
|
|
|
bool IsConsistent();
|
|
|
|
|
2017-12-11 18:10:24 +00:00
|
|
|
// The IRContext will look at the def and uses of |inst| and update any valid
|
|
|
|
// analyses will be updated accordingly.
|
|
|
|
inline void AnalyzeDefUse(Instruction* inst);
|
|
|
|
|
2017-11-09 16:24:41 +00:00
|
|
|
// Informs the IRContext that the uses of |inst| are going to change, and that
|
|
|
|
// is should forget everything it know about the current uses. Any valid
|
|
|
|
// analyses will be updated accordingly.
|
|
|
|
void ForgetUses(Instruction* inst);
|
|
|
|
|
|
|
|
// The IRContext will look at the uses of |inst| and update any valid analyses
|
|
|
|
// will be updated accordingly.
|
|
|
|
void AnalyzeUses(Instruction* inst);
|
|
|
|
|
2017-11-13 20:31:43 +00:00
|
|
|
// Kill all name and decorate ops targeting |id|.
|
|
|
|
void KillNamesAndDecorates(uint32_t id);
|
|
|
|
|
|
|
|
// Kill all name and decorate ops targeting the result id of |inst|.
|
|
|
|
void KillNamesAndDecorates(ir::Instruction* inst);
|
|
|
|
|
2017-11-14 19:11:50 +00:00
|
|
|
// Returns the next unique id for use by an instruction.
|
|
|
|
inline uint32_t TakeNextUniqueId() {
|
|
|
|
assert(unique_id_ != std::numeric_limits<uint32_t>::max());
|
|
|
|
|
|
|
|
// Skip zero.
|
|
|
|
return ++unique_id_;
|
|
|
|
}
|
|
|
|
|
2017-11-11 01:26:55 +00:00
|
|
|
// Returns true if |inst| is a combinator in the current context.
|
|
|
|
// |combinator_ops_| is built if it has not been already.
|
2018-04-26 19:07:48 +00:00
|
|
|
inline bool IsCombinatorInstruction(const Instruction* inst) {
|
2017-11-11 01:26:55 +00:00
|
|
|
if (!AreAnalysesValid(kAnalysisCombinators)) {
|
|
|
|
InitializeCombinators();
|
|
|
|
}
|
|
|
|
const uint32_t kExtInstSetIdInIndx = 0;
|
|
|
|
const uint32_t kExtInstInstructionInIndx = 1;
|
|
|
|
|
|
|
|
if (inst->opcode() != SpvOpExtInst) {
|
|
|
|
return combinator_ops_[0].count(inst->opcode()) != 0;
|
|
|
|
} else {
|
|
|
|
uint32_t set = inst->GetSingleWordInOperand(kExtInstSetIdInIndx);
|
|
|
|
uint32_t op = inst->GetSingleWordInOperand(kExtInstInstructionInIndx);
|
|
|
|
return combinator_ops_[set].count(op) != 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-27 19:20:32 +00:00
|
|
|
// Returns a pointer to the CFG for all the functions in |module_|.
|
|
|
|
ir::CFG* cfg() {
|
|
|
|
if (!AreAnalysesValid(kAnalysisCFG)) {
|
|
|
|
BuildCFG();
|
|
|
|
}
|
|
|
|
return cfg_.get();
|
|
|
|
}
|
|
|
|
|
2018-01-25 10:33:06 +00:00
|
|
|
// Gets the loop descriptor for function |f|.
|
|
|
|
ir::LoopDescriptor* GetLoopDescriptor(const ir::Function* f);
|
|
|
|
|
2017-11-27 21:21:26 +00:00
|
|
|
// Gets the dominator analysis for function |f|.
|
2018-04-20 16:28:40 +00:00
|
|
|
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f);
|
2018-04-17 14:31:09 +00:00
|
|
|
|
2017-11-27 21:21:26 +00:00
|
|
|
// Gets the postdominator analysis for function |f|.
|
2018-04-20 16:28:40 +00:00
|
|
|
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const ir::Function* f);
|
2018-04-17 14:31:09 +00:00
|
|
|
|
2017-11-27 21:21:26 +00:00
|
|
|
// Remove the dominator tree of |f| from the cache.
|
|
|
|
inline void RemoveDominatorAnalysis(const ir::Function* f) {
|
|
|
|
dominator_trees_.erase(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the postdominator tree of |f| from the cache.
|
|
|
|
inline void RemovePostDominatorAnalysis(const ir::Function* f) {
|
|
|
|
post_dominator_trees_.erase(f);
|
|
|
|
}
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// Return the next available SSA id and increment it.
|
|
|
|
inline uint32_t TakeNextId() { return module()->TakeNextIdBound(); }
|
|
|
|
|
2017-11-30 22:03:06 +00:00
|
|
|
opt::FeatureManager* get_feature_mgr() {
|
|
|
|
if (!feature_mgr_.get()) {
|
|
|
|
AnalyzeFeatures();
|
|
|
|
}
|
|
|
|
return feature_mgr_.get();
|
|
|
|
}
|
|
|
|
|
2018-01-10 19:23:47 +00:00
|
|
|
// Returns the grammar for this context.
|
|
|
|
const libspirv::AssemblyGrammar& grammar() const { return grammar_; }
|
|
|
|
|
2018-02-08 15:59:03 +00:00
|
|
|
// If |inst| has not yet been analysed by the def-use manager, then analyse
|
|
|
|
// its definitions and uses.
|
|
|
|
inline void UpdateDefUse(Instruction* inst);
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
private:
|
2017-11-10 14:39:00 +00:00
|
|
|
// Builds the def-use manager from scratch, even if it was already valid.
|
|
|
|
void BuildDefUseManager() {
|
|
|
|
def_use_mgr_.reset(new opt::analysis::DefUseManager(module()));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisDefUse;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Builds the instruction-block map for the whole module.
|
|
|
|
void BuildInstrToBlockMapping() {
|
|
|
|
instr_to_block_.clear();
|
|
|
|
for (auto& fn : *module_) {
|
|
|
|
for (auto& block : fn) {
|
|
|
|
block.ForEachInst([this, &block](ir::Instruction* inst) {
|
|
|
|
instr_to_block_[inst] = █
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisInstrToBlockMapping;
|
|
|
|
}
|
|
|
|
|
2017-11-13 20:31:43 +00:00
|
|
|
void BuildDecorationManager() {
|
|
|
|
decoration_mgr_.reset(new opt::analysis::DecorationManager(module()));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisDecorations;
|
|
|
|
}
|
|
|
|
|
2017-11-27 19:20:32 +00:00
|
|
|
void BuildCFG() {
|
|
|
|
cfg_.reset(new ir::CFG(module()));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisCFG;
|
|
|
|
}
|
|
|
|
|
2018-03-28 13:19:55 +00:00
|
|
|
void BuildScalarEvolutionAnalysis() {
|
|
|
|
scalar_evolution_analysis_.reset(new opt::ScalarEvolutionAnalysis(this));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisScalarEvolution;
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:31:09 +00:00
|
|
|
// Builds the liveness analysis from scratch, even if it was already valid.
|
|
|
|
void BuildRegPressureAnalysis() {
|
|
|
|
reg_pressure_.reset(new opt::LivenessAnalysis(this));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisRegisterPressure;
|
|
|
|
}
|
|
|
|
|
2018-04-26 19:07:48 +00:00
|
|
|
// Builds the value number table analysis from scratch, even if it was already
|
|
|
|
// valid.
|
|
|
|
void BuildValueNumberTable() {
|
|
|
|
vn_table_.reset(new opt::ValueNumberTable(this));
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisValueNumberTable;
|
|
|
|
}
|
|
|
|
|
2017-12-21 14:47:25 +00:00
|
|
|
// Removes all computed dominator and post-dominator trees. This will force
|
|
|
|
// the context to rebuild the trees on demand.
|
|
|
|
void ResetDominatorAnalysis() {
|
|
|
|
// Clear the cache.
|
|
|
|
dominator_trees_.clear();
|
|
|
|
post_dominator_trees_.clear();
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisDominatorAnalysis;
|
|
|
|
}
|
|
|
|
|
2018-01-25 10:33:06 +00:00
|
|
|
// Removes all computed loop descriptors.
|
|
|
|
void ResetLoopAnalysis() {
|
|
|
|
// Clear the cache.
|
|
|
|
loop_descriptors_.clear();
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisLoopAnalysis;
|
|
|
|
}
|
|
|
|
|
2017-11-30 22:03:06 +00:00
|
|
|
// Analyzes the features in the owned module. Builds the manager if required.
|
|
|
|
void AnalyzeFeatures() {
|
2017-12-19 19:18:13 +00:00
|
|
|
feature_mgr_.reset(new opt::FeatureManager(grammar_));
|
2017-11-30 22:03:06 +00:00
|
|
|
feature_mgr_->Analyze(module());
|
|
|
|
}
|
|
|
|
|
2017-11-11 01:26:55 +00:00
|
|
|
// Scans a module looking for it capabilities, and initializes combinator_ops_
|
|
|
|
// accordingly.
|
|
|
|
void InitializeCombinators();
|
|
|
|
|
|
|
|
// Add the combinator opcode for the given capability to combinator_ops_.
|
|
|
|
void AddCombinatorsForCapability(uint32_t capability);
|
|
|
|
|
|
|
|
// Add the combinator opcode for the given extension to combinator_ops_.
|
|
|
|
void AddCombinatorsForExtension(ir::Instruction* extension);
|
|
|
|
|
2018-02-13 04:28:38 +00:00
|
|
|
// Remove |inst| from |id_to_name_| if it is in map.
|
|
|
|
void RemoveFromIdToName(const Instruction* inst);
|
|
|
|
|
2018-03-06 16:20:28 +00:00
|
|
|
// Returns true if it is suppose to be valid but it is incorrect. Returns
|
|
|
|
// true if the cfg is invalidated.
|
|
|
|
bool CheckCFG();
|
|
|
|
|
2017-12-19 19:18:13 +00:00
|
|
|
// The SPIR-V syntax context containing grammar tables for opcodes and
|
|
|
|
// operands.
|
|
|
|
spv_context syntax_context_;
|
|
|
|
|
|
|
|
// Auxiliary object for querying SPIR-V grammar facts.
|
|
|
|
libspirv::AssemblyGrammar grammar_;
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// An unique identifier for instructions in |module_|. Can be used to order
|
2017-11-14 19:11:50 +00:00
|
|
|
// instructions in a container.
|
|
|
|
//
|
|
|
|
// This member is initialized to 0, but always issues this value plus one.
|
|
|
|
// Therefore, 0 is not a valid unique id for an instruction.
|
|
|
|
uint32_t unique_id_;
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// The module being processed within this IR context.
|
2017-10-30 15:13:24 +00:00
|
|
|
std::unique_ptr<Module> module_;
|
2017-12-07 21:42:27 +00:00
|
|
|
|
|
|
|
// A message consumer for diagnostics.
|
2017-11-02 18:25:48 +00:00
|
|
|
spvtools::MessageConsumer consumer_;
|
2017-12-07 21:42:27 +00:00
|
|
|
|
|
|
|
// The def-use manager for |module_|.
|
2017-11-02 18:25:48 +00:00
|
|
|
std::unique_ptr<opt::analysis::DefUseManager> def_use_mgr_;
|
2017-12-07 21:42:27 +00:00
|
|
|
|
|
|
|
// The instruction decoration manager for |module_|.
|
2017-11-13 20:31:43 +00:00
|
|
|
std::unique_ptr<opt::analysis::DecorationManager> decoration_mgr_;
|
2017-11-30 22:03:06 +00:00
|
|
|
std::unique_ptr<opt::FeatureManager> feature_mgr_;
|
2017-11-02 18:25:48 +00:00
|
|
|
|
2017-11-10 14:39:00 +00:00
|
|
|
// A map from instructions the the basic block they belong to. This mapping is
|
|
|
|
// built on-demand when get_instr_block() is called.
|
|
|
|
//
|
|
|
|
// NOTE: Do not traverse this map. Ever. Use the function and basic block
|
|
|
|
// iterators to traverse instructions.
|
|
|
|
std::unordered_map<ir::Instruction*, ir::BasicBlock*> instr_to_block_;
|
|
|
|
|
2017-11-02 18:25:48 +00:00
|
|
|
// A bitset indicating which analyes are currently valid.
|
|
|
|
Analysis valid_analyses_;
|
2017-11-11 01:26:55 +00:00
|
|
|
|
|
|
|
// Opcodes of shader capability core executable instructions
|
|
|
|
// without side-effect.
|
2017-11-27 15:16:41 +00:00
|
|
|
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> combinator_ops_;
|
2017-11-27 19:20:32 +00:00
|
|
|
|
|
|
|
// The CFG for all the functions in |module_|.
|
|
|
|
std::unique_ptr<ir::CFG> cfg_;
|
2017-11-27 21:21:26 +00:00
|
|
|
|
|
|
|
// Each function in the module will create its own dominator tree. We cache
|
|
|
|
// the result so it doesn't need to be rebuilt each time.
|
|
|
|
std::map<const ir::Function*, opt::DominatorAnalysis> dominator_trees_;
|
|
|
|
std::map<const ir::Function*, opt::PostDominatorAnalysis>
|
|
|
|
post_dominator_trees_;
|
2017-12-07 21:42:27 +00:00
|
|
|
|
2018-01-25 10:33:06 +00:00
|
|
|
// Cache of loop descriptors for each function.
|
|
|
|
std::unordered_map<const ir::Function*, ir::LoopDescriptor> loop_descriptors_;
|
|
|
|
|
2017-12-07 21:42:27 +00:00
|
|
|
// Constant manager for |module_|.
|
|
|
|
std::unique_ptr<opt::analysis::ConstantManager> constant_mgr_;
|
|
|
|
|
|
|
|
// Type manager for |module_|.
|
|
|
|
std::unique_ptr<opt::analysis::TypeManager> type_mgr_;
|
2018-02-13 04:28:38 +00:00
|
|
|
|
|
|
|
// A map from an id to its corresponding OpName and OpMemberName instructions.
|
|
|
|
std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
|
2018-03-28 13:19:55 +00:00
|
|
|
|
|
|
|
// The cache scalar evolution analysis node.
|
|
|
|
std::unique_ptr<opt::ScalarEvolutionAnalysis> scalar_evolution_analysis_;
|
2018-04-17 14:31:09 +00:00
|
|
|
|
|
|
|
// The liveness analysis |module_|.
|
|
|
|
std::unique_ptr<opt::LivenessAnalysis> reg_pressure_;
|
2018-04-26 19:07:48 +00:00
|
|
|
|
|
|
|
std::unique_ptr<opt::ValueNumberTable> vn_table_;
|
2017-10-30 15:13:24 +00:00
|
|
|
};
|
|
|
|
|
2018-01-30 21:43:55 +00:00
|
|
|
inline ir::IRContext::Analysis operator|(ir::IRContext::Analysis lhs,
|
|
|
|
ir::IRContext::Analysis rhs) {
|
2017-11-02 18:25:48 +00:00
|
|
|
return static_cast<ir::IRContext::Analysis>(static_cast<int>(lhs) |
|
|
|
|
static_cast<int>(rhs));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline ir::IRContext::Analysis& operator|=(ir::IRContext::Analysis& lhs,
|
|
|
|
ir::IRContext::Analysis rhs) {
|
|
|
|
lhs = static_cast<ir::IRContext::Analysis>(static_cast<int>(lhs) |
|
|
|
|
static_cast<int>(rhs));
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
2018-01-30 21:43:55 +00:00
|
|
|
inline ir::IRContext::Analysis operator<<(ir::IRContext::Analysis a,
|
|
|
|
int shift) {
|
2017-11-02 18:25:48 +00:00
|
|
|
return static_cast<ir::IRContext::Analysis>(static_cast<int>(a) << shift);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline ir::IRContext::Analysis& operator<<=(ir::IRContext::Analysis& a,
|
|
|
|
int shift) {
|
|
|
|
a = static_cast<ir::IRContext::Analysis>(static_cast<int>(a) << shift);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
std::vector<Instruction*> spvtools::ir::IRContext::GetConstants() {
|
|
|
|
return module()->GetConstants();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<const Instruction*> IRContext::GetConstants() const {
|
|
|
|
return ((const Module*)module())->GetConstants();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::annotation_begin() {
|
|
|
|
return module()->annotation_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::annotation_end() {
|
|
|
|
return module()->annotation_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::annotations() {
|
|
|
|
return module_->annotations();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::annotations() const {
|
|
|
|
return ((const Module*)module_.get())->annotations();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::capability_begin() {
|
|
|
|
return module()->capability_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::capability_end() {
|
|
|
|
return module()->capability_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::capabilities() {
|
|
|
|
return module()->capabilities();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::capabilities() const {
|
|
|
|
return ((const Module*)module())->capabilities();
|
|
|
|
}
|
|
|
|
|
|
|
|
ir::Module::inst_iterator IRContext::types_values_begin() {
|
|
|
|
return module()->types_values_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
ir::Module::inst_iterator IRContext::types_values_end() {
|
|
|
|
return module()->types_values_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::types_values() {
|
|
|
|
return module()->types_values();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::types_values() const {
|
|
|
|
return ((const Module*)module_.get())->types_values();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::ext_inst_import_begin() {
|
|
|
|
return module()->ext_inst_import_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::ext_inst_import_end() {
|
|
|
|
return module()->ext_inst_import_end();
|
|
|
|
}
|
|
|
|
|
2017-11-21 19:47:46 +00:00
|
|
|
IteratorRange<Module::inst_iterator> IRContext::ext_inst_imports() {
|
|
|
|
return module()->ext_inst_imports();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::ext_inst_imports() const {
|
|
|
|
return ((const Module*)module_.get())->ext_inst_imports();
|
|
|
|
}
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
Module::inst_iterator IRContext::debug1_begin() {
|
|
|
|
return module()->debug1_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::debug1_end() { return module()->debug1_end(); }
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::debugs1() {
|
|
|
|
return module()->debugs1();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::debugs1() const {
|
|
|
|
return ((const Module*)module_.get())->debugs1();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::debug2_begin() {
|
|
|
|
return module()->debug2_begin();
|
|
|
|
}
|
|
|
|
Module::inst_iterator IRContext::debug2_end() { return module()->debug2_end(); }
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::debugs2() {
|
|
|
|
return module()->debugs2();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::debugs2() const {
|
|
|
|
return ((const Module*)module_.get())->debugs2();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::debug3_begin() {
|
|
|
|
return module()->debug3_begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::inst_iterator IRContext::debug3_end() { return module()->debug3_end(); }
|
|
|
|
|
|
|
|
IteratorRange<Module::inst_iterator> IRContext::debugs3() {
|
|
|
|
return module()->debugs3();
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<Module::const_inst_iterator> IRContext::debugs3() const {
|
|
|
|
return ((const Module*)module_.get())->debugs3();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::debug_clear() { module_->debug_clear(); }
|
|
|
|
|
|
|
|
void IRContext::AddCapability(std::unique_ptr<Instruction>&& c) {
|
2017-11-11 01:26:55 +00:00
|
|
|
AddCombinatorsForCapability(c->GetSingleWordInOperand(0));
|
2017-10-30 15:13:24 +00:00
|
|
|
module()->AddCapability(std::move(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddExtension(std::unique_ptr<Instruction>&& e) {
|
|
|
|
module()->AddExtension(std::move(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddExtInstImport(std::unique_ptr<Instruction>&& e) {
|
2017-11-11 01:26:55 +00:00
|
|
|
AddCombinatorsForExtension(e.get());
|
2017-10-30 15:13:24 +00:00
|
|
|
module()->AddExtInstImport(std::move(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::SetMemoryModel(std::unique_ptr<Instruction>&& m) {
|
|
|
|
module()->SetMemoryModel(std::move(m));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddEntryPoint(std::unique_ptr<Instruction>&& e) {
|
|
|
|
module()->AddEntryPoint(std::move(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddExecutionMode(std::unique_ptr<Instruction>&& e) {
|
|
|
|
module()->AddExecutionMode(std::move(e));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddDebug1Inst(std::unique_ptr<Instruction>&& d) {
|
|
|
|
module()->AddDebug1Inst(std::move(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddDebug2Inst(std::unique_ptr<Instruction>&& d) {
|
2018-02-13 04:28:38 +00:00
|
|
|
if (AreAnalysesValid(kAnalysisNameMap)) {
|
|
|
|
if (d->opcode() == SpvOpName || d->opcode() == SpvOpMemberName) {
|
|
|
|
id_to_name_->insert({d->result_id(), d.get()});
|
|
|
|
}
|
|
|
|
}
|
2017-10-30 15:13:24 +00:00
|
|
|
module()->AddDebug2Inst(std::move(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddDebug3Inst(std::unique_ptr<Instruction>&& d) {
|
|
|
|
module()->AddDebug3Inst(std::move(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddAnnotationInst(std::unique_ptr<Instruction>&& a) {
|
2017-11-13 20:31:43 +00:00
|
|
|
if (AreAnalysesValid(kAnalysisDecorations)) {
|
|
|
|
get_decoration_mgr()->AddDecoration(a.get());
|
|
|
|
}
|
2017-10-30 15:13:24 +00:00
|
|
|
module()->AddAnnotationInst(std::move(a));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddType(std::unique_ptr<Instruction>&& t) {
|
|
|
|
module()->AddType(std::move(t));
|
2018-03-06 16:20:28 +00:00
|
|
|
if (AreAnalysesValid(kAnalysisDefUse)) {
|
|
|
|
get_def_use_mgr()->AnalyzeInstDef(&*(--types_values_end()));
|
|
|
|
}
|
2017-10-30 15:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddGlobalValue(std::unique_ptr<Instruction>&& v) {
|
|
|
|
module()->AddGlobalValue(std::move(v));
|
2018-03-06 16:20:28 +00:00
|
|
|
if (AreAnalysesValid(kAnalysisDefUse)) {
|
|
|
|
get_def_use_mgr()->AnalyzeInstDef(&*(--types_values_end()));
|
|
|
|
}
|
2017-10-30 15:13:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void IRContext::AddFunction(std::unique_ptr<Function>&& f) {
|
|
|
|
module()->AddFunction(std::move(f));
|
|
|
|
}
|
2017-11-11 01:26:55 +00:00
|
|
|
|
2017-12-11 18:10:24 +00:00
|
|
|
void IRContext::AnalyzeDefUse(Instruction* inst) {
|
|
|
|
if (AreAnalysesValid(kAnalysisDefUse)) {
|
|
|
|
get_def_use_mgr()->AnalyzeInstDefUse(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 15:59:03 +00:00
|
|
|
void IRContext::UpdateDefUse(Instruction* inst) {
|
|
|
|
if (AreAnalysesValid(kAnalysisDefUse)) {
|
|
|
|
get_def_use_mgr()->UpdateDefUse(inst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-13 04:28:38 +00:00
|
|
|
void IRContext::BuildIdToNameMap() {
|
|
|
|
id_to_name_.reset(new std::multimap<uint32_t, Instruction*>());
|
|
|
|
for (Instruction& debug_inst : debugs2()) {
|
|
|
|
if (debug_inst.opcode() == SpvOpMemberName ||
|
|
|
|
debug_inst.opcode() == SpvOpName) {
|
|
|
|
id_to_name_->insert({debug_inst.GetSingleWordInOperand(0), &debug_inst});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
valid_analyses_ = valid_analyses_ | kAnalysisNameMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
IteratorRange<std::multimap<uint32_t, Instruction*>::iterator>
|
|
|
|
IRContext::GetNames(uint32_t id) {
|
|
|
|
if (!AreAnalysesValid(kAnalysisNameMap)) {
|
|
|
|
BuildIdToNameMap();
|
|
|
|
}
|
|
|
|
auto result = id_to_name_->equal_range(id);
|
|
|
|
return make_range(std::move(result.first), std::move(result.second));
|
|
|
|
}
|
|
|
|
|
2017-10-30 15:13:24 +00:00
|
|
|
} // namespace ir
|
|
|
|
} // namespace spvtools
|
|
|
|
#endif // SPIRV_TOOLS_IR_CONTEXT_H
|