[llvm-dev] setjmp/longjmp and volatile stores, but non-volatile loads

Jonas Maebe via llvm-dev llvm-dev at lists.llvm.org
Fri Sep 16 10:13:01 PDT 2016


In our (non-C) compiler we use setjmp/longjmp to implement exception
handling. For the initial implementation LLVM backend, I'm keeping that
model. In order to ensure that changes performed in a try/setjmp==0
block survive the longjmp, the changes must be done via volatile operations.

Given that volatility is a property of individual load/store
instructions rather than of memory slots in LLVM, I thought I could
optimise this by only marking the stores in try-blocks as volatile.
After all, I don't mind LLVM removing extra loads of the same variable
in a try-block.

However, if I do that (instead of making all loads/stores to the
variable volatile), then some kind of (in my case invalid) value
propagation seems to happen from the try-block to the exception block.
>From what I can see with opt -print-after-all, it's the GVN pass that
does this.

I have attached a C program that demonstrates the issue: compiled with
clang -O0 or -O1 it works fine, but with -O2 it prints an error because
the "loops" variable has a wrong value on exit.

Mind you: I do not claim that the attached program is valid according to
any C standard or setjmp/longjmp documentation (it might be, but I don't
know). It's just that if you compile this program at with clang -O0
-emit-llvm, you get more or less the same LLVM IR as what we generate
for our code. (*) Next you can process the resulting .ll file with e.g.
opt -O2 to reproduce the issue (i.e., without any regard to a C
standard, to the extent that LLVM IR behaviour can be considered to be
unrelated to any C standard).

My question is: is this a bug in LLVM, or is this behaviour deemed to be
by design? Also: our setjmp is not called setjmp, but we do mark its
replacement also as "returns_twice". So even if the above behaviour
would be considered "expected" for setjmp, would the same go for any
function marked as "returns_twice"?

I tested with clang/LLVM 3.7.0 and the clang from 7.0.1. I don't have
newer versions available here.



(*) The only difference is that in our code there is no alias of the
"loops" variable through a pointer: we simply directly store to the
loops variable with a volatile store inside the try/setjmp==0 block. At
the LLVM IR level, that should not make a difference though since the
aliasing from the pointer to the loops variable is trivial. Removing the
aliasing manually from the generated IR does not change anything either,
as expected.

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: tint643c.c
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160916/01e8f0d3/attachment.c>

More information about the llvm-dev mailing list