Parrot: if vs. unless

leo on 2006-02-18T21:12:58

Parrot provides two opcodes to branch on the truthness of a register: if and unless. It looks like that it's just a matter of taste, which one to use. Is it really?

Not with modern CPUs with branch prediction rules and with JIT code inside tight inner loops. Below are two versions of the ackermann function, one written with if and one using unless. (If you are missing the loop in the code, well, that's coming from tailcall optimization, turned on with -Oc.)

$ cat ack-if.pir
.sub ack
  .param int x
  .param int y
  if x goto a1
    inc y
    .return (y)
a1:
  if y goto a2
    dec x
    .return ack(x, 1)
a2:
  dec y
  y = ack(x, y)
  dec x
  .return ack(x, y)
.end

$ cat ack-unless.pir
.sub ack
  .param int x
  .param int y
  unless x goto a1
  unless y goto a2
  dec y
  y = ack(x, y)
  dec x
  .return ack(x, y)
a1:
  inc y
  .return (y)
a2:
  dec x
  .return ack(x, 1)
.end

And here are the timings of both with ./parrot -Oc -Cj ack-xx.pir 12 on an AMD X2@2000:

ack-if      2.9 s
ack-unless  2.4 s

Branches with positive branch offsets (downwards) are considered to be likely not taken, that is the fall-through case is the default one. As there are a lot more positive numbers than the one zero, the unless is the better choice here (for some CPUs, YMMV). Well, that's at least my conclusion for now. But there is another issue: branch alignment. I've not yet experimented with different label alignments, but I know that alignment can cause timing differences like above too.


Not sure if this appears at the Parrot level...

merlyn on 2006-02-18T21:53:43

But "if" cannot be replaced by "unless" and vice versa in every case. Witness:
sub using_if {
  $value = 3;
  "bogus" if not $value;
}
sub using_unless {
  $value = 3;
  "bogus" unless $value;
}
my $result_if = using_if(); # will be "false" (result of "not $value")
my $result_unless = using_unless(); # will be 3 (result of $value)
A similar dichotomy results from "while" vs "until". So, both are needed.

PBP

sigzero on 2006-02-18T22:38:04

Since I am trying to get my code inline with "Perl Best Practices", "unless" is discouraged.

Also...

JonathanWorthington on 2006-02-18T22:48:25

"Branches with positive branch offsets (downwards) are considered to be likely not taken, that is the fall-through case is the default one."

Yup, this comes down to branch prediction in the CPU which is one of many performance tricks they do. You've probably guessed this, but they also expect that branches with negative branch offsets are likely to be taken, since they are probably loops. That means you're better off putting your termination test at the end of the loop, and to account for loops where you test the condition first branch to the test. And as that's an unconditional branch, there's no chance of predicting it wrong. :-)