rust-lang / rust-memory-model

Collecting examples and information to help design a memory model for Rust.
Apache License 2.0
126 stars 15 forks source link

optimizing around unchecked-get #20

Open nikomatsakis opened 8 years ago

nikomatsakis commented 8 years ago

The unchecked-get use case consists of safe code that contains one or two small unsafe calls which check application-level constraints -- for example, eliding a bounds check, or asserting that a string is utf-8:

fn foo() {
    let vec: Vec<i32> = vec![...];
    ...
    unsafe { vec.get_unchecked(i) }
    ...
}

Ideally, code like this would be optimized just as well as the original safe code (and of course would not have a bounds check). However, the introduction of an unsafe block and a call to an unsafe function can be a barrier to optimization, such as in the Tootsie Pop model (#21).

arielb1 commented 8 years ago

The traditional example is:

fn example_optimizable(b: &mut Context, bigs: &[Big]) {
    let index: usize = calculate_index(b);
    let tmp = unsafe { <[_]>::unchecked_get(bigs, index) };
    b.big = tmp;
}

Which is α-equivalent to

fn get_pointer_to_big(b: &Context) -> usize {
    &b.big as *const _ as usize
}

unsafe fn mutate_through_pointer(bigs: &[Big], index: usize) -> Big {
    Big {
        x: 0,
        y: (index as *const Big).x,
        ...
    }
}

fn example_nonoptimizable(b: &mut Context, bigs: &[Big]) {
    let index: usize = get_pointer_to_big(b);
    let tmp = unsafe { mutate_through_pointer(bigs, index) };
    b.big = tmp;
}

Disregarding panics, we want to do copy elimination in the first case, but not the second, but that is not really possible.

RalfJung commented 2 years ago

This is a problem in Tootsie Pop style models, but not in most others (such as Stacked Borrows) where unsafe blocks do not have any operational effect.