AnyDSL / thorin

The Higher-Order Intermediate Representation
https://anydsl.github.io
GNU Lesser General Public License v3.0
150 stars 15 forks source link

Closure conversion pass misses closures stored to memory #116

Open Hugobros3 opened 3 years ago

Hugobros3 commented 3 years ago

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 (?):