-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Open
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-rust-for-linuxRelevant for the Rust-for-Linux projectRelevant for the Rust-for-Linux projectC-bugCategory: This is a bug.Category: This is a bug.E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.Call for participation: Medium difficulty. Experience needed to fix: Intermediate.O-x86_32Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.WG-llvmWorking group: LLVM backend code generationWorking group: LLVM backend code generation
Description
The following code:
use std::ffi::c_void;
unsafe extern "C" {
fn memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn entrypoint(
len: usize, val: i32, ptr: *mut c_void
) -> *mut c_void {
unsafe { memset(ptr, val, len) }
}
Generates this asm:
entrypoint:
push esi
sub esp, 8
mov esi, ecx
sub esp, 4
push eax
push edx
push ecx
call memset
add esp, 16
mov eax, esi
add esp, 8
pop esi
ret
Which isn't right: it's taking the incoming args in eax
, edx
, ecx
(correct) and making pushing them to the stack before calling memset
(incorrect). regparm
should make both be passed in regs.
Generated IR:
define dso_local noundef ptr @entrypoint(i32 inreg noundef %len, i32 inreg noundef %val, ptr inreg noundef returned writeonly captures(ret: address, provenance) %ptr) unnamed_addr {
start:
%0 = trunc i32 %val to i8
tail call void @llvm.memset.p0.i32(ptr inreg noundef align 1 %ptr, i8 inreg noundef %0, i32 inreg noundef %len, i1 false) #2
ret ptr %ptr
}
declare void @llvm.memset.p0.i32(ptr writeonly captures(none), i8, i32, i1 immarg) #1
If we add the following, the output looks correct:
!llvm.module.flags = !{!2}
!2 = !{i32 1, !"NumRegisterParameters", i32 3}
entrypoint: # @entrypoint
push esi
mov esi, eax
mov eax, ecx
mov ecx, esi
pop esi
jmp memset # TAILCALL
So it seems like we need to add that module flag. Clang does this as well.
Demo of everything at https://rust.godbolt.org/z/ehnTjTx9b
Tracking issue: #131749
Metadata
Metadata
Assignees
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-rust-for-linuxRelevant for the Rust-for-Linux projectRelevant for the Rust-for-Linux projectC-bugCategory: This is a bug.Category: This is a bug.E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.Call for participation: Medium difficulty. Experience needed to fix: Intermediate.O-x86_32Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.WG-llvmWorking group: LLVM backend code generationWorking group: LLVM backend code generation