Missed bound check removal

6c6273d
Opened by leonardo-m at 2023-11-29 06:52:41

A little test program:

#[inline(never)]
fn almost_product(nums: &[i32]) -> Vec<i32> {
    let mut result = vec![0; nums.len()];

    let mut prod = 1;
    for (i, &x) in nums.iter().enumerate() {
        result[i] = prod;
        prod *= x;
    }
    result
}

fn main() {
    let data = [1, 2, 3, 4, 11];
    println!("{:?}", almost_product(&data));
    let data = [1, 2, 3, 4, 11, 26, 54, 6];
    println!("{:?}", almost_product(&data));
}

If I compile it with: nightly-x86_64-pc-windows-gnu - rustc 1.19.0-nightly (f4209651e 2017-05-05)

Using: rustc -C opt-level=3 --emit asm test1.rs

I get this asm for the loop:

_ZN5test114almost_product17he2636a2faa7b0543E:
...
.LBB4_9:
    cmpq    %r12, %rdi
    jae .LBB4_10
    movl    (%r15,%rdi,4), %eax
    movl    %esi, (%rcx,%rdi,4)
    incq    %rdi
    imull   %esi, %eax
    addq    $-4, %rbx
    movl    %eax, %esi
    jne .LBB4_9
...
.LBB4_10:
    leaq    panic_bounds_check_loc.5(%rip), %rcx
    movq    %rdi, %rdx
    movq    %r12, %r8
    callq   _ZN4core9panicking18panic_bounds_check17h1fe2f83f670bcee9E
    ud2

The bound check isn't removed. To remove it I need to use get_unchecked_mut(), or code like this (with the same main function):

#![feature(core_intrinsics)]
use std::intrinsics::assume;

#[inline(never)]
fn almost_product(nums: &[i32]) -> Vec<i32> {
    let mut result = vec![0; nums.len()];

    let mut prod = 1;
    for (i, &x) in nums.iter().enumerate() {
        unsafe { assume(i < result.len()); }
        result[i] = prod;
        prod *= x;
    }
    result
}

Now the loop gives a clean asm:

.LBB3_11:
    movl    %edx, %esi
    movl    (%r12,%rcx,4), %edx
    imull   %esi, %edx
    movl    %esi, (%rax,%rcx,4)
    incq    %rcx
    addq    $-4, %rdi
    cmpq    %rcx, %rbx
    jne .LBB3_11

If I use: unsafe { *result.get_unchecked_mut(i) = prod; }

The loop also gets unrolled four times:

.LBB3_15:
	movl	(%rcx), %esi
	imull	%edx, %esi
	movl	%edx, -12(%rbx)
	movl	4(%rcx), %edx
	imull	%esi, %edx
	movl	%esi, -8(%rbx)
	movl	8(%rcx), %esi
	imull	%edx, %esi
	movl	%edx, -4(%rbx)
	movl	12(%rcx), %edx
	imull	%esi, %edx
	movl	%esi, (%rbx)
	addq	$16, %rbx
	addq	$16, %rcx
	cmpq	%rdi, %rcx
	jne	.LBB3_15
  1. Something seems to still be a problem: https://godbolt.org/z/jW6K8qYvE

    Jubilee at 2023-11-29 06:52:41