Rust-GPU / Rust-GPU/rust-gpu

[Migrated] We should override `thir_body` to inject loop merge points for structurization.

Abierto
#103 1 comentario 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Lenguaje dominante
Rust
Estrellas
3.4k
Forks
126
Métricas de merge de PR
Sin PR fusionados en 30 d

Descripción

Issue automatically imported from old repo: https://github.com/EmbarkStudios/rust-gpu/issues/944

Originally creatd by eddyb on 2022-11-24T08:17:49Z 👍: 1


I was writing up this SPIR-T issue when I realized we can do much better than I ever thought we can:

The "subgroup reconvergence"/"loop merges" problem statement

the fundamental ambiguity here (wrt reconvergence), that explicit merges solve, looks like this:

loop {
    // ...
    if cond {  // the "then" edge *leaves the loop*
        A();   // !!! it might be important that this STAYS INSIDE the loop!
        break; // this is just a linear A -> B edge in the CFG (outside the loop's cycle)
    }
}
B(); // !!! it might be important that this STAYS OUTSIDE the loop!

because the A() -> B() edge just looks like a redundant fusable edge (isomorphic to a single A(); B(); basic block), structurizers will very likely either produce:

  • loop { ... if cond { break; } } A(); B(); (moving A() out of the loop)
    • A() no longer called for "early finishers" (losing a desired side-effect)
  • loop { ... if cond { A(); B(); break; } } (moving B() into the loop)
    • B() now being called for "early finishers" (gaining an undesired side-effect)

and they're both bad because a non-uniform break (i.e. an "early finisher") will block on subgroup neighbors (semantically, at least, in hardware the now-inactive lanes will likely stick around while loop instructions continue being executed for remaining lanes, until they all eventually break)

An actual reasonable solution for once (what prompted me to open this issue)

A better approach might be to "just" make up a SPIR-T instruction that acts as "loop merge barrier", i.e.:

loop {
    // ...
    if cond {
        A();   // !!! definitely INSIDE the loop
        break; // just an edge to the `LoopMerge`, in the CFG
    }
}
asm!("spirt.ControlInst.LoopMerge");
B(); // !!! definitely OUTSIDE the loop

Each LoopMerge would be consumed by one loop structurization - if you have nested loops, you'd need to be careful not to forget to add them to each loop.

But wait, even if we make this ergonomic with macros... we'd still want to check that you don't use any instructions that "care" about e.g. subgroups, right? That could be e.g. a MIR check pass, right? Which we can inject... just like...

Yes, that's right, rustc_codegen_spirv has enough query overriding power that it could override thir_body, which MIR construction uses as the source of truth, to introduce additional nodes around loops, allowing Rust to be on par with GLSL wrt structured control-flow guarantees.


Additionally, this could be used to replace #[spirv(unroll_loops)] (once that's removed, see https://github.com/EmbarkStudios/rust-gpu/pull/940#issuecomment-1320004784 for more context), as it would allow us to check for a (new) #[spirv(unroll)] attribute on the loop expression, and then store that in the injected merge point.

That would be much nicer than fn-level catch-alls, and generally a good fit for SPIR-V expressivity.

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con la referencia enlazada a la construcción de MIR de rustc y la sobrescritura de la consulta thir_body en rustc_codegen_spirv. Investiga cómo los nodos de bucle podrían incluir LoopMerge e información de unrolling a nivel de bucle, incluidos los bucles anidados y las instrucciones sensibles a subgrupos. Se considera terminado cuando los puntos de unión de los bucles y el atributo de unroll propuesto se inyectan y validan sin perder la semántica de control de flujo prevista.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
rust
Área
compilers
Tipo de issue
Nueva funcionalidad
Dificultad
5/5
Tiempo estimado
Más de una semana
Estado de actividad
Estancado
Claridad
Bastante claro
Aptitud para principiantes
25/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.