optimize: convert for-loop post-inc/dec to prefix to avoid zval copy (#79)
* optimize: convert for-loop post-inc/dec to prefix to avoid zval copy For-loop post-expressions (third clause of `for (init; cond; post)`) always discard the return value, so $i++ is semantically identical to ++$i in this context. Converting to prefix increment/decrement avoids the zval copy + destructor overhead from operator++(int)'s return value, saving ~6ns per increment per loop iteration. Changes: - LoopControlTrait: convert PostInc→PreInc, PostDec→PreDec in for-loop post-expressions only (while/do-while body untouched) - Add phpunit test verifying generated C++ contains ++i/--i for for-loops and retains i++ in while/do-while bodies - Add test data file with 7 test functions covering basic, multi-post, nested, mixed, and while/do-while cases * fix: restrict for-loop post-expr rewrite to simple variables onlymaster
parent
cde9ed2b58
commit
be5cc71a8b
3 changed files with 136 additions and 0 deletions
@ -0,0 +1,97 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
function test_post_inc_basic(): void { |
||||||
|
$sum = 0; |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
$sum += $i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_post_dec_basic(): void { |
||||||
|
$sum = 0; |
||||||
|
for ($i = 10; $i > 0; $i--) { |
||||||
|
$sum += $i; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_multi_post(): void { |
||||||
|
for ($i = 0, $j = 10; $i < 5; $i++, $j--) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_mixed_post(): void { |
||||||
|
$j = 0; |
||||||
|
for ($i = 0; $i < 10; $i++, $j += 2) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_nested_for(): void { |
||||||
|
for ($i = 0; $i < 5; $i++) { |
||||||
|
for ($j = 0; $j < 5; $j++) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_while_not_affected(): void { |
||||||
|
$i = 0; |
||||||
|
while ($i < 10) { |
||||||
|
$i++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_do_while_not_affected(): void { |
||||||
|
$i = 0; |
||||||
|
do { |
||||||
|
$i++; |
||||||
|
} while ($i < 10); |
||||||
|
} |
||||||
|
|
||||||
|
// --- Cases that must NOT be rewritten (property/static-property/array-element) --- |
||||||
|
|
||||||
|
class Counter { |
||||||
|
public int $value = 0; |
||||||
|
} |
||||||
|
|
||||||
|
class StaticCounter { |
||||||
|
public static int $count = 0; |
||||||
|
} |
||||||
|
|
||||||
|
function test_property_post_inc_not_rewritten(): void { |
||||||
|
$obj = new Counter(); |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
$obj->value++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_property_post_dec_not_rewritten(): void { |
||||||
|
$obj = new Counter(); |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
$obj->value--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_static_property_post_inc_not_rewritten(): void { |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
StaticCounter::$count++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_static_property_post_dec_not_rewritten(): void { |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
StaticCounter::$count--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_array_element_post_inc_not_rewritten(): void { |
||||||
|
$arr = [0, 0, 0]; |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
$arr[$i % 3]++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function test_array_element_post_dec_not_rewritten(): void { |
||||||
|
$arr = [10, 10, 10]; |
||||||
|
for ($i = 0; $i < 10; $i++) { |
||||||
|
$arr[$i % 3]--; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue