blob: d29c1e074bb9d9c85b58beb15d5fe23d95940f8a [file] [log] [blame]
Greg Fischer04fcc662016-11-10 10:11:50 -07001// Copyright (c) 2017 The Khronos Group Inc.
2// Copyright (c) 2017 Valve Corporation
3// Copyright (c) 2017 LunarG Inc.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
dan sinclair58a68762018-08-03 08:05:33 -040017#ifndef SOURCE_OPT_INLINE_PASS_H_
18#define SOURCE_OPT_INLINE_PASS_H_
Greg Fischer04fcc662016-11-10 10:11:50 -070019
20#include <algorithm>
Diego Novillod2938e42017-11-08 12:40:02 -050021#include <list>
Greg Fischer04fcc662016-11-10 10:11:50 -070022#include <memory>
dan sinclaireda2cfb2018-08-03 15:06:09 -040023#include <set>
Greg Fischer04fcc662016-11-10 10:11:50 -070024#include <unordered_map>
25#include <vector>
26
Jaebaek Seo50b15572020-05-21 13:09:43 -040027#include "source/opt/debug_info_manager.h"
dan sinclaireda2cfb2018-08-03 15:06:09 -040028#include "source/opt/decoration_manager.h"
29#include "source/opt/module.h"
30#include "source/opt/pass.h"
Greg Fischer04fcc662016-11-10 10:11:50 -070031
32namespace spvtools {
33namespace opt {
34
35// See optimizer.hpp for documentation.
36class InlinePass : public Pass {
dan sinclairc7da51a2018-07-12 15:14:43 -040037 using cbb_ptr = const BasicBlock*;
Greg Fischerbba812f2017-05-04 20:55:53 -060038
Greg Fischer04fcc662016-11-10 10:11:50 -070039 public:
Corentin Wallez4a59fd42021-03-09 13:16:43 +000040 virtual ~InlinePass() override = default;
Greg Fischer04fcc662016-11-10 10:11:50 -070041
GregFe28bd392017-08-01 17:20:13 -060042 protected:
dan sinclairf96b7f12018-07-12 09:08:45 -040043 InlinePass();
Greg Fischer04fcc662016-11-10 10:11:50 -070044
Steven Perronacd27812018-12-18 19:34:03 +000045 // Add pointer to type to module and return resultId. Returns 0 if the type
46 // could not be created.
Greg Fischer04fcc662016-11-10 10:11:50 -070047 uint32_t AddPointerToType(uint32_t type_id, SpvStorageClass storage_class);
48
49 // Add unconditional branch to labelId to end of block block_ptr.
dan sinclairc7da51a2018-07-12 15:14:43 -040050 void AddBranch(uint32_t labelId, std::unique_ptr<BasicBlock>* block_ptr);
Greg Fischer04fcc662016-11-10 10:11:50 -070051
Greg Fischerbba812f2017-05-04 20:55:53 -060052 // Add conditional branch to end of block |block_ptr|.
Diego Novillod2938e42017-11-08 12:40:02 -050053 void AddBranchCond(uint32_t cond_id, uint32_t true_id, uint32_t false_id,
dan sinclairc7da51a2018-07-12 15:14:43 -040054 std::unique_ptr<BasicBlock>* block_ptr);
Greg Fischerbba812f2017-05-04 20:55:53 -060055
56 // Add unconditional branch to labelId to end of block block_ptr.
57 void AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
dan sinclairc7da51a2018-07-12 15:14:43 -040058 std::unique_ptr<BasicBlock>* block_ptr);
Greg Fischerbba812f2017-05-04 20:55:53 -060059
Greg Fischer04fcc662016-11-10 10:11:50 -070060 // Add store of valId to ptrId to end of block block_ptr.
61 void AddStore(uint32_t ptrId, uint32_t valId,
Jaebaek Seo50b15572020-05-21 13:09:43 -040062 std::unique_ptr<BasicBlock>* block_ptr,
63 const Instruction* line_inst, const DebugScope& dbg_scope);
Greg Fischer04fcc662016-11-10 10:11:50 -070064
65 // Add load of ptrId into resultId to end of block block_ptr.
66 void AddLoad(uint32_t typeId, uint32_t resultId, uint32_t ptrId,
Jaebaek Seo50b15572020-05-21 13:09:43 -040067 std::unique_ptr<BasicBlock>* block_ptr,
68 const Instruction* line_inst, const DebugScope& dbg_scope);
Greg Fischer04fcc662016-11-10 10:11:50 -070069
70 // Return new label.
dan sinclairc7da51a2018-07-12 15:14:43 -040071 std::unique_ptr<Instruction> NewLabel(uint32_t label_id);
Greg Fischer04fcc662016-11-10 10:11:50 -070072
Greg Fischerbba812f2017-05-04 20:55:53 -060073 // Returns the id for the boolean false value. Looks in the module first
Steven Perronacd27812018-12-18 19:34:03 +000074 // and creates it if not found. Remembers it for future calls. Returns 0 if
75 // the value could not be created.
Greg Fischerbba812f2017-05-04 20:55:53 -060076 uint32_t GetFalseId();
77
Greg Fischer04fcc662016-11-10 10:11:50 -070078 // Map callee params to caller args
dan sinclairc7da51a2018-07-12 15:14:43 -040079 void MapParams(Function* calleeFn, BasicBlock::iterator call_inst_itr,
Greg Fischer04fcc662016-11-10 10:11:50 -070080 std::unordered_map<uint32_t, uint32_t>* callee2caller);
81
Steven Perronacd27812018-12-18 19:34:03 +000082 // Clone and map callee locals. Return true if successful.
83 bool CloneAndMapLocals(Function* calleeFn,
dan sinclairc7da51a2018-07-12 15:14:43 -040084 std::vector<std::unique_ptr<Instruction>>* new_vars,
Jaebaek Seo50b15572020-05-21 13:09:43 -040085 std::unordered_map<uint32_t, uint32_t>* callee2caller,
86 analysis::DebugInlinedAtContext* inlined_at_ctx);
Greg Fischer04fcc662016-11-10 10:11:50 -070087
Steven Perronacd27812018-12-18 19:34:03 +000088 // Create return variable for callee clone code. The return type of
89 // |calleeFn| must not be void. Returns the id of the return variable if
90 // created. Returns 0 if the return variable could not be created.
dan sinclairc7da51a2018-07-12 15:14:43 -040091 uint32_t CreateReturnVar(Function* calleeFn,
92 std::vector<std::unique_ptr<Instruction>>* new_vars);
Greg Fischer04fcc662016-11-10 10:11:50 -070093
94 // Return true if instruction must be in the same block that its result
95 // is used.
dan sinclairc7da51a2018-07-12 15:14:43 -040096 bool IsSameBlockOp(const Instruction* inst) const;
Greg Fischer04fcc662016-11-10 10:11:50 -070097
98 // Clone operands which must be in same block as consumer instructions.
99 // Look in preCallSB for instructions that need cloning. Look in
100 // postCallSB for instructions already cloned. Add cloned instruction
101 // to postCallSB.
Steven Perronacd27812018-12-18 19:34:03 +0000102 bool CloneSameBlockOps(std::unique_ptr<Instruction>* inst,
dan sinclairc7da51a2018-07-12 15:14:43 -0400103 std::unordered_map<uint32_t, uint32_t>* postCallSB,
104 std::unordered_map<uint32_t, Instruction*>* preCallSB,
105 std::unique_ptr<BasicBlock>* block_ptr);
Greg Fischer04fcc662016-11-10 10:11:50 -0700106
107 // Return in new_blocks the result of inlining the call at call_inst_itr
108 // within its block at call_block_itr. The block at call_block_itr can
109 // just be replaced with the blocks in new_blocks. Any additional branches
110 // are avoided. Debug instructions are cloned along with their callee
111 // instructions. Early returns are replaced by a store to a local return
112 // variable and a branch to a (created) exit block where the local variable
113 // is returned. Formal parameters are trivially mapped to their actual
114 // parameters. Note that the first block in new_blocks retains the label
115 // of the original calling block. Also note that if an exit block is
David Netoceb1d4f2017-03-31 10:36:58 -0400116 // created, it is the last block of new_blocks.
Greg Fischer04fcc662016-11-10 10:11:50 -0700117 //
118 // Also return in new_vars additional OpVariable instructions required by
119 // and to be inserted into the caller function after the block at
120 // call_block_itr is replaced with new_blocks.
Steven Perronacd27812018-12-18 19:34:03 +0000121 //
122 // Returns true if successful.
123 bool GenInlineCode(std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
dan sinclairc7da51a2018-07-12 15:14:43 -0400124 std::vector<std::unique_ptr<Instruction>>* new_vars,
125 BasicBlock::iterator call_inst_itr,
126 UptrVectorIterator<BasicBlock> call_block_itr);
Greg Fischer04fcc662016-11-10 10:11:50 -0700127
Greg Fischerbba812f2017-05-04 20:55:53 -0600128 // Return true if |inst| is a function call that can be inlined.
Steven Perronaa9e8f52019-07-17 14:59:05 -0400129 bool IsInlinableFunctionCall(const Instruction* inst);
David Netoceb1d4f2017-03-31 10:36:58 -0400130
Greg Fischerbba812f2017-05-04 20:55:53 -0600131 // Return true if |func| has no return in a loop. The current analysis
132 // requires structured control flow, so return false if control flow not
133 // structured ie. module is not a shader.
dan sinclairc7da51a2018-07-12 15:14:43 -0400134 bool HasNoReturnInLoop(Function* func);
Greg Fischerbba812f2017-05-04 20:55:53 -0600135
136 // Find all functions with multiple returns and no returns in loops
dan sinclairc7da51a2018-07-12 15:14:43 -0400137 void AnalyzeReturns(Function* func);
Greg Fischerbba812f2017-05-04 20:55:53 -0600138
139 // Return true if |func| is a function that can be inlined.
dan sinclairc7da51a2018-07-12 15:14:43 -0400140 bool IsInlinableFunction(Function* func);
GregFa107d342017-04-25 13:57:20 -0600141
Steven Perronf98473c2022-09-21 16:10:58 -0400142 // Returns true if |func| contains an abort instruction that is not an
143 // `OpUnreachable` instruction.
144 bool ContainsAbortOtherThanUnreachable(Function* func) const;
Steven Perronc18c9ff2019-10-04 13:05:32 -0400145
GregFe28bd392017-08-01 17:20:13 -0600146 // Update phis in succeeding blocks to point to new last block
147 void UpdateSucceedingPhis(
dan sinclairc7da51a2018-07-12 15:14:43 -0400148 std::vector<std::unique_ptr<BasicBlock>>& new_blocks);
Greg Fischer04fcc662016-11-10 10:11:50 -0700149
GregF429ca052017-08-15 17:58:28 -0600150 // Initialize state for optimization of |module|
dan sinclairf96b7f12018-07-12 09:08:45 -0400151 void InitializeInline();
Greg Fischer04fcc662016-11-10 10:11:50 -0700152
Greg Fischer04fcc662016-11-10 10:11:50 -0700153 // Map from function's result id to function.
dan sinclairc7da51a2018-07-12 15:14:43 -0400154 std::unordered_map<uint32_t, Function*> id2function_;
Greg Fischer04fcc662016-11-10 10:11:50 -0700155
Diego Novillofef669f2017-10-30 17:42:26 -0400156 // Map from block's label id to block. TODO(dnovillo): This is superfluous wrt
dan sinclairc7da51a2018-07-12 15:14:43 -0400157 // CFG. It has functionality not present in CFG. Consolidate.
158 std::unordered_map<uint32_t, BasicBlock*> id2block_;
Greg Fischer04fcc662016-11-10 10:11:50 -0700159
greg-lunarg67214782018-11-08 07:11:20 -0700160 // Set of ids of functions with early return.
161 std::set<uint32_t> early_return_funcs_;
Greg Fischerbba812f2017-05-04 20:55:53 -0600162
163 // Set of ids of functions with no returns in loop
164 std::set<uint32_t> no_return_in_loop_;
165
166 // Set of ids of inlinable functions
GregFa107d342017-04-25 13:57:20 -0600167 std::set<uint32_t> inlinable_;
168
Greg Fischerbba812f2017-05-04 20:55:53 -0600169 // result id for OpConstantFalse
170 uint32_t false_id_;
Steven Perronc18c9ff2019-10-04 13:05:32 -0400171
172 // Set of functions that are originally called directly or indirectly from a
173 // continue construct.
174 std::unordered_set<uint32_t> funcs_called_from_continue_;
Steven Perronbd0a2da2020-05-14 10:55:47 -0400175
176 private:
177 // Moves instructions of the caller function up to the call instruction
178 // to |new_blk_ptr|.
179 void MoveInstsBeforeEntryBlock(
180 std::unordered_map<uint32_t, Instruction*>* preCallSB,
181 BasicBlock* new_blk_ptr, BasicBlock::iterator call_inst_itr,
182 UptrVectorIterator<BasicBlock> call_block_itr);
183
184 // Returns a new guard block after adding a branch to the end of
185 // |new_blocks|.
186 std::unique_ptr<BasicBlock> AddGuardBlock(
187 std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
188 std::unordered_map<uint32_t, uint32_t>* callee2caller,
189 std::unique_ptr<BasicBlock> new_blk_ptr, uint32_t entry_blk_label_id);
190
191 // Add store instructions for initializers of variables.
192 InstructionList::iterator AddStoresForVariableInitializers(
193 const std::unordered_map<uint32_t, uint32_t>& callee2caller,
Jaebaek Seo50b15572020-05-21 13:09:43 -0400194 analysis::DebugInlinedAtContext* inlined_at_ctx,
Steven Perronbd0a2da2020-05-14 10:55:47 -0400195 std::unique_ptr<BasicBlock>* new_blk_ptr,
196 UptrVectorIterator<BasicBlock> callee_block_itr);
197
198 // Inlines a single instruction of the callee function.
Jaebaek Seo50b15572020-05-21 13:09:43 -0400199 bool InlineSingleInstruction(
Steven Perronbd0a2da2020-05-14 10:55:47 -0400200 const std::unordered_map<uint32_t, uint32_t>& callee2caller,
Jaebaek Seo50b15572020-05-21 13:09:43 -0400201 BasicBlock* new_blk_ptr, const Instruction* inst,
202 uint32_t dbg_inlined_at);
Steven Perronbd0a2da2020-05-14 10:55:47 -0400203
204 // Inlines the return instruction of the callee function.
205 std::unique_ptr<BasicBlock> InlineReturn(
206 const std::unordered_map<uint32_t, uint32_t>& callee2caller,
207 std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
Jaebaek Seo50b15572020-05-21 13:09:43 -0400208 std::unique_ptr<BasicBlock> new_blk_ptr,
209 analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
Steven Perronbd0a2da2020-05-14 10:55:47 -0400210 const Instruction* inst, uint32_t returnVarId);
211
212 // Inlines the entry block of the callee function.
213 bool InlineEntryBlock(
214 const std::unordered_map<uint32_t, uint32_t>& callee2caller,
215 std::unique_ptr<BasicBlock>* new_blk_ptr,
Jaebaek Seo50b15572020-05-21 13:09:43 -0400216 UptrVectorIterator<BasicBlock> callee_first_block,
217 analysis::DebugInlinedAtContext* inlined_at_ctx);
Steven Perronbd0a2da2020-05-14 10:55:47 -0400218
219 // Inlines basic blocks of the callee function other than the entry basic
220 // block.
221 std::unique_ptr<BasicBlock> InlineBasicBlocks(
222 std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
223 const std::unordered_map<uint32_t, uint32_t>& callee2caller,
Jaebaek Seo50b15572020-05-21 13:09:43 -0400224 std::unique_ptr<BasicBlock> new_blk_ptr,
225 analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn);
Steven Perronbd0a2da2020-05-14 10:55:47 -0400226
227 // Moves instructions of the caller function after the call instruction
228 // to |new_blk_ptr|.
229 bool MoveCallerInstsAfterFunctionCall(
230 std::unordered_map<uint32_t, Instruction*>* preCallSB,
231 std::unordered_map<uint32_t, uint32_t>* postCallSB,
232 std::unique_ptr<BasicBlock>* new_blk_ptr,
233 BasicBlock::iterator call_inst_itr, bool multiBlocks);
234
235 // Move the OpLoopMerge from the last block back to the first.
236 void MoveLoopMergeInstToFirstBlock(
237 std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
alan-baker286e9c12022-06-29 23:32:20 -0400238
239 // Update the structure of single block loops so that the inlined code ends
240 // up in the loop construct and a new continue target is added to satisfy
241 // structural dominance.
242 void UpdateSingleBlockLoopContinueTarget(
243 uint32_t new_id, std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
Greg Fischer04fcc662016-11-10 10:11:50 -0700244};
245
246} // namespace opt
247} // namespace spvtools
248
dan sinclair58a68762018-08-03 08:05:33 -0400249#endif // SOURCE_OPT_INLINE_PASS_H_