Skip to content

Commit cd54f4a

Browse files
committed
Refactor Analysis.cpp and fix bitwise operator rounding
Akarin.Expr rounds to nearest integer, so we do the same
1 parent 5ce1c33 commit cd54f4a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2446
-738
lines changed

docs/postfix.md

Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -102,59 +102,59 @@ These operators push a specific value onto the stack without needing an operand.
102102

103103
#### **3.1. Arithmetic Operators**
104104

105-
| Operator | Operands | Description |
106-
| :--- | :--- | :--- |
107-
| `+` | 2 | Addition |
108-
| `-` | 2 | Subtraction |
109-
| `*` | 2 | Multiplication |
110-
| `/` | 2 | Division |
111-
| `%` | 2 | C's `fmodf`. `x 1.0 %` gives the fractional part of `x`. |
105+
| Operator | Operands | Description |
106+
| :------- | :------- | :------------------------------------------------------- |
107+
| `+` | 2 | Addition |
108+
| `-` | 2 | Subtraction |
109+
| `*` | 2 | Multiplication |
110+
| `/` | 2 | Division |
111+
| `%` | 2 | C's `fmodf`. `x 1.0 %` gives the fractional part of `x`. |
112112

113113
#### **3.2. Comparison & Logical Operators**
114114

115115
These operators treat any value greater than 0 as `true`. They return `1.0` for true and `0.0` for false.
116116

117-
| Operator | Operands | Description |
118-
| :--- | :--- | :--- |
119-
| `>` | 2 | Greater than |
120-
| `<` | 2 | Less than |
121-
| `=` | 2 | Equal to |
122-
| `>=` | 2 | Greater than or equal to |
123-
| `<=` | 2 | Less than or equal to |
124-
| `and` | 2 | Logical AND |
125-
| `or` | 2 | Logical OR |
126-
| `xor` | 2 | Logical XOR |
127-
| `not` | 1 | Logical NOT |
117+
| Operator | Operands | Description |
118+
| :------- | :------- | :----------------------- |
119+
| `>` | 2 | Greater than |
120+
| `<` | 2 | Less than |
121+
| `=` | 2 | Equal to |
122+
| `>=` | 2 | Greater than or equal to |
123+
| `<=` | 2 | Less than or equal to |
124+
| `and` | 2 | Logical AND |
125+
| `or` | 2 | Logical OR |
126+
| `xor` | 2 | Logical XOR |
127+
| `not` | 1 | Logical NOT |
128128

129129
#### **3.3. Mathematical Functions**
130130

