Skip to content

asm goto miscompilation #74483

@dvyukov

Description

@dvyukov

As far as I understand asm goto now supports output arguments on all paths. If I am reading this correctly, in this case asm goto corrupts local state (output variable has incorrect value). The code is:

#include <stdio.h> long foo(long a, long b) { long x, y, z; asm goto( "movq %[a], %[x]; testq %[a], %[a]; jnz %l[label1]" : [x] "=&r"(x), [y] "=&r"(y), [z] "=&r"(z) : [a]"r"(a), [b]"r"(b) : "memory" : label1, label2); return 0; { label1: return x; } label2: return 1; } int main() { printf("%lu\n", foo(11, 22)); } 

With -O3 the program correctly prints 11:
https://godbolt.org/z/x17GnP4nK

But with -O0 it prints 0:
https://godbolt.org/z/h7MM9YTfP

The generated code is:

foo(long, long): # @foo(long, long) pushq %rbp movq %rsp, %rbp movq %rdi, -16(%rbp) movq %rsi, -24(%rbp) movq -16(%rbp), %rsi movq -24(%rbp), %rdi movq %rsi, %rax testq %rsi, %rsi jne .LBB0_2 movq %rdx, -96(%rbp) # 8-byte Spill movq %rcx, -88(%rbp) # 8-byte Spill movq %rax, -80(%rbp) # 8-byte Spill movq %rdx, -72(%rbp) # 8-byte Spill movq %rcx, -64(%rbp) # 8-byte Spill movq %rax, -56(%rbp) # 8-byte Spill jmp .LBB0_1 .LBB0_1: movq -72(%rbp), %rax # 8-byte Reload movq -64(%rbp), %rcx # 8-byte Reload movq -56(%rbp), %rdx # 8-byte Reload movq %rdx, -32(%rbp) movq %rcx, -40(%rbp) movq %rax, -48(%rbp) movq $0, -8(%rbp) jmp .LBB0_6 .LBB0_2: # Block address taken movq %rdx, -96(%rbp) # 8-byte Spill movq -80(%rbp), %rdx # 8-byte Reload movq %rcx, -88(%rbp) # 8-byte Spill movq -88(%rbp), %rcx # 8-byte Reload movq %rax, -80(%rbp) # 8-byte Spill movq -96(%rbp), %rax # 8-byte Reload movq %rdx, -32(%rbp) movq %rcx, -40(%rbp) movq %rax, -48(%rbp) jmp .LBB0_4 .LBB0_3: # Block address taken movq %rdx, -96(%rbp) # 8-byte Spill movq -80(%rbp), %rdx # 8-byte Reload movq %rcx, -88(%rbp) # 8-byte Spill movq -88(%rbp), %rcx # 8-byte Reload movq %rax, -80(%rbp) # 8-byte Spill movq -96(%rbp), %rax # 8-byte Reload movq %rdx, -32(%rbp) movq %rcx, -40(%rbp) movq %rax, -48(%rbp) jmp .LBB0_5 .LBB0_4: movq -32(%rbp), %rax movq %rax, -8(%rbp) jmp .LBB0_6 .LBB0_5: movq $1, -8(%rbp) .LBB0_6: movq -8(%rbp), %rax popq %rbp retq 

If we track the x variable, it's spilled to -80(%rbp), but then loaded from -32(%rbp):

foo(long, long): # @foo(long, long) ... movq %rsi, %rax ... jne .LBB0_2 ... .LBB0_2: # Block address taken ... movq %rax, -80(%rbp) # 8-byte Spill ... jmp .LBB0_4 ... .LBB0_4: movq -32(%rbp), %rax movq %rax, -8(%rbp) jmp .LBB0_6 ... .LBB0_6: movq -8(%rbp), %rax popq %rbp retq 

Metadata

Metadata

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions