-
Notifications
You must be signed in to change notification settings - Fork 14.8k
Description
Bugzilla Link | 17261 |
Version | unspecified |
OS | MacOS X |
Attachments | isolate.invoke.ll: LLVM input using invoke, isolate.call.ll: LLVM input using call, isolate.invoke.ll.s: assembly output when using invoke, isolate.call.ll.s: assembly output when using call (works) |
Reporter | LLVM Bugzilla Contributor |
Extended Description
This bug is an attempt to isolate the problem identified on the Rust project here:
rust-lang/rust#9129 (comment)
Summary bullet points for reproduction:
-
It appears to be a problem with
invoke
reloading a spilled call target; usingcall
fixes the problem. -
You need
llc -O0
to see the problem; higher optimization levels mask the problem. -
This bug report is written based on assembly code analysis, but the problem was discovered (as you might expect) based on actual crashes of compiled code.
The plot:
I have found a standalone .ll input for which an invoke
instruction compiles via llc
into code that loads from a location on the stack to which no value has been previously assigned. When I substitute a call
instruction for the same spot, llc
generates code that correctly loads a spilled value from the stack back into a register in preparation for the call.
I am running llc via command lines like this:
llc -o isolate.invoke.ll.s isolate.invoke.ll -O0 -filetype=asm
In particular, to reproduce the bug, you need to use -O0.
I am running with llc
compiled from:
"""
commit 107cfa2
Author: Tim Northover [email protected]
Date: Mon Sep 16 17:33:40 2013 +0000
TableGen: fix constness of new comparison function.
libc++ didn't seem to like a non-const call operator.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190797 91177308-0d34-0410-b5e6-96231b3b80d8
"""
I have not been able to come up with a C++ program that generates the offending code. I am hoping that people will be able to see the same problem on their own systems by inspecting the assembly (as I have been) and then be able to figure out why invoke
is not being compiled correctly.
I'm attaching four files: two are the input .ll files (one using call
, and the other using invoke
), and the other two are the output .s files.
For ease of reference, I am posting the most relevant bits of generated assembly here.
The variant that uses the call instruction generates correct machine code that looks like this (snippet):
## BB#0: ## %function top level
subq $56, %rsp
Ltmp1:
.cfi_def_cfa_offset 64
addq $8, %rdi
movq %rdi, 8(%rsp) ## 8-byte Spill
callq __ZN9breakdown17haf444eb869dbfb724v0.0E
movq %rax, 32(%rsp)
movq 32(%rsp), %rdi
movq 8(%rsp), %rax ## 8-byte Reload
callq *%rax
In particular, the spill and reload are both referring to the same stack location, 8(%rsp)
Conversely, the code that is generated from using invoke
looks like this:
BB#0: ## %function top level
subq $88, %rsp
Ltmp4:
.cfi_def_cfa_offset 96
addq $8, %rdi
Ltmp0:
movq %rdi, 40(%rsp) ## 8-byte Spill
callq __ZN9breakdown17haf444eb869dbfb724v0.0E
Ltmp1:
movq %rax, 32(%rsp) ## 8-byte Spill
jmp LBB1_1
LBB1_1: ## %normal return
movq 32(%rsp), %rax ## 8-byte Reload
movq %rax, 64(%rsp)
movq 64(%rsp), %rdi
movq 24(%rsp), %rcx ## 8-byte Reload
callq *%rcx
Note that the reload that establishes %rcx is coming from 24(%rsp)
, a stack location that has not been established by any register spills.
(Note: The attached code is only meant to illustrate incorrect assembly+machine code generation; it is the result of me iteratively reducing an initial function from the Rust bug linked above until I came up with something small enough for reasonable submission, i.e. <50 lines. But it does not run on its own, and at this point I removed so much of the original computation that it almost certainly would break if you did actually run it.)