macro simpl!(X) {
  ccp(X);
  simplify-cfg(X);
  lift-dc-math(X);
  gvn(X);
  phi-elim(X);
  dce(X);
  infer-schedules(X);
}

simpl!(*);

ip-sroa(*);
sroa(*);
simpl!(*);

no-memset(gaussian_smoothing@res);
fixpoint {
  forkify(gaussian_smoothing);
  fork-guard-elim(gaussian_smoothing);
  fork-coalesce(gaussian_smoothing);
}
predication(gaussian_smoothing);
simpl!(gaussian_smoothing);
predication(gaussian_smoothing);
simpl!(gaussian_smoothing);

if !feature("seq") {
  let par = gaussian_smoothing@image_loop \ gaussian_smoothing@filter_loop;
  fork-tile[4, 1, false, false](par);
  fork-tile[8, 0, false, false](par);
  fork-interchange[1, 2](par);
  let split = fork-split(par);
  let gaussian_smoothing_body = outline(split._0_gaussian_smoothing.fj2);
  fork-coalesce(gaussian_smoothing, gaussian_smoothing_body);
  simpl!(gaussian_smoothing, gaussian_smoothing_body);
  gaussian_smoothing = gaussian_smoothing_body;
}

no-memset(laplacian_estimate@res);
fixpoint {
  forkify(laplacian_estimate);
  fork-guard-elim(laplacian_estimate);
  fork-coalesce(laplacian_estimate);
}
simpl!(laplacian_estimate);

if !feature("seq") {
  let par = laplacian_estimate@image_loop \ laplacian_estimate@filter_loop;
  fork-tile[4, 1, false, false](par);
  fork-tile[8, 0, false, false](par);
  fork-interchange[1, 2](par);
  let split = fork-split(par);
  let body = split._1_laplacian_estimate.fj2;
  let laplacian_estimate_body = outline(body);
  fork-coalesce(laplacian_estimate, laplacian_estimate_body);
  simpl!(laplacian_estimate, laplacian_estimate_body);
  laplacian_estimate = laplacian_estimate_body;
}

no-memset(zero_crossings@res);
fixpoint {
  forkify(zero_crossings);
  fork-guard-elim(zero_crossings);
  fork-coalesce(zero_crossings);
}
simpl!(zero_crossings);

if !feature("seq") {
  let par = zero_crossings@image_loop \ zero_crossings@filter_loop;
  fork-tile[4, 1, false, false](par);
  fork-tile[8, 0, false, false](par);
  fork-interchange[1, 2](par);
  let split = fork-split(par);
  let body = split._2_zero_crossings.fj2;
  let zero_crossings_body = outline(body);
  fork-coalesce(zero_crossings, zero_crossings_body);
  simpl!(zero_crossings, zero_crossings_body);
  zero_crossings = zero_crossings_body;
}

no-memset(gradient@res);
fixpoint {
  forkify(gradient);
  fork-guard-elim(gradient);
  fork-coalesce(gradient);
}
predication(gradient);
simpl!(gradient);
predication(gradient);
simpl!(gradient);

fixpoint {
  forkify(max_gradient);
  fork-guard-elim(max_gradient);
  fork-coalesce(max_gradient);
}
simpl!(max_gradient);

if !feature("seq") {
  fork-dim-merge(max_gradient);
  simpl!(max_gradient);
  fork-tile[32, 0, false, false](max_gradient);
  let split = fork-split(max_gradient);
  clean-monoid-reduces(max_gradient);
  let out = outline(split._4_max_gradient.fj1);
  simpl!(max_gradient, out);
  unforkify(out);
  let out = fork-fission[split._4_max_gradient.fj0](max_gradient);
  simpl!(max_gradient);
  unforkify(out._4_max_gradient.fj_bottom);
} else {
  fork-split(max_gradient);
  unforkify(max_gradient);
}

no-memset(reject_zero_crossings@res);
fixpoint {
  forkify(reject_zero_crossings);
  fork-guard-elim(reject_zero_crossings);
  fork-coalesce(reject_zero_crossings);
}
predication(reject_zero_crossings);
simpl!(reject_zero_crossings);

if !feature("seq") {
  fork-tile[4, 1, false, false](reject_zero_crossings);
  fork-tile[8, 0, false, false](reject_zero_crossings);
  fork-interchange[1, 2](reject_zero_crossings);
  let split = fork-split(reject_zero_crossings);
  let reject_zero_crossings_body = outline(split._5_reject_zero_crossings.fj2);
  fork-coalesce(reject_zero_crossings, reject_zero_crossings_body);
  simpl!(reject_zero_crossings, reject_zero_crossings_body);
  reject_zero_crossings = reject_zero_crossings_body;
}

async-call(edge_detection@le, edge_detection@zc);

fork-split(gaussian_smoothing, laplacian_estimate, zero_crossings, gradient, reject_zero_crossings);
unforkify(gaussian_smoothing, laplacian_estimate, zero_crossings, gradient, reject_zero_crossings);

simpl!(*);

delete-uncalled(*);
gcm(*);