From ef7b9b95cff6824af041a7536588334aeed1ee12 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nicol=C3=A1s=20B=C3=A9rtolo?= <nicolasbertolo@gmail.com>
Date: Sat, 30 May 2020 18:33:58 -0300
Subject: [PATCH 2/2] Define casts using functions.

This is to dump prettier C files.
This does not affect compilation times in my tests.

* src/comp.c: Define a 15x15 cast matrix. Use it in emit_coerce().
---
 src/comp.c | 279 ++++++++++++++++++++---------------------------------
 1 file changed, 106 insertions(+), 173 deletions(-)

diff --git a/src/comp.c b/src/comp.c
index 2f78760764..9d8445de9a 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -455,6 +455,8 @@ #define F_RELOC_MAX_SIZE 1500
 
 static f_reloc_t freloc;
 
+#define NUM_CAST_TYPES 15
+
 /* C side of the compiler context.  */
 
 typedef struct {
@@ -513,21 +515,9 @@ #define F_RELOC_MAX_SIZE 1500
   /* libgccjit has really limited support for casting therefore this union will
      be used for the scope.  */
   gcc_jit_type *cast_union_type;
-  gcc_jit_field *cast_union_as_ll;
-  gcc_jit_field *cast_union_as_ull;
-  gcc_jit_field *cast_union_as_l;
-  gcc_jit_field *cast_union_as_ul;
-  gcc_jit_field *cast_union_as_u;
-  gcc_jit_field *cast_union_as_i;
-  gcc_jit_field *cast_union_as_b;
-  gcc_jit_field *cast_union_as_uintptr;
-  gcc_jit_field *cast_union_as_ptrdiff;
-  gcc_jit_field *cast_union_as_c_p;
-  gcc_jit_field *cast_union_as_v_p;
-  gcc_jit_field *cast_union_as_lisp_cons_ptr;
-  gcc_jit_field *cast_union_as_lisp_word;
-  gcc_jit_field *cast_union_as_lisp_word_tag;
-  gcc_jit_field *cast_union_as_lisp_obj_ptr;
+  gcc_jit_function *cast_functions_from_to[NUM_CAST_TYPES][NUM_CAST_TYPES];
+  gcc_jit_type *cast_types[NUM_CAST_TYPES];
+  gcc_jit_field *cast_union_fields[NUM_CAST_TYPES];
   gcc_jit_function *func; /* Current function being compiled.  */
   bool func_has_non_local; /* From comp-func has-non-local slot.  */
   gcc_jit_lvalue **f_frame; /* "Floating" frame for the current function.  */
@@ -685,47 +675,6 @@ bcall0 (Lisp_Object f)
   Ffuncall (1, &f);
 }
 
