Skip to content

LLVM 19.1.6 [[clang::preserve_most]] targeting x86-32 can clobber result register #122648

@Nick-Kooij

Description

@Nick-Kooij

Consider the following function, attributed with [[clang::preserve_most]]:

extern void bar( int* );

[[clang::preserve_most]] [[clang::noinline]] int foo( int x ) {
    bar( &x );
    return x * x;
}

When targeting x86-32, this emits the following incorrect code, which saves and restores the result register (EAX) breaking the return value:

<int foo(int)>:
               	push	edx
               	push	ecx
               	push	eax ; RESULT REGISTER SAVED
               	push	edi
               	push	esi
               	push	edx
               	push	ecx
               	push	ebp
               	push	edi
               	push	esi
               	push	ebp
               	push	esp
               	push	ebx
               	lea	eax, [esp + 0x38]
               	push	eax
               	call	 <L0>
		IMAGE_REL_I386_REL32	?bar@@YAXPAH@Z
<L0>:
               	add	esp, 0x4
               	mov	eax, dword ptr [esp + 0x38]
               	imul	eax, eax
               	pop	ebx
               	pop	esp
               	pop	ebp
               	pop	esi
               	pop	edi
               	pop	ebp
               	pop	ecx
               	pop	edx
               	pop	esi
               	pop	edi
              	pop	eax ; RESULT CLOBBERED
               	pop	ecx
               	pop	edx
               	ret

The following attached project, should print "64" and exit. x86-32 builds instead print the arbitrary value of whatever was in the EAX register when bar was called.

Note: I'm using LLVM through clang-cl under Visual Studio, bug I suspect the issue is more fundamental than the compiler driver.

Steps to reproduce:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions