Closure conversion pass misses closures stored to memory
Hugobros3 opened this issue · comments
The following Artic snippet (obtained by simplifying an example in rastify/anyosl)
#[import(cc = "C", name = "anydsl_print_string")] fn print_string(_: &[u8]) -> ();
struct Vector {
x: f32,
y: f32,
z: f32,
}
struct shader_inout {
P: Vector,
N: Vector,
Ci: fn(i32) -> i32,
}
struct mandelbrot_out {
fout: f32,
}
// #[export]
fn @(false) mandelbrot_impl(inout : shader_inout, dummy: fn(i32) -> i32) -> (mandelbrot_out, shader_inout) {
let mut fout: f32 = 0;
let mut P = inout.P;
let mut N = inout.N;
let mut Ci = inout.Ci;
//removing this makes it compile
print_string("kusa");
(mandelbrot_out {
fout = fout,
},
shader_inout {
P = P,
N = N,
Ci = Ci,
})
}
#[export]
fn fragmentShader() {
let si = shader_inout {
P = Vector{x=0,y=0, z=0},
N = Vector{x=0,y=0, z=0},
Ci = @| _ | { 7 },
};
mandelbrot_impl(si, fake);
}
produces invalid LLVM code.
From my analysis, the problem is allocating and storing the Ci
struct, that cannot be optimized away as we do not have dead store optimisations, and the closure conversion should thus process this as it remains in Thorin IR. However, because closure conversion works by looking at the signature of the continuations, it is unable to detect the issue in this particular case, as the stored value is obtained by looking at a global, and so does not appear in the signature. It follows that closure conversion leaves this unprocessed, leading to the LLVM emission pass trying to emit an alloca/store to a function value rather than a function pointer.
Possible fixes (?):
- Look specifically for memory operations during CC ?
- Make CC work in reverse from continuations and look at their uses ?
- Eagerly look in the contents of all continuations ?
- Make
Type
s intoDef
s and look at the uses of HOTs ?