131-
| Function | Operands | Description |
132-
| :--- | :--- | :--- |
133-
| **Power & Root** | | |
134-
| `pow` or `**` | 2 | `x y pow` raises `x` to the power of `y`. `**` is an alias. |
135-
| `sqrt` | 1 | `x sqrt` is the square root of `x`. |
136-
| **Exponential & Logarithmic** | | |
137-
| `exp` | 1 | `x exp` is e^x. |
138-
| `exp2` | 1 | `x exp2` computes 2^x. |
139-
| `log` | 1 | `x log` is the natural logarithm of `x`. |
140-
| `log2` | 1 | `x log2` computes the base-2 logarithm of `x`. |
141-
| `log10` | 1 | `x log10` computes the base-10 logarithm of `x`. |
142-
| **Trigonometric** | | |
143-
| `sin`, `cos`, `tan` | 1 | Sine, Cosine, Tangent. |
144-
| `asin`, `acos`, `atan` | 1 | Arc Sine, Arc Cosine, Arc Tangent. |
145-
| `atan2` | 2 | `y x atan2` computes `atan(y/x)` using signs to find the correct quadrant. |
146-
| `sinh`, `cosh`, `tanh` | 1 | Hyperbolic Sine, Cosine, Tangent. |
147-
| **Rounding** | | |
148-
| `floor` | 1 | Rounds down to the nearest integer. |
149-
| `ceil` | 1 | Rounds up to the nearest integer. |
150-
| `round` | 1 | Rounds to the nearest integer. |
151-
| `trunc` | 1 | Truncates towards zero. |
152-
| **Other** | | |
153-
| `abs` | 1 | `x abs` is the absolute value of `x`. |
154-
| `copysign` | 2 | `x y copysign` returns a value with the magnitude of `x` and the sign of `y`. |
155-
| `fma` | 3 | `a b c fma` computes `(a * b) + c` as a single fused multiply-add. |
156-
| `neg` | 1 | `x neg` negates `x`. |
157-
| `sgn` | 1 | `x sgn` is the sign of `x`: -1 if x<0; 0 when x==0; 1 if x>0. |
131+
| Function | Operands | Description |
132+
| :---------------------------- | :------- | :---------------------------------------------------------------------------- |
133+
| **Power & Root** | | |
134+
| `pow` or `**` | 2 | `x y pow` raises `x` to the power of `y`. `**` is an alias. |
135+
| `sqrt` | 1 | `x sqrt` is the square root of `x`. |
136+
| **Exponential & Logarithmic** | | |
137+
| `exp` | 1 | `x exp` is e^x. |
138+
| `exp2` | 1 | `x exp2` computes 2^x. |
139+
| `log` | 1 | `x log` is the natural logarithm of `x`. |
140+
| `log2` | 1 | `x log2` computes the base-2 logarithm of `x`. |
141+
| `log10` | 1 | `x log10` computes the base-10 logarithm of `x`. |
142+
| **Trigonometric** | | |
143+
| `sin`, `cos`, `tan` | 1 | Sine, Cosine, Tangent. |
144+
| `asin`, `acos`, `atan` | 1 | Arc Sine, Arc Cosine, Arc Tangent. |
145+
| `atan2` | 2 | `y x atan2` computes `atan(y/x)` using signs to find the correct quadrant. |
146+
| `sinh`, `cosh`, `tanh` | 1 | Hyperbolic Sine, Cosine, Tangent. |
147+
| **Rounding** | | |
148+
| `floor` | 1 | Rounds down to the nearest integer. |
149+
| `ceil` | 1 | Rounds up to the nearest integer. |
150+
| `round` | 1 | Rounds to the nearest integer. |
151+
| `trunc` | 1 | Truncates towards zero. |
152+
| **Other** | | |
153+
| `abs` | 1 | `x abs` is the absolute value of `x`. |
154+
| `copysign` | 2 | `x y copysign` returns a value with the magnitude of `x` and the sign of `y`. |
155+
| `fma` | 3 | `a b c fma` computes `(a * b) + c` as a single fused multiply-add. |
156+
| `neg` | 1 | `x neg` negates `x`. |
157+
| `sgn` | 1 | `x sgn` is the sign of `x`: -1 if x<0; 0 when x==0; 1 if x>0. |
158158

159159
#### **3.4. Conditional Operator**
160160

@@ -163,22 +163,22 @@ These operators treat any value greater than 0 as `true`. They return `1.0` for
163163

164164
#### **3.5. Min/Max & Clamping**
165165

166-
| Operator | Operands | Description |
167-
| :--- | :--- | :--- |
168-
| `max` | 2 | Returns the larger of the two values. |
169-
| `min` | 2 | Returns the smaller of the two values. |
170-
| `clip` or `clamp` | 3 | `x min_val max_val clip` clamps `x` to the range `[min_val, max_val]`. |
166+
| Operator | Operands | Description |
167+
| :---------------- | :------- | :--------------------------------------------------------------------- |
168+
| `max` | 2 | Returns the larger of the two values. |
169+
| `min` | 2 | Returns the smaller of the two values. |
170+
| `clip` or `clamp` | 3 | `x min_val max_val clip` clamps `x` to the range `[min_val, max_val]`. |
171171

172172
**Example:** `x 16 235 clip` clamps the pixel value to the broadcast-safe range [16, 235]. This is an `Expr` example.
173173

174174
#### **3.6. Bitwise Operators**
175175

176-
These operators truncate floating-point values to integers before the operation.
176+
These operators round floating-point values to nearest integers before the operation.
177177

178178
| Operator | Description |
179-
| :--- | :--- |
179+
| :------- | :---------- |
180180
| `bitand` | Bitwise AND |
181-
| `bitor` | Bitwise OR |
181+
| `bitor` | Bitwise OR |
182182
| `bitxor` | Bitwise XOR |
183183
| `bitnot` | Bitwise NOT |
184184

@@ -188,14 +188,14 @@ These operators truncate floating-point values to integers before the operation.
188188

189189
#### **4.1. Stack Manipulation**
190190

191-
| Operator | Description | Example |
192-
| :--- | :--- | :--- |
193-
| `dup` | (1 operand) Duplicates the top item. | `x dup *` is equivalent to `x 2 pow`. |
194-
| `swap` | (2 operands) Swaps the top two items. | `x y swap -` is equivalent to `y x -`. |
195-
| `dupN` | Duplicates the item N positions from the top. `dup0` is `dup`. | |
196-
| `swapN` | Swaps the top item with the item N positions down. `swap1` is `swap`. | |
197-
| `drop` / `dropN` | Drops the top N items. `drop` is an alias for `drop1`. | `1 2 3 drop2` results in a stack of `[1]`. |
198-
| `sortN` | Sorts the top N items, with the smallest value ending up on top. | `3 1 2 sort3` results in a stack of `[3, 2, 1]`. |
191+
| Operator | Description | Example |
192+
| :--------------- | :-------------------------------------------------------------------- | :----------------------------------------------- |
193+
| `dup` | (1 operand) Duplicates the top item. | `x dup *` is equivalent to `x 2 pow`. |
194+
| `swap` | (2 operands) Swaps the top two items. | `x y swap -` is equivalent to `y x -`. |
195+
| `dupN` | Duplicates the item N positions from the top. `dup0` is `dup`. | |
196+
| `swapN` | Swaps the top item with the item N positions down. `swap1` is `swap`. | |
197+
| `drop` / `dropN` | Drops the top N items. `drop` is an alias for `drop1`. | `1 2 3 drop2` results in a stack of `[1]`. |
198+
| `sortN` | Sorts the top N items, with the smallest value ending up on top. | `3 1 2 sort3` results in a stack of `[3, 2, 1]`. |
199199

200200
#### **4.2. Named Variables**
201201

