# Using Goto and Label in compiled function?

Below I post some rudimentary code to show that there is something wrong using Goto and Label commands in compiled functions (or I believe there is something wrong). It seems that the command Label is not found. Does anybody know what's going on?

toy=Compile[{{x,_Real}},
Label["t"];
y=RandomReal[{-1.,1.}];
If[x*y<-0.,Print[y*x];Goto["t"],Print[y*x," ","done"]]
];

toy[1.]

-

This one is weird, and by my understanding of things, it is a bug. Label and Goto are on the list of compilable functions, and in fact, if you make your function completely compilable (i.e. compilable to code that does not call MainEvaluate), there is no problem. For example, this works without a hitch:

toy = Compile[{{x, _Real}},
c = 0;
Label[t];
c++;
If[x*RandomReal[{-1., 1.}] < -0., Goto[t]];
c]


In your original function, however, the print statements prevented the Goto to be compiled, and it stayed inside a call to MainEvaluate. CompilePrint says your function is compiled into:

2   V17 = MainEvaluate[ Function[{x}, y = RandomReal[{-1., 1.}]][ R0]]
3   R3 = MainEvaluate[ Function[{x}, y][ R0]]
4   R4 = R0 * R3
5   B0 = R4 < R5 (tol R6)
6   R4 = MainEvaluate[ Function[{x}, If[x y < 0., Print[y x]; Goto[t], Print[y x,  , done]]][ R0]]


You see the Goto is still there, inside the MainEvaluate call, but the Label has been compiled away: thus, the warning that the label cannot be found.

If you remove the print statement near the Goto, the If is compiled and MainEvaluate is called only on its second branch:

toy3 = Compile[{{x, _Real}},
Label["t"];
y = RandomReal[{-1., 1.}];
If[x*y < -0., Goto["t"], Print[y*x, " ", "done"]]];


gives

2   V17 = MainEvaluate[ Function[{x}, y = RandomReal[{-1., 1.}]][ R0]]
3   R3 = MainEvaluate[ Function[{x}, y][ R0]]
4   R4 = R0 * R3
5   B0 = R4 < R5 (tol R6)
6   if[ !B0] goto 9
7   goto 2
8   goto 10
9   V17 = MainEvaluate[ Function[{x}, Print[y x,  , done]][ R0]]


which works fine too, because now both the Label and the Goto have been compiled.

The reason I call it a bug is that I don't see this limitation specified anywhere in the documentation. I suggest reporting it to Wolfram support.

-
The label is still there in both cases. The problem is that labels aren't shared between the VM and the main evaluator (which makes sense, as you can't jump into compiled code at an arbitrary point), so Goto[t] does not find its target. That the compiler can be tricked into divorcing a Goto from its corresponding Label probably is a bug, I guess stemming from an attempt to minimize the number of (expensive) calls back into the main evaluator. –  Oleksandr R. Sep 12 '12 at 10:48
I should mention as well that the performance of compiled code like this, peppered as it is with calls out of the VM, will be absolutely horrific. For example, a single Ordering call per iteration in an early version of this consumed about 80% of the runtime--and that's with a fairly substantial loop body. The practical impact of this bug, then, will probably be minimal in most cases (as performance improvement is usually the main reason why one would use Compile in the first place). –  Oleksandr R. Sep 12 '12 at 11:18

There is nothing wrong with Label. The problem is that print can not be compiled. (see the list of compilable functions). Also y must be localized.

So compare

Needs["CompiledFunctionTools"]
CompilePrint[toy]


which returns

        1 argument
2 Boolean registers
9 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}

R0 = A1
R2 = 1.
R6 = 7.
R1 = -1.
R7 = -0.6382060350723182
R5 = 0.
Result = R4

1
2   V17 = MainEvaluate[ Function[{x}, y = RandomReal[{-1., 1.}]][ R0]]
3   R3 = MainEvaluate[ Function[{x}, y][ R0]]
4   R4 = R0 * R3
5   B0 = R4 < R5 (tol R6)
6   R4 = MainEvaluate[ Function[{x}, If[x y < 0., Print[y x]; Goto[t], \
Print[y x,  , done]]][ R0]]
7   Return


(Notice all the call to MainEvaluate)

Now compare to this:

toy1 = Compile[{{x, _Real}}, Block[{y},
Label["t"];
y = RandomReal[{-1., 1.}];
If[x*y < -0., Goto["t"]];
x*y
]]

Needs["CompiledFunctionTools"]
CompilePrint[toy1]

1 argument
1 Boolean register
7 Real registers
Underflow checking off
Overflow checking off
Integer overflow checking on
RuntimeAttributes -> {}

R0 = A1
R2 = 1.
R6 = 7.
R1 = -1.
R5 = 0.
Result = R4

1
2   R3 = RandomReal[ R1, R2]]
3   R4 = R0 * R3
4   B0 = R4 < R5 (tol R6)
5   if[ !B0] goto 8
6   goto 2
7   goto 8
8   R4 = R0 * R3
9   Return


which returns a nicely compiled function without problems.

-
The Print goes to MainEvaluate but other functions are compiled. Compile[{{x, _Real}}, Block[{y}, Label["t"]; y = RandomReal[{-1., 1.}]; Print[x*y]; If[x*y < -0., Goto["t"]]; Print[y*x, " ", "done"]; x*y]] –  PlatoManiac Sep 12 '12 at 10:01
Does CompilationTarget -> "C" works for this example? For me it does not. –  PlatoManiac Sep 12 '12 at 10:05
@PlatoManiac looks like someone forgot to specify the C translation for the label opcode! –  Oleksandr R. Sep 12 '12 at 10:38
Thanks guys! Very helpful. –  Chris Sep 12 '12 at 11:24
@PlatoManiac Doesn't work for me either. Will anybody post a bug report to Wolfram? –  Ajasja Sep 12 '12 at 12:24