-
Notifications
You must be signed in to change notification settings - Fork 22
/
ir.h
1007 lines (899 loc) · 39.8 KB
/
ir.h
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
/*
* IR - Lightweight JIT Compilation Framework
* (Public API)
* Copyright (C) 2022 Zend by Perforce.
* Authors: Dmitry Stogov <dmitry@php.net>
*/
#ifndef IR_H
#define IR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define IR_VERSION "0.0.1"
#ifdef _WIN32
/* TODO Handle ARM, too. */
# if defined(_M_X64) || defined(_M_ARM64)
# define __SIZEOF_SIZE_T__ 8
# elif defined(_M_IX86)
# define __SIZEOF_SIZE_T__ 4
# endif
/* Only supported is little endian for any arch on Windows,
so just fake the same for all. */
# define __ORDER_LITTLE_ENDIAN__ 1
# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
# ifndef __has_builtin
# define __has_builtin(arg) (0)
# endif
#endif
/* target auto detection */
#if !defined(IR_TARGET_X86) && !defined(IR_TARGET_X64) && !defined(IR_TARGET_AARCH64)
# if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
# define IR_TARGET_X64
# elif defined(i386) || defined(__i386) || defined(__i386__) || defined(_M_IX86)
# define IR_TARGET_X86
# elif defined(__aarch64__) || defined(_M_ARM64)
# define IR_TARGET_AARCH64
# elif defined (_WIN64)
# define IR_TARGET_X64
# elif defined (_WIN32)
# define IR_TARGET_X86
# endif
#endif
#if defined(IR_TARGET_X86)
# define IR_TARGET "x86"
#elif defined(IR_TARGET_X64)
# ifdef _WIN64
# define IR_TARGET "Windows-x86_64" /* 64-bit Windows use different ABI and calling convention */
# else
# define IR_TARGET "x86_64"
# endif
#elif defined(IR_TARGET_AARCH64)
# define IR_TARGET "aarch64"
#else
# error "Unknown IR target"
#endif
#if defined(__SIZEOF_SIZE_T__)
# if __SIZEOF_SIZE_T__ == 8
# define IR_64 1
# elif __SIZEOF_SIZE_T__ != 4
# error "Unknown addr size"
# endif
#else
# error "Unknown addr size"
#endif
#if defined(__BYTE_ORDER__)
# if defined(__ORDER_LITTLE_ENDIAN__)
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define IR_STRUCT_LOHI(lo, hi) struct {lo; hi;}
# endif
# endif
# if defined(__ORDER_BIG_ENDIAN__)
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define IR_STRUCT_LOHI(lo, hi) struct {hi; lo;}
# endif
# endif
#endif
#ifndef IR_STRUCT_LOHI
# error "Unknown byte order"
#endif
#ifdef __has_attribute
# if __has_attribute(always_inline)
# define IR_ALWAYS_INLINE static inline __attribute__((always_inline))
# endif
# if __has_attribute(noinline)
# define IR_NEVER_INLINE __attribute__((noinline))
# endif
#else
# define __has_attribute(x) 0
#endif
#ifndef IR_ALWAYS_INLINE
# define IR_ALWAYS_INLINE static inline
#endif
#ifndef IR_NEVER_INLINE
# define IR_NEVER_INLINE
#endif
#ifdef IR_PHP
# include "ir_php.h"
#endif
/* IR Type flags (low 4 bits are used for type size) */
#define IR_TYPE_SIGNED (1<<4)
#define IR_TYPE_UNSIGNED (1<<5)
#define IR_TYPE_FP (1<<6)
#define IR_TYPE_SPECIAL (1<<7)
#define IR_TYPE_BOOL (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED)
#define IR_TYPE_ADDR (IR_TYPE_SPECIAL|IR_TYPE_UNSIGNED)
#define IR_TYPE_CHAR (IR_TYPE_SPECIAL|IR_TYPE_SIGNED)
/* List of IR types */
#define IR_TYPES(_) \
_(BOOL, bool, b, IR_TYPE_BOOL) \
_(U8, uint8_t, u8, IR_TYPE_UNSIGNED) \
_(U16, uint16_t, u16, IR_TYPE_UNSIGNED) \
_(U32, uint32_t, u32, IR_TYPE_UNSIGNED) \
_(U64, uint64_t, u64, IR_TYPE_UNSIGNED) \
_(ADDR, uintptr_t, addr, IR_TYPE_ADDR) \
_(CHAR, char, c, IR_TYPE_CHAR) \
_(I8, int8_t, i8, IR_TYPE_SIGNED) \
_(I16, int16_t, i16, IR_TYPE_SIGNED) \
_(I32, int32_t, i32, IR_TYPE_SIGNED) \
_(I64, int64_t, i64, IR_TYPE_SIGNED) \
_(DOUBLE, double, d, IR_TYPE_FP) \
_(FLOAT, float, f, IR_TYPE_FP) \
#define IR_IS_TYPE_UNSIGNED(t) ((t) < IR_CHAR)
#define IR_IS_TYPE_SIGNED(t) ((t) >= IR_CHAR && (t) < IR_DOUBLE)
#define IR_IS_TYPE_INT(t) ((t) < IR_DOUBLE)
#define IR_IS_TYPE_FP(t) ((t) >= IR_DOUBLE)
#define IR_TYPE_ENUM(name, type, field, flags) IR_ ## name,
typedef enum _ir_type {
IR_VOID,
IR_TYPES(IR_TYPE_ENUM)
IR_LAST_TYPE
} ir_type;
#ifdef IR_64
# define IR_SIZE_T IR_U64
# define IR_SSIZE_T IR_I64
# define IR_UINTPTR_T IR_U64
# define IR_INTPTR_T IR_I64
# define IR_C_UINTPTR IR_U64
# define IR_C_INTPTR IR_I64
#else
# define IR_SIZE_T IR_U32
# define IR_SSIZE_T IR_I32
# define IR_UINTPTR_T IR_U32
# define IR_INTPTR_T IR_I32
# define IR_C_UINTPTR IR_U32
# define IR_C_INTPTR IR_I32
#endif
/* List of IR opcodes
* ==================
*
* Each instruction is described by a type (opcode, flags, op1_type, op2_type, op3_type)
*
* flags
* -----
* v - void
* d - data IR_OP_FLAG_DATA
* r - ref IR_OP_FLAG_DATA alias
* p - pinned IR_OP_FLAG_DATA + IR_OP_FLAG_PINNED
* c - control IR_OP_FLAG_CONTROL
* S - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_START
* E - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END
* T - control IR_OP_FLAG_CONTROL + IR_OP_FLAG_BB_END + IR_OP_FLAG_TERMINATOR
* l - load IR_OP_FLAG_MEM + IR_OP_FLAG_MEM_LOAD
* s - store IR_OP_FLAG_MEM + IR_OP_FLAG_STORE
* x - call IR_OP_FLAG_MEM + IR_OP_FLAG_CALL
* a - alloc IR_OP_FLAG_MEM + IR_OP_FLAG_ALLOC
* 0-3 - number of input edges
* N - number of arguments is defined in the insn->inputs_count (MERGE, PHI, CALL)
* X1-X3 - number of extra data ops
* C - commutative operation ("d2C" => IR_OP_FLAG_DATA + IR_OP_FLAG_COMMUTATIVE)
*
* operand types
* -------------
* ___ - unused
* def - reference to a definition op (data-flow use-def dependency edge)
* ref - memory reference (data-flow use-def dependency edge)
* var - variable reference (data-flow use-def dependency edge)
* arg - argument reference CALL/TAILCALL/CARG->CARG
* src - reference to a previous control region (IF, IF_TRUE, IF_FALSE, MERGE, LOOP_BEGIN, LOOP_END, RETURN)
* reg - data-control dependency on region (PHI, VAR, PARAM)
* ret - reference to a previous RETURN instruction (RETURN)
* str - string: variable/argument name (VAR, PARAM, CALL, TAILCALL)
* num - number: argument number (PARAM)
* prb - branch probability 1-99 (0 - unspecified): (IF_TRUE, IF_FALSE, CASE_VAL, CASE_DEFAULT)
* opt - optional number
* pro - function prototype
*
* The order of IR opcodes is carefully selected for efficient folding.
* - foldable instruction go first
* - NOP is never used (code 0 is used as ANY pattern)
* - CONST is the most often used instruction (encode with 1 bit)
* - equality inversion: EQ <-> NE => op =^ 1
* - comparison inversion: [U]LT <-> [U]GT, [U]LE <-> [U]GE => op =^ 3
*/
#define IR_OPS(_) \
/* special op (must be the first !!!) */ \
_(NOP, v, ___, ___, ___) /* empty instruction */ \
\
/* constants reference */ \
_(C_BOOL, r0, ___, ___, ___) /* constant */ \
_(C_U8, r0, ___, ___, ___) /* constant */ \
_(C_U16, r0, ___, ___, ___) /* constant */ \
_(C_U32, r0, ___, ___, ___) /* constant */ \
_(C_U64, r0, ___, ___, ___) /* constant */ \
_(C_ADDR, r0, ___, ___, ___) /* constant */ \
_(C_CHAR, r0, ___, ___, ___) /* constant */ \
_(C_I8, r0, ___, ___, ___) /* constant */ \
_(C_I16, r0, ___, ___, ___) /* constant */ \
_(C_I32, r0, ___, ___, ___) /* constant */ \
_(C_I64, r0, ___, ___, ___) /* constant */ \
_(C_DOUBLE, r0, ___, ___, ___) /* constant */ \
_(C_FLOAT, r0, ___, ___, ___) /* constant */ \
\
/* equality ops */ \
_(EQ, d2C, def, def, ___) /* equal */ \
_(NE, d2C, def, def, ___) /* not equal */ \
\
/* comparison ops (order matters, LT must be a modulo of 4 !!!) */ \
_(LT, d2, def, def, ___) /* less */ \
_(GE, d2, def, def, ___) /* greater or equal */ \
_(LE, d2, def, def, ___) /* less or equal */ \
_(GT, d2, def, def, ___) /* greater */ \
_(ULT, d2, def, def, ___) /* unsigned less */ \
_(UGE, d2, def, def, ___) /* unsigned greater or equal */ \
_(ULE, d2, def, def, ___) /* unsigned less or equal */ \
_(UGT, d2, def, def, ___) /* unsigned greater */ \
\
/* arithmetic ops */ \
_(ADD, d2C, def, def, ___) /* addition */ \
_(SUB, d2, def, def, ___) /* subtraction (must be ADD+1) */ \
_(MUL, d2C, def, def, ___) /* multiplication */ \
_(DIV, d2, def, def, ___) /* division */ \
_(MOD, d2, def, def, ___) /* modulo */ \
_(NEG, d1, def, ___, ___) /* change sign */ \
_(ABS, d1, def, ___, ___) /* absolute value */ \
/* (LDEXP, MIN, MAX, FPMATH) */ \
\
/* type conversion ops */ \
_(SEXT, d1, def, ___, ___) /* sign extension */ \
_(ZEXT, d1, def, ___, ___) /* zero extension */ \
_(TRUNC, d1, def, ___, ___) /* truncates to int type */ \
_(BITCAST, d1, def, ___, ___) /* binary representation */ \
_(INT2FP, d1, def, ___, ___) /* int to float conversion */ \
_(FP2INT, d1, def, ___, ___) /* float to int conversion */ \
_(FP2FP, d1, def, ___, ___) /* float to float conversion */ \
_(PROTO, d1X1, def, pro, ___) /* apply function prototype */ \
\
/* overflow-check */ \
_(ADD_OV, d2C, def, def, ___) /* addition */ \
_(SUB_OV, d2, def, def, ___) /* subtraction */ \
_(MUL_OV, d2C, def, def, ___) /* multiplication */ \
_(OVERFLOW, d1, def, ___, ___) /* overflow check add/sub/mul */ \
\
/* bitwise and shift ops */ \
_(NOT, d1, def, ___, ___) /* bitwise NOT */ \
_(OR, d2C, def, def, ___) /* bitwise OR */ \
_(AND, d2C, def, def, ___) /* bitwise AND */ \
_(XOR, d2C, def, def, ___) /* bitwise XOR */ \
_(SHL, d2, def, def, ___) /* logic shift left */ \
_(SHR, d2, def, def, ___) /* logic shift right */ \
_(SAR, d2, def, def, ___) /* arithmetic shift right */ \
_(ROL, d2, def, def, ___) /* rotate left */ \
_(ROR, d2, def, def, ___) /* rotate right */ \
_(BSWAP, d1, def, ___, ___) /* byte swap */ \
_(CTPOP, d1, def, ___, ___) /* count population */ \
_(CTLZ, d1, def, ___, ___) /* count leading zeros */ \
_(CTTZ, d1, def, ___, ___) /* count trailing zeros */ \
\
/* branch-less conditional ops */ \
_(MIN, d2C, def, def, ___) /* min(op1, op2) */ \
_(MAX, d2C, def, def, ___) /* max(op1, op2) */ \
_(COND, d3, def, def, def) /* op1 ? op2 : op3 */ \
\
/* data-flow and miscellaneous ops */ \
_(PHI, pN, reg, def, def) /* SSA Phi function */ \
_(COPY, d1X1, def, opt, ___) /* COPY (last foldable op) */ \
_(PI, p2, reg, def, ___) /* e-SSA Pi constraint ??? */ \
_(FRAME_ADDR, d0, ___, ___, ___) /* function frame address */ \
/* (USE, RENAME) */ \
\
/* data ops */ \
_(PARAM, p1X2, reg, str, num) /* incoming parameter proj. */ \
_(VAR, p1X1, reg, str, ___) /* local variable */ \
_(FUNC_ADDR, r0, ___, ___, ___) /* constant func ref */ \
_(FUNC, r0, ___, ___, ___) /* constant func ref */ \
_(SYM, r0, ___, ___, ___) /* constant symbol ref */ \
_(STR, r0, ___, ___, ___) /* constant str ref */ \
\
/* call ops */ \
_(CALL, xN, src, def, def) /* CALL(src, func, args...) */ \
_(TAILCALL, xN, src, def, def) /* CALL+RETURN */ \
\
/* memory reference and load/store ops */ \
_(ALLOCA, a2, src, def, ___) /* alloca(def) */ \
_(AFREE, a2, src, def, ___) /* revert alloca(def) */ \
_(BLOCK_BEGIN, a1, src, ___, ___) /* stacksave */ \
_(BLOCK_END, a2, src, def, ___) /* stackrestore */ \
_(VADDR, d1, var, ___, ___) /* load address of local var */ \
_(VLOAD, l2, src, var, ___) /* load value of local var */ \
_(VSTORE, s3, src, var, def) /* store value to local var */ \
_(RLOAD, l1X2, src, num, opt) /* load value from register */ \
_(RSTORE, s2X1, src, def, num) /* store value into register */ \
_(LOAD, l2, src, ref, ___) /* load from memory */ \
_(STORE, s3, src, ref, def) /* store to memory */ \
_(TLS, l1X2, src, num, num) /* thread local variable */ \
_(TRAP, x1, src, ___, ___) /* DebugBreak */ \
/* memory reference ops (A, H, U, S, TMP, STR, NEW, X, V) ??? */ \
\
/* va_args */ \
_(VA_START, x2, src, def, ___) /* va_start(va_list) */ \
_(VA_END, x2, src, def, ___) /* va_end(va_list) */ \
_(VA_COPY, x3, src, def, def) /* va_copy(dst, stc) */ \
_(VA_ARG, x2, src, def, ___) /* va_arg(va_list) */ \
\
/* guards */ \
_(GUARD, c3, src, def, def) /* IF without second successor */ \
_(GUARD_NOT , c3, src, def, def) /* IF without second successor */ \
\
/* deoptimization */ \
_(SNAPSHOT, xN, src, def, def) /* SNAPSHOT(src, args...) */ \
\
/* control-flow nodes */ \
_(START, S0X1, ret, ___, ___) /* function start */ \
_(ENTRY, S1X1, src, num, ___) /* entry with a fake src edge */ \
_(BEGIN, S1, src, ___, ___) /* block start */ \
_(IF_TRUE, S1X1, src, prb, ___) /* IF TRUE proj. */ \
_(IF_FALSE, S1X1, src, prb, ___) /* IF FALSE proj. */ \
_(CASE_VAL, S2X1, src, def, prb) /* switch proj. */ \
_(CASE_DEFAULT, S1X1, src, prb, ___) /* switch proj. */ \
_(MERGE, SN, src, src, src) /* control merge */ \
_(LOOP_BEGIN, SN, src, src, src) /* loop start */ \
_(END, E1, src, ___, ___) /* block end */ \
_(LOOP_END, E1, src, ___, ___) /* loop end */ \
_(IF, E2, src, def, ___) /* conditional control split */ \
_(SWITCH, E2, src, def, ___) /* multi-way control split */ \
_(RETURN, T2X1, src, def, ret) /* function return */ \
_(IJMP, T2X1, src, def, ret) /* computed goto */ \
_(UNREACHABLE, T1X2, src, ___, ret) /* unreachable (tailcall, etc) */ \
\
/* deoptimization helper */ \
_(EXITCALL, x2, src, def, ___) /* save CPU regs and call op2 */ \
#define IR_OP_ENUM(name, flags, op1, op2, op3) IR_ ## name,
typedef enum _ir_op {
IR_OPS(IR_OP_ENUM)
#ifdef IR_PHP
IR_PHP_OPS(IR_OP_ENUM)
#endif
IR_LAST_OP
} ir_op;
/* IR Opcode and Type Union */
#define IR_OPT_OP_MASK 0x00ff
#define IR_OPT_TYPE_MASK 0xff00
#define IR_OPT_TYPE_SHIFT 8
#define IR_OPT_INPUTS_SHIFT 16
#define IR_OPT(op, type) ((uint16_t)(op) | ((uint16_t)(type) << IR_OPT_TYPE_SHIFT))
#define IR_OPTX(op, type, n) ((uint32_t)(op) | ((uint32_t)(type) << IR_OPT_TYPE_SHIFT) | ((uint32_t)(n) << IR_OPT_INPUTS_SHIFT))
#define IR_OPT_TYPE(opt) (((opt) & IR_OPT_TYPE_MASK) >> IR_OPT_TYPE_SHIFT)
/* IR References */
typedef int32_t ir_ref;
#define IR_IS_CONST_REF(ref) ((ref) < 0)
/* IR Constant Value */
#define IR_UNUSED 0
#define IR_NULL (-1)
#define IR_FALSE (-2)
#define IR_TRUE (-3)
#define IR_LAST_FOLDABLE_OP IR_COPY
#define IR_CONSTS_LIMIT_MIN (-(IR_TRUE - 1))
#define IR_INSNS_LIMIT_MIN (IR_UNUSED + 1)
#ifndef IR_64
# define ADDR_MEMBER uintptr_t addr;
#else
# define ADDR_MEMBER
#endif
typedef union _ir_val {
double d;
uint64_t u64;
int64_t i64;
#ifdef IR_64
uintptr_t addr;
#endif
IR_STRUCT_LOHI(
union {
uint32_t u32;
int32_t i32;
float f;
ADDR_MEMBER
ir_ref name;
ir_ref str;
IR_STRUCT_LOHI(
union {
uint16_t u16;
int16_t i16;
IR_STRUCT_LOHI(
union {
uint8_t u8;
int8_t i8;
bool b;
char c;
},
uint8_t u8_hi
);
},
uint16_t u16_hi
);
},
uint32_t u32_hi
);
} ir_val;
#undef ADDR_MEMBER
/* IR Instruction */
typedef struct _ir_insn {
IR_STRUCT_LOHI(
union {
IR_STRUCT_LOHI(
union {
IR_STRUCT_LOHI(
uint8_t op,
uint8_t type
);
uint16_t opt;
},
union {
uint16_t inputs_count; /* number of input control edges for MERGE, PHI, CALL, TAILCALL */
uint16_t prev_insn_offset; /* 16-bit backward offset from current instruction for CSE */
uint16_t proto;
}
);
uint32_t optx;
ir_ref ops[1];
},
union {
ir_ref op1;
ir_ref prev_const;
}
);
union {
IR_STRUCT_LOHI(
ir_ref op2,
ir_ref op3
);
ir_val val;
};
} ir_insn;
/* IR Hash Tables API (private) */
typedef struct _ir_hashtab ir_hashtab;
/* IR String Tables API (implementation in ir_strtab.c) */
typedef struct _ir_strtab {
void *data;
uint32_t mask;
uint32_t size;
uint32_t count;
uint32_t pos;
char *buf;
uint32_t buf_size;
uint32_t buf_top;
} ir_strtab;
#define ir_strtab_count(strtab) (strtab)->count
typedef void (*ir_strtab_apply_t)(const char *str, uint32_t len, ir_ref val);
void ir_strtab_init(ir_strtab *strtab, uint32_t count, uint32_t buf_size);
ir_ref ir_strtab_lookup(ir_strtab *strtab, const char *str, uint32_t len, ir_ref val);
ir_ref ir_strtab_find(const ir_strtab *strtab, const char *str, uint32_t len);
ir_ref ir_strtab_update(ir_strtab *strtab, const char *str, uint32_t len, ir_ref val);
const char *ir_strtab_str(const ir_strtab *strtab, ir_ref idx);
const char *ir_strtab_strl(const ir_strtab *strtab, ir_ref idx, size_t *len);
void ir_strtab_apply(const ir_strtab *strtab, ir_strtab_apply_t func);
void ir_strtab_free(ir_strtab *strtab);
/* IR Context Flags */
#define IR_FUNCTION (1<<0) /* Generate a function. */
#define IR_FASTCALL_FUNC (1<<1) /* Generate a function with fastcall calling convention, x86 32-bit only. */
#define IR_VARARG_FUNC (1<<2)
#define IR_BUILTIN_FUNC (1<<3)
#define IR_STATIC (1<<4)
#define IR_EXTERN (1<<5)
#define IR_CONST (1<<6)
#define IR_INITIALIZED (1<<7) /* sym data flag: constant or an initialized variable */
#define IR_CONST_STRING (1<<8) /* sym data flag: constant string */
#define IR_SKIP_PROLOGUE (1<<8) /* Don't generate function prologue. */
#define IR_USE_FRAME_POINTER (1<<9)
#define IR_PREALLOCATED_STACK (1<<10)
#define IR_NO_STACK_COMBINE (1<<11)
#define IR_START_BR_TARGET (1<<12)
#define IR_ENTRY_BR_TARGET (1<<13)
#define IR_GEN_ENDBR (1<<14)
#define IR_MERGE_EMPTY_ENTRIES (1<<15)
#define IR_OPT_INLINE (1<<16)
#define IR_OPT_FOLDING (1<<17)
#define IR_OPT_CFG (1<<18) /* merge BBs, by remove END->BEGIN nodes during CFG construction */
#define IR_OPT_CODEGEN (1<<19)
#define IR_GEN_NATIVE (1<<20)
#define IR_GEN_CODE (1<<21) /* C or LLVM */
#define IR_GEN_CACHE_DEMOTE (1<<22) /* Demote the generated code from closest CPU caches */
/* debug related */
#ifdef IR_DEBUG
# define IR_DEBUG_SCCP (1<<26)
# define IR_DEBUG_GCM (1<<27)
# define IR_DEBUG_GCM_SPLIT (1<<28)
# define IR_DEBUG_SCHEDULE (1<<29)
# define IR_DEBUG_RA (1<<30)
# define IR_DEBUG_BB_SCHEDULE (1U<<31)
#endif
typedef struct _ir_ctx ir_ctx;
typedef struct _ir_use_list ir_use_list;
typedef struct _ir_block ir_block;
typedef struct _ir_arena ir_arena;
typedef struct _ir_live_interval ir_live_interval;
typedef struct _ir_live_range ir_live_range;
typedef struct _ir_loader ir_loader;
typedef int8_t ir_regs[4];
typedef void (*ir_snapshot_create_t)(ir_ctx *ctx, ir_ref addr);
#if defined(IR_TARGET_AARCH64)
typedef const void *(*ir_get_exit_addr_t)(uint32_t exit_num);
typedef const void *(*ir_get_veneer_t)(ir_ctx *ctx, const void *addr);
typedef bool (*ir_set_veneer_t)(ir_ctx *ctx, const void *addr, const void *veneer);
#endif
typedef struct _ir_code_buffer {
void *start;
void *end;
void *pos;
} ir_code_buffer;
struct _ir_ctx {
ir_insn *ir_base; /* two directional array - instructions grow down, constants grow up */
ir_ref insns_count; /* number of instructions stored in instructions buffer */
ir_ref insns_limit; /* size of allocated instructions buffer (it's extended when overflow) */
ir_ref consts_count; /* number of constants stored in constants buffer */
ir_ref consts_limit; /* size of allocated constants buffer (it's extended when overflow) */
uint32_t flags; /* IR context flags (see IR_* defines above) */
uint32_t flags2; /* IR context private flags (see IR_* defines in ir_private.h) */
ir_type ret_type; /* Function return type */
uint32_t mflags; /* CPU specific flags (see IR_X86_... macros below) */
int32_t status; /* non-zero error code (see IR_ERROR_... macros), app may use negative codes */
ir_ref fold_cse_limit; /* CSE finds identical insns backward from "insn_count" to "fold_cse_limit" */
ir_insn fold_insn; /* temporary storage for folding engine */
ir_hashtab *binding;
ir_use_list *use_lists; /* def->use lists for each instruction */
ir_ref *use_edges; /* the actual uses: use = ctx->use_edges[ctx->use_lists[def].refs + n] */
ir_ref use_edges_count; /* number of elements in use_edges[] array */
uint32_t cfg_blocks_count; /* number of elements in cfg_blocks[] array */
uint32_t cfg_edges_count; /* number of elements in cfg_edges[] array */
ir_block *cfg_blocks; /* list of basic blocks (starts from 1) */
uint32_t *cfg_edges; /* the actual basic blocks predecessors and successors edges */
uint32_t *cfg_map; /* map of instructions to basic block number */
uint32_t *cfg_schedule; /* BB order for code generation */
uint32_t *rules; /* array of target specific code-generation rules (for each instruction) */
uint32_t *vregs;
ir_ref vregs_count;
int32_t spill_base; /* base register for special spill area (e.g. PHP VM frame pointer) */
uint64_t fixed_regset; /* fixed registers, excluded for regular register allocation */
int32_t fixed_stack_red_zone; /* reusable stack allocated by caller (default 0) */
int32_t fixed_stack_frame_size; /* fixed stack allocated by generated code for spills and registers save/restore */
int32_t fixed_call_stack_size; /* fixed preallocated stack for parameter passing (default 0) */
uint64_t fixed_save_regset; /* registers that always saved/restored in prologue/epilogue */
uint32_t locals_area_size;
uint32_t gp_reg_params;
uint32_t fp_reg_params;
int32_t param_stack_size;
ir_live_interval **live_intervals;
ir_arena *arena;
ir_live_range *unused_ranges;
ir_regs *regs;
ir_strtab *fused_regs;
ir_ref *prev_ref;
union {
void *data;
ir_ref control; /* used by IR construction API (see ir_builder.h) */
ir_ref bb_start; /* used by target CPU instruction matcher */
ir_ref vars; /* list of VARs (used by register allocator) */
};
ir_snapshot_create_t snapshot_create;
int32_t stack_frame_alignment;
int32_t stack_frame_size; /* spill stack frame size (used by register allocator and code generator) */
int32_t call_stack_size; /* stack for parameter passing (used by register allocator and code generator) */
uint64_t used_preserved_regs;
#ifdef IR_TARGET_X86
int32_t ret_slot;
#endif
uint32_t rodata_offset;
uint32_t jmp_table_offset;
uint32_t entries_count;
uint32_t *entries; /* array of ENTRY blocks */
void *osr_entry_loads;
ir_code_buffer *code_buffer;
#if defined(IR_TARGET_AARCH64)
int32_t deoptimization_exits;
const void *deoptimization_exits_base;
ir_get_exit_addr_t get_exit_addr;
ir_get_veneer_t get_veneer;
ir_set_veneer_t set_veneer;
#endif
ir_loader *loader;
ir_strtab strtab;
ir_ref prev_insn_chain[IR_LAST_FOLDABLE_OP + 1];
ir_ref prev_const_chain[IR_LAST_TYPE];
};
/* Basic IR Construction API (implementation in ir.c) */
void ir_init(ir_ctx *ctx, uint32_t flags, ir_ref consts_limit, ir_ref insns_limit);
void ir_free(ir_ctx *ctx);
void ir_truncate(ir_ctx *ctx);
ir_ref ir_const(ir_ctx *ctx, ir_val val, uint8_t type);
ir_ref ir_const_i8(ir_ctx *ctx, int8_t c);
ir_ref ir_const_i16(ir_ctx *ctx, int16_t c);
ir_ref ir_const_i32(ir_ctx *ctx, int32_t c);
ir_ref ir_const_i64(ir_ctx *ctx, int64_t c);
ir_ref ir_const_u8(ir_ctx *ctx, uint8_t c);
ir_ref ir_const_u16(ir_ctx *ctx, uint16_t c);
ir_ref ir_const_u32(ir_ctx *ctx, uint32_t c);
ir_ref ir_const_u64(ir_ctx *ctx, uint64_t c);
ir_ref ir_const_bool(ir_ctx *ctx, bool c);
ir_ref ir_const_char(ir_ctx *ctx, char c);
ir_ref ir_const_float(ir_ctx *ctx, float c);
ir_ref ir_const_double(ir_ctx *ctx, double c);
ir_ref ir_const_addr(ir_ctx *ctx, uintptr_t c);
ir_ref ir_const_func_addr(ir_ctx *ctx, uintptr_t c, ir_ref proto);
ir_ref ir_const_func(ir_ctx *ctx, ir_ref str, ir_ref proto);
ir_ref ir_const_sym(ir_ctx *ctx, ir_ref str);
ir_ref ir_const_str(ir_ctx *ctx, ir_ref str);
ir_ref ir_unique_const_addr(ir_ctx *ctx, uintptr_t c);
void ir_print_const(const ir_ctx *ctx, const ir_insn *insn, FILE *f, bool quoted);
ir_ref ir_str(ir_ctx *ctx, const char *s);
ir_ref ir_strl(ir_ctx *ctx, const char *s, size_t len);
const char *ir_get_str(const ir_ctx *ctx, ir_ref idx);
const char *ir_get_strl(const ir_ctx *ctx, ir_ref idx, size_t *len);
#define IR_MAX_PROTO_PARAMS 255
typedef struct _ir_proto_t {
uint8_t flags;
uint8_t ret_type;
uint8_t params_count;
uint8_t param_types[5];
} ir_proto_t;
ir_ref ir_proto_0(ir_ctx *ctx, uint8_t flags, ir_type ret_type);
ir_ref ir_proto_1(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1);
ir_ref ir_proto_2(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2);
ir_ref ir_proto_3(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3);
ir_ref ir_proto_4(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
ir_type t4);
ir_ref ir_proto_5(ir_ctx *ctx, uint8_t flags, ir_type ret_type, ir_type t1, ir_type t2, ir_type t3,
ir_type t4, ir_type t5);
ir_ref ir_proto(ir_ctx *ctx, uint8_t flags, ir_type ret_type, uint32_t params_counts, uint8_t *param_types);
ir_ref ir_emit(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
ir_ref ir_emit0(ir_ctx *ctx, uint32_t opt);
ir_ref ir_emit1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
ir_ref ir_emit2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
ir_ref ir_emit3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
ir_ref ir_emit_N(ir_ctx *ctx, uint32_t opt, int32_t count);
void ir_set_op(ir_ctx *ctx, ir_ref ref, int32_t n, ir_ref val);
IR_ALWAYS_INLINE void ir_set_op1(ir_ctx *ctx, ir_ref ref, ir_ref val)
{
ctx->ir_base[ref].op1 = val;
}
IR_ALWAYS_INLINE void ir_set_op2(ir_ctx *ctx, ir_ref ref, ir_ref val)
{
ctx->ir_base[ref].op2 = val;
}
IR_ALWAYS_INLINE void ir_set_op3(ir_ctx *ctx, ir_ref ref, ir_ref val)
{
ctx->ir_base[ref].op3 = val;
}
ir_ref ir_get_op(ir_ctx *ctx, ir_ref ref, int32_t n);
IR_ALWAYS_INLINE ir_ref ir_insn_op(const ir_insn *insn, int32_t n)
{
const ir_ref *p = insn->ops + n;
return *p;
}
IR_ALWAYS_INLINE void ir_insn_set_op(ir_insn *insn, int32_t n, ir_ref val)
{
ir_ref *p = insn->ops + n;
*p = val;
}
ir_ref ir_fold(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
ir_ref ir_fold0(ir_ctx *ctx, uint32_t opt);
ir_ref ir_fold1(ir_ctx *ctx, uint32_t opt, ir_ref op1);
ir_ref ir_fold2(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2);
ir_ref ir_fold3(ir_ctx *ctx, uint32_t opt, ir_ref op1, ir_ref op2, ir_ref op3);
ir_ref ir_param(ir_ctx *ctx, ir_type type, ir_ref region, const char *name, int pos);
ir_ref ir_var(ir_ctx *ctx, ir_type type, ir_ref region, const char *name);
ir_ref ir_bind(ir_ctx *ctx, ir_ref var, ir_ref def);
/* Def -> Use lists */
void ir_build_def_use_lists(ir_ctx *ctx);
/* CFG - Control Flow Graph (implementation in ir_cfg.c) */
int ir_build_cfg(ir_ctx *ctx);
int ir_remove_unreachable_blocks(ir_ctx *ctx);
int ir_build_dominators_tree(ir_ctx *ctx);
int ir_find_loops(ir_ctx *ctx);
int ir_schedule_blocks(ir_ctx *ctx);
void ir_build_prev_refs(ir_ctx *ctx);
/* SCCP - Sparse Conditional Constant Propagation (implementation in ir_sccp.c) */
int ir_sccp(ir_ctx *ctx);
/* GCM - Global Code Motion and scheduling (implementation in ir_gcm.c) */
int ir_gcm(ir_ctx *ctx);
int ir_schedule(ir_ctx *ctx);
/* Liveness & Register Allocation (implementation in ir_ra.c) */
#define IR_REG_NONE -1
#define IR_REG_SPILL_LOAD (1<<6)
#define IR_REG_SPILL_STORE (1<<6)
#define IR_REG_SPILL_SPECIAL (1<<7)
#define IR_REG_SPILLED(r) \
((r) & (IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))
#define IR_REG_NUM(r) \
((int8_t)((r) == IR_REG_NONE ? IR_REG_NONE : ((r) & ~(IR_REG_SPILL_LOAD|IR_REG_SPILL_STORE|IR_REG_SPILL_SPECIAL))))
int ir_assign_virtual_registers(ir_ctx *ctx);
int ir_compute_live_ranges(ir_ctx *ctx);
int ir_coalesce(ir_ctx *ctx);
int ir_compute_dessa_moves(ir_ctx *ctx);
int ir_reg_alloc(ir_ctx *ctx);
int ir_regs_number(void);
bool ir_reg_is_int(int32_t reg);
const char *ir_reg_name(int8_t reg, ir_type type);
int32_t ir_get_spill_slot_offset(ir_ctx *ctx, ir_ref ref);
/* Target CPU instruction selection and code generation (see ir_x86.c) */
int ir_match(ir_ctx *ctx);
void *ir_emit_code(ir_ctx *ctx, size_t *size);
bool ir_needs_thunk(ir_code_buffer *code_buffer, void *addr);
void *ir_emit_thunk(ir_code_buffer *code_buffer, void *addr, size_t *size_ptr);
void ir_fix_thunk(void *thunk_entry, void *addr);
/* Target address resolution (implementation in ir_emit.c) */
void *ir_resolve_sym_name(const char *name);
/* Target CPU disassembler (implementation in ir_disasm.c) */
int ir_disasm_init(void);
void ir_disasm_free(void);
void ir_disasm_add_symbol(const char *name, uint64_t addr, uint64_t size);
const char* ir_disasm_find_symbol(uint64_t addr, int64_t *offset);
int ir_disasm(const char *name,
const void *start,
size_t size,
bool asm_addr,
ir_ctx *ctx,
FILE *f);
/* Linux perf interface (implementation in ir_perf.c) */
int ir_perf_jitdump_open(void);
int ir_perf_jitdump_close(void);
int ir_perf_jitdump_register(const char *name, const void *start, size_t size);
void ir_perf_map_register(const char *name, const void *start, size_t size);
/* GDB JIT interface (implementation in ir_gdb.c) */
int ir_gdb_register(const char *name,
const void *start,
size_t size,
uint32_t sp_offset,
uint32_t sp_adjustment);
void ir_gdb_unregister_all(void);
bool ir_gdb_present(void);
/* IR load API (implementation in ir_load.c) */
struct _ir_loader {
uint32_t default_func_flags;
bool (*init_module) (ir_loader *loader, const char *name, const char *filename, const char *target);
bool (*external_sym_dcl) (ir_loader *loader, const char *name, uint32_t flags);
bool (*external_func_dcl) (ir_loader *loader, const char *name,
uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
bool (*forward_func_dcl) (ir_loader *loader, const char *name,
uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types);
bool (*sym_dcl) (ir_loader *loader, const char *name, uint32_t flags, size_t size);
bool (*sym_data) (ir_loader *loader, ir_type type, uint32_t count, const void *data);
bool (*sym_data_str) (ir_loader *loader, const char *str, size_t len);
bool (*sym_data_pad) (ir_loader *loader, size_t offset);
bool (*sym_data_ref) (ir_loader *loader, ir_op op, const char *ref, uintptr_t offset);
bool (*sym_data_end) (ir_loader *loader, uint32_t flags);
bool (*func_init) (ir_loader *loader, ir_ctx *ctx, const char *name);
bool (*func_process) (ir_loader *loader, ir_ctx *ctx, const char *name);
void*(*resolve_sym_name) (ir_loader *loader, const char *name, bool add_thunk);
bool (*has_sym) (ir_loader *loader, const char *name);
bool (*add_sym) (ir_loader *loader, const char *name, void *addr);
};
void ir_loader_init(void);
void ir_loader_free(void);
int ir_load(ir_loader *loader, FILE *f);
/* IR LLVM load API (implementation in ir_load_llvm.c) */
int ir_load_llvm_bitcode(ir_loader *loader, const char *filename);
int ir_load_llvm_asm(ir_loader *loader, const char *filename);
/* IR save API (implementation in ir_save.c) */
#define IR_SAVE_CFG (1<<0) /* add info about CFG */
#define IR_SAVE_CFG_MAP (1<<1) /* add info about CFG block assignment */
#define IR_SAVE_USE_LISTS (1<<2) /* add info about def->use lists */
#define IR_SAVE_RULES (1<<3) /* add info about selected code-generation rules */
#define IR_SAVE_REGS (1<<4) /* add info about selected registers */
void ir_print_proto(const ir_ctx *ctx, ir_ref proto, FILE *f);
void ir_save(const ir_ctx *ctx, uint32_t save_flags, FILE *f);
/* IR debug dump API (implementation in ir_dump.c) */
void ir_dump(const ir_ctx *ctx, FILE *f);
void ir_dump_dot(const ir_ctx *ctx, const char *name, FILE *f);
void ir_dump_use_lists(const ir_ctx *ctx, FILE *f);
void ir_dump_cfg(ir_ctx *ctx, FILE *f);
void ir_dump_cfg_map(const ir_ctx *ctx, FILE *f);
void ir_dump_live_ranges(const ir_ctx *ctx, FILE *f);
void ir_dump_codegen(const ir_ctx *ctx, FILE *f);
/* IR to C conversion (implementation in ir_emit_c.c) */
int ir_emit_c(ir_ctx *ctx, const char *name, FILE *f);
void ir_emit_c_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f);
void ir_emit_c_sym_decl(const char *name, uint32_t flags, FILE *f);
/* IR to LLVM conversion (implementation in ir_emit_llvm.c) */
int ir_emit_llvm(ir_ctx *ctx, const char *name, FILE *f);
void ir_emit_llvm_func_decl(const char *name, uint32_t flags, ir_type ret_type, uint32_t params_count, const uint8_t *param_types, FILE *f);
void ir_emit_llvm_sym_decl(const char *name, uint32_t flags, FILE *f);
/* IR verification API (implementation in ir_check.c) */
bool ir_check(const ir_ctx *ctx);
void ir_consistency_check(void);
/* Code patching (implementation in ir_patch.c) */
int ir_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr);
/* CPU information (implementation in ir_cpuinfo.c) */
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
# define IR_X86_SSE2 (1<<0)
# define IR_X86_SSE3 (1<<1)
# define IR_X86_SSSE3 (1<<2)
# define IR_X86_SSE41 (1<<3)
# define IR_X86_SSE42 (1<<4)
# define IR_X86_AVX (1<<5)
# define IR_X86_AVX2 (1<<6)
# define IR_X86_BMI1 (1<<7)
# define IR_X86_CLDEMOTE (1<<8)
#endif
uint32_t ir_cpuinfo(void);
/* Deoptimization helpers */
const void *ir_emit_exitgroup(uint32_t first_exit_point, uint32_t exit_points_per_group, const void *exit_addr, ir_code_buffer *code_buffer, size_t *size_ptr);
/* A reference IR JIT compiler */
IR_ALWAYS_INLINE void *ir_jit_compile(ir_ctx *ctx, int opt_level, size_t *size)
{
if (opt_level == 0) {
if (ctx->flags & IR_OPT_FOLDING) {
// IR_ASSERT(0 && "IR_OPT_FOLDING is incompatible with -O0");
return NULL;
}
ctx->flags &= ~(IR_OPT_CFG | IR_OPT_CODEGEN);
ir_build_def_use_lists(ctx);
if (!ir_build_cfg(ctx)
|| !ir_match(ctx)
|| !ir_assign_virtual_registers(ctx)
|| !ir_compute_dessa_moves(ctx)) {
return NULL;
}
return ir_emit_code(ctx, size);
} else if (opt_level == 1 || opt_level == 2) {
if (!(ctx->flags & IR_OPT_FOLDING)) {
// IR_ASSERT(0 && "IR_OPT_FOLDING must be set in ir_init() for -O1 and -O2");
return NULL;
}
ctx->flags |= IR_OPT_CFG | IR_OPT_CODEGEN;
ir_build_def_use_lists(ctx);
if (opt_level == 2
&& !ir_sccp(ctx)) {
return NULL;
}
if (!ir_build_cfg(ctx)
|| !ir_build_dominators_tree(ctx)
|| !ir_find_loops(ctx)
|| !ir_gcm(ctx)
|| !ir_schedule(ctx)
|| !ir_match(ctx)
|| !ir_assign_virtual_registers(ctx)
|| !ir_compute_live_ranges(ctx)
|| !ir_coalesce(ctx)
|| !ir_reg_alloc(ctx)
|| !ir_schedule_blocks(ctx)) {
return NULL;
}
return ir_emit_code(ctx, size);
} else {
// IR_ASSERT(0 && "wrong optimization level");
return NULL;
}
}
#define IR_ERROR_CODE_MEM_OVERFLOW 1
#define IR_ERROR_FIXED_STACK_FRAME_OVERFLOW 2
#define IR_ERROR_UNSUPPORTED_CODE_RULE 3
#define IR_ERROR_LINK 4
#define IR_ERROR_ENCODE 5
/* IR Memmory Allocation */
#ifndef ir_mem_malloc
# define ir_mem_malloc malloc
#endif
#ifndef ir_mem_calloc
# define ir_mem_calloc calloc
#endif
#ifndef ir_mem_realloc
# define ir_mem_realloc realloc
#endif
#ifndef ir_mem_free
# define ir_mem_free free
#endif
#ifndef ir_mem_pmalloc
# define ir_mem_pmalloc malloc
#endif
#ifndef ir_mem_pcalloc
# define ir_mem_pcalloc calloc
#endif
#ifndef ir_mem_prealloc
# define ir_mem_prealloc realloc
#endif
#ifndef ir_mem_pfree
# define ir_mem_pfree free
#endif
void *ir_mem_mmap(size_t size);
int ir_mem_unmap(void *ptr, size_t size);
int ir_mem_protect(void *ptr, size_t size);
int ir_mem_unprotect(void *ptr, size_t size);