@@ -340,10 +340,10 @@ Since `SingleExpr` has no concept of a "current pixel," all data I/O must be exp
340340
341341
These operators provide fine-grained control over the default per-pixel output behavior in `Expr`. They are not available in `SingleExpr`.
342342
343-
| Operator | Operands | Description |
344-
| :--- | :--- | :--- |
345-
| `@[]` | 3 | `val absX absY @[]` pops a value `val` and two coordinates `absX`, `absY`, and writes `val` to the output pixel at `[absX, absY]` *in the current plane*. This allows an expression for one pixel to write to another. If the coordinates are not integers, they will be truncated to integers. |
346-
| `^exit^` | 0 | Pushes a special marker value onto the stack. If, after the entire `Expr` expression is evaluated for a pixel, this marker is the *only* item remaining on the stack, the default write to the current pixel `[X, Y]` is suppressed. This is useful in expressions that only use `@[]` to write to other pixels. |
343+
| Operator | Operands | Description |
344+
| :------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
345+
| `@[]` | 3 | `val absX absY @[]` pops a value `val` and two coordinates `absX`, `absY`, and writes `val` to the output pixel at `[absX, absY]` *in the current plane*. This allows an expression for one pixel to write to another. If the coordinates are not integers, they will be truncated to integers. |
346+
| `^exit^` | 0 | Pushes a special marker value onto the stack. If, after the entire `Expr` expression is evaluated for a pixel, this marker is the *only* item remaining on the stack, the default write to the current pixel `[X, Y]` is suppressed. This is useful in expressions that only use `@[]` to write to other pixels. |
347347
348348
**Stack Requirements at Exit:**
349349
- **`Expr`:** The stack must contain exactly one value, which becomes the output for the current pixel. Alternatively, it can contain only the `^exit^` marker to suppress output.
@@ -384,23 +384,20 @@ The following expression calculates `x` to the power of 4, equivalent to `x 4 po
384384
385385
**Execution Trace:**
386386
387-
1. **Pre-initialization (automatic):**
388-
- All variables (`base`, `result`, `counter`) are automatically allocated and initialized to `0.0`.
389-
390-
2. **Initialization:**
387+
1. **Initialization:**
391388
- `x base!`: Stores the pixel value of clip `x` into the variable `base`.
392389
- `1 result!`: Initializes `result` to 1.
393390
- `4 counter!`: Initializes a loop `counter` to 4.
394391
- Stack is now empty.
395392
396-
3. **Loop Start (`#loop`):**
393+
2. **Loop Start (`#loop`):**
397394
- `result@ base@ * result!`: `result` becomes `result * base`.
398395
- `counter@ 1 - counter!`: Decrements the `counter`.
399396
- `counter@`: Pushes the current value of `counter` onto the stack.
400397
- `loop#`: Pops `counter`.
401398
- If `counter` was > 0, execution jumps back to `#loop`.
402399
- If `counter` was 0, the jump is not taken.
403400
404-
4. **Termination:**
401+
3. **Termination:**
405402
- After the loop finishes (when `counter` reaches 0), the expression continues.
406403
- `result@`: The final calculated value is pushed onto the stack, becoming the output for the pixel.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Copyright (C) 2025 yuygfgg
3+
*
4+
* This file is part of Vapoursynth-llvmexpr.
5+
*
6+
* Vapoursynth-llvmexpr is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Vapoursynth-llvmexpr is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Vapoursynth-llvmexpr. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef LLVMEXPR_ANALYSIS_RESULTS_HPP
21+
#define LLVMEXPR_ANALYSIS_RESULTS_HPP
22+
23+
#include "framework/AnalysisManager.hpp"
24+
#include "passes/BlockAnalysisPass.hpp"
25+
#include "passes/BuildCFGPass.hpp"
26+
#include "passes/StackSafetyPass.hpp"
27+
#include "passes/StaticArrayOptPass.hpp"
28+
#include <map>
29+
#include <string>
30+
#include <vector>
31+
32+
namespace analysis {
33+
34+
class ExpressionAnalysisResults {
35+
public:
36+
explicit ExpressionAnalysisResults(const AnalysisManager& manager)
37+
: manager(manager) {}
38+
39+
[[nodiscard]] const std::vector<CFGBlock>& getCFGBlocks() const {
40+
return manager.getResult<BlockAnalysisPass>().cfg_blocks;
41+
}
42+
43+
[[nodiscard]] const std::map<std::string, int>& getLabelToBlockIdx() const {
44+
return manager.getResult<BuildCFGPass>().label_to_block_idx;
45+
}
46+
47+
[[nodiscard]] const std::vector<int>& getStackDepthIn() const {
48+
return manager.getResult<StackSafetyPass>().stack_depth_in;
49+
}
50+
51+
[[nodiscard]] const std::map<std::string, int>&
52+
getStaticArraySizes() const {
53+
return manager.getResult<StaticArrayOptPass>().static_array_sizes;
54+
}
55+
56+
[[nodiscard]] const AnalysisManager& getManager() const { return manager; }
57+
58+
private:
59+
const AnalysisManager& manager;
60+
};
61+
62+
} // namespace analysis
63+
64+
#endif // LLVMEXPR_ANALYSIS_RESULTS_HPP
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copyright (C) 2025 yuygfgg
3+
*
4+
* This file is part of Vapoursynth-llvmexpr.
5+
*
6+
* Vapoursynth-llvmexpr is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Vapoursynth-llvmexpr is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Vapoursynth-llvmexpr. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "ExpressionAnalyzer.hpp"
21+
#include "framework/AnalysisError.hpp"
22+
#include "llvmexpr/analysis/passes/StackSafetyPass.hpp"
23+
#include "llvmexpr/analysis/passes/ValidationPass.hpp"
24+
#include "passes/StaticArrayOptPass.hpp"
25+
26+
namespace analysis {
27+
28+
void ExpressionAnalyzer::analyze() {
29+
if (manager.getTokens().empty()) {
30+
if (manager.getExpectedFinalDepth() != 0) {
31+
throw AnalysisError("Expression cannot be empty.");
32+
}
33+
}
34+
35+
manager.getResult<ValidationPass>();
36+
manager.getResult<StackSafetyPass>();
37+
manager.getResult<StaticArrayOptPass>();
38+
}
39+
40+
} // namespace analysis
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Copyright (C) 2025 yuygfgg
3+
*
4+
* This file is part of Vapoursynth-llvmexpr.
5+
*
6+
* Vapoursynth-llvmexpr is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Vapoursynth-llvmexpr is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with Vapoursynth-llvmexpr. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef LLVMEXPR_EXPRESSION_ANALYZER_HPP
21+
#define LLVMEXPR_EXPRESSION_ANALYZER_HPP
22+
23+
#include "framework/AnalysisManager.hpp"
24+
25+
namespace analysis {
26+
27+
class ExpressionAnalyzer {
28+
public:
29+
explicit ExpressionAnalyzer(AnalysisManager& manager) : manager(manager) {}
30+
31+
void analyze();
32+
33+
[[nodiscard]] AnalysisManager& getManager() { return manager; }
34+
35+
[[nodiscard]] const AnalysisManager& getManager() const { return manager; }
36+
37+
private:
38+
AnalysisManager& manager;
39+
};
40+
41+
} // namespace analysis
42+
43+
#endif // LLVMEXPR_EXPRESSION_ANALYZER_HPP

0 commit comments

Comments
 (0)