Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Comment(by scpmw): I can't simply attach what crashed for me because it requires a number of additional GHC patches to reproduce - all of which are ''very'' experimental at this stage. I will have another go at reproducing it, the incomplete test case probably just needs one of the normally-saved registers to be live across r to fail. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Comment(by scpmw): Okay, seems you are indeed right. Once registers are actually live, they get saved and the code does what it should. The root cause here was my GHC tinkering, which happened to generate primitive calls without paying attention to live variables - which is in itself perfectly safe except that LLVM codegen counts on this unnecessary register saving taking place in order to produce correct code. Whew, didn't expect that. Apologies for the confusion. I guess this can be closed, as the upsides have now been reduced to just less redundant code getting generated. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls --+- Reporter: scpmw| Owner: davidterei@… Type: bug | Status: closed Priority: normal | Milestone: Component: Compiler (LLVM) |Version: 7.1 Resolution: invalid | Keywords: Testcase: | Blockedby: Difficulty: | Os: Linux Blocking: | Architecture: x86_64 (amd64) Failure: Runtime crash| --+- Changes (by dterei): * status: patch = closed * resolution: = invalid Comment: Cool! I wouldn't say that not paying attention to live variables is perfectly safe though. The native code generator as I understand also relies on this saving and restoring of live registers to have already been done in the Cmm representation. The only reason it didn't crash on the same code I assume is that the code for the primitive call never touched the live registers. Its perfectly legal for it to do so though, so there are some cases with bigger primitive calls where it would fail for the native code generator. LLVM failed earlier as the registers are trashed to prevent code duplication and slowdown and as there was no save and restore in the Cmm LLVM correctly used the actually live registers for intermediate code in the function. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Comment(by dterei): Is it not possible for you to simply attach the original program that crashes without the patch? If its private code you could just share it with me via email if you would prefer. I am not 100% convinced this patch solves the root of the problem. Across C calls (regardless of prim or not) the registers are trashed because GHC has previously generated code to save and restore the appropriate registers. In the Cmm code given to the LLVM backend spill/reload of the R3... registers already exists and so to have LLVM do it as well just duplicates work. Thats why the backend simply trashes all the caller save registers blindly. This isn't the best solution but it shouldn't cause any bugs. e.g so if R3 is live across a call you should see code like: {{{ %lnXe = load i64* %R3_Var store i64 %ln1zX, i64* %ln1zZ store i64 undef, i64* %R3_Var store i64 undef, i64* %R4_Var store i64 undef, i64* %R5_Var store i64 undef, i64* %R6_Var store float undef, float* %F1_Var store float undef, float* %F2_Var store float undef, float* %F3_Var store float undef, float* %F4_Var store double undef, double* %D1_Var store double undef, double* %D2_Var %ln1A0 = call ccc double (double)* @tan( double 0x3FE0 ) nounwind store i64 %lnXe, i64* %R3_Var }}} -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Comment(by scpmw): Producing a test case for isn't straightforward... It would have to construct a situation where LLVM is pressured for (non-floating-point) registers while at the same time making heavy use of LLVM primitives. At the moment, these all concern floating-point operations, which makes this hard. Using round, for example, makes the code pieces end up in different thunks. I suppose that's the reason why this problem hasn't shown up so far. It might be possible to come up with something by addressing the primops directly and using unsafeCoerce in order to force GHC to pull some ints out of nowhere... But I'm not really sure the testcase would even be useful at that point. The problem surfaced for me when I tried to add a primop for querying the cycle counter (llvm.readcyclecounter), which always uses two integer registers and therefore quickly ends up overwriting important stuff. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Comment(by scpmw): I have attached my best shot at reproducing the problem with just tan. It generates roughly the following code before the patch: {{{ subq$72, %rsp movq%r15, 40(%rsp) # 8-byte Spill movq%r14, 32(%rsp) # 8-byte Spill movq%r12, 24(%rsp) # 8-byte Spill movq%rbp, 8(%rsp) # 8-byte Spill movq%r13, 16(%rsp) # 8-byte Spill movaps %xmm5, %xmm0 callq tan cvttsd2siq %xmm0, %rax movq%rax, 56(%rsp) # 8-byte Spill }}} And then goes on using all available registers, which is clearly dangerous. With the patch applied, a lot more registers are saved on top of the stack. I'm unsure though how to craft an actually failing program out of this. Maybe somebody with a better overview can put in the missing piece? (Fun fact: The program actually manages to crash the LLVM optimizer both with and without the patch. Compiling without -O works.) -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
[GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls ---+ Reporter: scpmw | Owner: davidterei@… Type: bug | Status: new Priority: normal | Component: Compiler (LLVM) Version: 7.1 |Keywords: Testcase: | Blockedby: Os: Linux |Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash ---+ When calling, the LLVM backend will generate code that sets a number of global registers to undefined to prevent LLVM from saving them. I suppose that's a good idea for C calls, but for primitive calls it is unnecessary, even dangerous. tan 0.5 will have the backend generate code like follows: {{{ ... store i64 %ln1zX, i64* %ln1zZ store i64 undef, i64* %R3_Var store i64 undef, i64* %R4_Var store i64 undef, i64* %R5_Var store i64 undef, i64* %R6_Var store float undef, float* %F1_Var store float undef, float* %F2_Var store float undef, float* %F3_Var store float undef, float* %F4_Var store double undef, double* %D1_Var store double undef, double* %D2_Var %ln1A0 = call ccc double (double)* @tan( double 0x3FE0 ) nounwind ... }}} A few lines later, these registers are then read again, with LLVM probably assuming that the read results don't matter, as it can deduce that tan can't have written them. I discovered this when investigating why my programs using additional primitive operations kept crashing. Removing the trashing for primitive calls seems to fix the problem nicely, patch attached. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls ---+ Reporter: scpmw | Owner: davidterei@… Type: bug | Status: new Priority: normal | Component: Compiler (LLVM) Version: 7.1 |Keywords: Testcase: | Blockedby: Os: Linux |Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash ---+ Comment(by dterei): Looks good. Could you please attach a test case though. -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs
Re: [GHC] #4992: LLVM trashes registers for primitive calls
#4992: LLVM trashes registers for primitive calls +--- Reporter: scpmw|Owner: davidterei@… Type: bug | Status: patch Priority: normal |Milestone: Component: Compiler (LLVM) | Version: 7.1 Keywords: | Testcase: Blockedby: | Difficulty: Os: Linux| Blocking: Architecture: x86_64 (amd64) | Failure: Runtime crash +--- Changes (by igloo): * status: new = patch -- Ticket URL: http://hackage.haskell.org/trac/ghc/ticket/4992#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler ___ Glasgow-haskell-bugs mailing list Glasgow-haskell-bugs@haskell.org http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs