VapourSynth-llvmexpr
Loading...
Searching...
No Matches
StaticArrayOptPass.cpp
Go to the documentation of this file.
1
19
23#include "BlockAnalysisPass.hpp"
24#include "ConstPropPass.hpp"
25
26#include <algorithm>
27#include <map>
28#include <optional>
29#include <ranges>
30
31namespace {
32constexpr int SINGLEEXPR_STACK_ALLOC_THRESHOLD = 1024;
33} // namespace
34
35namespace analysis {
36
37PreservedAnalyses StaticArrayOptPass::run(std::vector<Token>& tokens,
38 AnalysisManager& am) {
39 const auto& const_result = am.getResult<ConstPropPass>();
40 const auto& in_stacks = const_result.const_stack_in;
41
42 const auto& block_result = am.getResult<BlockAnalysisPass>();
43 const auto& cfg_blocks = block_result.cfg_blocks;
44
45 std::map<std::string, int> array_alloc_count;
46 for (const auto& token : tokens) {
47 if (token.type == TokenType::ArrayAllocStatic ||
48 token.type == TokenType::ArrayAllocDyn) {
49 const auto& payload = std::get<TokenPayloadArrayOp>(token.payload);
50 array_alloc_count[payload.name]++;
51 }
52 }
53
54 std::map<int, int> dyn_to_static;
55
56 for (size_t block_idx = 0; block_idx < cfg_blocks.size(); ++block_idx) {
57 const auto& block = cfg_blocks[block_idx];
58
59 auto current_stack = in_stacks[block_idx];
60
61 for (int token_idx = block.start_token_idx;
62 token_idx < block.end_token_idx; ++token_idx) {
63 const auto& token = tokens[token_idx];
64 const auto behavior = get_token_behavior(token);
65
66 while (current_stack.size() < static_cast<size_t>(behavior.arity)) {
67 current_stack.insert(current_stack.begin(), std::nullopt);
68 }
69
70 std::vector<std::optional<double>> args;
71 for (int k = 0; k < behavior.arity; ++k) {
72 args.push_back(current_stack.back());
73 current_stack.pop_back();
74 }
75 std::ranges::reverse(args);
76
77 if (token.type == TokenType::ArrayAllocDyn) {
78 const auto& payload =
79 std::get<TokenPayloadArrayOp>(token.payload);
80 // Convert to static allocation if:
81 // 1. Size is a compile-time constant (from ConstPropPass)
82 // 2. Size <= threshold
83 // 3. Only allocated once
84 if (args[0].has_value() &&
85 array_alloc_count[payload.name] == 1) {
86 int size = static_cast<int>(args[0].value());
87 if (size > 0 && size <= SINGLEEXPR_STACK_ALLOC_THRESHOLD) {
88 dyn_to_static[token_idx] = size;
89 }
90 }
91 }
92
93 for (int k = 0; k < behavior.arity + behavior.stack_effect; ++k) {
94 current_stack.emplace_back(std::nullopt);
95 }
96 }
97 }
98
99 std::vector<std::pair<int, Token>> insertions; // position, token to insert
100
101 for (auto& it : std::ranges::reverse_view(dyn_to_static)) {
102 int token_idx = it.first;
103 int size = it.second;
104
105 auto& token = tokens[token_idx];
106 auto& payload = std::get<TokenPayloadArrayOp>(token.payload);
107
108 token.type = TokenType::ArrayAllocStatic;
109 token.text = payload.name + "{}^" + std::to_string(size);
110 payload.static_size = size;
111
112 Token drop_token{.type = TokenType::Drop,
113 .text = "drop1",
114 .payload = TokenPayloadStackOp{.n = 1}};
115
116 insertions.emplace_back(token_idx, drop_token);
117 }
118
119 for (const auto& [pos, drop_token] : insertions) {
120 tokens.insert(tokens.begin() + pos, drop_token);
121 }
122
123 if (!dyn_to_static.empty()) {
125 }
126
127 return PreservedAnalyses::all();
128}
129
130} // namespace analysis
TokenBehavior get_token_behavior(const Token &token)
@ ArrayAllocStatic
Definition Tokenizer.hpp:51
static PreservedAnalyses all()
static PreservedAnalyses none()
PreservedAnalyses run(std::vector< Token > &tokens, AnalysisManager &am) override