[GHC] #9346: AtomicPrimOps tests failing on 32-bit x86
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Keywords: | Differential Revisions: Operating System: Unknown/Multiple | Architecture: Type of failure: None/Unknown | Unknown/Multiple Test Case: | Difficulty: Unknown Blocking: | Blocked By: | Related Tickets: -------------------------------------+------------------------------------- concurrent/should_test/AtomicPrimops test fails on 32-bit archs as reported on the mailing list by Páli Gábor János [http://www.haskell.org/pipermail/ghc-devs/2014-July/005706.html]. More info: AtomicPrimOps.hs flakes out for: fetchAndTest fetchNandTest fetchOrTest fetchXorTest casTest but not for fetchAddSubTest and readWriteTest. If I step through it, the segfault comes at line 166, it doesn't reach the .fetchXXXIntArray function that was called from the thread (at least ghci doesn't hit a breakpoint set at it). GDB says the bad instruction is: 4475: f0 8b 4c 24 40 lock mov 0x40(%esp),%ecx -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Changes (by tibbe): * cc: tibbe (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Changes (by pgj): * cc: pgj (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by tibbe): The `mov` instruction doesn't support a lock prefix. From: "Intel® 64 and IA-32 ArchitecturesSoftware Developer’s Manual":
The LOCK prefix can be prepended only to the following instructions and only to those forms of the instructions where the destination operand is a memory operand: ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG. If the LOCK prefix is used with one of these instructions and the source operand is a memory operand, an undefined opcode exception (#UD) may be generated. An undefined opcode exception will also be generated if the LOCK prefix is used with any instruction not in the above list. The XCHG instruction always asserts the LOCK# signal regardless of the presence or absence of the LOCK prefix
However, I cannot see a place where we're adding one in the x86 codegen: https://github.com/ghc/ghc/blob/master/compiler/nativeGen/X86/CodeGen.hs -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by pgj): I may be wrong here, but looks like the native code generator generates bad code. The {{{lock cmpxchg}}} instruction appears to be interleaved with the preceding {{{mov}}} instruction, hence {{{lock mov}}} is got. For {{{AtomicPrimops}}}, the following snippet is present in the generated assembly code: {{{ .Ln3sa: movl %ecx,64(%esp) movl %eax,%ecx movl %edx,76(%esp) movl %eax,%edx movl %ecx,88(%esp) movl 76(%esp),%ecx xorl %ecx,%edx lock movl 64(%esp),%ecx cmpxchgl %edx,(%ecx) jne .Ln3sd movl 88(%esp),%eax movl $ghczmprim_GHCziTuple_Z0T_closure+1,%esi jmp *(%ebp) .Ln3sd: movl 76(%esp),%edx jmp .Ln3sa }}} According to the sources, this does not seem to be intended. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86
-------------------------------------+-------------------------------------
Reporter: niklasl | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.9
Resolution: | Keywords:
Differential Revisions: | Operating System: Unknown/Multiple
Architecture: | Type of failure: None/Unknown
Unknown/Multiple | Test Case:
Difficulty: Unknown | Blocking:
Blocked By: |
Related Tickets: |
-------------------------------------+-------------------------------------
Comment (by tibbe):
Aside: I've confirmed that loads don't need any kind of fences but we need
an `mfence` for stores, which we don't have currently. You can see GCC
outputting one here:
{{{
#include
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by niklasl): Seems like the lock gets separated from the compxchg somewhere in the register allocation. I don't know why it's treated as a separate instruction, I can't think of a case where you wouldn't want it glued to the parent instruction. And the move looks bogus too, ecx and that stack slot already contains the same stuff. {{{ ==================== Native code ==================== movl %vI_c2eB,%vI_n2tm movl %vI_c2eA,%vI_n2tn movl %vI_n2tn,%eax lock cmpxchgl %vI_n2tm,(%vI_n2tl) movl %eax,%vI_s1Rr movl %vI_s1Rr,%vI_s1Ru jmp _c2eD }}} {{{ ==================== Liveness annotations added ==================== movl %vI_c2ez,%vI_n2tl # born: %vI_n2tl # r_dying: %vI_c2ez movl %vI_c2eB,%vI_n2tm # born: %vI_n2tm # r_dying: %vI_c2eB movl %vI_c2eA,%vI_n2tn # born: %vI_n2tn # r_dying: %vI_c2eA movl %vI_n2tn,%eax # born: %r0 # r_dying: %vI_n2tn lock cmpxchgl %vI_n2tm,(%vI_n2tl) # r_dying: %vI_n2tl %vI_n2tm movl %eax,%vI_s1Rr # born: %vI_s1Rr # r_dying: %r0 movl %vI_s1Rr,%vI_s1Ru # born: %vI_s1Ru # r_dying: %vI_s1Rr jmp _c2eD # r_dying: %vI_s1Ru }}} {{{ ==================== Registers allocated ==================== movl 88(%esp),%ecx movl %eax,100(%esp) movl %ecx,%eax lock movl 100(%esp),%ecx cmpxchgl %ecx,(%edx) jmp _c2eD }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by pgj): I have written a simple patch to implement the strict pairing with the LOCK prefix. It almost works, but some of the tests (of ways {{{ghci}}} and {{{threaded2}}}) are still failing with this one, though. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by tibbe): The only reason `LOCK` is a separate instruction is that I wanted to avoid adding e.g. a separate `Bool` argument to the e.g. the `MOV` constructor, as I would have to fix *all* uses of that instruction. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by niklasl): I think the patch is a nice way to solve that problem, have the LOCK take the instruction to be modified. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Differential Revisions: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: Difficulty: Unknown | Blocking: Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Comment (by tibbe): That indeed looks much nicer. What are the validate issues? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86
-------------------------------------+-------------------------------------
Reporter: niklasl | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.9
Resolution: | Keywords:
Differential Revisions: | Operating System: Unknown/Multiple
Architecture: | Type of failure: None/Unknown
Unknown/Multiple | Test Case:
Difficulty: Unknown | Blocking:
Blocked By: |
Related Tickets: |
-------------------------------------+-------------------------------------
Comment (by pgj):
The first one is that:
{{{
$ make TEST=AtomicPrimops WAY=ghci
...
=====> AtomicPrimops(ghci) 41 of 93 [0, 0, 0]
cd . && inplace/bin/ghc-stage2 -fforce-recomp -dcore-lint -dcmm-lint -dno-
debug-output -no-user-package-db -rtsopts -fno-ghci-history
AtomicPrimops.hs --interactive -v0 -ignore-dot-ghci +RTS -I0.1 -RTS
AtomicPrimops.interp.stdout
2>AtomicPrimops.interp.stderr
Wrong exit code (expected 0 , actual 132 )
Stdout:
fetchAddSubTest: OK
Stderr:
*** unexpected failure for AtomicPrimops(ghci)
...
}}}
That is, GHCi cannot run {{{AtomicPrimops}}}. Perhaps that is due to the
byte code generation, I could not really find the exact reason.
The other one is that:
{{{
$ make TEST=AtomicPrimops WAY=threaded2
...
=====> AtomicPrimops(threaded2) 41 of 93 [0, 0, 0]
cd . && inplace/bin/ghc-stage2 -fforce-recomp -dcore-lint -dcmm-lint -dno-
debug-output -no-user-package-db -rtsopts -fno-ghci-history -o
AtomicPrimops AtomicPrimops.hs -O -threaded -eventlog
>AtomicPrimops.comp.stderr 2>&1
cd . && ./AtomicPrimops +RTS -N2 -ls -RTS AtomicPrimops.run.stdout 2>AtomicPrimops.run.stderr
Actual stdout output differs from expected:
--- ./AtomicPrimops.stdout 2014-07-22 01:03:55.843169393 +0000
+++ ./AtomicPrimops.run.stdout 2014-07-22 20:26:04.769552990 +0000
@@ -1,6 +1,8 @@
fetchAddSubTest: OK
fetchAndTest: OK
-fetchNandTest: OK
+fetchNandTest: FAIL
+Expected: 1717991287
+ Actual: -1431651397
fetchOrTest: OK
fetchXorTest: OK
casTest: OK
*** unexpected failure for AtomicPrimops(threaded2)
...
}}}
That is, the NAND atomic does not work properly when {{{AtomicPrimops}}}
is run with multiple threads.
--
Ticket URL:
GHC
The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): I'm looking into the test failures. The `ghci` way does pass for me, on a 64-bit Linux machine. `fetchNandTest` fails for me as well. I will look into it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): Figured it out. My test is wrong. `complement ((complement (n0 .&. t1pat)) .&. t2pat) /= complement ((complement (n0 .&. t2pat)) .&. t1pat)`, which the test asserted. Patch on the way. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by pgj): Replying to [comment:12 tibbe]:
The `ghci` way does pass for me, on a 64-bit Linux machine.
I believe that will only fail on a 32-bit machine. I got that with FreeBSD/i386 ({{{-march=i686}}}). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): I've attached three patches that we should apply. The first one is pgj's patch, but as a git patch, the second fixes the incorrect test, and the third one adds a missing memory fence that I found. The three commits validate. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:15 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by tibbe): * status: new => patch -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:16 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: patch Priority: normal | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): Note that I haven't looked into the ghci issue, which I think is separate. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:17 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: patch Priority: highest | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by niklasl): * priority: normal => highest Comment: Yeah, fixing the bad code generation shouldn't wait for that. Let's increase the priority too. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:18 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: patch Priority: highest | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): Fixed by 23773b25863a0a439d81332cb8eee14f6f2c0098 and c11b35f5c5efe8f11039583c493e245bb6bcb33c. While we haven't seen any failure due to it, fc53ed5da1a2455b0da2f8ef3ec317e1a96ed83d fixes an issue with a missing memory fence for stores. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:19 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: patch Priority: highest | Milestone: Component: Compiler | Version: 7.9 Resolution: | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Comment (by tibbe): I moved the ghci issue to #9354. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:20 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
#9346: AtomicPrimOps tests failing on 32-bit x86 -------------------------------------+------------------------------------- Reporter: niklasl | Owner: Type: bug | Status: closed Priority: highest | Milestone: Component: Compiler | Version: 7.9 Resolution: fixed | Keywords: Operating System: | Architecture: Unknown/Multiple Unknown/Multiple | Difficulty: Unknown Type of failure: | Blocked By: None/Unknown | Related Tickets: Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by tibbe): * status: patch => closed * resolution: => fixed -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9346#comment:21 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC