From 7dc297cc14196ec1f9a4908395d89dfd00de859a Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Thu, 11 May 2023 13:11:57 -0400 Subject: [PATCH] nir: Add nir_foreach_phi(_safe) macro Serious preprocessor voodoo here. There are two tricks here. 1. Iterating only phis. We know that phis come only at the beginning of a block, so all over the tree, we open-code iteration like: nir_foreach_instr(instr, block) { if (instr->type != phi) break; /* do stuff */ } We can express this equivalently as nir_foreach_instr(instr, block) if (instr->type != phi) break; else { /* do stuff */ } So, we can define a macro #define nir_foreach_phi(instr, block) if (instr->type != phi) break; else and then nir_foreach_phi(..) statement; and nir_foreach_phi(..) { ... } will expand to the right thing. 2. Automatically getting the phi as a phi. We want the instruction to go to some hidden variable, and then automatically insert nir_phi_instr *phi = nir_instr_as_phi(instr_internal); We can't do that directly, since we need to express the assignment implicitly in the control flow for the above trick to work. But we can do it indirectly with a loop initializer. for (nir_phi_instr *phi = nir_instr_as_phi(instr_internal); ...) That loop needs to break after exactly one iteration. We know that phi will always be non-null on its first iteration, since the original instruction is non-null, so we can use phi==NULL as a sentinel and express a one-iteration loop as for (phi = nonnull; phi != NULL; phi = NULL). Putting these together gives the macros implemented used. Signed-off-by: Alyssa Rosenzweig Reviewed-by: Konstantin Seurer Reviewed-by: Jesse Natalie Part-of: --- src/compiler/nir/nir.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 9776aca7e0d..45edbaaa619 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -2896,6 +2896,22 @@ nir_block_ends_in_break(nir_block *block) #define nir_foreach_instr_reverse_safe(instr, block) \ foreach_list_typed_reverse_safe(nir_instr, instr, node, &(block)->instr_list) +/* Phis come first in the block */ +#define nir_foreach_phi_internal(instr, phi) \ + if (instr->type != nir_instr_type_phi) \ + break; \ + else \ + for (nir_phi_instr *phi = nir_instr_as_phi(instr); phi != NULL; \ + phi = NULL) + +#define nir_foreach_phi(instr, block) \ + nir_foreach_instr(nir_foreach_phi_##instr, block) \ + nir_foreach_phi_internal(nir_foreach_phi_##instr, instr) + +#define nir_foreach_phi_safe(instr, block) \ + nir_foreach_instr_safe(nir_foreach_phi_safe_##instr, block) \ + nir_foreach_phi_internal(nir_foreach_phi_safe_##instr, instr) + static inline nir_phi_instr * nir_block_last_phi_instr(nir_block *block) {