<html>
    <head>
      <base href="http://llvm.org/bugs/" />
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW --- - incorrect X86 code gen for 64-bit atomic add with literal operand 0xffffffff80000000ULL"
   href="http://llvm.org/bugs/show_bug.cgi?id=21099">21099</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>incorrect X86 code gen for 64-bit atomic add with literal operand 0xffffffff80000000ULL
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Backend: X86
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>warren_ristow@playstation.sony.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvmbugs@cs.uiuc.edu
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>The following test-case, when compiled at -O2 (for x86_64 target):

// ===========================================================
long long atomicAdd64(long long *p) {
  return __sync_fetch_and_add(p, 0xffffffff80000000ULL);
}
void foo(long long *p) { atomicAdd64(p); }
// ===========================================================

produces incorrect assembly code.  The call to 'atomicAdd64()' in 'foo()' has
been inlined, but the code to implement the fetch-and-add isn't there.  Here is
a disassembly for a compilation with r218661, done with
'-O2 -target x86_64-pc-linux-gnu':

    test.o: file format ELF64-x86-64

    Disassembly of section .text:
    _Z11atomicAdd64Px:
           0:       48 c7 c0 00 00 00 80            movq    $-2147483648, %rax
           7:       f0                              lock
           8:       48 0f c1 07                     xaddq   %rax, (%rdi)
           c:       c3                              retq
           d:       0f 1f 00                        nopl    (%rax)

    _Z3fooPx:
          10:       c3                              retq

Two relevant points are:

  1.  The behavior changed with r216768.  Prior to that revision, there was a
      compiler crash with the command:

        clang++ -c -O2 -target x86_64-pc-linux-gnu test.cpp

      If an assembly file is produced (when using a compiler prior to r216768)
      there isn't a compiler crash, and the underlying issue is clearer when
      attempting to assemble it.  Specifically, an illegal literal value is in
      the generated assembly code.  Using r216767:

        $ clang++ -S -O2 -target x86_64-pc-linux-gnu test.cpp
        $ clang++ -c -target x86_64-pc-linux-gnu test.s
        test.s:24:7: error: invalid operand for instruction
                subq    $2147483648, (%rdi)     # imm = 0x80000000
                        ^~~~~~~~~~~
        $

      That is, prior to r216768, an illegal assembly instruction was generated,
      causing a build-time failure.  Beginning with r216768, that illegal
      instruction isn't generated, but rather than being replaced with
      corrected instructions, no instruction is generated, allowing the build
      to complete, but causing a potential run-time failure.

  2.  Using an assertion-checking build of the compiler, an assert fires.  The
      failing check changes with r216768, but there is a failure both before
      and after.  Prior to r216768, the assertion-failure was:

        Assertion failed: isReg() && "This is not a register operand!",
                file ..../llvm/include/llvm/MC/MCInst.h, line 64

      Beginning with r216768, the failing check is:

        Assertion failed: Opc != 0 && "Invalid arith lock transform!",
                file ..../llvm/lib/Target/X86/X86ISelDAGToDAG.cpp, line 1823

The key issue seems to be that if the immediate value is representable as a
signed 32-bit number, the Addition for '__sync_fetch_and_add()' is changed to a
Subtraction, and the immediate value is negated.  In this case, the immediate
value is -2147483648, but since the negation of it isn't representable as a
32-bit signed number, that transformation can't be done.  Also, some other
optimization/transformation appears relevant, in that (for the example given)
the code for 'atomicAdd64()' is correct, but the code for 'foo()' (the caller
of 'atomicAdd64()') shows the problem (has the illegal immediate value prior to
r216768, and the missing instructions beginning with r216768).</pre>
        </div>
      </p>
      <hr>
      <span>You are receiving this mail because:</span>
      
      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>