-static gcc_jit_field *
-type_to_cast_field (gcc_jit_type *type)
-{
-  gcc_jit_field *field;
-
-  if (type == comp.long_long_type)
-    field = comp.cast_union_as_ll;
-  else if (type == comp.unsigned_long_long_type)
-    field = comp.cast_union_as_ull;
-  else if (type == comp.long_type)
-    field = comp.cast_union_as_l;
-  else if (type == comp.unsigned_long_type)
-    field = comp.cast_union_as_ul;
-  else if (type == comp.unsigned_type)
-    field = comp.cast_union_as_u;
-  else if (type == comp.int_type)
-    field = comp.cast_union_as_i;
-  else if (type == comp.bool_type)
-    field = comp.cast_union_as_b;
-  else if (type == comp.void_ptr_type)
-    field = comp.cast_union_as_v_p;
-  else if (type == comp.uintptr_type)
-    field = comp.cast_union_as_uintptr;
-  else if (type == comp.ptrdiff_type)
-    field = comp.cast_union_as_ptrdiff;
-  else if (type == comp.char_ptr_type)
-    field = comp.cast_union_as_c_p;
-  else if (type == comp.lisp_cons_ptr_type)
-    field = comp.cast_union_as_lisp_cons_ptr;
-  else if (type == comp.lisp_word_type)
-    field = comp.cast_union_as_lisp_word;
-  else if (type == comp.lisp_word_tag_type)
-    field = comp.cast_union_as_lisp_word_tag;
-  else if (type == comp.lisp_obj_ptr_type)
-    field = comp.cast_union_as_lisp_obj_ptr;
-  else
-    xsignal1 (Qnative_ice, build_string ("unsupported cast"));
-
-  return field;
-}
-
 static gcc_jit_block *
 retrive_block (Lisp_Object block_name)
 {
@@ -986,11 +935,19 @@ emit_cond_jump (gcc_jit_rvalue *test,
 
 }
 
+static int
+type_to_cast_index (gcc_jit_type * type)
+{
+  for (int i = 0; i < NUM_CAST_TYPES; ++i)
+    if (type == comp.cast_types[i])
+      return i;
+
+  xsignal1 (Qnative_ice, build_string ("unsupported cast"));
+}
+
 static gcc_jit_rvalue *
 emit_coerce (gcc_jit_type *new_type, gcc_jit_rvalue *obj)
 {
-  static ptrdiff_t i;
-
   gcc_jit_type *old_type = gcc_jit_rvalue_get_type (obj);
 
   if (new_type == old_type)
@@ -1022,25 +979,14 @@ emit_coerce (gcc_jit_type *new_type, gcc_jit_rvalue *obj)
     }
 #endif
 
-  gcc_jit_field *orig_field =
-    type_to_cast_field (old_type);
-  gcc_jit_field *dest_field = type_to_cast_field (new_type);
-
-  gcc_jit_lvalue *tmp_u =
-    gcc_jit_function_new_local (comp.func,
-				NULL,
-				comp.cast_union_type,
-				format_string ("union_cast_%td", i++));
-  gcc_jit_block_add_assignment (comp.block,
-				NULL,
-				gcc_jit_lvalue_access_field (tmp_u,
-							     NULL,
-							     orig_field),
-				obj);
+  int old_index = type_to_cast_index (old_type);
+  int new_index = type_to_cast_index (new_type);
 
-  return gcc_jit_rvalue_access_field ( gcc_jit_lvalue_as_rvalue (tmp_u),
-				       NULL,
-				       dest_field);
+  /* Lookup the appropriate cast function in the cast matrix.  */
+  return gcc_jit_context_new_call (comp.ctxt,
+           NULL,
+           comp.cast_functions_from_to[old_index][new_index],
+           1, &obj);
 }
 
 static gcc_jit_rvalue *
@@ -3123,109 +3069,96 @@ define_thread_state_struct (void)
     gcc_jit_type_get_pointer (gcc_jit_struct_as_type (comp.thread_state_s));
 }
 
-static void
-define_cast_union (void)
+struct cast_type
 {
+  gcc_jit_type *type;
+  const char *name;
+};
 
-  comp.cast_union_as_ll =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.long_long_type,
-			       "ll");
-  comp.cast_union_as_ull =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.unsigned_long_long_type,
-			       "ull");
-  comp.cast_union_as_l =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.long_type,
-			       "l");
-  comp.cast_union_as_ul =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.unsigned_long_type,
-			       "ul");
-  comp.cast_union_as_u =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.unsigned_type,
-			       "u");
-  comp.cast_union_as_i =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.int_type,
-			       "i");
-  comp.cast_union_as_b =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.bool_type,
-			       "b");
-  comp.cast_union_as_uintptr =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.uintptr_type,
-			       "uintptr");
-  comp.cast_union_as_ptrdiff =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.ptrdiff_type,
-			       "ptrdiff");
-  comp.cast_union_as_c_p =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.char_ptr_type,
-			       "c_p");
-  comp.cast_union_as_v_p =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.void_ptr_type,
-			       "v_p");
-  comp.cast_union_as_lisp_cons_ptr =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.lisp_cons_ptr_type,
-			       "cons_ptr");
-  comp.cast_union_as_lisp_word =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.lisp_word_type,
-			       "lisp_word");
-  comp.cast_union_as_lisp_word_tag =
-    gcc_jit_context_new_field (comp.ctxt,
+static gcc_jit_function *
+define_cast_from_to (struct cast_type from, int from_index, struct cast_type to,
+                    int to_index)
+{
+  Lisp_Object name = CALLN (Fformat,
+                            build_string ("cast_from_%s_to_%s"),
+                            build_string (from.name),
+                            build_string (to.name));
+  gcc_jit_param *param = gcc_jit_context_new_param (comp.ctxt, NULL,
+                                                    from.type, "arg");
+  gcc_jit_function *result = gcc_jit_context_new_function (comp.ctxt,
                                NULL,
-                               comp.lisp_word_tag_type,
-                               "lisp_word_tag");
-  comp.cast_union_as_lisp_obj_ptr =
-    gcc_jit_context_new_field (comp.ctxt,
-			       NULL,
-			       comp.lisp_obj_ptr_type,
-			       "lisp_obj_ptr");
-
-
-  gcc_jit_field *cast_union_fields[] =
-    { comp.cast_union_as_ll,
-      comp.cast_union_as_ull,
-      comp.cast_union_as_l,
-      comp.cast_union_as_ul,
-      comp.cast_union_as_u,
-      comp.cast_union_as_i,
-      comp.cast_union_as_b,
-      comp.cast_union_as_uintptr,
-      comp.cast_union_as_ptrdiff,
-      comp.cast_union_as_c_p,
-      comp.cast_union_as_v_p,
-      comp.cast_union_as_lisp_cons_ptr,
-      comp.cast_union_as_lisp_word,
-      comp.cast_union_as_lisp_word_tag,
-      comp.cast_union_as_lisp_obj_ptr };
+                               GCC_JIT_FUNCTION_ALWAYS_INLINE,
+                               to.type,
+                               SSDATA (name),
+                               1,
+                               &param,
+                               0);
+
+  DECL_BLOCK (entry_block, result);
+
+  gcc_jit_lvalue *tmp_union
+    = gcc_jit_function_new_local (result,
+                                  NULL,
+                                  comp.cast_union_type,
+                                  "union_cast");
+
+  gcc_jit_block_add_assignment (entry_block, NULL,
+                                gcc_jit_lvalue_access_field (tmp_union, NULL,
+                                  comp.cast_union_fields[from_index]),
+                                gcc_jit_param_as_rvalue (param));
+
+  gcc_jit_block_end_with_return (entry_block,
+                                 NULL,
+                                 gcc_jit_rvalue_access_field (
+                                   gcc_jit_lvalue_as_rvalue (tmp_union),
+                                   NULL,
+                                   comp.cast_union_fields[to_index]));
+
+  return result;
+}
+
+static void
+define_cast_functions (void)
+{
+  struct cast_type cast_types[NUM_CAST_TYPES]
+    = {{comp.bool_type, "bool"},
+       {comp.char_ptr_type, "char_ptr"},
+       {comp.int_type, "int"},
+       {comp.lisp_cons_ptr_type, "cons_ptr"},
+       {comp.lisp_obj_ptr_type, "lisp_obj_ptr"},
+       {comp.lisp_word_tag_type, "lisp_word_tag"},
+       {comp.lisp_word_type, "lisp_word"},
+       {comp.long_long_type, "long_long"},
+       {comp.long_type, "long"},
+       {comp.ptrdiff_type, "ptrdiff"},
+       {comp.uintptr_type, "uintptr"},
+       {comp.unsigned_long_long_type, "unsigned_long_long"},
+       {comp.unsigned_long_type, "unsigned_long"},
+       {comp.unsigned_type, "unsigned"},
+       {comp.void_ptr_type, "void_ptr"}};
+
+  /* Define the union used for casting.  */
+  for (int i = 0; i < NUM_CAST_TYPES; ++i)
+    {
+      comp.cast_types[i] = cast_types[i].type;
+      comp.cast_union_fields[i] = gcc_jit_context_new_field (comp.ctxt,
+                                    NULL,
+                                    cast_types[i].type,
+                                    cast_types[i].name);
+    }
+
   comp.cast_union_type =
     gcc_jit_context_new_union_type (comp.ctxt,
 				    NULL,
 				    "cast_union",
-				    ARRAYELTS (cast_union_fields),
-				    cast_union_fields);
+				    NUM_CAST_TYPES,
+				    comp.cast_union_fields);
+
+  /* Define the cast functions using a matrix.  */
+  for (int i = 0; i < NUM_CAST_TYPES; ++i)
+    for (int j = 0; j < NUM_CAST_TYPES; ++j)
+        comp.cast_functions_from_to[i][j]
+          = define_cast_from_to (cast_types[i], i, cast_types[j], j);
 }
 
 static void
@@ -4036,7 +3969,7 @@ DEFUN ("comp--init-ctxt", Fcomp__init_ctxt, Scomp__init_ctxt,
   define_jmp_buf ();
   define_handler_struct ();
   define_thread_state_struct ();
-  define_cast_union ();
+  define_cast_functions ();
   define_naive_bzero ();
   define_naive_memcpy ();
 
-- 
2.25.1.windows.1

