commit f616cb096a6817069948ce912baf045bfd0b42ef
parent 704f1a09fbf4c1342cfcdc75a1e41468bd1e4bc6
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 13 Jun 2026 09:32:48 -0700
perf(type): hoist the cg_id cache check above the type_cg_builtin switch
In type_cg_lower the builtin-kind switch ran before the t->cg_id cache check, so
an already-lowered non-builtin type (ptr/array/func/record/enum) paid the switch
every call. Move the VALUE-mode cache check above the switch. A primitive node
never carries a cg_id (primitives return from the switch before the cache-store
and type_unqual routes primitives through type_prim, not *nt=*t), so the hoist
only short-circuits non-builtin types — pure reorder, byte-identical.
Gate PASS all categories; test-cg-api / test-toy 0 failures.
Diffstat:
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lang/c/type/type.c b/lang/c/type/type.c
@@ -837,14 +837,18 @@ static KitCgTypeId type_cg_lower(TypeCgLower* l, const Type* t,
int cacheable;
int outer_incomplete;
if (!l || !t) return KIT_CG_TYPE_NONE;
- id = type_cg_builtin(l->c, (TypeKind)t->kind);
- if (id != KIT_CG_TYPE_NONE) return id;
/* Only VALUE-mode lowering is memoized on the node: TYPE_CG_RECORD_FIELD
* collapses pointers to void*, so the same Type* lowers differently there
- * (and that mode is used only transiently for record fields / func params). */
+ * (and that mode is used only transiently for record fields / func params).
+ * Check the cache BEFORE the builtin switch: a primitive node never carries a
+ * cg_id (it returns from the switch below before the cache-store), so this
+ * hoist only short-circuits already-lowered non-builtin types and never
+ * mis-returns a primitive's id — byte-identical, but skips the switch. */
cacheable = (mode == TYPE_CG_VALUE);
if (cacheable && t->cg_id != KIT_CG_TYPE_NONE)
return t->cg_id; /* cached => was incomplete-free => still stable */
+ id = type_cg_builtin(l->c, (TypeKind)t->kind);
+ if (id != KIT_CG_TYPE_NONE) return id;
/* Scope saw_incomplete to this subtree so the post-recursion check reflects
* only whether *this* node's lowering touched an incomplete record. */
outer_incomplete = l->saw_incomplete;