performance regress in masked `u128` field updates on x86_64
Open
Nobody has claimed this yet.
A-LLVM
C-bug
I-prioritize
llvm-fixed-upstream
regression-untriaged
T-compiler
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
I tried this code:
const LOW_MASK: u128 = 0xFFFF_FFFF;
#[repr(transparent)]
pub struct Token(u128);
impl Token {
#[inline(always)]
fn set_start_mask(&mut self, start: u32) {
self.0 &= !LOW_MASK;
self.0 |= start as u128;
}
#[inline(always)]
fn set_end_mask(&mut self, end: u32) {
self.0 &= !(LOW_MASK << 32);
self.0 |= (end as u128) << 32;
}
#[inline(always)]
fn set_start_ptr(&mut self, start: u32) {
#[cfg(target_endian = "little")]
unsafe {
core::ptr::from_mut(&mut self.0).cast::<u32>().write(start);
}
#[cfg(not(target_endian = "little"))]
{
self.0 &= !LOW_MASK;
self.0 |= start as u128;
}
}
#[inline(always)]
fn set_end_ptr(&mut self, end: u32) {
#[cfg(target_endian = "little")]
unsafe {
core::ptr::from_mut(&mut self.0).cast::<u32>().add(1).write(end);
}
#[cfg(not(target_endian = "little"))]
{
token.0 &= !(LOW_MASK << 32);
token.0 |= (end as u128) << 32;
}
}
}
#[unsafe(no_mangle)]
pub extern "C" fn hot_start_mask(token: &mut Token, start: u32) -> u128 {
token.set_start_mask(start);
token.0
}
#[unsafe(no_mangle)]
pub extern "C" fn hot_end_mask(token: &mut Token, end: u32) -> u128 {
token.set_end_mask(end);
token.0
}
#[unsafe(no_mangle)]
pub extern "C" fn hot_start_ptr(token: &mut Token, start: u32) -> u128 {
token.set_start_ptr(start);
token.0
}
#[unsafe(no_mangle)]
pub extern "C" fn hot_end_ptr(token: &mut Token, end: u32) -> u128 {
token.set_end_ptr(end);
token.0
}
I expected to see this happen:
hot_end_mask:
mov rdx, qword ptr [rdi + 8]
mov eax, dword ptr [rdi]
shl rsi, 32
or rax, rsi
mov qword ptr [rdi], rax
ret
hot_end_ptr:
mov dword ptr [rdi + 4], esi
mov rdx, qword ptr [rdi + 8]
mov rax, qword ptr [rdi]
ret
hot_start_mask:
mov rdx, qword ptr [rdi + 8]
mov ecx, dword ptr [rdi + 4]
shl rcx, 32
mov eax, esi
or rax, rcx
mov qword ptr [rdi], rax
ret
hot_start_ptr:
mov dword ptr [rdi], esi
mov rdx, qword ptr [rdi + 8]
mov rax, qword ptr [rdi]
ret
Instead, this happened:
hot_end_mask:
pshufd xmm0, xmmword ptr [rdi], 238
mov eax, dword ptr [rdi]
movq rdx, xmm0
shl rsi, 32
or rax, rsi
movq qword ptr [rdi + 8], xmm0
mov qword ptr [rdi], rax
ret
hot_end_ptr:
mov dword ptr [rdi + 4], esi
mov rdx, qword ptr [rdi + 8]
mov rax, qword ptr [rdi]
ret
.LCPI2_0:
.long 0
.long 4294967295
.long 4294967295
.long 4294967295
hot_start_mask:
movdqa xmm0, xmmword ptr [rdi]
pshufd xmm1, xmm0, 238
pand xmm0, xmmword ptr [rip + .LCPI2_0]
movq rdx, xmm1
movq rcx, xmm0
mov eax, esi
or rax, rcx
movq qword ptr [rdi + 8], xmm1
mov qword ptr [rdi], rax
ret
hot_start_ptr:
mov dword ptr [rdi], esi
mov rdx, qword ptr [rdi + 8]
mov rax, qword ptr [rdi]
ret
Version it worked on
It most recently worked on: 1.94
Version with regression
rustc --version --verbose:
1.95
References: https://github.com/oxc-project/oxc/pull/21509
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling the provided Rust reproducer with rustc 1.94 and 1.95 for x86_64 and compare the emitted assembly for the four hot_* functions. Investigate the compiler change affecting masked u128 updates, then verify that the regression is removed while the functions retain their expected behavior and assembly quality.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100