Hi,I'm trying to prevent llvm instruction motion around an intrinsic function call. Throughout my experimenting, I was told that setjmp could create fake entry points into a region of code and that might prevent code motion.What I found is something surprising, and probably is a misuse of setjmp but I couldn't find an explanation for it.Consider this:#include <csetjmp> std::jmp_buf jb;int main() { int s = 1; setjmp(jb); if (s) { s = 0; std::longjmp(jb, 1); return 2; } return 1;} One would expect that the load of s in the if condition is not optimized away (by being replaced with if(1)), but clang at -O3 (on linux) generates this:define signext i32 @main() local_unnamed_addr #0 {entry: %call = call signext i32 @_setjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @jb, i64 0, i64 0)) #3 call void @longjmp(%struct.__jmp_buf_tag* getelementptr inbounds ([1 x %struct.__jmp_buf_tag], [1 x %struct.__jmp_buf_tag]* @jb, i64 0, i64 0), i32 signext 1) #4 unreachable} which leads to an infinite loop execution at runtime.Aren't we breaking the as-if rule because the semantics of the program imply that the value of s is unknown after the setjmp (because you can enter main from the location of setjmp in the program). Thanks. Wael -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20170602/5d9da202/attachment.html>
Hi Wael, On 2 June 2017 at 14:50, Wael Yehia via llvm-dev <llvm-dev at lists.llvm.org> wrote:> Aren't we breaking the as-if rule because the semantics of the program imply > that the value of s is unknown after the setjmp (because you can enter main > from the location of setjmp in the program).Congratulations! You've found one of 2.5 valid uses for "volatile". In C11 (7.3.2.1p3):> All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate.So the value of "s" is indeterminate because it's not declared volatile. C++ inherits these rules and adds a couple more restrictions about destructors.> I'm trying to prevent llvm instruction motion around an intrinsic function call.This is pretty much impossible in LLVM if you mean instructions LLVM considers side-effect free (e.g. a simple "add"). It's theoretically a pain in the neck when dealing with cycle-counters for performance. Though in practice it usually doesn't matter much: LLVM usually doesn't do anything problematic, and if it does putting the region of interest into a noinline function tends to be enough. Cheers. Tim.
(Adding the list back in, especially as other people have taken an interest in really immobile intrinsics before). On 2 June 2017 at 18:33, Wael Yehia <wmyehia2001 at yahoo.com> wrote:> Thank you Tim. The C spec never stops enlightening me with new quirks. > Out of curiousity, did you know about this or grep'ed the spec for setjmp?I've got a standing interest in both threading (a canonical place where volatile is definitely not what you want) and OS programming (the extra 0.5 where it is, for memory mapped I/O) so I've read lots and lots about it. The final standards-blessed use is for reading variables in a signal handler.> BTW, how confident are you about the statement you made: > "This is pretty much impossible in LLVM if you mean instructions LLVM > considers side-effect free (e.g. a simple "add")." > Because I was tempted for a while to just ask the community about it, after having > spent few weeks experimenting, with a hope that there's a way to actually prevent > all instructions (including the side-effect free ones) from moving across calls.Pretty sure, I'm afraid. Even the strongest property, HasSideEffects which is basically a "this does stuff you don't understand" instruction to LLVM doesn't prevent that kind of code motion. Because even though the intrinsic might do things LLVM doesn't understand, "add" doesn't. Cheers. Tim.