<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </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 - [Win64] XMM registers saved in funclet prologues clobber register saves in parent function"
   href="https://bugs.llvm.org/show_bug.cgi?id=32507">32507</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>[Win64] XMM registers saved in funclet prologues clobber register saves in parent function
          </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>enhancement
          </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>rnk@google.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>This C++ program illustrates the bug:

$ cat a.cpp
double get_xmm(double);
void throw_internally();
void use_xmm(double d);
int main() {
  double xmm = get_xmm(1.0);
  use_xmm(xmm);
  throw_internally();
  use_xmm(xmm);
}

$ cat b.cpp
extern "C" int printf(const char *, ...);
void use_xmm(double d) { printf("%f\n", d); }
double __declspec(noinline) get_xmm(double d) {
  asm volatile("" : "=m"(d) : "0"(d));
  return d;
}
void throw_internally() {
  double r1 = get_xmm(2.0);
  use_xmm(r1);
  use_xmm(r1);
  try {
    throw 42;
  } catch (...) {
    double r2 = get_xmm(3.0);
    use_xmm(r2);
  }
  use_xmm(r1);
}

$ clang-cl -Z7 -EHsc -O0 a.cpp b.cpp -Fet.exe && ./t.exe
1.000000
2.000000
2.000000
3.000000
2.000000
1.000000

$ clang-cl -Z7 -EHsc -O2 a.cpp b.cpp -Fet.exe && ./t.exe
1.000000
2.000000
2.000000
3.000000
2.000000
2.000000  # BUG: should be 1.0

The buggy code is in the catch funclet prologue. It does this:

"?catch$2@?0??throw_internally@@YAXXZ@4HA":
.seh_proc "?catch$2@?0??throw_internally@@YAXXZ@4HA"
        .seh_handler __CxxFrameHandler3, @unwind, @except
        movq    %rdx, 16(%rsp)
        pushq   %rbp
        .seh_pushreg 5
        pushq   %rsi
        .seh_pushreg 6
        subq    $40, %rsp
        .seh_stackalloc 40
        leaq    80(%rdx), %rbp
        movdqa  %xmm6, -16(%rbp)        # 16-byte Spill
        .seh_savexmm 6, 64
        .seh_endprologue

We set up RBP to point back to the parent stack frame, and then do XMM spills
through RBP. This is no good, because when we eventually return from
throw_internally, we will now restore XMM6 to the value it contained before
running the catch handler (2.0 in the example), and not the value it contained
before calling throw_internally (1.0 in the example).

Funclets should allocate their own stack memory to spill XMM registers.

This bug could probably also be observed by re-throwing the exception out of
the catch handler, since the .seh_savexmm directives we emit for the catch
handler are definitely wrong.</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>