Commit graph

172 commits

Author SHA1 Message Date
Sei Lisa
42bc44d583 New copyright year 2025-02-01 12:30:52 +01:00
Sei Lisa
c1c1b8c58d Further generalize the < operator
Use the node's min and max for both sides. Constants are just a special case where min = max = value.
2024-05-11 18:32:27 +02:00
Sei Lisa
d2e3b9a3bd Add getMin() and getMax(), which can detect constants 2024-05-07 00:35:47 +02:00
Sei Lisa
65326115d8 Fix/extend the < operator; promote min/max from symbol to node
- Fix case where CONST < FNCALL or FNCALL < CONST, when the function was marked as SEF but the args were not SEF, could result in the FNCALL being optimized out, thus failing to apply the side effects of the arguments.
- Copy the function's `min` and `max` present in the symbol table, to the node; use the node's `min` and `max` properties in the `<` operator instead of looking up the symbol and using that.
- Extend it to cover all cases where CONST < SEFexpr and SEFexpr < CONST where SEFexpr.min and SEFexpr.max are defined.
2024-05-06 23:55:55 +02:00
Sei Lisa
1e1f181b82 Fix deletion of if (SEF_expr) ;
Fixes #29. Thanks @KrsityKu for the test case, which was added to the test suite.
2024-04-20 20:11:01 +02:00
Sei Lisa
f854e94349 New copyright year 2024-04-14 11:40:21 +02:00
Sei Lisa
231c16b90e New copyright year 2023-02-03 13:06:18 +01:00
Sei Lisa
08c429f22b Add IfElseSwap option
This enables an option that was being done unconditionally: to swap the `if` and `else` branches if the condition is shorter when negated.

Enabled by default.
2022-10-31 20:08:26 +01:00
Sei Lisa
8d413f910e Forgot to update copyright year 2022-06-07 19:46:31 +02:00
Sei Lisa
81906475ff Update copyright year 2021-01-05 23:27:21 +01:00
Sei Lisa
f8cf78dfac Progress towards dual Python 2 & 3 2020-11-09 02:28:57 +01:00
Sei Lisa
0affbf13dd Fix "" + list_expr producing list_expr
The type checks were not strong enough. While on it, strengthen other similar checks as well.

Reported by @Tonaie. Fixes #13.
2020-04-23 13:47:57 +02:00
Sei Lisa
234b9b23a3 Bump copyright year 2020-04-23 00:38:20 +02:00
Sei Lisa
980b588986 Add FIXME and TODO 2019-10-11 19:38:05 +02:00
Sei Lisa
c02998518a Rename FoldCond -> FoldAsBool which better expresses the idea 2019-07-25 17:44:45 +02:00
Sei Lisa
1ab9dd69b4 Fix optimization of fn > -1 and fn < 0 when fn's minimum is -1 in conditions
E.g. llSubStringIndex(...) > -1 was converted into !~llSubStringIndex(...) which is incorrect. We even had a test case for it... with a wrong expected response file.

Bug report and test case by Sinha Hynes (thanks!)
2019-07-16 01:58:19 +02:00
Sei Lisa
1bdaff32ab When optimizing nonconst * const, cast the result to the type of the operator.
Per bug report by @Welcius.

Fixes #8.
2019-07-02 15:40:20 +02:00
Sei Lisa
fe2dd9a721 First baby steps towards dual Python2+3 compatibility 2019-01-16 00:15:06 +01:00
Sei Lisa
06f8370886 Add a reference to the author name's origin
Add TODO on vectors and rotations, too.
2019-01-10 21:56:26 +01:00
Sei Lisa
1b3c8a4d89 Check min and max to determine truth value of condition
Also added some min/max values for a few functions.

This allows optimizing things like:

  ! llGetNumberOfPrims()  ->  0
2019-01-07 00:15:38 +01:00
Sei Lisa
7fbde0269c Fix indentation typo (cosmetic) 2019-01-04 19:35:36 +01:00
Sei Lisa
42750c56d7 Fix some comments 2019-01-02 00:38:44 +01:00
Sei Lisa
f243f3a3c1 New copyright year 2019-01-01 22:54:34 +01:00
Sei Lisa
76f483fc11 Add scope field to {} nodes
Since we need to add variables, we need to know which scope to add them to. Add this information to the {} node, which is what creates a new scope.

An alternative would be to scan for any variable or label declaration within the braces and use that or create a new one if none, which is more expensive and may waste symbol tables.
2018-12-29 21:10:14 +01:00
Sei Lisa
6f32b4710a Remove handling of corner cases that we decided to not support
There was some remaining code trying to deal with labels in the single statement part of IFs and FORs.
2018-12-26 19:25:11 +01:00
Sei Lisa
b329b2b28e Avoid a possibly unnecessary expansion
When transforming if(!non-bool | !bool) to if(!(non-bool & -bool)), don't negate the bool if non-bool is actually an AND-bool.
2018-12-24 17:22:54 +01:00
Sei Lisa
c9f73bd429 Extend an optimization to cover some (admittedly rare) cases.
The value of bool|const is const when bit 0 of const is 1. This is a generalization of the case bool|1 = 1.
2018-12-24 17:22:54 +01:00
Sei Lisa
141301d7ff Reformatting 2018-12-24 17:22:54 +01:00
Sei Lisa
e123866e6e Apply DeMorgan in some cases that were not caught.
Example: the optimization of if(i < 2 || i) was suboptimal, because FoldTree was done before FoldCond. In a first stage, the || was removed: if(!!(i < 2 | i)); when folded, the inner ! was optimized first and the result was if(!(1 < i & (!i))), which FoldCond wasn't smart enough to handle.

The new optimization takes over from there, and converts if(!(!a & b)) with b boolean, in any order, to if(a | !b). When applied to the above expression, it gets folded to if(i < 2 | i) as expected, which is optimal.

Also, new function: IsAndBool (see docstring), used on b in the above example.
2018-12-24 17:18:48 +01:00
Sei Lisa
0a6155bb13 Apply an associativity rule to strings
It's not general associativity, it just folds CONST + (CONST + expr). Some day we'll implement sum flattening, to make this possible.
2018-12-22 10:27:37 +01:00
Sei Lisa
b9fe0b6c85 Add TODO item about side-effect analysis of UDFs 2018-11-19 21:15:52 +01:00
Sei Lisa
18d19b4653 Fix bug where 1 + (2 + function) was folded as 4 + function
After folding, our cached values changed under us. Re-cache them.
2018-11-19 20:43:58 +01:00
Sei Lisa
960cbfaa09 Fix "Value of unknown type" on bit shift optimization
When converting x << constant to a product, we neglected to truncate the converted constant to S32.

Per bug report by Tonaie Resident.
2018-07-25 15:59:04 +02:00
Sei Lisa
6502a1a0b6 Remove TODO because there was nothing to do after checking. 2018-06-08 00:14:16 +02:00
Sei Lisa
e88e39127b Save a comparison (fixes a FIXME) 2018-06-08 00:07:36 +02:00
Sei Lisa
0808938894 Optimizations based on addition algebra for floats and integers
Float addition is commutative. Swap the constant to the left side if it's not there. This is a "cheap" version of a bigger change that is planned, to minimize stack usage as much as possible on savepoints.

Float addition is not associative, therefore we don't optimize e.g. 1 + (2 + float).

Integer addition is commutative and associative. If there's a constant, we swap it to the left side. If there's a chained summation of the form const + (const + expression), we apply associativity to turn it into (const + const) + expression and reoptimize.

This doesn't cover all possible cases. Expressions of the form (const + expr) + (const + expr) are not optimized. We need to flatten sums if we want to do the right thing here, but that's not yet implemented.

Get rid of some older code and TODOs that are no longer needed.
2018-06-07 23:57:21 +02:00
Sei Lisa
ac254efb77 Minor details
Assert that it can't be key where we say it can't, and that it is integer where we say it must.

Adjust some comments.
2018-06-07 02:14:15 +02:00
Sei Lisa
a33dc8540f Implement ~-~-~-expr -> expr + -3
Gets rid of a TODO
2018-06-07 02:14:15 +02:00
Sei Lisa
89c627b0c0 Remove jumps that just go to the next statement
This might help a bit with switch().
2018-05-17 09:46:06 +02:00
Sei Lisa
285c7172fd Get rid of DoesSomething() in favour of SEF
The missing bit was to mark labels are SEF when they are not referenced. Label references are now counted at parse time, enabling us to do this.

Also, make FoldStmt clearer when the node is an expression.
2018-05-17 09:08:48 +02:00
Sei Lisa
a93ea0ca19 Delete statements in a {} block when they are SEF
This is probably equivalent to what we did, as FoldStmt changes SEF statements to ';' statements, but it's simpler.
2018-05-17 09:08:35 +02:00
Sei Lisa
caf50c4e14 Change while (cond) /*empty*/; into do /*empty*/; while (cond); 2018-05-17 06:38:33 +02:00
Sei Lisa
8f93386108 Get rid of label checks in some situations no longer supported 2018-05-17 06:38:12 +02:00
Sei Lisa
6ef4c03994 Remove support for labels as immediate children of IF/ELSE/WHILE/FOR/DO.
This extremely uncommon coding pattern was becoming a hell to support. It has caused many bugs in past that need them being treated as special cases.

Getting rid of the possibility entirely seems like the best approach.

It's still supported if the code is not to be optimized (e.g. with --pretty).
2018-04-01 20:05:35 +02:00
Sei Lisa
075d3aba0c Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.

The new nr (node record) class has built-in dump capabilities, rather than using print_node().

SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).

Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.

A few minor bugfixes were applied while going through the code.

- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
  - TODO: ~-~-~-expr  ->  expr + -3.
  - FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
  - TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
  - FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-04-01 02:14:00 +02:00
Sei Lisa
877d5fc10c Optimize -a == -b, !(a - b), !(a + b)
-a == -b  ->  a == b

If both a and b either are constants or have a minus sign, negate both.

!(a - b) can be optimized to a == b.

!(a + b) can be optimized to -a == b, relying on the first optimization to remove redundant minus signs.
2018-03-23 19:02:42 +01:00
Sei Lisa
d0d6d6744b Bump copyright year
The help text in main.py was still at 2015. Oops.
2018-03-23 16:36:45 +01:00
Sei Lisa
a1f1f13739 Better optimization of (non-)equality comparisons.
int != int was not properly optimized, because the != was transformed into the equivalent !(int == int) at an earlier stage. Fixed.

!(a ^ b) can be optimized to a == b, so do it.
2018-03-23 16:04:18 +01:00
Sei Lisa
e42479756b Fix bug with nested if's; fix missing EXPR wrap.
097c054 introduced a bug that we hadn't caught until now.

In some occasions, it could swap nested conditions in such a way that the 'else' of the outer statement was made to belong to the inner one, like this:

    if (a)
        if (b)
            stuff;
    else
        stuff;

That is of course parsed with the 'else' belonging to if(b).

Fix implemented at output time, by detecting 'if(a) stmt; else y;' with stmt being an 'if' without 'else', and wrapping the stmt in {} like this: 'if(a){if(b) x;} else y;'. This has some similarity with parenthesis addition.

But the fix has the corner case that, since {} hides visibility of labels, when the inner 'if' has a label as direct child, it can't be swapped lest the label becomes out of scope. So these cases are detected and skipped in the constant folding module.

In the case of 'if(cond);', we transform it to 'cond;', but we forgot to wrap the cond in an EXPR node as required. Fixed too.
2017-11-13 04:04:13 +01:00
Sei Lisa
a4b3c1eadd Handle list+list more sanely. 2017-11-04 22:50:32 +01:00