Skip to content

Instantly share code, notes, and snippets.

@staabm
Created August 15, 2026 11:20
Show Gist options
  • Select an option

  • Save staabm/c5c89119edea93e6ad83833dc2568c26 to your computer and use it in GitHub Desktop.

Select an option

Save staabm/c5c89119edea93e6ad83833dc2568c26 to your computer and use it in GitHub Desktop.
negated_conditions_repro.php
@ -0,0 +1,175 @@
<?php
declare(strict_types=1);
/**
* Reproducer for commit d363881c66bf4a301bb0af9c5b8119e50f2a7494:
* "Compile negated conditions as inverted jumps"
*
* Run this script on:
* 1) a build before that commit and
* 2) a build including that commit
*
* Expected: ratios for "negated / positive" move closer to 1.00x.
*/
if (PHP_SAPI !== 'cli') {
fwrite(STDERR, "Run from CLI.\n");
exit(1);
}
$ifIters = isset($argv[1]) ? max(1, (int) $argv[1]) : 25_000_000;
$outer = isset($argv[2]) ? max(1, (int) $argv[2]) : 80_000;
$inner = isset($argv[3]) ? max(1, (int) $argv[3]) : 64;
$rounds = isset($argv[4]) ? max(1, (int) $argv[4]) : 5;
function run_case(string $label, int $rounds, callable $fn): array
{
$times = [];
$sink = 0;
$sink ^= $fn();
for ($r = 0; $r < $rounds; $r++) {
$start = hrtime(true);
$sink ^= $fn();
$elapsed = (hrtime(true) - $start) / 1e9;
$times[] = $elapsed;
}
sort($times);
$best = $times[0];
$avg = array_sum($times) / count($times);
return [
'label' => $label,
'best' => $best,
'avg' => $avg,
'sink' => $sink,
];
}
$cases = [
run_case('if_positive', $rounds, static function () use ($ifIters): int {
$acc = 0;
for ($i = 0; $i < $ifIters; $i++) {
$x = ($i & 1) === 0;
if ($x) {
$acc += 1;
} else {
$acc += 2;
}
}
return $acc;
}),
run_case('if_negated', $rounds, static function () use ($ifIters): int {
$acc = 0;
for ($i = 0; $i < $ifIters; $i++) {
$x = ($i & 1) === 0;
if (!$x) {
$acc += 2;
} else {
$acc += 1;
}
}
return $acc;
}),
run_case('ternary_positive', $rounds, static function () use ($ifIters): int {
$acc = 0;
for ($i = 0; $i < $ifIters; $i++) {
$x = ($i & 1) === 0;
$acc += $x ? 1 : 2;
}
return $acc;
}),
run_case('ternary_negated', $rounds, static function () use ($ifIters): int {
$acc = 0;
for ($i = 0; $i < $ifIters; $i++) {
$x = ($i & 1) === 0;
$acc += !$x ? 2 : 1;
}
return $acc;
}),
run_case('while_positive', $rounds, static function () use ($outer, $inner): int {
$acc = 0;
for ($o = 0; $o < $outer; $o++) {
$j = 0;
while ($j < $inner) {
$acc += $j & 1;
$j++;
}
}
return $acc;
}),
run_case('while_negated', $rounds, static function () use ($outer, $inner): int {
$acc = 0;
for ($o = 0; $o < $outer; $o++) {
$j = 0;
while (!($j >= $inner)) {
$acc += $j & 1;
$j++;
}
}
return $acc;
}),
run_case('do_while_positive', $rounds, static function () use ($outer, $inner): int {
$acc = 0;
for ($o = 0; $o < $outer; $o++) {
$j = 0;
do {
$acc += $j & 1;
$j++;
} while ($j < $inner);
}
return $acc;
}),
run_case('do_while_negated', $rounds, static function () use ($outer, $inner): int {
$acc = 0;
for ($o = 0; $o < $outer; $o++) {
$j = 0;
do {
$acc += $j & 1;
$j++;
} while (!($j >= $inner));
}
return $acc;
}),
];
$byLabel = [];
foreach ($cases as $row) {
$byLabel[$row['label']] = $row;
}
printf(
"PHP %s\nifIters=%d outer=%d inner=%d rounds=%d\n\n",
PHP_VERSION,
$ifIters,
$outer,
$inner,
$rounds
);
echo str_pad('case', 20) . str_pad('best(s)', 12) . str_pad('avg(s)', 12) . "sink\n";
echo str_repeat('-', 54) . "\n";
foreach ($cases as $row) {
printf(
"%-20s%-12.6f%-12.6f%d\n",
$row['label'],
$row['best'],
$row['avg'],
$row['sink']
);
}
echo "\nnegated/positive ratios (best time, lower is better):\n";
$pairs = [
['if', 'if_negated', 'if_positive'],
['ternary', 'ternary_negated', 'ternary_positive'],
['while', 'while_negated', 'while_positive'],
['do_while', 'do_while_negated', 'do_while_positive'],
];
foreach ($pairs as [$name, $neg, $pos]) {
$ratio = $byLabel[$neg]['best'] / $byLabel[$pos]['best'];
printf("%-10s %.4fx\n", $name, $ratio);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment