VapourSynth-llvmexpr
Loading...
Searching...
No Matches
DynamicArrayAllocOptPass.cpp
Go to the documentation of this file.
1
19
23#include "BlockAnalysisPass.hpp"
24
25#include <map>
26#include <queue>
27#include <set>
28#include <string>
29#include <vector>
30
31namespace analysis {
32
33namespace {
34
35int find_block_for_token(int token_idx,
36 const std::vector<CFGBlock>& cfg_blocks) {
37 for (size_t i = 0; i < cfg_blocks.size(); ++i) {
38 if (token_idx >= cfg_blocks[i].start_token_idx &&
39 token_idx < cfg_blocks[i].end_token_idx) {
40 return static_cast<int>(i);
41 }
42 }
43 return -1;
44}
45
46bool is_array_used_in_range(const std::string& array_name,
47 const std::vector<Token>& tokens,
48 int start_token_idx, int end_token_idx) {
49 for (int i = start_token_idx; i < end_token_idx; ++i) {
50 const auto& token = tokens[i];
51 if (token.type == TokenType::ArrayLoad ||
52 token.type == TokenType::ArrayStore) {
53 const auto& payload = std::get<TokenPayloadArrayOp>(token.payload);
54 if (payload.name == array_name) {
55 return true;
56 }
57 }
58 }
59 return false;
60}
61
62bool is_array_used_between(const std::string& array_name,
63 const std::vector<Token>& tokens,
64 const std::vector<CFGBlock>& cfg_blocks,
65 int start_token_idx, int end_token_idx) {
66 int start_block = find_block_for_token(start_token_idx, cfg_blocks);
67 int end_block = find_block_for_token(end_token_idx, cfg_blocks);
68
69 if (start_block == -1 || end_block == -1) {
70 return true; // Assume used if we can't determine
71 }
72
73 if (start_block == end_block) {
74 return is_array_used_in_range(array_name, tokens, start_token_idx + 1,
75 end_token_idx);
76 }
77
78 std::queue<int> to_visit;
79 std::set<int> visited;
80
81 to_visit.push(start_block);
82 visited.insert(start_block);
83
84 while (!to_visit.empty()) {
85 int current_block = to_visit.front();
86 to_visit.pop();
87
88 const auto& block = cfg_blocks[current_block];
89
90 int check_start = block.start_token_idx;
91 int check_end = block.end_token_idx;
92
93 if (current_block == start_block) {
94 check_start = start_token_idx + 1;
95 }
96
97 if (current_block == end_block) {
98 check_end = end_token_idx;
99 }
100
101 if (is_array_used_in_range(array_name, tokens, check_start,
102 check_end)) {
103 return true;
104 }
105
106 if (current_block == end_block) {
107 continue;
108 }
109
110 for (int successor : block.successors) {
111 if (!visited.contains(successor)) {
112 visited.insert(successor);
113 to_visit.push(successor);
114 }
115 }
116 }
117
118 return false;
119}
120
121} // namespace
122
124 AnalysisManager& am) {
125 const auto& block_result = am.getResult<BlockAnalysisPass>();
126 const auto& cfg_blocks = block_result.cfg_blocks;
127
128 std::set<int> allocations_to_remove;
129
130 std::map<std::string, std::vector<int>> dynamic_allocations;
131
132 for (size_t i = 0; i < tokens.size(); ++i) {
133 const auto& token = tokens[i];
134 if (token.type == TokenType::ArrayAllocDyn) {
135 const auto& payload = std::get<TokenPayloadArrayOp>(token.payload);
136 dynamic_allocations[payload.name].push_back(static_cast<int>(i));
137 }
138 }
139
140 for (const auto& [array_name, alloc_indices] : dynamic_allocations) {
141 if (alloc_indices.size() < 2) {
142 continue;
143 }
144
145 for (size_t i = 0; i < alloc_indices.size() - 1; ++i) {
146 int first_alloc = alloc_indices[i];
147 int second_alloc = alloc_indices[i + 1];
148
149 bool used = is_array_used_between(array_name, tokens, cfg_blocks,
150 first_alloc, second_alloc);
151
152 if (!used) {
153 allocations_to_remove.insert(first_alloc);
154 }
155 }
156 }
157
158 if (allocations_to_remove.empty()) {
159 return PreservedAnalyses::all();
160 }
161
162 for (int token_idx : allocations_to_remove) {
163 auto& token = tokens[token_idx];
164 token.type = TokenType::Drop;
165 token.text = "drop1";
166 token.payload = TokenPayloadStackOp{.n = 1};
167 }
168
170}
171
172} // namespace analysis
PreservedAnalyses run(std::vector< Token > &tokens, AnalysisManager &am) override
static PreservedAnalyses all()
static PreservedAnalyses none()