Closed
Description
These two functions should logically compile to the same code but don't:
pub fn unchecked(dst: &mut [u8], offset: usize) {
let mut i = offset;
if i.checked_add(4).unwrap() <= dst.len() {
unsafe {
*(dst.get_unchecked_mut(i)) = 1;
i += 1;
*(dst.get_unchecked_mut(i)) = 2;
i += 1;
*(dst.get_unchecked_mut(i)) = 3;
i += 1;
*(dst.get_unchecked_mut(i)) = 4;
}
}
}
pub fn checked(dst: &mut [u8], offset: usize) {
let mut i = offset;
if i.checked_add(4).unwrap() <= dst.len() {
dst[i] = 1;
i += 1;
dst[i] = 2;
i += 1;
dst[i] = 3;
i += 1;
dst[i] = 4;
}
}
The output is:
example::unchecked:
push rax
mov rax, rdx
add rax, 4
jb .LBB0_4
cmp rax, rsi
ja .LBB0_3
mov dword ptr [rdi + rdx], 67305985
.LBB0_3:
pop rax
ret
.LBB0_4:
lea rdi, [rip + .L__unnamed_1]
call qword ptr [rip + _ZN4core9panicking5panic17hd62333a8bd86ba63E@GOTPCREL]
ud2
example::checked:
push rax
mov rcx, rdx
add rcx, 4
jb .LBB1_14
mov rax, rsi
cmp rcx, rsi
ja .LBB1_7
cmp rdx, rax
jae .LBB1_8
mov byte ptr [rdi + rdx], 1
lea rsi, [rdx + 1]
cmp rsi, rax
jae .LBB1_11
mov byte ptr [rdi + rdx + 1], 2
lea rsi, [rdx + 2]
cmp rsi, rax
jae .LBB1_12
mov byte ptr [rdi + rdx + 2], 3
add rdx, 3
cmp rdx, rax
jae .LBB1_13
mov byte ptr [rdi + rdx], 4
.LBB1_7:
pop rax
ret
.LBB1_14:
lea rdi, [rip + .L__unnamed_1]
call qword ptr [rip + _ZN4core9panicking5panic17hd62333a8bd86ba63E@GOTPCREL]
ud2
.LBB1_8:
lea rdi, [rip + .L__unnamed_2]
mov rsi, rdx
mov rdx, rax
call qword ptr [rip + _ZN4core9panicking18panic_bounds_check17h8f5d51613726af8dE@GOTPCREL]
ud2
.LBB1_11:
lea rdi, [rip + .L__unnamed_3]
mov rdx, rax
call qword ptr [rip + _ZN4core9panicking18panic_bounds_check17h8f5d51613726af8dE@GOTPCREL]
ud2
.LBB1_12:
lea rdi, [rip + .L__unnamed_4]
mov rdx, rax
call qword ptr [rip + _ZN4core9panicking18panic_bounds_check17h8f5d51613726af8dE@GOTPCREL]
ud2
.LBB1_13:
lea rdi, [rip + .L__unnamed_5]
mov rsi, rdx
mov rdx, rax
call qword ptr [rip + _ZN4core9panicking18panic_bounds_check17h8f5d51613726af8dE@GOTPCREL]
ud2
.L__unnamed_6:
.ascii "called `Option::unwrap()` on a `None` value"
.L__unnamed_7:
.ascii "libcore/option.rs"
.L__unnamed_1:
.quad .L__unnamed_6
.asciz "+\000\000\000\000\000\000"
.quad .L__unnamed_7
.asciz "\021\000\000\000\000\000\000\000c\001\000\000\025\000\000"
str.0:
.ascii "/tmp/compiler-explorer-compiler118917-56-2jgk8f.vziuf/example.rs"
.L__unnamed_2:
.quad str.0
.quad 64
.long 19
.long 9
.L__unnamed_3:
.quad str.0
.quad 64
.long 21
.long 9
.L__unnamed_4:
.quad str.0
.quad 64
.long 23
.long 9
.L__unnamed_5:
.quad str.0
.quad 64
.long 25
.long 9
That is, the safe function emits bound checks for each write via slice subscript despite there being enough information to decide that the bound checks cannot fail.
In encoding_rs
the use of unsafe
as seen in the first function is necessary for the UTF-16 to UTF-8 encoder to be competitive with C++.
Metadata
Metadata
Assignees
Labels
Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.Issue: Problems and improvements with respect to performance of generated code.Relevant to the compiler team, which will review and decide on the PR/issue.