VapourSynth-llvmexpr
Loading...
Searching...
No Matches
analysis::StaticArrayOptPass Class Reference

#include <llvmexpr/analysis/passes/StaticArrayOptPass.hpp>

Inheritance diagram for analysis::StaticArrayOptPass:
Collaboration diagram for analysis::StaticArrayOptPass:

Public Member Functions

const char * getName () const override
PreservedAnalyses run (std::vector< Token > &tokens, AnalysisManager &am) override
Public Member Functions inherited from analysis::Pass
 Pass ()=default
virtual ~Pass ()=default
 Pass (const Pass &)=delete
Passoperator= (const Pass &)=delete
 Pass (Pass &&)=delete
Passoperator= (Pass &&)=delete

Detailed Description

Converts dynamic array allocations to static allocations when possible. This optimization transforms ARRAY_ALLOC_DYN to ARRAY_ALLOC_STATIC when:

  1. Array size is known at compile time (via constant propagation)
  2. Array size is <= threshold (1024 elements)
  3. Array is allocated only once in the entire expression

The transformation involves:

  • Changing token type from ARRAY_ALLOC_DYN to ARRAY_ALLOC_STATIC
  • Setting the static_size in the payload
  • Inserting a DROP instruction to consume the size value from stack

Depends on: ConstPropPass, BlockAnalysisPass

Definition at line 41 of file StaticArrayOptPass.hpp.

Member Function Documentation

◆ getName()

const char * analysis::StaticArrayOptPass::getName ( ) const
inlinenodiscardoverridevirtual

Implements analysis::Pass.

Definition at line 43 of file StaticArrayOptPass.hpp.

43 {
44 return "Static Array Optimization Pass";
45 }

◆ run()

PreservedAnalyses analysis::StaticArrayOptPass::run ( std::vector< Token > & tokens,
AnalysisManager & am )
overridevirtual

Implements analysis::TransformationPass.

Definition at line 37 of file StaticArrayOptPass.cpp.

38 {
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}
TokenBehavior get_token_behavior(const Token &token)
@ ArrayAllocStatic
Definition Tokenizer.hpp:51
static PreservedAnalyses all()
static PreservedAnalyses none()
preprocessor_detail::Token Token

References analysis::PreservedAnalyses::all(), ArrayAllocDyn, ArrayAllocStatic, Drop, get_token_behavior(), analysis::AnalysisManager::getResult(), and analysis::PreservedAnalyses::none().


The documentation for this class was generated from the following files: