File: function_basic_block.h

package info (click to toggle)
vulkan-validationlayers 1.4.321.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 47,412 kB
  • sloc: cpp: 594,175; python: 11,321; sh: 24; makefile: 20; xml: 14
file content (131 lines) | stat: -rw-r--r-- 5,468 bytes parent folder | download | duplicates (6)
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
/* Copyright (c) 2024-2025 LunarG, 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.
 */
#pragma once

#include <stdint.h>
#include <vector>
#include <list>
#include <memory>
#include <spirv/unified1/spirv.hpp>
#include "state_tracker/shader_instruction.h"

namespace gpuav {
namespace spirv {

class Module;
struct Function;

// Core data structure of module.
// We use the vector for Instruction because inside a block these should be together in memory. We should rarly need to update
// randomly in a block, for those cases, we just need to manage the iterator The unique_ptr allows us to create instructions outside
// module scope and bring them back.
using Instruction = ::spirv::Instruction;
using InstructionList = std::vector<std::unique_ptr<Instruction>>;
using InstructionIt = InstructionList::iterator;

// Since CFG analysis/manipulation is not a main focus, Blocks/Funcitons are just simple containers for ordering Instructions
struct BasicBlock {
    // Used when loading initial SPIR-V
    BasicBlock(std::unique_ptr<Instruction> label, Function& function);
    BasicBlock(Module& module, Function& function);

    void ToBinary(std::vector<uint32_t>& out);

    uint32_t GetLabelId() const;

    // "All OpVariable instructions in a function must be the first instructions in the first block"
    // So need to get the first valid location in block.
    InstructionIt GetFirstInjectableInstrution();
    // Finds instruction before the Block Termination Instruction.
    InstructionIt GetLastInjectableInstrution();

    // Creates an instruction and inserts it before an optional target inst_it.
    // If an InstructionIt is provided, inst_it will be updated to still point at the original target instruction.
    // Otherwise, the new instruction will be created at block end.
    void CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, InstructionIt* inst_it = nullptr);

    InstructionList instructions_;
    Function& function_;

    // For blocks that are a Loop hader, points to the Merge Target
    uint32_t loop_header_merge_target_ = 0;
    bool IsLoopHeader() const { return loop_header_merge_target_ != 0; }

    // If block terminates with OpBranchConditional/OpSwtich, mark the ID they point to
    uint32_t selection_merge_target_ = 0;
    uint32_t branch_conditional_true_ = 0;
    uint32_t branch_conditional_false_ = 0;
    uint32_t switch_default_ = 0;
    std::vector<uint32_t> switch_cases_;
};

// Control Flow can be tricky, so having this as a List allows use to easily add/remove/edit blocks around without worrying about
// the iterator breaking from under us.
using BasicBlockList = std::list<std::unique_ptr<BasicBlock>>;
using BasicBlockIt = BasicBlockList::iterator;

struct Function {
    // Used to add functions building up SPIR-V the first time
    Function(Module& module, std::unique_ptr<Instruction> function_inst, bool is_entry_point);
    // Used to link in new functions
    Function(Module& module) : module_(module), is_entry_point_(false), instrumentation_added_(true) {}

    void ToBinary(std::vector<uint32_t>& out);

    const Instruction& GetDef() { return *pre_block_inst_[0].get(); }
    BasicBlock& GetFirstBlock() { return *blocks_.front(); }

    // Adds a new block after and returns reference to it
    BasicBlockIt InsertNewBlock(BasicBlockIt it);
    BasicBlock& InsertNewBlockEnd();

    void ReplaceAllUsesWith(uint32_t old_word, uint32_t new_word);

    Module& module_;
    // OpFunction and parameters
    InstructionList pre_block_inst_;
    // All basic blocks inside this function in specification order
    BasicBlockList blocks_;
    // normally just OpFunctionEnd, but could be non-semantic
    InstructionList post_block_inst_;

    vvl::unordered_map<uint32_t, const Instruction*> inst_map_;
    const Instruction* FindInstruction(uint32_t id) const;

    // A slower version of BasicBlock::CreateInstruction() that will search the entire function for |id| and then inject the
    // instruction after. Only to be used if you need to suddenly walk back to find an instruction, but normally instructions should
    // be added as you go forward only.
    void CreateInstruction(spv::Op opcode, const std::vector<uint32_t>& words, uint32_t id);

    // This is the uvec4 most consumers will need
    uint32_t stage_info_id_ = 0;
    // The individual IDs making up the uvec4
    uint32_t stage_info_x_id_ = 0;
    uint32_t stage_info_y_id_ = 0;
    uint32_t stage_info_z_id_ = 0;
    uint32_t stage_info_w_id_ = 0;

    // Lets us know if the function on OpReturn will exit the shader or nor
    const bool is_entry_point_;

    // The main usage of this is for things like DebugPrintf that might want to actually run over previously instrumented functions
    const bool instrumentation_added_;
};

using FunctionList = std::vector<std::unique_ptr<Function>>;
using FunctionIt = FunctionList::iterator;

}  // namespace spirv
}  // namespace gpuav