remove optimization when values move between pointers, it was unsound (see comment in source)

This commit is contained in:
Folkert 2022-03-26 18:50:47 +01:00
parent e6ae01384f
commit 75ab8afc2b
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -2537,28 +2537,39 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
value, value,
layout layout
); );
let value_ptr = value.into_pointer_value();
// We can only do this if the function itself writes data into this // What we want to do here is
// pointer. If the pointer is passed as an argument, then we must copy //
// from one pointer to our destination pointer // let value_ptr = value.into_pointer_value();
if value_ptr.get_first_use().is_some() { // if false && value_ptr.get_first_use().is_some() {
value_ptr.replace_all_uses_with(destination); // value_ptr.replace_all_uses_with(destination);
} else { //
let size = env // In other words, if the source pointer is used,
.ptr_int() // then we just subsitute the source for the input pointer, done.
.const_int(layout.stack_size(env.target_info) as u64, false); //
// Only that does not work if the source is not written to.
// A simple example is the identity function
//
// A slightly more complex case that will also make the above not
// work is when the source pointer is only incremented, but not
// written to. Then there is a first_use, but it's still invalid to
// subsitute source with destination
//
// Hence, we explicitly memcpy source to destination, and rely on
// LLVM optimizing away any inefficiencies.
let size = env
.ptr_int()
.const_int(layout.stack_size(env.target_info) as u64, false);
env.builder env.builder
.build_memcpy( .build_memcpy(
destination, destination,
align_bytes, align_bytes,
value.into_pointer_value(), value.into_pointer_value(),
align_bytes, align_bytes,
size, size,
) )
.unwrap(); .unwrap();
}
} }
} else { } else {
env.builder.build_store(destination, value); env.builder.build_store(destination, value);