diff options
| author | Nicolás Bértolo | 2020-05-20 00:34:32 -0300 |
|---|---|---|
| committer | Andrea Corallo | 2020-05-31 17:50:07 +0100 |
| commit | 3efb2808d415f723ade4a0f9f61738e1a707156c (patch) | |
| tree | 0aacaaa573dea99aee35508721ef625bba1d695c /src/comp.c | |
| parent | 5cf148cfef23b827629950048dab678f3b9af2d3 (diff) | |
| download | emacs-3efb2808d415f723ade4a0f9f61738e1a707156c.tar.gz emacs-3efb2808d415f723ade4a0f9f61738e1a707156c.zip | |
* Cut down compile-time emitting static data as string literals
This change drastically reduce compile time. Apparently GCC optimizer
does not scale up well at all for long sequences of assignments into a
single array.
Nicolás Bértolo <nicolasbertolo@gmail.com>
Andrea Corallo <akrl@sdf.org>
* src/comp.c (gcc_jit_context_new_string_literal)
(gcc_jit_block_add_assignment_op): New imports.
(comp_t): New 'size_t_type' 'memcpy' fields.
(emit_static_object): Define static objects using string literals
and memcpy.
(define_memcpy): New function.
(Fcomp__init_ctxt): Define 'size_t_type' and 'memcpy'.
Diffstat (limited to 'src/comp.c')
| -rw-r--r-- | src/comp.c | 120 |
1 files changed, 105 insertions, 15 deletions
diff --git a/src/comp.c b/src/comp.c index f288fc2551a..81c4d2fe32a 100644 --- a/src/comp.c +++ b/src/comp.c | |||
| @@ -46,6 +46,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 46 | # include "w32common.h" | 46 | # include "w32common.h" |
| 47 | 47 | ||
| 48 | #undef gcc_jit_block_add_assignment | 48 | #undef gcc_jit_block_add_assignment |
| 49 | #undef gcc_jit_block_add_assignment_op | ||
| 49 | #undef gcc_jit_block_add_comment | 50 | #undef gcc_jit_block_add_comment |
| 50 | #undef gcc_jit_block_add_eval | 51 | #undef gcc_jit_block_add_eval |
| 51 | #undef gcc_jit_block_end_with_conditional | 52 | #undef gcc_jit_block_end_with_conditional |
| @@ -75,6 +76,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 75 | #undef gcc_jit_context_new_rvalue_from_int | 76 | #undef gcc_jit_context_new_rvalue_from_int |
| 76 | #undef gcc_jit_context_new_rvalue_from_long | 77 | #undef gcc_jit_context_new_rvalue_from_long |
| 77 | #undef gcc_jit_context_new_rvalue_from_ptr | 78 | #undef gcc_jit_context_new_rvalue_from_ptr |
| 79 | #undef gcc_jit_context_new_string_literal | ||
| 78 | #undef gcc_jit_context_new_struct_type | 80 | #undef gcc_jit_context_new_struct_type |
| 79 | #undef gcc_jit_context_new_unary_op | 81 | #undef gcc_jit_context_new_unary_op |
| 80 | #undef gcc_jit_context_new_union_type | 82 | #undef gcc_jit_context_new_union_type |
| @@ -164,6 +166,8 @@ DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_rvalue_from_long, | |||
| 164 | (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, long value)); | 166 | (gcc_jit_context *ctxt, gcc_jit_type *numeric_type, long value)); |
| 165 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_rvalue_from_ptr, | 167 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_rvalue_from_ptr, |
| 166 | (gcc_jit_context *ctxt, gcc_jit_type *pointer_type, void *value)); | 168 | (gcc_jit_context *ctxt, gcc_jit_type *pointer_type, void *value)); |
| 169 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_string_literal, | ||
| 170 | (gcc_jit_context *ctxt, const char *value)); | ||
| 167 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_unary_op, | 171 | DEF_DLL_FN (gcc_jit_rvalue *, gcc_jit_context_new_unary_op, |
| 168 | (gcc_jit_context *ctxt, gcc_jit_location *loc, | 172 | (gcc_jit_context *ctxt, gcc_jit_location *loc, |
| 169 | enum gcc_jit_unary_op op, gcc_jit_type *result_type, | 173 | enum gcc_jit_unary_op op, gcc_jit_type *result_type, |
| @@ -197,6 +201,10 @@ DEF_DLL_FN (gcc_jit_type *, gcc_jit_type_get_pointer, (gcc_jit_type *type)); | |||
| 197 | DEF_DLL_FN (void, gcc_jit_block_add_assignment, | 201 | DEF_DLL_FN (void, gcc_jit_block_add_assignment, |
| 198 | (gcc_jit_block *block, gcc_jit_location *loc, gcc_jit_lvalue *lvalue, | 202 | (gcc_jit_block *block, gcc_jit_location *loc, gcc_jit_lvalue *lvalue, |
| 199 | gcc_jit_rvalue *rvalue)); | 203 | gcc_jit_rvalue *rvalue)); |
| 204 | DEF_DLL_FN (void, gcc_jit_block_add_assignment_op, | ||
| 205 | (gcc_jit_block *block, gcc_jit_location *loc, | ||
| 206 | gcc_jit_lvalue *lvalue, enum gcc_jit_binary_op op, | ||
| 207 | gcc_jit_rvalue *rvalue)); | ||
| 200 | DEF_DLL_FN (void, gcc_jit_block_add_eval, | 208 | DEF_DLL_FN (void, gcc_jit_block_add_eval, |
| 201 | (gcc_jit_block *block, gcc_jit_location *loc, | 209 | (gcc_jit_block *block, gcc_jit_location *loc, |
| 202 | gcc_jit_rvalue *rvalue)); | 210 | gcc_jit_rvalue *rvalue)); |
| @@ -239,6 +247,7 @@ init_gccjit_functions (void) | |||
| 239 | 247 | ||
| 240 | /* In alphabetical order */ | 248 | /* In alphabetical order */ |
| 241 | LOAD_DLL_FN (library, gcc_jit_block_add_assignment); | 249 | LOAD_DLL_FN (library, gcc_jit_block_add_assignment); |
| 250 | LOAD_DLL_FN (library, gcc_jit_block_add_assignment_op); | ||
| 242 | LOAD_DLL_FN (library, gcc_jit_block_add_comment); | 251 | LOAD_DLL_FN (library, gcc_jit_block_add_comment); |
| 243 | LOAD_DLL_FN (library, gcc_jit_block_add_eval); | 252 | LOAD_DLL_FN (library, gcc_jit_block_add_eval); |
| 244 | LOAD_DLL_FN (library, gcc_jit_block_end_with_conditional); | 253 | LOAD_DLL_FN (library, gcc_jit_block_end_with_conditional); |
| @@ -268,6 +277,7 @@ init_gccjit_functions (void) | |||
| 268 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_int); | 277 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_int); |
| 269 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_long); | 278 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_long); |
| 270 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_ptr); | 279 | LOAD_DLL_FN (library, gcc_jit_context_new_rvalue_from_ptr); |
| 280 | LOAD_DLL_FN (library, gcc_jit_context_new_string_literal); | ||
| 271 | LOAD_DLL_FN (library, gcc_jit_context_new_struct_type); | 281 | LOAD_DLL_FN (library, gcc_jit_context_new_struct_type); |
| 272 | LOAD_DLL_FN (library, gcc_jit_context_new_unary_op); | 282 | LOAD_DLL_FN (library, gcc_jit_context_new_unary_op); |
| 273 | LOAD_DLL_FN (library, gcc_jit_context_new_union_type); | 283 | LOAD_DLL_FN (library, gcc_jit_context_new_union_type); |
| @@ -296,6 +306,7 @@ init_gccjit_functions (void) | |||
| 296 | 306 | ||
| 297 | /* In alphabetical order */ | 307 | /* In alphabetical order */ |
| 298 | #define gcc_jit_block_add_assignment fn_gcc_jit_block_add_assignment | 308 | #define gcc_jit_block_add_assignment fn_gcc_jit_block_add_assignment |
| 309 | #define gcc_jit_block_add_assignment_op fn_gcc_jit_block_add_assignment_op | ||
| 299 | #define gcc_jit_block_add_comment fn_gcc_jit_block_add_comment | 310 | #define gcc_jit_block_add_comment fn_gcc_jit_block_add_comment |
| 300 | #define gcc_jit_block_add_eval fn_gcc_jit_block_add_eval | 311 | #define gcc_jit_block_add_eval fn_gcc_jit_block_add_eval |
| 301 | #define gcc_jit_block_end_with_conditional fn_gcc_jit_block_end_with_conditional | 312 | #define gcc_jit_block_end_with_conditional fn_gcc_jit_block_end_with_conditional |
| @@ -325,6 +336,7 @@ init_gccjit_functions (void) | |||
| 325 | #define gcc_jit_context_new_rvalue_from_int fn_gcc_jit_context_new_rvalue_from_int | 336 | #define gcc_jit_context_new_rvalue_from_int fn_gcc_jit_context_new_rvalue_from_int |
| 326 | #define gcc_jit_context_new_rvalue_from_long fn_gcc_jit_context_new_rvalue_from_long | 337 | #define gcc_jit_context_new_rvalue_from_long fn_gcc_jit_context_new_rvalue_from_long |
| 327 | #define gcc_jit_context_new_rvalue_from_ptr fn_gcc_jit_context_new_rvalue_from_ptr | 338 | #define gcc_jit_context_new_rvalue_from_ptr fn_gcc_jit_context_new_rvalue_from_ptr |
| 339 | #define gcc_jit_context_new_string_literal fn_gcc_jit_context_new_string_literal | ||
| 328 | #define gcc_jit_context_new_struct_type fn_gcc_jit_context_new_struct_type | 340 | #define gcc_jit_context_new_struct_type fn_gcc_jit_context_new_struct_type |
| 329 | #define gcc_jit_context_new_unary_op fn_gcc_jit_context_new_unary_op | 341 | #define gcc_jit_context_new_unary_op fn_gcc_jit_context_new_unary_op |
| 330 | #define gcc_jit_context_new_union_type fn_gcc_jit_context_new_union_type | 342 | #define gcc_jit_context_new_union_type fn_gcc_jit_context_new_union_type |
| @@ -462,6 +474,7 @@ typedef struct { | |||
| 462 | gcc_jit_type *char_ptr_type; | 474 | gcc_jit_type *char_ptr_type; |
| 463 | gcc_jit_type *ptrdiff_type; | 475 | gcc_jit_type *ptrdiff_type; |
| 464 | gcc_jit_type *uintptr_type; | 476 | gcc_jit_type *uintptr_type; |
| 477 | gcc_jit_type *size_t_type; | ||
| 465 | #if LISP_WORDS_ARE_POINTERS | 478 | #if LISP_WORDS_ARE_POINTERS |
| 466 | gcc_jit_type *lisp_X; | 479 | gcc_jit_type *lisp_X; |
| 467 | #endif | 480 | #endif |
| @@ -548,6 +561,7 @@ typedef struct { | |||
| 548 | gcc_jit_rvalue *data_relocs_ephemeral; | 561 | gcc_jit_rvalue *data_relocs_ephemeral; |
| 549 | /* Synthesized struct holding func relocs. */ | 562 | /* Synthesized struct holding func relocs. */ |
| 550 | gcc_jit_lvalue *func_relocs; | 563 | gcc_jit_lvalue *func_relocs; |
| 564 | gcc_jit_function *memcpy; | ||
| 551 | Lisp_Object d_default_idx; | 565 | Lisp_Object d_default_idx; |
| 552 | Lisp_Object d_impure_idx; | 566 | Lisp_Object d_impure_idx; |
| 553 | Lisp_Object d_ephemeral_idx; | 567 | Lisp_Object d_ephemeral_idx; |
| @@ -2347,7 +2361,7 @@ emit_static_object (const char *name, Lisp_Object obj) | |||
| 2347 | /* libgccjit has no support for initialized static data. | 2361 | /* libgccjit has no support for initialized static data. |
| 2348 | The mechanism below is certainly not aesthetic but I assume the bottle neck | 2362 | The mechanism below is certainly not aesthetic but I assume the bottle neck |
| 2349 | in terms of performance at load time will still be the reader. | 2363 | in terms of performance at load time will still be the reader. |
| 2350 | NOTE: we can not relay on libgccjit even for valid NULL terminated C | 2364 | NOTE: we can not rely on libgccjit even for valid NULL terminated C |
| 2351 | strings cause of this funny bug that will affect all pre gcc10 era gccs: | 2365 | strings cause of this funny bug that will affect all pre gcc10 era gccs: |
| 2352 | https://gcc.gnu.org/ml/jit/2019-q3/msg00013.html */ | 2366 | https://gcc.gnu.org/ml/jit/2019-q3/msg00013.html */ |
| 2353 | 2367 | ||
| @@ -2405,22 +2419,78 @@ emit_static_object (const char *name, Lisp_Object obj) | |||
| 2405 | gcc_jit_lvalue *arr = | 2419 | gcc_jit_lvalue *arr = |
| 2406 | gcc_jit_lvalue_access_field (data_struct, NULL, fields[1]); | 2420 | gcc_jit_lvalue_access_field (data_struct, NULL, fields[1]); |
| 2407 | 2421 | ||
| 2408 | for (ptrdiff_t i = 0; i < len; i++, p++) | 2422 | gcc_jit_lvalue *ptrvar = gcc_jit_function_new_local (f, NULL, |
| 2423 | comp.char_ptr_type, | ||
| 2424 | "ptr"); | ||
| 2425 | |||
| 2426 | gcc_jit_block_add_assignment ( | ||
| 2427 | block, | ||
| 2428 | NULL, | ||
| 2429 | ptrvar, | ||
| 2430 | gcc_jit_lvalue_get_address ( | ||
| 2431 | gcc_jit_context_new_array_access ( | ||
| 2432 | comp.ctxt, | ||
| 2433 | NULL, | ||
| 2434 | gcc_jit_lvalue_as_rvalue (arr), | ||
| 2435 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, comp.int_type, 0)), | ||
| 2436 | NULL)); | ||
| 2437 | |||
| 2438 | for (ptrdiff_t i = 0; i < len;) | ||
| 2409 | { | 2439 | { |
| 2410 | gcc_jit_block_add_assignment ( | 2440 | /* We can't use string literals longer that 200 bytes because |
| 2411 | block, | 2441 | they cause a crash in older versions of gccjit. |
| 2412 | NULL, | 2442 | https://gcc.gnu.org/ml/jit/2019-q3/msg00013.html. */ |
| 2413 | gcc_jit_context_new_array_access ( | 2443 | char str[200]; |
| 2414 | comp.ctxt, | 2444 | strncpy (str, p, 200); |
| 2415 | NULL, | 2445 | str[199] = 0; |
| 2416 | gcc_jit_lvalue_as_rvalue (arr), | 2446 | uintptr_t l = strlen (str); |
| 2417 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | 2447 | |
| 2418 | comp.ptrdiff_type, | 2448 | if (l != 0) |
| 2419 | i)), | 2449 | { |
| 2420 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | 2450 | p += l; |
| 2421 | comp.char_type, | 2451 | i += l; |
| 2422 | *p)); | 2452 | |
| 2453 | gcc_jit_rvalue *args[3] | ||
| 2454 | = {gcc_jit_lvalue_as_rvalue (ptrvar), | ||
| 2455 | gcc_jit_context_new_string_literal (comp.ctxt, str), | ||
| 2456 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | ||
| 2457 | comp.size_t_type, | ||
| 2458 | l)}; | ||
| 2459 | |||
| 2460 | gcc_jit_block_add_eval (block, NULL, | ||
| 2461 | gcc_jit_context_new_call (comp.ctxt, NULL, | ||
| 2462 | comp.memcpy, | ||
| 2463 | ARRAYELTS (args), | ||
| 2464 | args)); | ||
| 2465 | gcc_jit_block_add_assignment (block, NULL, ptrvar, | ||
| 2466 | gcc_jit_lvalue_get_address ( | ||
| 2467 | gcc_jit_context_new_array_access (comp.ctxt, NULL, | ||
| 2468 | gcc_jit_lvalue_as_rvalue (ptrvar), | ||
| 2469 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | ||
| 2470 | comp.uintptr_type, | ||
| 2471 | l)), | ||
| 2472 | NULL)); | ||
| 2473 | } | ||
| 2474 | else | ||
| 2475 | { | ||
| 2476 | /* If strlen returned 0 that means that the static object | ||
| 2477 | contains a NULL byte. In that case just move over to the | ||
| 2478 | next block. We can rely on the byte being zero because | ||
| 2479 | of the previous call to bzero and because the dynamic | ||
| 2480 | linker cleared it. */ | ||
| 2481 | p++; | ||
| 2482 | i++; | ||
| 2483 | gcc_jit_block_add_assignment ( | ||
| 2484 | block, NULL, ptrvar, | ||
| 2485 | gcc_jit_lvalue_get_address ( | ||
| 2486 | gcc_jit_context_new_array_access ( | ||
| 2487 | comp.ctxt, NULL, gcc_jit_lvalue_as_rvalue (ptrvar), | ||
| 2488 | gcc_jit_context_new_rvalue_from_int (comp.ctxt, | ||
| 2489 | comp.uintptr_type, 1)), | ||
| 2490 | NULL)); | ||
| 2491 | } | ||
| 2423 | } | 2492 | } |
| 2493 | |||
| 2424 | gcc_jit_block_add_assignment ( | 2494 | gcc_jit_block_add_assignment ( |
| 2425 | block, | 2495 | block, |
| 2426 | NULL, | 2496 | NULL, |
| @@ -2766,6 +2836,21 @@ define_jmp_buf (void) | |||
| 2766 | 1, &field); | 2836 | 1, &field); |
| 2767 | } | 2837 | } |
| 2768 | 2838 | ||
| 2839 | static void | ||
| 2840 | define_memcpy (void) | ||
| 2841 | { | ||
| 2842 | |||
| 2843 | gcc_jit_param *params[] = | ||
| 2844 | { gcc_jit_context_new_param (comp.ctxt, NULL, comp.void_ptr_type, "dest"), | ||
| 2845 | gcc_jit_context_new_param (comp.ctxt, NULL, comp.void_ptr_type, "src"), | ||
| 2846 | gcc_jit_context_new_param (comp.ctxt, NULL, comp.size_t_type, "n") }; | ||
| 2847 | |||
| 2848 | comp.memcpy = | ||
| 2849 | gcc_jit_context_new_function (comp.ctxt, NULL, GCC_JIT_FUNCTION_IMPORTED, | ||
| 2850 | comp.void_ptr_type, "memcpy", | ||
| 2851 | ARRAYELTS (params), params, false); | ||
| 2852 | } | ||
| 2853 | |||
| 2769 | /* struct handler definition */ | 2854 | /* struct handler definition */ |
| 2770 | 2855 | ||
| 2771 | static void | 2856 | static void |
| @@ -3772,6 +3857,9 @@ DEFUN ("comp--init-ctxt", Fcomp__init_ctxt, Scomp__init_ctxt, | |||
| 3772 | comp.uintptr_type = gcc_jit_context_get_int_type (comp.ctxt, | 3857 | comp.uintptr_type = gcc_jit_context_get_int_type (comp.ctxt, |
| 3773 | sizeof (void *), | 3858 | sizeof (void *), |
| 3774 | false); | 3859 | false); |
| 3860 | comp.size_t_type = gcc_jit_context_get_int_type (comp.ctxt, | ||
| 3861 | sizeof (size_t), | ||
| 3862 | false); | ||
| 3775 | 3863 | ||
| 3776 | comp.exported_funcs_h = CALLN (Fmake_hash_table, QCtest, Qequal); | 3864 | comp.exported_funcs_h = CALLN (Fmake_hash_table, QCtest, Qequal); |
| 3777 | /* | 3865 | /* |
| @@ -3780,6 +3868,8 @@ DEFUN ("comp--init-ctxt", Fcomp__init_ctxt, Scomp__init_ctxt, | |||
| 3780 | */ | 3868 | */ |
| 3781 | comp.imported_funcs_h = CALLN (Fmake_hash_table); | 3869 | comp.imported_funcs_h = CALLN (Fmake_hash_table); |
| 3782 | 3870 | ||
| 3871 | define_memcpy (); | ||
| 3872 | |||
| 3783 | /* Define data structures. */ | 3873 | /* Define data structures. */ |
| 3784 | 3874 | ||
| 3785 | define_lisp_cons (); | 3875 | define_lisp_cons (); |