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

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

Inheritance diagram for analysis::StackSafetyPass:
Collaboration diagram for analysis::StackSafetyPass:

Public Types

using Result = StackSafetyResult
Public Types inherited from analysis::AnalysisPass< StackSafetyPass, StackSafetyResult >
using Result

Public Member Functions

const char * getName () const override
Result run (const 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

Verifies that:

  1. All execution paths have consistent stack depths at merge points
  2. No stack underflows occur (sufficient depth before pop operations)
  3. All reachable terminal blocks end with expected final depth This is the final safety check before code generation. Depends on: BlockAnalysisPass

Definition at line 41 of file StackSafetyPass.hpp.

Member Typedef Documentation

◆ Result

Member Function Documentation

◆ getName()

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

Implements analysis::Pass.

Definition at line 46 of file StackSafetyPass.hpp.

46 {
47 return "Stack Safety Pass";
48 }

◆ run()

StackSafetyPass::Result analysis::StackSafetyPass::run ( const std::vector< Token > & tokens,
AnalysisManager & am )
overridevirtual

Implements analysis::AnalysisPass< StackSafetyPass, StackSafetyResult >.

Definition at line 29 of file StackSafetyPass.cpp.

30 {
31 const auto& block_result = am.getResult<BlockAnalysisPass>();
32 const auto& cfg_blocks = block_result.cfg_blocks;
33
34 int expected_final_depth = am.getExpectedFinalDepth();
35
36 Result result;
37 result.stack_depth_in.assign(cfg_blocks.size(), -1);
38
39 std::vector<int> worklist;
40
41 if (!cfg_blocks.empty()) {
42 result.stack_depth_in[0] = 0;
43 worklist.push_back(0);
44 }
45
46 size_t processed_count = 0;
47 while (!worklist.empty()) {
48 processed_count++;
49 if (processed_count >
50 cfg_blocks.size() * cfg_blocks.size()) { // Heuristic
51 throw AnalysisError(std::format(
52 "Failed to prove stack safety; check loops. "
53 "processed_count = {}, cfg_blocks = {}, heuristic_limit = {}, "
54 "worklist_size = {}, next_block_candidate = {}",
55 processed_count, cfg_blocks.size(),
56 cfg_blocks.size() * cfg_blocks.size(), worklist.size(),
57 worklist.back()));
58 }
59
60 int block_idx = worklist.back();
61 worklist.pop_back();
62
63 const auto& block = cfg_blocks[block_idx];
64 int depth_in = result.stack_depth_in[block_idx];
65
66 if (depth_in < block.min_stack_needed) {
67 throw AnalysisError(
68 std::format("Stack underflow before executing block {}: "
69 "depth_in = {}, min_needed = {}, start token '{}'",
70 block_idx, depth_in, block.min_stack_needed,
71 tokens[block.start_token_idx].text),
72 block.start_token_idx);
73 }
74
75 int depth_out = depth_in + block.stack_effect;
76
77 for (int succ_idx : block.successors) {
78 if (result.stack_depth_in[succ_idx] == -1) {
79 result.stack_depth_in[succ_idx] = depth_out;
80 worklist.push_back(succ_idx);
81 } else if (result.stack_depth_in[succ_idx] != depth_out) {
82 throw AnalysisError(
83 std::format(
84 "Stack depth mismatch on converging paths: "
85 "block {} -> successor {}. "
86 "incoming depth = {}, recorded successor depth = {}, "
87 "current start token '{}', successor start token '{}'",
88 block_idx, succ_idx, depth_out,
89 result.stack_depth_in[succ_idx],
90 tokens[block.start_token_idx].text,
91 tokens[cfg_blocks[succ_idx].start_token_idx].text),
92 cfg_blocks[succ_idx].start_token_idx);
93 }
94 }
95 }
96
97 for (size_t i = 0; i < cfg_blocks.size(); ++i) {
98 if (result.stack_depth_in[i] != -1 &&
99 cfg_blocks[i].successors.empty()) { // Reachable terminal block
100 int final_depth =
101 result.stack_depth_in[i] + cfg_blocks[i].stack_effect;
102 if (final_depth != expected_final_depth) {
103 throw AnalysisError(
104 std::format(
105 "Expression stack not balanced on "
106 "reachable terminal block {}: "
107 "final depth = {}, expected = {}, start token '{}'",
108 i, final_depth, expected_final_depth,
109 tokens[cfg_blocks[i].start_token_idx].text),
110 cfg_blocks[i].start_token_idx);
111 }
112 }
113 }
114
115 return result;
116}

References analysis::AnalysisManager::getExpectedFinalDepth(), analysis::AnalysisManager::getResult(), and analysis::StackSafetyResult::stack_depth_in.


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