forked from KhronosGroup/SPIRV-Tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fold_spec_constant_op_and_composite_pass.h
203 lines (179 loc) · 9.99 KB
/
fold_spec_constant_op_and_composite_pass.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// Copyright (c) 2016 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 LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_
#define LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <vector>
#include "constants.h"
#include "def_use_manager.h"
#include "module.h"
#include "pass.h"
#include "type_manager.h"
namespace spvtools {
namespace opt {
// The optimization pass that folds "Spec Constants", which are defined by
// OpSpecConstantOp and OpSpecConstantComposite instruction, to "Normal
// Constants", which are defined by OpConstantTrue, OpConstantFalse,
// OpConstant, OpConstantNull and OpConstantComposite instructions. Note that
// Spec Constants defined with OpSpecConstant, OpSpecConstantTrue and
// OpSpecConstantFalse instructions are not handled, as these instructions
// indicate their value are not determined and can be changed in future. A
// Spec Constant is foldable if all of its value(s) can be determined from the
// module. For example, an Integer Spec Constant defined with OpSpecConstantOp
// instruction can be folded if its value won't change later. This pass will
// replace the original OpSpecContantOp instruction with an OpConstant
// instruction. When folding composite type Spec Constants, new instructions
// may be inserted to define the components of the composite constant first,
// then the original Spec Constants will be replace with OpConstantComposite
// instructions.
// There are some operations not supported:
// OpSConvert, OpFConvert, OpQuantizeToF16 and all the operations under Kernel
// capability.
// TODO(qining): Add support for the operations listed above.
class FoldSpecConstantOpAndCompositePass : public Pass {
public:
explicit FoldSpecConstantOpAndCompositePass(const MessageConsumer& c);
const char* name() const override { return "fold-spec-const-op-composite"; }
bool Process(ir::Module* module) override {
Initialize(module);
return ProcessImpl(module);
};
private:
// Initializes the type manager, def-use manager and get the maximal id used
// in the module.
void Initialize(ir::Module* module) {
type_mgr_.reset(new analysis::TypeManager(consumer(), *module));
def_use_mgr_.reset(new analysis::DefUseManager(consumer(), module));
for (const auto& id_def : def_use_mgr_->id_to_defs()) {
max_id_ = std::max(max_id_, id_def.first);
}
module_ = module;
};
// The real entry of processing. Iterates through the types-constants-globals
// section of the given module, finds the Spec Constants defined with
// OpSpecConstantOp and OpSpecConstantComposite instructions. If the result
// value of those spec constants can be folded, fold them to their
// corresponding normal constants. Returns true if the module was modified.
bool ProcessImpl(ir::Module*);
// Processes the OpSpecConstantOp instruction pointed by the given
// instruction iterator, folds it to normal constants if possible. Returns
// true if the spec constant is folded to normal constants. New instructions
// will be inserted before the OpSpecConstantOp instruction pointed by the
// instruction iterator. The instruction iterator, which is passed by
// pointer, will still point to the original OpSpecConstantOp instruction. If
// folding is done successfully, the original OpSpecConstantOp instruction
// will be changed to Nop and new folded instruction will be inserted before
// it.
bool ProcessOpSpecConstantOp(ir::Module::inst_iterator* pos);
// Try to fold the OpSpecConstantOp CompositeExtract instruction pointed by
// the given instruction iterator to a normal constant defining instruction.
// Returns the pointer to the new constant defining instruction if succeeded.
// Otherwise returns nullptr.
ir::Instruction* DoCompositeExtract(ir::Module::inst_iterator* inst_iter_ptr);
// Try to fold the OpSpecConstantOp VectorShuffle instruction pointed by the
// given instruction iterator to a normal constant defining instruction.
// Returns the pointer to the new constant defining instruction if succeeded.
// Otherwise return nullptr.
ir::Instruction* DoVectorShuffle(ir::Module::inst_iterator* inst_iter_ptr);
// Try to fold the OpSpecConstantOp <component wise operations> instruction
// pointed by the given instruction iterator to a normal constant defining
// instruction. Returns the pointer to the new constant defining instruction
// if succeeded, otherwise return nullptr.
ir::Instruction* DoComponentWiseOperation(
ir::Module::inst_iterator* inst_iter_ptr);
// Creates a constant defining instruction for the given Constant instance
// and inserts the instruction at the position specified by the given
// instruction iterator. Returns a pointer to the created instruction if
// succeeded, otherwise returns a null pointer. The instruction iterator
// points to the same instruction before and after the insertion. This is the
// only method that actually manages id creation/assignment and instruction
// creation/insertion for a new Constant instance.
ir::Instruction* BuildInstructionAndAddToModule(
std::unique_ptr<analysis::Constant> c, ir::Module::inst_iterator* pos);
// Creates a Constant instance to hold the constant value of the given
// instruction. If the given instruction defines a normal constants whose
// value is already known in the module, returns the unique pointer to the
// created Constant instance. Otherwise does not create anything and returns a
// nullptr.
std::unique_ptr<analysis::Constant> CreateConstFromInst(
ir::Instruction* inst);
// Creates a Constant instance with the given type and a vector of constant
// defining words. Returns an unique pointer to the created Constant instance
// if the Constant instance can be created successfully. To create scalar
// type constants, the vector should contain the constant value in 32 bit
// words and the given type must be of type Bool, Integer or Float. To create
// composite type constants, the vector should contain the component ids, and
// those component ids should have been recorded before as Normal Constants.
// And the given type must be of type Struct, Vector or Array. When creating
// VectorType Constant instance, the components must be scalars of the same
// type, either Bool, Integer or Float. If any of the rules above failed, the
// creation will fail and nullptr will be returned. If the vector is empty,
// a NullConstant instance will be created with the given type.
std::unique_ptr<analysis::Constant> CreateConst(
const analysis::Type* type,
const std::vector<uint32_t>& literal_words_or_ids);
// Creates an instruction with the given result id to declare a constant
// represented by the given Constant instance. Returns an unique pointer to
// the created instruction if the instruction can be created successfully.
// Otherwise, returns a null pointer.
std::unique_ptr<ir::Instruction> CreateInstruction(uint32_t result_id,
analysis::Constant* c);
// Creates an OpConstantComposite instruction with the given result id and
// the CompositeConst instance which represents a composite constant. Returns
// an unique pointer to the created instruction if succeeded. Otherwise
// returns a null pointer.
std::unique_ptr<ir::Instruction> CreateCompositeInstruction(
uint32_t result_id, analysis::CompositeConstant* cc);
// A helper function to get the collected normal constant with the given id.
// Returns the pointer to the Constant instance in case it is found.
// Otherwise, returns null pointer.
analysis::Constant* FindRecordedConst(uint32_t id);
// A helper function to get the id of a collected constant with the pointer
// to the Constant instance. Returns 0 in case the constant is not found.
uint32_t FindRecordedConst(const analysis::Constant* c);
// A helper function to get a vector of Constant instances with the specified
// ids. If can not find the Constant instance for any one of the ids, returns
// an empty vector.
std::vector<const analysis::Constant*> GetConstsFromIds(
const std::vector<uint32_t>& ids);
// A helper function to get the result type of the given instrution. Returns
// nullptr if the instruction does not have a type id (type id is 0).
analysis::Type* GetType(const ir::Instruction* inst) {
return type_mgr_->GetType(inst->type_id());
}
// The maximum used ID.
uint32_t max_id_;
// A pointer to the module under process.
ir::Module* module_;
// DefUse manager
std::unique_ptr<analysis::DefUseManager> def_use_mgr_;
// Type manager
std::unique_ptr<analysis::TypeManager> type_mgr_;
// A mapping from the result ids of Normal Constants to their
// analysis::Constant instances. All Normal Constants in the module, either
// existing ones before optimization or the newly generated ones, should have
// their Constant instance stored and their result id registered in this map.
std::unordered_map<uint32_t, std::unique_ptr<analysis::Constant>>
id_to_const_val_;
// A mapping from the analsis::Constant instance of Normal Contants to their
// result id in the module. This is a mirror map of id_to_const_val_. All
// Normal Constants that defining instructions in the module should have
// their analysis::Constant and their result id registered here.
std::unordered_map<const analysis::Constant*, uint32_t> const_val_to_id_;
};
} // namespace opt
} // namespace spvtools
#endif // LIBSPIRV_OPT_FOLD_SPEC_CONSTANT_OP_AND_COMPOSITE_PASS_H_