llvm-gcc4 and setjmp

Hello, Jay.

the resulting bitcode doesn't use LLVM's exception handling
intrinsics, it just has a call to a function called "_setjmp". And
there doesn't seem to be any provision for returning the current value
of the volatile variable v if setjmp returns non-zero - the bitcode
always returns zero, whereas the spec for setjmp() says that f()
should return 1 if g() does a longjmp().

This seems to be well-known problem with interacting setjmp/longjmp and
optimization passes. Actually, this is LLVM PR1520. The problem is that
setjmp/longjmp changes codeflow in inpredictable manner (especially, if
jump buffer escapes from function). We need some clever idea how to
represent such stuff.

PS: Compiling with -O0 should be easy workaround.

Hi Anton,

This seems to be well-known problem with interacting setjmp/longjmp and
optimization passes. Actually, this is LLVM PR1520.

I didn’t find that PR because it doesn’t mention setjmp!

The problem is that
setjmp/longjmp changes codeflow in inpredictable manner (especially, if
jump buffer escapes from function). We need some clever idea how to
represent such stuff.

I would expect llvm-gcc to use LLVM’s setjmp/longjmp intrinsics and then to run the LowerSetJmp pass to turn the intrinsic calls into uses of invoke and unwind. At that point, the control flow is explicit, isn’t it?

Thanks,
Jay.

Hi Anton,

I would expect llvm-gcc to use LLVM’s setjmp/longjmp intrinsics and
then to run the LowerSetJmp pass to turn the intrinsic calls into uses
of invoke and unwind. At that point, the control flow is explicit,
isn’t it?
Unfortunately, no. You can call setjmp/longjmp on the same jump buffer
multiple times. So, in general it’s not possible to determine, where
jump destination is. The problem is much worse in case, when jump buffer
escapes from the function, where it was initialized (like in your case -
longjmp is called in the g() routine).

LowerSetJmp should handle this by turning the call to g() into an invoke. If g() calls longjmp(), it will do an unwind.

Are you saying that the LowerSetJmp pass doesn’t work? Or that the whole idea of lowering setjmp/longjmp to invoke/unwind doesn’t work?

Thanks,
Jay.

> Unfortunately, no. You can call setjmp/longjmp on the same jump buffer
> multiple times. So, in general it's not possible to determine, where
> jump destination is. The problem is much worse in case, when jump buffer
> escapes from the function, where it was initialized (like in your case -
> longjmp is called in the g() routine).

LowerSetJmp should handle this by turning the call to g() into an invoke. If
g() calls longjmp(), it will do an unwind.

Are you saying that the LowerSetJmp pass doesn't work? Or that the whole
idea of lowering setjmp/longjmp to invoke/unwind doesn't work?

If setjmp/longjmp are turned into invoke + unwind, how does this interact
with exception handling codegen (-enable-eh)? Won't eh codegen break this
trick?

Ciao,

Duncan.

Hi,

is there documentation about what happens to setjmp() et al, and how one
should handle the setjmp intrinsics? Are setjmp() function calls transformed
to intrinsics, or are the intrinsics only used for EH?

Thanks,
Torvald

Hello, Torvald

is there documentation about what happens to setjmp() et al, and how one
should handle the setjmp intrinsics?

You shouldn't use them at all.

Are setjmp() function calls transformed to intrinsics, or are
the intrinsics only used for EH?

Intrisincs are used for representing necessary EH code flow. User's
setjmp() are just function calls. We fixed recently optimization passes
not to touch volatile loads/stores. So, now everything connected with
setjmp should be ok.

Hi Anton,

Intrisincs are used for representing necessary EH code flow. User's
setjmp() are just function calls. We fixed recently optimization passes
not to touch volatile loads/stores. So, now everything connected with
setjmp should be ok.

I don't think you can treat setjmp() just like a normal function call.
The C standard says that after a longjmp(), non-volatile variables
that have not been changed since the call to setjmp() should have the
correct value. To implement this, I think the compiler needs to know
that in a function that calls setjmp(), it shouldn't keep any such
variables in callee-saves registers across a call.

Jay.