mirrored from git://git.sv.gnu.org/emacs.git
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathcomp.el
4363 lines (4025 loc) · 182 KB
/
comp.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; comp.el --- compilation of Lisp code into native code -*- lexical-binding: t -*-
;; Copyright (C) 2019-2022 Free Software Foundation, Inc.
;; Author: Andrea Corallo <akrl@sdf.org>
;; Keywords: lisp
;; Package: emacs
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This code is an attempt to make the pig fly.
;; Or, to put it another way to make a 911 out of a turbocharged VW Bug.
;;; Code:
(require 'bytecomp)
(require 'cl-extra)
(require 'cl-lib)
(require 'cl-macs)
(require 'cl-seq)
(require 'gv)
(require 'rx)
(require 'subr-x)
(require 'warnings)
(require 'comp-cstr)
(defgroup comp nil
"Emacs Lisp native compiler."
:group 'lisp)
(defcustom native-comp-speed 2
"Optimization level for native compilation, a number between -1 and 3.
-1 functions are kept in bytecode form and no native compilation is performed
(but *.eln files are still produced, and include the compiled code in
bytecode form).
0 native compilation is performed with no optimizations.
1 light optimizations.
2 max optimization level fully adherent to the language semantic.
3 max optimization level, to be used only when necessary.
Warning: with 3, the compiler is free to perform dangerous optimizations."
:type 'integer
:safe #'integerp
:version "28.1")
(defcustom native-comp-debug 0
"Debug level for native compilation, a number between 0 and 3.
This is intended for debugging the compiler itself.
0 no debug output.
1 emit debug symbols.
2 emit debug symbols and dump pseudo C code.
3 emit debug symbols and dump: pseudo C code, GCC intermediate
passes and libgccjit log file."
:type 'natnum
:safe #'natnump
:version "29.1")
(defcustom native-comp-verbose 0
"Compiler verbosity for native compilation, a number between 0 and 3.
This is intended for debugging the compiler itself.
0 no logging.
1 final LIMPLE is logged.
2 LAP, final LIMPLE, and some pass info are logged.
3 max verbosity."
:type 'natnum
:risky t
:version "28.1")
(defcustom native-comp-always-compile nil
"Non-nil means unconditionally (re-)compile all files."
:type 'boolean
:version "28.1")
(defcustom native-comp-deferred-compilation-deny-list
'()
"List of regexps to exclude matching files from deferred native compilation.
Files whose names match any regexp are excluded from native compilation."
:type '(repeat regexp)
:version "28.1")
(defcustom native-comp-bootstrap-deny-list
'()
"List of regexps to exclude files from native compilation during bootstrap.
Files whose names match any regexp are excluded from native compilation
during bootstrap."
:type '(repeat regexp)
:version "28.1")
(defcustom native-comp-never-optimize-functions
'(;; The following two are mandatory for Emacs to be working
;; correctly (see comment in `advice--add-function'). DO NOT
;; REMOVE.
macroexpand rename-buffer)
"Primitive functions to exclude from trampoline optimization."
:type '(repeat symbol)
:version "28.1")
(defcustom native-comp-async-jobs-number 0
"Default number of subprocesses used for async native compilation.
Value of zero means to use half the number of the CPU's execution units,
or one if there's just one execution unit."
:type 'natnum
:risky t
:version "28.1")
(defcustom native-comp-async-cu-done-functions nil
"List of functions to call when asynchronous compilation of a file is done.
Each function is called with one argument FILE, the filename whose
compilation has completed."
:type 'hook
:version "28.1")
(defcustom native-comp-async-all-done-hook nil
"Hook run after completing asynchronous compilation of all input files."
:type 'hook
:version "28.1")
(defcustom native-comp-async-env-modifier-form nil
"Form evaluated before compilation by each asynchronous compilation subprocess.
Used to modify the compiler environment."
:type 'sexp
:risky t
:version "28.1")
(defcustom native-comp-async-report-warnings-errors t
"Whether to report warnings and errors from asynchronous native compilation.
When native compilation happens asynchronously, it can produce
warnings and errors, some of which might not be emitted by a
byte-compilation. The typical case for that is native-compiling
a file that is missing some `require' of a necessary feature,
while having it already loaded into the environment when
byte-compiling.
As asynchronous native compilation always starts from a pristine
environment, it is more sensitive to such omissions, and might be
unable to compile such Lisp source files correctly.
Set this variable to nil to suppress warnings altogether, or to
the symbol `silent' to log warnings but not pop up the *Warnings*
buffer."
:type '(choice
(const :tag "Do not report warnings" nil)
(const :tag "Report and display warnings" t)
(const :tag "Report but do not display warnings" silent))
:version "28.1")
(defcustom native-comp-async-query-on-exit nil
"Whether to query the user about killing async compilations when exiting.
If this is non-nil, Emacs will ask for confirmation to exit and kill the
asynchronous native compilations if any are running. If nil, when you
exit Emacs, it will silently kill those asynchronous compilations even
if `confirm-kill-processes' is non-nil."
:type 'boolean
:version "28.1")
(defcustom native-comp-compiler-options nil
"Command line options passed verbatim to GCC compiler.
Note that not all options are meaningful and some options might even
break your Emacs. Use at your own risk.
Passing these options is only available in libgccjit version 9
and above."
:type '(repeat string)
:version "28.1")
(defcustom native-comp-driver-options (when (eq system-type 'darwin)
'("-Wl,-w"))
"Options passed verbatim to the native compiler's back-end driver.
Note that not all options are meaningful; typically only the options
affecting the assembler and linker are likely to be useful.
Passing these options is only available in libgccjit version 9
and above."
:type '(repeat string)
:version "28.1")
(defcustom comp-libgccjit-reproducer nil
"When non-nil produce a libgccjit reproducer.
The reproducer is a file ELNFILENAME_libgccjit_repro.c deposed in
the .eln output directory."
:type 'boolean
:version "28.1")
(defcustom native-comp-warning-on-missing-source t
"Emit a warning if a byte-code file being loaded has no corresponding source.
The source file is necessary for native code file look-up and deferred
compilation mechanism."
:type 'boolean
:version "28.1")
(defvar no-native-compile nil
"Non-nil to prevent native-compiling of Emacs Lisp code.
Note that when `no-byte-compile' is set to non-nil it overrides the value of
`no-native-compile'.
This is normally set in local file variables at the end of the
Emacs Lisp file:
\;; Local Variables:\n;; no-native-compile: t\n;; End:")
;;;###autoload(put 'no-native-compile 'safe-local-variable 'booleanp)
(defvar native-compile-target-directory nil
"When non-nil force the target directory for the eln files being compiled.")
(defvar comp-log-time-report nil
"If non-nil, log a time report for each pass.")
(defvar comp-dry-run nil
"If non-nil, run everything but the C back-end.")
(defconst comp-valid-source-re (rx ".el" (? ".gz") eos)
"Regexp to match filename of valid input source files.")
(defconst comp-log-buffer-name "*Native-compile-Log*"
"Name of the native-compiler log buffer.")
(defconst comp-async-buffer-name "*Async-native-compile-log*"
"Name of the async compilation buffer log.")
(defvar comp-native-compiling nil
"This gets bound to t during native compilation.
Intended to be used by code that needs to work differently when
native compilation runs.")
(defvar comp-pass nil
"Every native-compilation pass can bind this to whatever it likes.")
(defvar comp-curr-allocation-class 'd-default
"Current allocation class.
Can be one of: `d-default', `d-impure' or `d-ephemeral'. See `comp-ctxt'.")
(defconst comp-passes '(comp-spill-lap
comp-limplify
comp-fwprop
comp-call-optim
comp-ipa-pure
comp-add-cstrs
comp-fwprop
comp-tco
comp-fwprop
comp-remove-type-hints
comp-final)
"Passes to be executed in order.")
(defvar comp-disabled-passes '()
"List of disabled passes.
For internal use by the test suite only.")
(defvar comp-post-pass-hooks '()
"Alist whose elements are of the form (PASS FUNCTIONS...).
Each function in FUNCTIONS is run after PASS.
Useful to hook into pass checkers.")
;; FIXME this probably should not be here but... good for now.
(defconst comp-known-type-specifiers
`(
;; Functions we can trust not to be or if redefined should expose
;; the same type. Vast majority of these is either pure or
;; primitive, the original list is the union of pure +
;; side-effect-free-fns + side-effect-and-error-free-fns:
(% (function ((or number marker) (or number marker)) number))
(* (function (&rest (or number marker)) number))
(+ (function (&rest (or number marker)) number))
(- (function (&rest (or number marker)) number))
(/ (function ((or number marker) &rest (or number marker)) number))
(/= (function ((or number marker) (or number marker)) boolean))
(1+ (function ((or number marker)) number))
(1- (function ((or number marker)) number))
(< (function ((or number marker) &rest (or number marker)) boolean))
(<= (function ((or number marker) &rest (or number marker)) boolean))
(= (function ((or number marker) &rest (or number marker)) boolean))
(> (function ((or number marker) &rest (or number marker)) boolean))
(>= (function ((or number marker) &rest (or number marker)) boolean))
(abs (function (number) number))
(acos (function (number) float))
(append (function (&rest t) t))
(aref (function (t fixnum) t))
(arrayp (function (t) boolean))
(ash (function (integer integer) integer))
(asin (function (number) float))
(assq (function (t list) list))
(atan (function (number &optional number) float))
(atom (function (t) boolean))
(bignump (function (t) boolean))
(bobp (function () boolean))
(bolp (function () boolean))
(bool-vector-count-consecutive (function (bool-vector boolean integer) fixnum))
(bool-vector-count-population (function (bool-vector) fixnum))
(bool-vector-not (function (bool-vector &optional bool-vector) bool-vector))
(bool-vector-p (function (t) boolean))
(bool-vector-subsetp (function (bool-vector bool-vector) boolean))
(boundp (function (symbol) boolean))
(buffer-end (function ((or number marker)) integer))
(buffer-file-name (function (&optional buffer) (or string null)))
(buffer-list (function (&optional frame) list))
(buffer-local-variables (function (&optional buffer) list))
(buffer-modified-p (function (&optional buffer) boolean))
(buffer-size (function (&optional buffer) integer))
(buffer-string (function () string))
(buffer-substring (function ((or integer marker) (or integer marker)) string))
(bufferp (function (t) boolean))
(byte-code-function-p (function (t) boolean))
(capitalize (function (or integer string) (or integer string)))
(car (function (list) t))
(car-less-than-car (function (list list) boolean))
(car-safe (function (t) t))
(case-table-p (function (t) boolean))
(cdr (function (list) t))
(cdr-safe (function (t) t))
(ceiling (function (number &optional number) integer))
(char-after (function (&optional (or marker integer)) (or fixnum null)))
(char-before (function (&optional (or marker integer)) (or fixnum null)))
(char-equal (function (integer integer) boolean))
(char-or-string-p (function (t) boolean))
(char-to-string (function (fixnum) string))
(char-width (function (fixnum) fixnum))
(characterp (function (t &optional t) boolean))
(charsetp (function (t) boolean))
(commandp (function (t &optional t) boolean))
(compare-strings (function (string (or integer marker null) (or integer marker null) string (or integer marker null) (or integer marker null) &optional t) (or (member t) fixnum)))
(concat (function (&rest sequence) string))
(cons (function (t t) cons))
(consp (function (t) boolean))
(coordinates-in-window-p (function (cons window) boolean))
(copy-alist (function (list) list))
(copy-marker (function (&optional (or integer marker) boolean) marker))
(copy-sequence (function (sequence) sequence))
(copysign (function (float float) float))
(cos (function (number) float))
(count-lines (function ((or integer marker) (or integer marker) &optional t) integer))
(current-buffer (function () buffer))
(current-global-map (function () cons))
(current-indentation (function () integer))
(current-local-map (function () (or cons null)))
(current-minor-mode-maps (function () (or cons null)))
(current-time (function () cons))
(current-time-string (function (&optional (or number list)
(or symbol string cons integer))
string))
(current-time-zone (function (&optional (or number list)
(or symbol string cons integer))
cons))
(custom-variable-p (function (symbol) boolean))
(decode-char (function (cons t) (or fixnum null)))
(decode-time (function (&optional (or number list)
(or symbol string cons integer)
symbol)
cons))
(default-boundp (function (symbol) boolean))
(default-value (function (symbol) t))
(degrees-to-radians (function (number) float))
(documentation (function ((or function symbol subr) &optional t) (or null string)))
(downcase (function ((or fixnum string)) (or fixnum string)))
(elt (function (sequence integer) t))
(encode-char (function (fixnum symbol) (or fixnum null)))
(encode-time (function (cons &rest t) cons))
(eobp (function () boolean))
(eolp (function () boolean))
(eq (function (t t) boolean))
(eql (function (t t) boolean))
(equal (function (t t) boolean))
(error-message-string (function (list) string))
(eventp (function (t) boolean))
(exp (function (number) float))
(expt (function (number number) float))
(fboundp (function (symbol) boolean))
(fceiling (function (float) float))
(featurep (function (symbol &optional symbol) boolean))
(ffloor (function (float) float))
(file-directory-p (function (string) boolean))
(file-exists-p (function (string) boolean))
(file-locked-p (function (string) boolean))
(file-name-absolute-p (function (string) boolean))
(file-newer-than-file-p (function (string string) boolean))
(file-readable-p (function (string) boolean))
(file-symlink-p (function (string) boolean))
(file-writable-p (function (string) boolean))
(fixnump (function (t) boolean))
(float (function (number) float))
(float-time (function (&optional (or number list)) float))
(floatp (function (t) boolean))
(floor (function (number &optional number) integer))
(following-char (function () fixnum))
(format (function (string &rest t) string))
(format-time-string (function (string &optional (or number list)
(or symbol string cons integer))
string))
(frame-first-window (function ((or frame window)) window))
(frame-root-window (function (&optional (or frame window)) window))
(frame-selected-window (function (&optional (or frame window)) window))
(frame-visible-p (function (frame) boolean))
(framep (function (t) boolean))
(fround (function (float) float))
(ftruncate (function (float) float))
(get (function (symbol symbol) t))
(get-buffer (function ((or buffer string)) (or buffer null)))
(get-buffer-window (function (&optional (or buffer string) (or symbol (integer 0 0))) (or null window)))
(get-file-buffer (function (string) (or null buffer)))
(get-largest-window (function (&optional t t t) (or window null)))
(get-lru-window (function (&optional t t t) (or window null)))
(getenv (function (string &optional frame) (or null string)))
(gethash (function (t hash-table &optional t) t))
(hash-table-count (function (hash-table) integer))
(hash-table-p (function (t) boolean))
(identity (function (t) t))
(ignore (function (&rest t) null))
(int-to-string (function (number) string))
(integer-or-marker-p (function (t) boolean))
(integerp (function (t) boolean))
(interactive-p (function () boolean))
(intern-soft (function ((or string symbol) &optional vector) symbol))
(invocation-directory (function () string))
(invocation-name (function () string))
(isnan (function (float) boolean))
(keymap-parent (function (cons) (or cons null)))
(keymapp (function (t) boolean))
(keywordp (function (t) boolean))
(last (function (list &optional integer) list))
(lax-plist-get (function (list t) t))
(ldexp (function (number integer) float))
(length (function (t) (integer 0 *)))
(length< (function (sequence fixnum) boolean))
(length= (function (sequence fixnum) boolean))
(length> (function (sequence fixnum) boolean))
(line-beginning-position (function (&optional integer) integer))
(line-end-position (function (&optional integer) integer))
(list (function (&rest t) list))
(listp (function (t) boolean))
(local-variable-if-set-p (function (symbol &optional buffer) boolean))
(local-variable-p (function (symbol &optional buffer) boolean))
(locale-info (function ((member codeset days months paper)) (or null string)))
(log (function (number number) float))
(log10 (function (number) float))
(logand (function (&rest (or integer marker)) integer))
(logb (function (number) integer))
(logcount (function (integer) integer))
(logior (function (&rest (or integer marker)) integer))
(lognot (function (integer) integer))
(logxor (function (&rest (or integer marker)) integer))
;; (lsh (function ((integer ,most-negative-fixnum *) integer) integer)) ?
(lsh (function (integer integer) integer))
(make-byte-code (function ((or fixnum list) string vector integer &optional string t &rest t) vector))
(make-list (function (integer t) list))
(make-marker (function () marker))
(make-string (function (integer fixnum &optional t) string))
(make-symbol (function (string) symbol))
(mark (function (&optional t) (or integer null)))
(mark-marker (function () marker))
(marker-buffer (function (marker) (or buffer null)))
(markerp (function (t) boolean))
(max (function ((or number marker) &rest (or number marker)) number))
(max-char (function (&optional t) fixnum))
(member (function (t list) list))
(memory-limit (function () integer))
(memq (function (t list) list))
(memql (function (t list) list))
(min (function ((or number marker) &rest (or number marker)) number))
(minibuffer-selected-window (function () (or window null)))
(minibuffer-window (function (&optional frame) window))
(mod (function ((or number marker) (or number marker)) (or (integer 0 *) (float 0 *))))
(mouse-movement-p (function (t) boolean))
(multibyte-char-to-unibyte (function (fixnum) fixnum))
(natnump (function (t) boolean))
(next-window (function (&optional window t t) window))
(nlistp (function (t) boolean))
(not (function (t) boolean))
(nth (function (integer list) t))
(nthcdr (function (integer t) t))
(null (function (t) boolean))
(number-or-marker-p (function (t) boolean))
(number-to-string (function (number) string))
(numberp (function (t) boolean))
(one-window-p (function (&optional t t) boolean))
(overlayp (function (t) boolean))
(parse-colon-path (function (string) cons))
(plist-get (function (list t &optional t) t))
(plist-member (function (list t &optional t) list))
(point (function () integer))
(point-marker (function () marker))
(point-max (function () integer))
(point-min (function () integer))
(preceding-char (function () fixnum))
(previous-window (function (&optional window t t) window))
(prin1-to-string (function (t &optional t t) string))
(processp (function (t) boolean))
(proper-list-p (function (t) boolean))
(propertize (function (string &rest t) string))
(radians-to-degrees (function (number) float))
(rassoc (function (t list) list))
(rassq (function (t list) list))
(read-from-string (function (string &optional integer integer) cons))
(recent-keys (function (&optional (or cons null)) vector))
(recursion-depth (function () integer))
(regexp-opt (function (list) string))
(regexp-quote (function (string) string))
(region-beginning (function () integer))
(region-end (function () integer))
(reverse (function (sequence) sequence))
(round (function (number &optional number) integer))
(safe-length (function (t) integer))
(selected-frame (function () frame))
(selected-window (function () window))
(sequencep (function (t) boolean))
(sin (function (number) float))
(sqrt (function (number) float))
(standard-case-table (function () char-table))
(standard-syntax-table (function () char-table))
(string (function (&rest fixnum) string))
(string-as-multibyte (function (string) string))
(string-as-unibyte (function (string) string))
(string-equal (function ((or string symbol) (or string symbol)) boolean))
(string-lessp (function ((or string symbol) (or string symbol)) boolean))
(string-make-multibyte (function (string) string))
(string-make-unibyte (function (string) string))
(string-search (function (string string &optional integer) (or integer null)))
(string-to-char (function (string) fixnum))
(string-to-multibyte (function (string) string))
(string-to-number (function (string &optional integer) number))
(string-to-syntax (function (string) (or cons null)))
(string< (function ((or string symbol) (or string symbol)) boolean))
(string= (function ((or string symbol) (or string symbol)) boolean))
(stringp (function (t) boolean))
(subrp (function (t) boolean))
(substring (function ((or string vector) &optional integer integer) (or string vector)))
(sxhash (function (t) integer))
(sxhash-eq (function (t) integer))
(sxhash-eql (function (t) integer))
(sxhash-equal (function (t) integer))
(symbol-function (function (symbol) t))
(symbol-name (function (symbol) string))
(symbol-plist (function (symbol) list))
(symbol-value (function (symbol) t))
(symbolp (function (t) boolean))
(syntax-table (function () char-table))
(syntax-table-p (function (t) boolean))
(tan (function (number) float))
(this-command-keys (function () string))
(this-command-keys-vector (function () vector))
(this-single-command-keys (function () vector))
(this-single-command-raw-keys (function () vector))
(time-convert (function ((or number list) &optional (or symbol integer))
(or cons number)))
(truncate (function (number &optional number) integer))
(type-of (function (t) symbol))
(unibyte-char-to-multibyte (function (fixnum) fixnum)) ;; byte is fixnum
(upcase (function ((or fixnum string)) (or fixnum string)))
(user-full-name (function (&optional integer) (or string null)))
(user-login-name (function (&optional integer) (or string null)))
(user-original-login-name (function (&optional integer) (or string null)))
(user-real-login-name (function () string))
(user-real-uid (function () integer))
(user-uid (function () integer))
(vconcat (function (&rest sequence) vector))
(vector (function (&rest t) vector))
(vectorp (function (t) boolean))
(visible-frame-list (function () list))
(wholenump (function (t) boolean))
(window-configuration-p (function (t) boolean))
(window-live-p (function (t) boolean))
(window-valid-p (function (t) boolean))
(windowp (function (t) boolean))
(zerop (function (number) boolean))
;; Type hints
(comp-hint-fixnum (function (t) fixnum))
(comp-hint-cons (function (t) cons))
;; Non returning functions
(throw (function (t t) nil))
(error (function (string &rest t) nil))
(signal (function (symbol t) nil)))
"Alist used for type propagation.")
(defconst comp-known-func-cstr-h
(cl-loop
with comp-ctxt = (make-comp-cstr-ctxt)
with h = (make-hash-table :test #'eq)
for (f type-spec) in comp-known-type-specifiers
for cstr = (comp-type-spec-to-cstr type-spec)
do (puthash f cstr h)
finally return h)
"Hash table function -> `comp-constraint'.")
(defconst comp-known-predicates
'((arrayp . array)
(atom . atom)
(characterp . fixnum)
(booleanp . boolean)
(bool-vector-p . bool-vector)
(bufferp . buffer)
(natnump . (integer 0 *))
(char-table-p . char-table)
(hash-table-p . hash-table)
(consp . cons)
(integerp . integer)
(floatp . float)
(functionp . (or function symbol))
(integerp . integer)
(keywordp . keyword)
(listp . list)
(numberp . number)
(null . null)
(numberp . number)
(sequencep . sequence)
(stringp . string)
(symbolp . symbol)
(vectorp . vector)
(integer-or-marker-p . integer-or-marker))
"Alist predicate -> matched type specifier.")
(defconst comp-known-predicates-h
(cl-loop
with comp-ctxt = (make-comp-cstr-ctxt)
with h = (make-hash-table :test #'eq)
for (pred . type-spec) in comp-known-predicates
for cstr = (comp-type-spec-to-cstr type-spec)
do (puthash pred cstr h)
finally return h)
"Hash table function -> `comp-constraint'.")
(defun comp-known-predicate-p (predicate)
"Return t if PREDICATE is known."
(when (gethash predicate comp-known-predicates-h) t))
(defun comp-pred-to-cstr (predicate)
"Given PREDICATE, return the corresponding constraint."
(gethash predicate comp-known-predicates-h))
(defconst comp-symbol-values-optimizable '(most-positive-fixnum
most-negative-fixnum)
"Symbol values we can resolve at compile-time.")
(defconst comp-type-hints '(comp-hint-fixnum
comp-hint-cons)
"List of fake functions used to give compiler hints.")
(defconst comp-limple-sets '(set
setimm
set-par-to-local
set-args-to-local
set-rest-args-to-local)
"Limple set operators.")
(defconst comp-limple-assignments `(assume
fetch-handler
,@comp-limple-sets)
"Limple operators that clobber the first m-var argument.")
(defconst comp-limple-calls '(call
callref
direct-call
direct-callref)
"Limple operators used to call subrs.")
(defconst comp-limple-branches '(jump cond-jump)
"Limple operators used for conditional and unconditional branches.")
(defconst comp-limple-ops `(,@comp-limple-calls
,@comp-limple-assignments
,@comp-limple-branches
return)
"All Limple operators.")
(defvar comp-func nil
"Bound to the current function by most passes.")
(defvar comp-block nil
"Bound to the current basic block by some passes.")
(define-error 'native-compiler-error-dyn-func
"can't native compile a non-lexically-scoped function"
'native-compiler-error)
(define-error 'native-compiler-error-empty-byte
"empty byte compiler output"
'native-compiler-error)
(defvar comp-no-spawn nil
"Non-nil don't spawn native compilation processes.")
;; Moved early to avoid circularity when comp.el is loaded and
;; `macroexpand' needs to be advised (bug#47049).
;;;###autoload
(defun comp-subr-trampoline-install (subr-name)
"Make SUBR-NAME effectively advice-able when called from native code."
(unless (or (null comp-enable-subr-trampolines)
(memq subr-name native-comp-never-optimize-functions)
(gethash subr-name comp-installed-trampolines-h))
(cl-assert (subr-primitive-p (symbol-function subr-name)))
(when-let ((trampoline (or (comp-trampoline-search subr-name)
(comp-trampoline-compile subr-name))))
(comp--install-trampoline subr-name trampoline))))
(cl-defstruct (comp-vec (:copier nil))
"A re-sizable vector like object."
(data (make-hash-table :test #'eql) :type hash-table
:documentation "Payload data.")
(beg 0 :type integer)
(end 0 :type natnum))
(defsubst comp-vec-copy (vec)
"Return a copy of VEC."
(make-comp-vec :data (copy-hash-table (comp-vec-data vec))
:beg (comp-vec-beg vec)
:end (comp-vec-end vec)))
(defsubst comp-vec-length (vec)
"Return the number of elements of VEC."
(- (comp-vec-end vec) (comp-vec-beg vec)))
(defsubst comp-vec--verify-idx (vec idx)
"Check whether IDX is in bounds for VEC."
(cl-assert (and (< idx (comp-vec-end vec))
(>= idx (comp-vec-beg vec)))))
(defsubst comp-vec-aref (vec idx)
"Return the element of VEC whose index is IDX."
(declare (gv-setter (lambda (val)
`(comp-vec--verify-idx ,vec ,idx)
`(puthash ,idx ,val (comp-vec-data ,vec)))))
(comp-vec--verify-idx vec idx)
(gethash idx (comp-vec-data vec)))
(defsubst comp-vec-append (vec elt)
"Append ELT into VEC.
Returns ELT."
(puthash (comp-vec-end vec) elt (comp-vec-data vec))
(cl-incf (comp-vec-end vec))
elt)
(defsubst comp-vec-prepend (vec elt)
"Prepend ELT into VEC.
Returns ELT."
(puthash (1- (comp-vec-beg vec)) elt (comp-vec-data vec))
(cl-decf (comp-vec-beg vec))
elt)
(eval-when-compile
(defconst comp-op-stack-info
(cl-loop with h = (make-hash-table)
for k across byte-code-vector
for v across byte-stack+-info
when k
do (puthash k v h)
finally return h)
"Hash table lap-op -> stack adjustment."))
(define-hash-table-test 'comp-imm-equal-test #'equal-including-properties
#'sxhash-equal-including-properties)
(cl-defstruct comp-data-container
"Data relocation container structure."
(l () :type list
:documentation "Constant objects used by functions.")
(idx (make-hash-table :test 'comp-imm-equal-test) :type hash-table
:documentation "Obj -> position into the previous field."))
(cl-defstruct (comp-ctxt (:include comp-cstr-ctxt))
"Lisp side of the compiler context."
(output nil :type string
:documentation "Target output file-name for the compilation.")
(speed native-comp-speed :type number
:documentation "Default speed for this compilation unit.")
(debug native-comp-debug :type number
:documentation "Default debug level for this compilation unit.")
(compiler-options native-comp-compiler-options :type list
:documentation "Options for the GCC compiler.")
(driver-options native-comp-driver-options :type list
:documentation "Options for the GCC driver.")
(top-level-forms () :type list
:documentation "List of spilled top level forms.")
(funcs-h (make-hash-table :test #'equal) :type hash-table
:documentation "c-name -> comp-func.")
(sym-to-c-name-h (make-hash-table :test #'eq) :type hash-table
:documentation "symbol-function -> c-name.
This is only for optimizing intra CU calls at speed 3.")
(byte-func-to-func-h (make-hash-table :test #'equal) :type hash-table
:documentation "byte-function -> comp-func.
Needed to replace immediate byte-compiled lambdas with the compiled reference.")
(lambda-fixups-h (make-hash-table :test #'equal) :type hash-table
:documentation "Hash table byte-func -> mvar to fixup.")
(function-docs (make-hash-table :test #'eql) :type (or hash-table vector)
:documentation "Documentation index -> documentation")
(d-default (make-comp-data-container) :type comp-data-container
:documentation "Standard data relocated in use by functions.")
(d-impure (make-comp-data-container) :type comp-data-container
:documentation "Relocated data that cannot be moved into pure space.
This is typically for top-level forms other than defun.")
(d-ephemeral (make-comp-data-container) :type comp-data-container
:documentation "Relocated data not necessary after load.")
(with-late-load nil :type boolean
:documentation "When non-nil support late load."))
(cl-defstruct comp-args-base
(min nil :type integer
:documentation "Minimum number of arguments allowed."))
(cl-defstruct (comp-args (:include comp-args-base))
(max nil :type integer
:documentation "Maximum number of arguments allowed."))
(cl-defstruct (comp-nargs (:include comp-args-base))
"Describe args when the function signature is of kind:
(ptrdiff_t nargs, Lisp_Object *args)."
(nonrest nil :type integer
:documentation "Number of non rest arguments.")
(rest nil :type boolean
:documentation "t if rest argument is present."))
(cl-defstruct (comp-block (:copier nil)
(:constructor nil))
"A base class for basic blocks."
(name nil :type symbol)
(insns () :type list
:documentation "List of instructions.")
(closed nil :type boolean
:documentation "t if closed.")
;; All the following are for SSA and CGF analysis.
;; Keep in sync with `comp-clean-ssa'!!
(in-edges () :type list
:documentation "List of incoming edges.")
(out-edges () :type list
:documentation "List of out-coming edges.")
(idom nil :type (or null comp-block)
:documentation "Immediate dominator.")
(df (make-hash-table) :type (or null hash-table)
:documentation "Dominance frontier set. Block-name -> block")
(post-num nil :type (or null number)
:documentation "Post order number.")
(final-frame nil :type (or null comp-vec)
:documentation "This is a copy of the frame when leaving the block.
Is in use to help the SSA rename pass."))
(cl-defstruct (comp-block-lap (:copier nil)
(:include comp-block)
(:constructor make--comp-block-lap
(addr sp name))) ; Positional
"A basic block created from lap (real code)."
;; These two slots are used during limplification.
(sp nil :type number
:documentation "When non-nil indicates the sp value while entering
into it.")
(addr nil :type number
:documentation "Start block LAP address.")
(non-ret-insn nil :type list
:documentation "Insn known to perform a non local exit.
`comp-fwprop' may identify and store here basic blocks performing
non local exits and mark it rewrite it later.")
(no-ret nil :type boolean
:documentation "t when the block is known to perform a
non local exit (ends with an `unreachable' insn)."))
(cl-defstruct (comp-latch (:copier nil)
(:include comp-block))
"A basic block for a latch loop.")
(cl-defstruct (comp-block-cstr (:copier nil)
(:include comp-block))
"A basic block holding only constraints.")
(cl-defstruct (comp-edge (:copier nil) (:constructor make--comp-edge))
"An edge connecting two basic blocks."
(src nil :type (or null comp-block))
(dst nil :type (or null comp-block))
(number nil :type number
:documentation "The index number corresponding to this edge in the
edge hash."))
(defun make-comp-edge (&rest args)
"Create a `comp-edge' with basic blocks SRC and DST."
(let ((n (funcall (comp-func-edge-cnt-gen comp-func))))
(puthash
n
(apply #'make--comp-edge :number n args)
(comp-func-edges-h comp-func))))
(defun comp-block-preds (basic-block)
"Return the list of predecessors of BASIC-BLOCK."
(mapcar #'comp-edge-src (comp-block-in-edges basic-block)))
(defun comp-gen-counter ()
"Return a sequential number generator."
(let ((n -1))
(lambda ()
(cl-incf n))))
(cl-defstruct (comp-func (:copier nil))
"LIMPLE representation of a function."
(name nil :type symbol
:documentation "Function symbol name. Nil indicates anonymous.")
(c-name nil :type string
:documentation "The function name in the native world.")
(byte-func nil
:documentation "Byte-compiled version.")
(doc nil :type string
:documentation "Doc string.")
(int-spec nil :type list
:documentation "Interactive form.")
(command-modes nil :type list
:documentation "Command modes.")
(lap () :type list
:documentation "LAP assembly representation.")
(ssa-status nil :type symbol
:documentation "SSA status either: nil, `dirty' or t.
Once in SSA form this *must* be set to `dirty' every time the topology of the
CFG is mutated by a pass.")
(frame-size nil :type integer)
(vframe-size 0 :type integer)
(blocks (make-hash-table :test #'eq) :type hash-table
:documentation "Basic block symbol -> basic block.")
(lap-block (make-hash-table :test #'equal) :type hash-table
:documentation "LAP label -> LIMPLE basic block name.")
(edges-h (make-hash-table) :type hash-table
:documentation "Hash edge-num -> edge connecting basic two blocks.")
(block-cnt-gen (funcall #'comp-gen-counter) :type function
:documentation "Generates block numbers.")
(edge-cnt-gen (funcall #'comp-gen-counter) :type function
:documentation "Generates edges numbers.")
(has-non-local nil :type boolean
:documentation "t if non local jumps are present.")
(speed nil :type number
:documentation "Optimization level (see `native-comp-speed').")
(pure nil :type boolean
:documentation "t if pure nil otherwise.")
(type nil :type (or null comp-mvar)
:documentation "Mvar holding the derived return type."))
(cl-defstruct (comp-func-l (:include comp-func))
"Lexically-scoped function."
(args nil :type comp-args-base
:documentation "Argument specification of the function"))
(cl-defstruct (comp-func-d (:include comp-func))
"Dynamically-scoped function."
(lambda-list nil :type list
:documentation "Original lambda-list."))
(cl-defstruct (comp-mvar (:constructor make--comp-mvar)
(:include comp-cstr))
"A meta-variable being a slot in the meta-stack."
(id nil :type (or null number)
:documentation "Unique id when in SSA form.")
(slot nil :type (or fixnum symbol)
:documentation "Slot number in the array if a number or
`scratch' for scratch slot."))
(defun comp-mvar-type-hint-match-p (mvar type-hint)
"Match MVAR against TYPE-HINT.
In use by the back-end."
(cl-ecase type-hint
(cons (comp-cstr-cons-p mvar))
(fixnum (comp-cstr-fixnum-p mvar))))
(defun comp-ensure-native-compiler ()
"Make sure Emacs has native compiler support and libgccjit can be loaded.
Signal an error otherwise.
To be used by all entry points."
(cond
((null (featurep 'native-compile))
(error "Emacs was not compiled with native compiler support (--with-native-compilation)"))
((null (native-comp-available-p))
(error "Cannot find libgccjit library"))))
(defun comp-equality-fun-p (function)
"Equality functions predicate for FUNCTION."
(when (memq function '(eq eql equal)) t))
(defun comp-arithm-cmp-fun-p (function)
"Predicate for arithmetic comparison functions."
(when (memq function '(= > < >= <=)) t))
(defun comp-set-op-p (op)
"Assignment predicate for OP."
(when (memq op comp-limple-sets) t))
(defun comp-assign-op-p (op)
"Assignment predicate for OP."
(when (memq op comp-limple-assignments) t))
(defun comp-call-op-p (op)
"Call predicate for OP."
(when (memq op comp-limple-calls) t))