devicetree: re-work DT_INST_FOREACH()

Due to the use of UTIL_EVAL*() macros, the UTIL_LISTIFY() macro used
by DT_INST_FOREACH(foo) can cause long build errors when there is a
build error in the expansion for "foo". More than a thousand lines of
build error output have been observed for an error in a single line of
faulty C.

To improve the situation, re-work the implementation details so the
errors are a bit shorter and easier to read. The use of COND_CODE_1
still makes the error messages quite long, due to GCC generating notes
for various intermediate expansions (__DEBRACKET,
__GET_ARG_2_DEBRACKET, __COND_CODE, Z_COND_CODE_1, COND_CODE1), but
it's better than the long list of UTIL_EVAL notes.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py
index cf112f7..13f2759 100755
--- a/scripts/dts/gen_defines.py
+++ b/scripts/dts/gen_defines.py
@@ -525,9 +525,24 @@
             if bus is not None and bus not in compat2buses[compat]:
                 compat2buses[compat].append(bus)
 
-    out_comment("Number of enabled instances of each compatible\n")
+    out_comment("Helpers for calling a macro/function a fixed number of times"
+                "\n")
+    for numinsts in range(1, max(compat2numinst.values(), default=0) + 1):
+        out_define(f"DT_FOREACH_IMPL_{numinsts}(fn)",
+                   " ".join([f"fn({i});" for i in range(numinsts)]))
+
+    out_comment("Macros for enabled instances of each compatible\n")
+    n_inst_macros = {}
+    for_each_macros = {}
     for compat, numinst in compat2numinst.items():
-        out_define(f"DT_N_INST_{str2ident(compat)}_NUM", numinst)
+        ident = str2ident(compat)
+        n_inst_macros[f"DT_N_INST_{ident}_NUM"] = numinst
+        for_each_macros[f"DT_FOREACH_INST_{ident}(fn)"] = \
+            f"DT_FOREACH_IMPL_{numinst}(fn)"
+    for macro, value in n_inst_macros.items():
+        out_define(macro, value)
+    for macro, value in for_each_macros.items():
+        out_define(macro, value)
 
     out_comment("Bus information for enabled nodes of each compatible\n")
     for compat, buses in compat2buses.items():